:root{
  /* The app is dark by default. color-scheme is a real property, not a token,
     and it is what makes the Log tab's native date picker, the scrollbars and
     the form-control chrome match the palette instead of the browser default. */
  color-scheme:dark;

  /* ------------------------------------------------------------------
     Palette tokens — TURQUOISE & TACK. Every colour in this file resolves
     to one of these, so a re-theme is a change to this block and nothing
     else. Semantic role first, hue second: `--accent` is "the app's one
     loud colour", not "turquoise".

     The theme is the gear: oiled saddle leather for ground, cream stitching
     for type, brass for hardware, and a stone turquoise for the one thing
     asking for attention. It also inverts the usual convention on purpose —

         turquoise = your turn    brass = you own this    dust = not yet

     — which is what the numbers wanted: ready-vs-learned is the pair the Tree
     tab actually asks you to compare, and turquoise against brass separates it
     by ΔE 70 under simulated colour blindness, against 35.2 for the
     amber-on-slate this replaced. The original argument also leaned on
     gold-for-earned reading well in an app with a Cup in it. The Cup has since
     been removed; the separation measurement is what still holds it up.

     The alternatives, including that predecessor, live in palettes.css.
     ------------------------------------------------------------------ */

  /* ground: four steps of elevation, darkest to lightest. Saddle, not soot —
     there is red in this brown, and the surfaces stay near-black so they read
     as leather rather than as a brown filter over a grey app. */
  --bg:#180f07;
  --surface:#2a1c10;
  --surface-2:#382614;
  --sunk:#1c1209;            /* recessed wells: the graph canvas */
  --void:#0d0805;            /* video letterbox */

  --line:#4a3419;
  /* --line-bright draws input/button/checkbox boundaries, so it has to clear
     3:1 against both card surfaces (WCAG 1.4.11) — and because it draws every
     control, it is the largest run of colour in the app after the ground,
     larger than the accent, which only shows up where there is state. Making
     it brass rather than tan is what carries the theme's character. */
  --line-bright:#b08f52;

  --text:#fdf6e6;
  --text-dim:#d2bc97;
  /* --text-faint carries real data (coverage %, tiers, counts) at small sizes
     on both --surface and --surface-2, so it is held to 4.5:1 on the lighter
     of the two rather than to the ground. */
  --text-faint:#bda27c;

  /* --locked is the graph's third state and has its own token on purpose:
     "de-emphasised text" and "you cannot do this yet" are different jobs, and
     at fit zoom the node colour is the only channel left. Sun-faded dust, held
     just above the 4.5:1 floor rather than well above it, because locked
     should recede. It is the one state colour a warm palette cannot hold cool
     — a cool slate here collides with the turquoise under deuteranopia. */
  --locked:#8d8d76;

  /* accent — the one loud colour. Progress, focus, "your turn". Stone rather
     than brand teal: Kingman turquoise leans green, and the green is what
     stops it reading as a dashboard accent. A bandana red was the first idea
     and is not possible — --accent carries small text (eyebrows, the streak,
     coverage percentages) and red tops out near 4:1 on a dark ground before
     it turns pink. */
  --accent:#3fc9c2;
  --accent-dim:#0e5f61;      /* filled chip/tag ground */
  --accent-well:#06211f;     /* faintest accent ground, behind body text */
  --accent-ink:#04191a;      /* text and glyphs ON an accent fill */
  --accent-deep:#0d3b3d;     /* secondary text on an accent fill */
  --accent-text:#86e0da;     /* accent AS text, on dark grounds */
  --accent-pale:#c9f2ee;     /* accent as text on --accent-dim */

  /* good — learned, credited, passed. Marigold brass: the trophy metal. */
  --good:#f0b43c;
  --good-line:#8a651a;
  --good-well:#2e2008;
  --good-ink:#1a1203;
  --good-text:#f7d68b;

  /* bad — errors, destructive actions, the over-drilled dance. Chile red.
     It has to separate from the accent, not from the marigold — the Log tab's
     frequency bars pair accent bars against one bad bar, and that is the
     only place either colour is read against the other. */
  --bad:#ef6a62;
  /* --bad-line is the boundary of the "Erase all data" button, so it is a
     control boundary and owes 3:1 (1.4.11). The predecessor's #6b3a34
     measured 1.81:1 — the border on the one irreversible button in the app
     was effectively invisible. */
  --bad-line:#d15454;

  /* Two step-sheet provenance flags, distinct from accent and from good. They
     carry no state, which makes them the one place the palette can be loud for
     free: nopal green and rodeo violet, off a rhinestone suit. */
  --warn-well:#1d2a12; --warn-line:#4e6b2a; --warn-text:#a8cf6b;
  --flag-well:#251a30; --flag-line:#65508a; --flag-text:#cdaef0;

  --shadow:rgba(24,12,0,.7);

  /* Strength of the state tint behind a graph node, in two bands, because the
     two zoom levels want opposite things. At reading zoom a LABEL sits on the
     fill, so the fill must stay light. At fit zoom the labels are dropped and
     the fill is the only channel left, so it wants all the saturation it can
     get. Over a dark ground one value serves both; over a light one it cannot,
     and a light palette raises --tint-lod alone. */
  --tint:22%;
  --tint-lod:26%;


  /* ==================================================================
     SCALES — the non-colour half of the system.

     Each scale was derived from a census of what this stylesheet already
     used, not from a ratio picked in advance: the steps land on the values
     the app leaned on hardest, so the commonest sizes did not move when the
     rules were migrated onto them and the outliers snapped by at most 0.1rem.
     That is the whole trick to retrofitting a scale onto a design that was
     hand-tuned first — fit the scale to the design, then let the scale hold
     the line from there on.
     ================================================================== */

  /* type — 9 steps. .7 / .85 / .95 were the three most-used sizes (10, 13 and
     8 rules) and are exact. Anything smaller than --fs-2xs is not a size, it
     is an accident. */
  --fs-2xs:.7rem;      /* eyebrows, tags, table headers, unit labels */
  --fs-xs:.8rem;       /* dense data, captions, help text */
  --fs-sm:.85rem;      /* secondary body, table cells, button labels */
  --fs-md:.95rem;      /* body */
  --fs-lg:1.05rem;     /* h3, lead-in, big-ish numbers */
  --fs-xl:1.2rem;      /* segment name */
  --fs-2xl:1.4rem;     /* bpm field */
  --fs-3xl:1.55rem;    /* h2, stat figures */
  --fs-4xl:2rem;       /* top of the scale; unused since the Cup total went */
  --fs-display:clamp(3rem,17vw,5rem);   /* the beat counter, and nothing else */
  --fs-display-sm:4rem;                 /* …once there is room beside it */

  /* space — tenths of a rem up to 1, then 2. Ten steps looks like a lot until
     you try nine: this stylesheet was hand-tuned at 0.05rem granularity, and a
     tidier x1.5 run collapses .5/.55/.6/.65 into one step and grows the app
     about 5% taller down the page. A second attempt still snapped .hbar's
     .7rem padding up to .8 — which moved the header, and therefore every
     screen, by a tenth of a rem.

     So the scale is fitted to the design rather than the other way round. The
     rule is easy to hold: spacing is a tenth of a rem, and if you want
     something between two steps you are looking at a rounding error rather
     than a design decision. Nothing snaps by more than .05rem except three
     one-off declarations above 1rem. */
  --s-1:.1rem;
  --s-2:.2rem;
  --s-3:.3rem;
  --s-4:.4rem;
  --s-5:.5rem;
  --s-6:.6rem;
  --s-7:.7rem;
  --s-8:.8rem;
  --s-9:1rem;
  --s-10:2rem;

  /* radius — --r is the default and everything else is a deliberate exception:
     -xs for a hairline chip, -pill for a track, -round for a knob. */
  --r-xs:2px;
  --r-sm:3px;
  --r:6px;
  --r-lg:8px;
  --r-pill:99px;
  --r-round:50%;

  /* brogue — the perforation motif, in the units a punch actually has.

     Brogueing is a row of holes punched through leather along a seam. Two
     things make it read as leather rather than as a dotted border, and both
     were found by rendering rather than by reasoning:

     1. The sizes have to ALTERNATE. A single row of even dots is a dashed
        border, full stop — 3px against 2px was indistinguishable at arm's
        length. 5px against 2px reads as brogueing. It costs one extra
        background layer, offset by half the pitch so the small holes fall
        between the large ones.

     2. --punch-ink is not a colour, it is a shadow — a translucent wash of
        --void over whatever the ornament sits on, so one value covers every
        palette without knowing the ground.

     …with one exception, which is real rather than a fudge. Over dark leather
     a shadow has almost nowhere to go, and a punched hole in a dark hide is
     visible in life because of the BURNISHED RIM where the punch compressed
     and lightened the edge. So dark palettes get a rim and light ones do not,
     which is the same split palettes.css already makes for --tint-lod: a wash
     behaves differently over paper than over black. The rim is drawn in
     --line-bright, the palette's hardware colour, so brass leather gets
     brass-rimmed holes and the blue-black hall gets steel. */
  --punch:5px;         /* the main hole */
  --punch-sm:3px;      /* the flanking hole, centred between two large ones —
                          3px not 2px because the rim needs a pixel to live in,
                          and at 2px the small holes disappeared on dark
                          leather and took the alternation with them */
  --punch-gap:12px;    /* centre to centre, large to small */
  --punch-inset:7px;   /* how far the run sits in from the edge it follows */
  --punch-off:calc((var(--punch) - var(--punch-sm))/2);  /* small-hole centring */
  --punch-ink:color-mix(in srgb,var(--void) 75%,transparent);
  --punch-rim:color-mix(in srgb,var(--line-bright) 55%,transparent);

  /* One hole: ink to 52%, then the burnished rim out to 92%. Where a palette
     wants no rim it points --punch-rim at --punch-ink, which collapses the
     two stops into a plain punch. The 92% rather than 100% is antialiasing —
     a hard edge on a 5px circle shimmers.

     The stops are a token of their own because the seam and the card edge
     draw the same hole but have to place it differently inside its tile, and
     the colours must not drift apart between them. */
  --punch-stops:var(--punch-ink) 52%,var(--punch-rim) 60% 92%,transparent;
  --punch-hole:radial-gradient(circle closest-side,var(--punch-stops));

  /* motion — --t-tick is for things that must not look animated at all (the
     beat lamp at 180bpm gets 333ms between hits, so its transition has to be
     an order of magnitude shorter). All of it is switched off wholesale by the
     prefers-reduced-motion block at the end of this file. */
  --t-tick:.05s;
  --t-fast:.13s;
  --t-base:.2s;
  --t-slow:.9s;

  /* control heights — the floor is --ctl-lg (48px), which is the smallest
     comfortable touch target; --ctl-xs and -sm are for controls that sit in a
     row of their own and are never the primary action on a screen. This app is
     used with a phone on the floor and a foot's worth of distance, so the
     bias is deliberately toward the large end. */
  --ctl-xs:34px;
  --ctl-sm:38px;
  --ctl-md:44px;
  --ctl-lg:48px;
  --ctl-xl:52px;

  /* stacking — five layers, named for what lives there, so a new overlay does
     not have to guess a number. */
  --z-raise:2;      /* nav edge fades, graph controls */
  --z-float:3;      /* the nav paging chevrons, above those fades */
  --z-header:50;    /* the sticky header */
  --z-skip:100;     /* the skip link, above the header it skips */
  --z-toast:200;    /* the credit toast, above everything */

  --fs-base:17px;
}

*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
/* One guard for the whole app: an element with [hidden] is hidden, whatever
   display its own class sets. Without this, any rule with display:flex/grid
   silently defeats element.hidden = true. */
[hidden]{display:none!important}
html{-webkit-text-size-adjust:100%}
body{
  background:var(--bg);color:var(--text);
  font:var(--fs-base)/1.55 ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  font-variant-numeric:tabular-nums;
  padding-bottom:5rem;
  overflow-x:hidden;
}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}

.sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.skiplink{position:absolute;left:.5rem;top:-3rem;z-index:var(--z-skip);background:var(--accent);
  color:var(--accent-ink);font-weight:700;padding:.55rem .9rem;border-radius:var(--r);transition:top .15s}
.skiplink:focus{top:.5rem}

/* ---- header ---- */
header{
  position:sticky;top:0;z-index:var(--z-header);background:color-mix(in srgb,var(--bg) 96%,transparent);
  border-bottom:1px solid var(--line);backdrop-filter:blur(8px);
}
.hbar{display:flex;align-items:center;gap:var(--s-7);padding:var(--s-7) var(--s-9) .55rem}
.hbar svg{flex:0 0 auto;color:var(--accent)}
.htitle{font-size:var(--fs-md);font-weight:700;letter-spacing:.02em;line-height:1.15;min-width:0}
.htitle span{display:block;font-size:var(--fs-2xs);font-weight:500;letter-spacing:.1em;
  text-transform:uppercase;color:var(--text-faint);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.hstreak{margin-left:auto;text-align:right;font-size:var(--fs-2xs);letter-spacing:.08em;
  text-transform:uppercase;color:var(--text-faint);white-space:nowrap}
.hstreak b{display:block;font-size:1.15rem;color:var(--accent);letter-spacing:0}

/* ---- tab strip ----
   Eight tabs overflow a phone. The strip scrolls, so it needs affordances that
   say so: edge fades whenever there is more in that direction, paging chevrons,
   and the selected tab scrolled into view on every change. */
.navwrap{position:relative;border-top:1px solid var(--line)}
.navwrap::before,.navwrap::after{
  content:"";position:absolute;top:0;bottom:0;width:2.6rem;z-index:var(--z-raise);
  pointer-events:none;opacity:0;transition:opacity .18s linear}
.navwrap::before{left:0;background:linear-gradient(90deg,var(--bg) 25%,transparent)}
.navwrap::after{right:0;background:linear-gradient(270deg,var(--bg) 25%,transparent)}
.navwrap.can-l::before,.navwrap.can-r::after{opacity:1}
nav{display:flex;overflow-x:auto;scrollbar-width:none;scroll-behavior:smooth}
nav::-webkit-scrollbar{display:none}
nav button{
  flex:1 0 auto;min-height:var(--ctl-xl);padding:var(--s-6) var(--s-9);background:none;border:0;
  border-bottom:3px solid transparent;color:var(--text-dim);font:inherit;font-size:.9rem;
  font-weight:600;letter-spacing:.03em;cursor:pointer;white-space:nowrap;
}
nav button[aria-selected="true"]{color:var(--text);border-bottom-color:var(--accent)}
.navpage{
  position:absolute;top:0;bottom:3px;z-index:var(--z-float);width:2.1rem;padding:0;
  background:none;border:0;color:var(--text);font-size:1.5rem;line-height:1;
  cursor:pointer;display:grid;place-items:center}
.navpage.prev{left:0}
.navpage.next{right:0}
.navpage:active{color:var(--accent)}

main{max-width:920px;margin:0 auto;padding:var(--s-9)}
.panel[hidden]{display:none}
.panel:focus{outline:none}

/* ---- primitives ---- */
/* The padding carries the punched edge as well as the content: the run sits
   --punch-inset in from the border and is --punch tall, so the content has to
   start clear of both or the text reads as if it is sitting on the holes. */
.card{background:var(--surface);border:1px solid var(--line);border-radius:var(--r);
  padding:calc(var(--s-9) + var(--punch-inset));margin-bottom:var(--s-9)}

/* A card is a panel of leather, so its edge is punched the way a seam is: a
   run of holes set in from the border, alternating large and small. Drawn on
   pseudo-elements rather than on the card itself so it cannot collide with a
   card that sets its own background.

   Four layers per element: ::before runs along the top and bottom, ::after
   down the left and right, each drawing both hole sizes.

   Both sizes come out of ONE tile — a large hole a quarter of the way along
   it and a small one three quarters — rather than from two runs offset half
   a pitch from each other. That is the whole trick, and it is worth saying
   why, because offsetting is the obvious way to interleave and it does not
   survive contact with a card of arbitrary width.

   Every run repeats with `round`, which rescales the tile so a whole number
   fits. Tile boundaries then land exactly on the ends of the run, so the
   repetition that spills past the end is cut between holes rather than
   through one — and each hole sits a quarter tile clear of the cut anyway.
   Offsetting a second run breaks precisely that: the offset walks one of its
   holes onto the end of the area, where it renders as a sliced half-hole in
   the corner. Two holes in one tile keeps every layer at phase zero, so the
   guarantee holds at any size, and the alternation is exact by construction
   rather than by arithmetic that has to come out right.

   The run is then held half a pitch clear of the corner by padding, with
   background-origin AND background-clip both content-box so the repetition
   is cut there too. Clipping to the content box is safe only because the
   padding is on one axis: across the run the content box still reaches the
   card edge, so the band itself is not clipped away. It is also why the two
   axes need separate elements — they inset on opposite axes.

   The corner is left unpunched, a pitch clear on both sides, which is how a
   run of punches meets another on a boot: it stops short, and the corner is
   plain leather. */
.card{position:relative}
.card::before,.card::after{
  content:"";position:absolute;inset:var(--punch-inset);pointer-events:none;
  background-origin:content-box;background-clip:content-box;
}
/* top and bottom. --punch-off is the 1px that centres the small hole on the
   large one's row: both tiles are anchored to the same edge, but the small
   tile is 2px shorter. */
.card::before{
  padding:0 calc(var(--punch-gap)/2);
  background-repeat:round no-repeat;
  background-position:
    left 0 top 0,   left 0 top var(--punch-off),
    left 0 bottom 0,left 0 bottom var(--punch-off);
  background-size:
    calc(var(--punch-gap)*2) var(--punch),   calc(var(--punch-gap)*2) var(--punch-sm),
    calc(var(--punch-gap)*2) var(--punch),   calc(var(--punch-gap)*2) var(--punch-sm);
  background-image:
    radial-gradient(circle closest-side at 25% 50%,var(--punch-stops)),
    radial-gradient(circle closest-side at 75% 50%,var(--punch-stops)),
    radial-gradient(circle closest-side at 25% 50%,var(--punch-stops)),
    radial-gradient(circle closest-side at 75% 50%,var(--punch-stops));
}
/* left and right */
.card::after{
  padding:calc(var(--punch-gap)/2) 0;
  background-repeat:no-repeat round;
  background-position:
    left 0 top 0,                 left var(--punch-off) top 0,
    right 0 top 0,                right var(--punch-off) top 0;
  background-size:
    var(--punch) calc(var(--punch-gap)*2),   var(--punch-sm) calc(var(--punch-gap)*2),
    var(--punch) calc(var(--punch-gap)*2),   var(--punch-sm) calc(var(--punch-gap)*2);
  background-image:
    radial-gradient(circle closest-side at 50% 25%,var(--punch-stops)),
    radial-gradient(circle closest-side at 50% 75%,var(--punch-stops)),
    radial-gradient(circle closest-side at 50% 25%,var(--punch-stops)),
    radial-gradient(circle closest-side at 50% 75%,var(--punch-stops));
}
h2{font-size:1.5rem;line-height:1.15;letter-spacing:-.01em;margin-bottom:.15rem}
h3{font-size:var(--fs-lg);letter-spacing:.01em;margin-bottom:var(--s-5)}
.eyebrow{font-size:.72rem;letter-spacing:.15em;text-transform:uppercase;
  color:var(--accent);font-weight:700;margin-bottom:var(--s-3)}
.sub{color:var(--text-dim);font-size:var(--fs-md)}
p+p{margin-top:var(--s-6)}
a{color:var(--accent);text-underline-offset:3px}
ul,ol{padding-left:1.2rem}
li{margin:.35rem 0}
/* ---- brogue ----
   A punched seam. `hr` is the one place in the app that was already saying
   "these two things are different" with nothing but a hairline, so it is the
   one place the ornament replaces something rather than adding to it. The
   class exists so the next seam does not have to be an `hr` to get one.

   Two repeating layers on one element: large holes at twice the pitch, small
   holes at twice the pitch offset by one pitch, so they interleave. The hole
   itself is --punch-hole, shared with the card edge. */
.brogue,hr{
  border:0;height:var(--punch);
  background-repeat:repeat-x;
  background-position:0 center,var(--punch-gap) center;
  background-image:var(--punch-hole),var(--punch-hole);
  background-size:
    calc(var(--punch-gap)*2) var(--punch),
    calc(var(--punch-gap)*2) var(--punch-sm);
}
hr{margin:var(--s-9) 0}

/* Ornament is the first thing to go when the user has asked for plain
   contrast: a translucent wash means nothing in a forced palette, and a
   divider that vanishes is worse than a plain one. */
@media (forced-colors:active){
  .brogue,hr{background:none;height:0;border-top:1px solid}
  .card::before,.card::after{display:none}
}

/* collapsible explainer, so a tab opens on its controls not on a lecture */
details.explain summary{list-style:none;cursor:pointer;display:flex;flex-wrap:wrap;
  align-items:baseline;gap:var(--s-5)}
details.explain summary::-webkit-details-marker{display:none}
details.explain summary .eyebrow{margin-bottom:0}
details.explain summary .sub{font-size:var(--fs-sm);color:var(--text-faint)}
details.explain summary::after{content:"show";margin-left:auto;font-size:.72rem;
  letter-spacing:.12em;text-transform:uppercase;color:var(--text-faint);font-weight:700}
details.explain[open] summary::after{content:"hide"}
details.explain summary:focus-visible{outline:2px solid var(--accent);outline-offset:3px}
/* .inline sits inside a card that has other content below it */
details.explain.inline{margin-bottom:var(--s-2)}

.meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:var(--s-6);margin:.9rem 0}
.meta div{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r);padding:.55rem var(--s-7)}
.meta dt{font-size:var(--fs-2xs);letter-spacing:.13em;text-transform:uppercase;color:var(--text-faint)}
.meta dd{font-size:var(--fs-md);font-weight:600;margin-top:.15rem}

.ladder{display:flex;flex-wrap:wrap;gap:var(--s-4);margin-top:.15rem}
.rung{background:var(--surface-2);border:1px solid var(--line-bright);border-radius:var(--r-pill);
  padding:.25rem var(--s-7);font-size:var(--fs-sm);font-weight:600}

.callout{border-left:3px solid var(--accent);background:var(--surface-2);
  padding:var(--s-7) .9rem;border-radius:0 var(--r) var(--r) 0;color:var(--text-dim);font-size:.93rem}
.callout b{color:var(--text)}

/* ---- buttons ---- */
button,select,input,textarea{font:inherit;color:var(--text)}
.btn{min-height:var(--ctl-lg);padding:var(--s-6) 1.1rem;background:var(--surface-2);
  border:1px solid var(--line-bright);border-radius:var(--r);font-weight:600;cursor:pointer;
  letter-spacing:.02em}
.btn:active{transform:translateY(1px)}
.btn.primary{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}
.btn.on{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}
.btn.sm{min-height:var(--ctl-sm);padding:.35rem var(--s-7);font-size:var(--fs-sm)}
.btn.danger{color:var(--bad);border-color:var(--bad-line)}
.btn.flash{animation:flash var(--t-slow) ease-out}
@keyframes flash{0%{background:var(--good);border-color:var(--good);color:var(--good-ink)}
  100%{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}}
.row{display:flex;flex-wrap:wrap;gap:var(--s-5)}

input[type=number],input[type=text],input[type=date],select,textarea{
  width:100%;min-height:var(--ctl-lg);padding:.55rem var(--s-7);background:var(--surface-2);
  border:1px solid var(--line-bright);border-radius:var(--r);appearance:none}
input[readonly]{color:var(--text-dim);border-style:dashed;cursor:default}
textarea{min-height:76px;resize:vertical}
input:focus-visible,select:focus-visible,textarea:focus-visible,button:focus-visible,
[role=tab]:focus-visible,summary:focus-visible,label:focus-within{
  outline:2px solid var(--accent);outline-offset:2px}
label.fld{display:block;margin-bottom:var(--s-7)}
label.fld span{display:block;font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;
  color:var(--text-faint);margin-bottom:.25rem}

/* ---- checklist ---- */
.check{display:flex;gap:var(--s-7);align-items:flex-start;padding:var(--s-7);min-height:var(--ctl-xl);
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r);
  margin-bottom:var(--s-5);cursor:pointer}
.check input{appearance:none;flex:0 0 26px;width:26px;height:26px;margin-top:1px;
  border:2px solid var(--line-bright);border-radius:4px;background:transparent;cursor:pointer}
.check input:checked{background:var(--accent);border-color:var(--accent)}
.check input:checked::after{content:"";display:block;width:7px;height:13px;margin:1px auto 0;
  border:solid var(--accent-ink);border-width:0 3px 3px 0;transform:rotate(42deg)}
.check input:checked+span{color:var(--text-faint);text-decoration:line-through}
.check span{font-size:var(--fs-md)}

/* ---- video ---- */
.vid{margin-bottom:var(--s-9);border:1px solid var(--line);border-radius:var(--r);overflow:hidden;
  background:var(--surface-2)}
.vframe{position:relative;width:100%;aspect-ratio:16/9;background:var(--void)}
.vframe iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
/* Facade: nothing is requested from YouTube until the user asks for the video. */
.vfacade{position:absolute;inset:0;width:100%;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:var(--s-5);cursor:pointer;
  background:radial-gradient(circle at 50% 45%,var(--surface-2),var(--bg) 70%);
  border:0;color:var(--text-dim);font:inherit;text-align:center;padding:var(--s-9)}
.vfacade:hover,.vfacade:focus-visible{color:var(--text)}
.vfacade .play{width:56px;height:56px;border-radius:var(--r-round);border:2px solid var(--accent);
  display:grid;place-items:center;flex:0 0 auto}
.vfacade .play::after{content:"";width:0;height:0;margin-left:4px;
  border-left:16px solid var(--accent);border-top:10px solid transparent;
  border-bottom:10px solid transparent}
.vfacade small{font-size:.75rem;color:var(--text-faint);letter-spacing:.06em;text-transform:uppercase}
.vmeta{padding:var(--s-6) .75rem}
.vmeta h4{font-size:var(--fs-md);line-height:1.3}
.vmeta p{font-size:var(--fs-sm);color:var(--text-dim);margin-top:var(--s-3)}
.tags{display:flex;flex-wrap:wrap;gap:.35rem;margin-top:var(--s-4)}
.tag{font-size:var(--fs-2xs);letter-spacing:.09em;text-transform:uppercase;font-weight:700;
  padding:var(--s-2) var(--s-5);border-radius:var(--r-sm);border:1px solid var(--line-bright);color:var(--text-dim)}
.tag.back-view{background:var(--good-well);border-color:var(--good-line);color:var(--good-text)}
.tag.partial{background:var(--warn-well);border-color:var(--warn-line);color:var(--warn-text)}
.tag.unconfirmed{background:var(--flag-well);border-color:var(--flag-line);color:var(--flag-text)}
.tag.target{background:var(--accent-dim);border-color:var(--accent);color:var(--accent-pale)}
.tag.deep{background:var(--surface);border-color:var(--line-bright);color:var(--text-dim)}

/* ---- metronome ---- */
.metrogrid{display:grid;gap:var(--s-9);align-items:start}
.pulse{margin:var(--s-2) 0 .9rem}
.beats{display:grid;grid-template-columns:repeat(8,1fr);gap:.35rem;margin:.9rem auto 0;
  max-width:29rem}
.beat{aspect-ratio:1;display:grid;place-items:center;border-radius:var(--r);
  background:var(--surface-2);border:1px solid var(--line);font-weight:700;font-size:var(--fs-lg);
  color:var(--text-faint);transition:background var(--t-tick) linear,color var(--t-tick) linear}
.beat.dn{border-color:var(--line-bright)}
.beat.hit{background:var(--text-dim);color:var(--bg);border-color:var(--text-dim)}
.beat.hit.dn{background:var(--accent);color:var(--accent-ink);border-color:var(--accent)}
.bignum{font-size:var(--fs-display);line-height:1;font-weight:800;letter-spacing:-.03em;
  text-align:center;font-variant-numeric:tabular-nums}
.bignum.dn{color:var(--accent)}
.bignum.idle{color:var(--text-faint);opacity:.5}
.bpmwrap{display:flex;align-items:center;gap:var(--s-5)}
.bpmwrap input{text-align:center;font-size:var(--fs-2xl);font-weight:700}
.bpmwrap .btn{flex:0 0 56px;font-size:var(--fs-2xl);padding:0}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:var(--s-5)}
.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s-5)}
.presets{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:var(--s-5)}
.presets .btn{display:flex;flex-direction:column;align-items:flex-start;gap:var(--s-1);text-align:left;
  font-size:var(--fs-sm);line-height:1.25}
.presets .btn em{font-style:normal;font-size:.72rem;color:var(--text-faint);font-weight:500}
.presets .btn.on em{color:var(--accent-deep)}
.effbpm{text-align:center;color:var(--text-dim);font-size:.9rem;margin-top:var(--s-5)}
.effbpm b{color:var(--text);font-size:var(--fs-lg)}
@media (min-width:880px){
  .metrogrid{grid-template-columns:1.15fr .85fr}
  .metrogrid .card{margin-bottom:0}
  .beats{max-width:24rem}
  .bignum{font-size:var(--fs-display-sm)}
}

/* ---- timer ---- */
.seg{display:flex;align-items:center;gap:var(--s-6);padding:var(--s-6) var(--s-7);border-radius:var(--r);
  border:1px solid var(--line);background:var(--surface-2);margin-bottom:var(--s-4);
  width:100%;text-align:left;cursor:pointer;font:inherit;color:var(--text)}
.seg.active{border-color:var(--accent);background:var(--accent-well)}
.seg.done{opacity:.55}
.seg b{flex:0 0 auto;min-width:5.6rem;font-size:var(--fs-md)}
.seg small{color:var(--text-dim);font-size:.82rem;line-height:1.3}
.seg .sd{margin-left:auto;flex:0 0 auto;font-weight:700;font-variant-numeric:tabular-nums}
.bar{height:8px;background:var(--surface-2);border-radius:var(--r-pill);overflow:hidden;margin:var(--s-6) 0}
.bar i{display:block;height:100%;background:var(--accent);transition:width .25s linear}
.segname{font-size:var(--fs-xl);font-weight:700;text-align:center;letter-spacing:.02em}
.segwhat{text-align:center;color:var(--text-dim);font-size:.9rem;min-height:2.5em;margin-top:var(--s-3)}
.keepawake{font-size:var(--fs-xs);color:var(--text-faint);text-align:center;margin-top:var(--s-6)}

/* ---- tables ---- */
.tw{overflow-x:auto;-webkit-overflow-scrolling:touch;margin:0 -1rem;padding:0 var(--s-9)}
table{border-collapse:collapse;width:100%;font-size:.88rem;min-width:540px}
th,td{text-align:left;padding:var(--s-5) .55rem;border-bottom:1px solid var(--line);vertical-align:top}
th{font-size:var(--fs-2xs);letter-spacing:.1em;text-transform:uppercase;color:var(--text-faint);
  font-weight:700;position:sticky;top:0;background:var(--surface)}
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums;white-space:nowrap}
tbody tr:hover{background:var(--surface-2)}

/* ---- log ---- */
.freq{margin-top:var(--s-4)}
.freq .fr{display:grid;grid-template-columns:5.2rem 1fr 2rem;gap:var(--s-5);align-items:center;
  margin-bottom:var(--s-4);font-size:var(--fs-sm)}
.freq .fb{height:16px;background:var(--surface-2);border-radius:var(--r-sm);overflow:hidden}
.freq .fb i{display:block;height:100%;background:var(--accent);min-width:2px}
.freq .fr b{text-align:right;font-variant-numeric:tabular-nums}
.freq .fr.dom .fb i{background:var(--bad)}
.cleanline{font-size:var(--fs-sm);color:var(--text-faint);margin-top:var(--s-6)}
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:var(--s-4);margin-bottom:var(--s-9)}
.stat{background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r);
  padding:.55rem var(--s-3);text-align:center}
.stat b{display:block;font-size:1.6rem;line-height:1.1;color:var(--accent)}
.stat span{font-size:.72rem;letter-spacing:.05em;text-transform:uppercase;color:var(--text-faint)}
.scrollhint{font-size:.72rem;letter-spacing:.09em;text-transform:uppercase;
  color:var(--text-faint);margin-top:var(--s-4)}
.dots{display:flex;flex-wrap:wrap;gap:3px;margin-top:var(--s-6)}
.dot{width:13px;height:13px;border-radius:var(--r-xs);background:var(--surface-2);border:1px solid var(--line)}
.dot.on{background:var(--accent);border-color:var(--accent)}
.empty{color:var(--text-faint);font-size:.9rem;padding:var(--s-9) 0;text-align:center}
.impstatus{margin-top:var(--s-7);font-size:.88rem}
.impstatus.ok{color:var(--good-text)}
.impstatus.err{color:var(--bad)}

/* ---- week nav ---- */
.wknav{display:flex;gap:var(--s-4);margin-bottom:var(--s-8)}
.wknav .btn{flex:1}
.wknav.wrap{flex-wrap:wrap;gap:.35rem}
.wknav.wrap .btn{flex:0 0 auto;min-width:3.4rem;min-height:40px;padding:var(--s-3) var(--s-5);
  font-size:.82rem;text-align:center;position:relative}
.wknav.wrap .btn.stub{color:var(--text-faint)}
.wknav.wrap .btn.stub.on{color:var(--accent-ink)}
.wknav.wrap .btn.passed{border-color:var(--good)}
.wknav.wrap .btn.today::after{content:"";position:absolute;left:50%;bottom:3px;
  transform:translateX(-50%);width:4px;height:4px;border-radius:var(--r-round);background:var(--accent)}
.wknav.wrap .btn.today.on::after{background:var(--accent-ink)}
/* today / start-date bar on the Weeks tab */
.todaybar{display:flex;flex-wrap:wrap;gap:var(--s-6);align-items:center;
  background:var(--surface-2);border:1px solid var(--line-bright);border-radius:var(--r);
  padding:var(--s-6) .75rem;margin-bottom:var(--s-8);font-size:.9rem}
.todaybar b{color:var(--accent)}
.todaybar .grow{flex:1 1 auto;min-width:9rem}
.todaybar input[type=date]{min-height:40px;max-width:11rem}
.todaybar .btn{min-height:var(--ctl-sm);padding:var(--s-3) var(--s-7);font-size:var(--fs-sm)}

@media (max-width:420px){
  main{padding:.75rem}
  .card{padding:calc(.85rem + var(--punch-inset))}
  .grid4{grid-template-columns:repeat(2,1fr)}
  .beats{gap:.25rem}
  .beat{font-size:.9rem}
  .tw{margin:0 -.85rem;padding:0 .85rem}
  .freq .fr{grid-template-columns:4.6rem 1fr 1.8rem}
}
@media (prefers-reduced-motion:reduce){
  *{transition:none!important;animation:none!important}
  nav{scroll-behavior:auto}
}

/* ---- moves roster ---- */
.learnbar{margin-top:.9rem}
.lcount{display:flex;align-items:baseline;gap:.45rem}
.lcount b{font-size:1.6rem;font-weight:800;color:var(--accent);letter-spacing:-.01em}
.lcount span{font-size:var(--fs-2xs);letter-spacing:.12em;text-transform:uppercase;color:var(--text-faint)}
.mvbreak{font-size:var(--fs-sm);color:var(--text-faint);margin-top:var(--s-1)}
.chips{display:flex;flex-wrap:wrap;gap:.35rem}
.chip{padding:var(--s-3) .65rem;min-height:var(--ctl-xs);border-radius:var(--r-pill);background:var(--surface-2);
  border:1px solid var(--line-bright);color:var(--text-dim);font:inherit;font-size:var(--fs-xs);
  font-weight:600;cursor:pointer;letter-spacing:.02em}
.chip.on{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}
.mv{display:flex;gap:.65rem;align-items:flex-start;padding:var(--s-6) .65rem;border:1px solid var(--line);
  border-radius:var(--r);background:var(--surface-2);margin-bottom:var(--s-4)}
.mv input{appearance:none;flex:0 0 24px;width:24px;height:24px;margin-top:.15rem;
  border:2px solid var(--line-bright);border-radius:4px;background:transparent;cursor:pointer}
.mv input:checked{background:var(--good);border-color:var(--good)}
.mv input:checked::after{content:"";display:block;width:6px;height:12px;margin:0 auto;
  border:solid var(--good-ink);border-width:0 3px 3px 0;transform:rotate(42deg)}
.mv.done{opacity:.72}
.mv.done .mvname{text-decoration:line-through}
.mvbody{flex:1;min-width:0}
.mvname{font-size:var(--fs-md);font-weight:600;line-height:1.25}
.mvtags{display:flex;flex-wrap:wrap;gap:var(--s-3);margin-top:var(--s-3)}
.mvpre{font-size:.82rem;color:var(--text-faint);margin-top:var(--s-3)}
.mvcov{flex:0 0 auto;text-align:right;font-variant-numeric:tabular-nums;line-height:1.2}
.mvcov b{display:block;font-size:1rem;color:var(--accent)}
.mvcov span{display:block;font-size:var(--fs-2xs);color:var(--text-faint)}
.tag.wk{background:var(--surface);border-color:var(--line-bright);color:var(--text-dim)}
.tag.own{background:var(--good-well);border-color:var(--good-line);color:var(--good-text)}
.tag.cred{background:var(--good-well);border-color:var(--good-line);color:var(--good-text)}
.tag.fam{background:var(--surface);border-color:var(--line);color:var(--text-faint)}
.notyet{color:var(--text-faint);font-size:.9rem}

/* ---- audio controls & diagnostics ---- */
.audiowarn{
  display:flex;flex-wrap:wrap;gap:var(--s-6);align-items:center;
  background:color-mix(in srgb,var(--accent) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--accent) 50%,transparent);
  border-radius:var(--r-lg);padding:var(--s-7) var(--s-8);margin-bottom:.9rem;
  font-size:.88rem;line-height:1.4;
}
.audiowarn b{display:block;width:100%}
.audiostate{
  font-size:var(--fs-xs);letter-spacing:.04em;text-transform:uppercase;
  color:var(--text-faint);white-space:nowrap;
}
.audiostate.good{color:var(--good-text)}
.audiostate.bad{color:var(--accent)}
input.slider{
  -webkit-appearance:none;appearance:none;width:100%;height:34px;
  background:transparent;margin:0;
}
input.slider::-webkit-slider-runnable-track{
  height:6px;border-radius:var(--r-sm);background:var(--line-bright);
}
input.slider::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;width:26px;height:26px;margin-top:-10px;
  border-radius:var(--r-round);background:var(--accent);border:2px solid var(--bg);cursor:pointer;
}
input.slider::-moz-range-track{height:6px;border-radius:var(--r-sm);background:var(--line-bright)}
input.slider::-moz-range-thumb{
  width:24px;height:24px;border-radius:var(--r-round);background:var(--accent);
  border:2px solid var(--bg);cursor:pointer;
}

/* ---- move tree (Tree tab) ---- */
.readysum{display:flex;gap:var(--s-5);flex-wrap:wrap;margin:var(--s-7) 0 var(--s-8)}
.readysum span{flex:1;min-width:5.5rem;background:var(--surface-2);border:1px solid var(--line);
  border-radius:var(--r);padding:.45rem .55rem;font-size:var(--fs-2xs);letter-spacing:.08em;
  text-transform:uppercase;color:var(--text-faint)}
.readysum b{display:block;font-size:1.15rem;letter-spacing:0;text-transform:none;color:var(--text)}
/* ready / known / locked, in the same three colours the graph uses — and in
   the same order of loudness. Locked was inheriting plain --text, which made
   the number you can do least about the brightest one on the card. */
.readysum span:nth-child(1) b{color:var(--accent)}
.readysum span:nth-child(2) b{color:var(--good-text)}
.readysum span:nth-child(3) b{color:var(--locked)}

.trrow{display:flex;gap:var(--s-6);align-items:flex-start;padding:var(--s-6) 0;border-top:1px solid var(--line)}
.trrow:first-child{border-top:0}
.trrow.sel{background:color-mix(in srgb,var(--accent) 8%,transparent)}
.trrank{flex:0 0 1.5rem;height:1.5rem;border-radius:var(--r-round);background:var(--surface-2);
  border:1px solid var(--line-bright);color:var(--accent);font-size:.78rem;font-weight:700;
  display:flex;align-items:center;justify-content:center;margin-top:var(--s-1)}
.trmain{flex:1;min-width:0}
.trname{background:none;border:0;padding:0;color:var(--text);font:inherit;font-weight:700;
  font-size:var(--fs-md);text-align:left;cursor:pointer;line-height:1.25}
.trname:hover{color:var(--accent)}
.trcov{display:flex;flex-wrap:wrap;gap:.35rem;margin:var(--s-2) 0 .18rem}
.cv{font-size:var(--fs-2xs);letter-spacing:.04em;text-transform:uppercase;color:var(--text-faint);
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r-sm);padding:.05rem var(--s-3)}
.cv b{color:var(--text-dim);letter-spacing:0;text-transform:none;font-size:.78rem}
.trsub{font-size:.82rem;color:var(--text-dim);line-height:1.4}
.trsub .good{color:var(--good-text)}
.trsub .bad{color:var(--bad)}
.trrow .learnbtn{flex:0 0 auto;align-self:center;white-space:nowrap}
.trrow.lock .trrank{display:none}

.pathlink{background:none;border:0;padding:0;margin:0;color:inherit;font:inherit;
  text-align:left;cursor:pointer;text-decoration:underline;text-decoration-color:var(--line-bright);
  text-underline-offset:3px}
.pathlink:hover{color:var(--accent);text-decoration-color:var(--accent)}
.mvname .pathlink{font-weight:700}

.pathhead h4{font-size:var(--fs-lg);margin-bottom:.25rem}
.pathlist{list-style:none;margin:var(--s-8) 0 var(--s-2);padding:0}
.pathlist li{display:flex;gap:.55rem;align-items:flex-start;padding:.42rem 0;border-top:1px solid var(--line)}
.pathlist li.target{border-top:1px solid var(--accent-dim)}
.stepn{flex:0 0 1.35rem;height:1.35rem;border-radius:var(--r-sm);background:var(--surface-2);
  border:1px solid var(--line-bright);font-size:.72rem;font-weight:700;color:var(--text-dim);
  display:flex;align-items:center;justify-content:center;margin-top:.12rem}
.pathlist li.target .stepn{background:var(--accent);border-color:var(--accent);color:var(--accent-ink)}
.stepbody{min-width:0}
.stepbody .trsub{display:block}

.key{font-size:var(--fs-2xs);padding:.05rem .35rem;border-radius:var(--r-sm);border:1px solid var(--line-bright)}
.key.ok{border-color:var(--good);color:var(--good-text)}
.key.rdy{border-color:var(--accent);color:var(--accent-text)}
.key.lok{color:var(--locked)}

/* credit toast */
.toast{position:fixed;left:.7rem;right:.7rem;bottom:calc(.9rem + env(safe-area-inset-bottom));
  z-index:var(--z-toast);background:var(--surface-2);border:1px solid var(--good);
  border-left:3px solid var(--good);border-radius:var(--r);padding:var(--s-6) var(--s-10) var(--s-6) .75rem;
  font-size:var(--fs-sm);color:var(--text-dim);box-shadow:0 8px 26px var(--shadow);cursor:pointer}
.toast b{color:var(--text)}
.toast::after{content:"\00d7";position:absolute;right:.6rem;top:50%;transform:translateY(-50%);
  font-size:1.1rem;color:var(--text-faint);line-height:1}
@media(min-width:640px){.toast{left:auto;right:1.2rem;max-width:26rem}}

@media(max-width:600px){
  .trrow{flex-wrap:wrap}
  .trrow .learnbtn{margin-left:2.1rem}
}

/* ---- DAG graph ---- */
.gxhelp{font-size:var(--fs-sm);color:var(--text-faint);margin-bottom:.55rem}
.gxhelp b{color:var(--text-dim);font-weight:600}
.gxtouch{display:none}
@media (hover:none){.gxdesk{display:none}.gxtouch{display:inline}}
.gxlegend{display:flex;flex-wrap:wrap;gap:.35rem;margin-bottom:.55rem}
.gxwrap{position:relative;border:1px solid var(--line);border-radius:var(--r);
  background:linear-gradient(180deg,var(--sunk),var(--bg));overflow:hidden}
.gxhost{height:620px;width:100%;overflow:hidden}
/* pan-y keeps a one-finger vertical swipe scrolling the PAGE; horizontal drags
   and two-finger gestures still reach the graph's own pointer handlers. */
.gxsvg{display:block;touch-action:pan-y;cursor:grab;user-select:none;-webkit-user-select:none}
.gxsvg.dragging{cursor:grabbing}
.gxsvg:focus{outline:none}
.gxsvg:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.gxcol{fill:var(--text-faint);font-size:11px;font-weight:700;letter-spacing:.14em}
.gxedge{fill:none;stroke:var(--line-bright);stroke-width:1.1;opacity:.6;
  transition:opacity var(--t-fast) linear,stroke var(--t-fast) linear}
.gxedge.ok{stroke:var(--good);opacity:.5}
.gxedge.hi{stroke:var(--text);opacity:.95;stroke-width:1.8}
.gxedge.faded{opacity:.13}
.gxn{cursor:pointer}
.gxn .gxhit{fill:transparent}
.gxn .gxrect{fill:var(--surface-2);stroke:var(--locked);stroke-width:1;
  transition:opacity var(--t-fast) linear}
.gxn .gxlabel{fill:var(--text-dim);
  font:600 13px ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  pointer-events:none}
.gxn.ok .gxrect{fill:color-mix(in srgb,var(--good) var(--tint),transparent);stroke:var(--good)}
.gxn.ok .gxlabel{fill:var(--good-text)}
.gxn.rdy .gxrect{fill:color-mix(in srgb,var(--accent) var(--tint),transparent);stroke:var(--accent)}
.gxn.rdy .gxlabel{fill:var(--accent-text)}
/* Fit zoom: no labels to sit on the fill, so push the tint for separation. */
.gxsvg.lod .gxn.ok .gxrect{fill:color-mix(in srgb,var(--good) var(--tint-lod),transparent)}
.gxsvg.lod .gxn.rdy .gxrect{fill:color-mix(in srgb,var(--accent) var(--tint-lod),transparent)}
.gxn.lok .gxrect{fill:var(--surface);stroke:var(--locked)}
.gxn.lok .gxlabel{fill:var(--locked)}
.gxn.faded{opacity:.16}
.gxn.sel .gxrect{stroke:var(--text);stroke-width:2.4}
.gxn.sel .gxlabel{fill:var(--text)}
.gxn.dep .gxrect{stroke:var(--good);stroke-width:2}
.gxn.upx .gxrect{stroke:var(--accent);stroke-width:2}
.gxn:focus{outline:none}
.gxn.kfocus .gxrect{stroke:var(--text);stroke-width:2.4;stroke-dasharray:3 2}
/* Below the legibility threshold labels are dropped rather than shrunk to
   unreadable pixel mush; the node still reads as a coloured state marker. */
.gxsvg.lod .gxlabel{display:none}
.gxsvg.lod .gxcol{font-size:15px}
.gxctl{position:absolute;right:.45rem;bottom:.45rem;display:flex;gap:var(--s-3);z-index:var(--z-raise)}
.gxctl button{font:inherit;font-size:var(--fs-sm);line-height:1;min-width:2.4rem;height:2.4rem;
  border-radius:5px;border:1px solid var(--line-bright);
  background:color-mix(in srgb,var(--surface) 94%,transparent);
  color:var(--text-dim);cursor:pointer;padding:0 .45rem}
.gxctl button:active{background:var(--surface-2);color:var(--text)}
.gxhint{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:var(--z-float);
  background:color-mix(in srgb,var(--surface) 95%,transparent);
  border:1px solid var(--line-bright);border-radius:var(--r);
  padding:var(--s-5) var(--s-8);font-size:var(--fs-sm);color:var(--text);pointer-events:none;
  box-shadow:0 6px 20px var(--shadow)}
.gxstat{margin-top:.45rem;font-size:.75rem;color:var(--text-faint)}

@media (max-width:600px){
  .gxhost{height:460px}
  .gxctl button{min-width:2.6rem;height:2.6rem}
}
