/* AISU HERO · base (WP0). SPEC 1.3 rem scaling, 1.6 z-layers, 1.7 geometry, 1.8 legibility, 1.9 responsive,
   3.0 screen map, 3.14 debug, 4.2 exits, 4.8 reduced motion / reduced graphics.

   Three parts:
   A. FOUNDATION   reset, rem, layers, screen visibility (body[data-screen]), data-prev exits, the stall and
                   results field visibility, per-screen .shade, debug, reduced-motion and .lowfx switches.
                   Normal specificity: these are contracts.
   B. GEOMETRY     where every region of every screen sits (SPEC 3.x boxes), from the tokens.css variables.
                   Written inside :where() (zero specificity): screen packages override any of it with any selector.
   C. SCAFFOLD     a minimal, legible look so every screen is usable before WP1 (components) and the screen
                   packages land. Also zero specificity. The integrator trims it once components.css covers it.
   No blur, no dimming layer over Aisu, no backdrop filtering, no filter on ancestors of animated content. */

/* =========================================================================================== A. FOUNDATION */

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

/* 16px @1440x900, 12.8px @1280x720, 19.2px @1920x1080: layouts in rem follow the height at 16:9 and 16:10 */
html { font-size: clamp(12px, min(1.778vh, 1.111vw), 24px); -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
html, body { margin: 0; height: 100%; overflow: hidden; background: var(--night); }
body {
  color: var(--ivory); font-family: var(--font-body); font-weight: 800; font-size: var(--fs-body); line-height: 1.45;
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
}
/* element resets are zero-specificity too, so the :where() scaffold below and every later package win over them */
:where(button, input, select, textarea, output) { font: inherit; color: inherit; }
:where(button) { cursor: pointer; }
:where(h1, h2, h3, p, dl, dd, figure) { margin: 0; }
:where(ol, ul) { margin: 0; padding: 0; list-style: none; }
::selection { background: var(--red); color: var(--ivory); }
* { scrollbar-width: thin; scrollbar-color: var(--ink-2) transparent; }
::-webkit-scrollbar { width: .5rem; height: .5rem; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--ink-2); border-radius: var(--r-pill); border: 2px solid transparent; background-clip: padding-box; }
[inert] { pointer-events: none; }

/* ---------------------------------------------------------------- z-layers (1.6): all fixed at the root */
#gl { position: fixed; inset: 0; width: 100%; height: 100%; display: block; z-index: 0; }
#mv { display: none; }
.shade { position: fixed; inset: 0; z-index: 1; pointer-events: none; }
#backdrop { position: fixed; inset: 0; z-index: 2; pointer-events: none; }
.screen { position: fixed; inset: 0; z-index: 3; isolation: isolate; }
#fx { position: fixed; inset: 0; z-index: 4; pointer-events: none; }        /* wipe, curtain (4) */
#fx > #bichito { z-index: 5; }                                               /* the one mascot actor (5) */
#fx > #cursor { z-index: 6; }                                                /* the one focus cursor (6) */
#fx > #wipe, #fx > #curtain { z-index: 1; }
#error { position: fixed; z-index: 10; }
.narrow-pill { position: fixed; z-index: 9; }
#hud { pointer-events: none !important; }
#backdrop *, #fx *, .mascot-anchor { pointer-events: none; }
/* decorative hosts never take a click or a hover meant for a control (rule 0.2.9); deco.js fills them later */
:where([data-lanterns], [data-crowd], [data-fireworks], [data-embers], [data-bunting], .rays, .lockup__rays,
       .res-field__rays, .res-field__flames, .edge-flames, .loading__swirl, .tape, .stall__lanterns) { pointer-events: none; }

/* judgement words (SPEC 2.13): hud-view reads these two in px (registered <length>, so getComputedStyle resolves
   the vw/vh maths) to clamp --jx between Aisu + halo and the dock. Contract, do not rename. */
@property --judge-safe-l { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --judge-dock-l { syntax: '<length>'; inherits: false; initial-value: 0px; }
#judge-host { --judge-safe-l: var(--safe-judge-l); --judge-dock-l: var(--play-dock-l); }

/* ---------------------------------------------------------------- screen visibility (3.0)
   Hidden sections are display:none, so their loops do not run and do not count in document.getAnimations().
   Showing a section restarts its entrance keyframes. ui.show() stays synchronous; focus targets are focusable at once. */
.screen { display: none; pointer-events: none; }
body[data-screen="loading"]   #loading,
body[data-screen="title"]     #title,
body[data-screen="welcome"]   #welcome,
body[data-screen="code"]      #code,
body[data-screen="select"]    #select,
body[data-screen="board"]     #board,
body[data-screen="settings"]  #settings,
body[data-screen="calibrate"] #calibrate,
body[data-screen="playing"]   #hud,
body[data-screen="paused"]    #hud,
body[data-screen="paused"]    #pause,
body[data-screen="results"]   #results { display: block; pointer-events: auto; }

/* data-prev exits (4.2 #9): ui.show() keeps body[data-prev] for 160ms; the outgoing section sinks out in 140ms,
   inert and click-through. #loading leaves at once (the curtain in #fx covers the switch).
   Not with a camera move (body[data-move], below): Aisu sweeps through the old screen's regions within 50ms, so the
   outgoing section leaves at once (measured: impl/tools/move_clear.py). */
@media (prefers-reduced-motion: no-preference) {
  body[data-prev="title"]:not([data-screen="title"], [data-move])         #title,
  body[data-prev="welcome"]:not([data-screen="welcome"], [data-move])     #welcome,
  body[data-prev="code"]:not([data-screen="code"], [data-move])           #code,
  body[data-prev="select"]:not([data-screen="select"], [data-move])       #select,
  body[data-prev="board"]:not([data-screen="board"], [data-move])         #board,
  body[data-prev="settings"]:not([data-screen="settings"], [data-move])   #settings,
  body[data-prev="calibrate"]:not([data-screen="calibrate"], [data-move]) #calibrate,
  body[data-prev="results"]:not([data-screen="results"], [data-move])     #results,
  body[data-prev="paused"]:not([data-screen="paused"], [data-move])       #pause,
  body:is([data-prev="playing"], [data-prev="paused"]):not([data-screen="playing"], [data-screen="paused"], [data-move]) #hud {
    display: block; pointer-events: none;
    animation: ff-sink-out var(--t-quick) var(--ease-in) forwards;
  }
}

/* camera moves (rule 0.2.1, SPEC 3.14). ui.show() sets body[data-move] = "<from shot>-<to shot>" and the inline
   --move-at (ms, dom.js MOVE_AT) when the screen change comes with a non-instant stage.setShot(); both stay for
   --move-at + 260ms. Until --move-at, Aisu and her halo may still cross any region of the arriving screen, so its
   section, #stall and #res-field wait invisible and then fade in (the persistent .shade is held by ui.show() itself).
   Zero specificity on purpose: a screen package that animates its regions replaces this, adds var(--move-at) to its
   own delays, and may enter earlier only where impl/tools/g0_screens.py --motion proves 0px over Aisu + halo. */
@media (prefers-reduced-motion: no-preference) {
  :where(body[data-move]) :where(.screen, #stall, #res-field) { animation: ff-fade 160ms linear var(--move-at, 0ms) backwards; }
}

/* ---------------------------------------------------------------- shared backdrop (z 2)
   #stall shows on every menu-shot screen (select, board, settings, calibrate always; welcome and code only when the
   camera is on the menu shot, body[data-shot=menu]). #res-field shows on results. */
#stall, #res-field { display: none; }
body:is([data-screen="select"], [data-screen="board"], [data-screen="settings"], [data-screen="calibrate"]) #stall,
body[data-shot="menu"]:is([data-screen="welcome"], [data-screen="code"]) #stall { display: block; }
body[data-screen="results"] #res-field { display: block; }
@media (prefers-reduced-motion: no-preference) {
  body:is([data-prev="select"], [data-prev="board"], [data-prev="settings"], [data-prev="calibrate"]):not([data-screen="select"], [data-screen="board"], [data-screen="settings"], [data-screen="calibrate"], [data-screen="welcome"], [data-screen="code"], [data-move]) #stall {
    display: block; animation: ff-sink-out var(--t-quick) var(--ease-in) forwards;
  }
}

/* welcome / code: the menu-shot variant brings its own stall sign and anchor; the title-shot variant its own */
.stall__sign--menu, #welcome > .mascot-anchor[data-mascot-anchor="stall"], #code > .mascot-anchor[data-mascot-anchor="stall"] { display: none; }
body[data-shot="menu"] :is(#welcome, #code) > .stall__sign--menu { display: flex; }
body[data-shot="menu"] :is(#welcome, #code) > .mascot-anchor[data-mascot-anchor="stall"] { display: block; }
body[data-shot="menu"] #welcome .mascot-anchor[data-mascot-anchor="ema"],
body[data-shot="menu"] #code .mascot-anchor[data-mascot-anchor="code"],
body[data-shot="menu"] #aisu-say { display: none; }

/* welcome hint bar: items tagged data-form follow the visible form */
#welcome:has(#form-create[hidden]) .hint[data-form="create"],
#welcome:has(#form-code[hidden]) .hint[data-form="code"] { display: none; }

/* ---------------------------------------------------------------- legibility without blur (1.8): local .shade gradients
   They reach 0 before Aisu's halo. Background swaps instantly; only opacity transitions. */
.shade { opacity: 0; transition: opacity var(--t-panel) var(--ease-out); }
body:is([data-screen="title"], [data-screen="welcome"], [data-screen="code"]) .shade {
  opacity: 1;
  background: linear-gradient(90deg, rgb(13 11 22 / .82) 0, rgb(13 11 22 / .55) calc(var(--safe-title-r) - 22rem), transparent calc(var(--safe-title-r) - 2rem));
}
body:is([data-screen="select"], [data-screen="board"], [data-screen="settings"], [data-screen="calibrate"]) .shade,
body[data-shot="menu"]:is([data-screen="welcome"], [data-screen="code"]) .shade {
  opacity: 1;
  background: radial-gradient(70rem 30rem at 100% 100%, rgb(13 11 22 / .7), transparent 70%);
}
/* loading (opaque curtain), playing, paused, results (its field is #res-field), debug: no shade */

/* ---------------------------------------------------------------- debug (3.14): no UI at all */
body[data-screen="debug"] :is(#fx, #backdrop, .narrow-pill) { display: none; }
body[data-screen="debug"] .shade { opacity: 0; }

/* ---------------------------------------------------------------- error toast: shown with .on by ui.error() */
#error { display: none; }
#error.on { display: block; }

/* ---------------------------------------------------------------- narrow window notice (1.9): CSS only, 4s */
.narrow-pill { display: none; }
@media (max-width: 959px), (max-height: 599px), (max-aspect-ratio: 1/1) {
  .narrow-pill { display: block; animation: ff-fade-out var(--t-base) linear 4s forwards; }
}

/* ---------------------------------------------------------------- reduced motion (4.8) and reduced graphics (body.lowfx)
   Tag hooks for decorations: [data-fireworks] [data-embers] [data-crowd] [data-lanterns] [data-bunting] (hosts built
   by deco.js), .firework .poof .rays, plus the generic .lowfx-off (hidden under lowfx) and .lowfx-still /
   .sway (animation stopped under lowfx). Particles also go under reduced motion. */
@media (prefers-reduced-motion: reduce) {
  :is([data-fireworks], [data-embers], .firework, .poof, .rays, .res-field__rays, #wipe) { display: none !important; }
  html { scroll-behavior: auto !important; }
  /* no motion, but fades stay: only opacity may transition (transform / translate / scale / rotate jump at once),
     each with its own duration. Entrances and loops are handled in motion.css (--anim / --loop). */
  *, *::before, *::after { transition-property: opacity !important; }
}
body.lowfx :is([data-fireworks], [data-embers], [data-crowd], .firework, .poof, .rays, .res-field__rays,
               .res-field__flames, .edge-flames, #edge-glow, #wipe, .lowfx-off) { display: none !important; }
body.lowfx .foil::after { display: none !important; }
body.lowfx :is([data-lanterns], [data-bunting], .stall__lanterns, .sway, .lowfx-still),
body.lowfx :is([data-lanterns], [data-bunting], .stall__lanterns, .sway, .lowfx-still) * { animation: none !important; }

/* ============================================================================================= B. GEOMETRY */

/* every region is positioned inside its fixed full-viewport section */
:where(.screen) > :where(*) { position: absolute; }
:where(.mascot-anchor) { position: absolute; display: block; visibility: hidden; }

/* ---------------------------------------------------------------- loading (3.1): opaque curtain, centred card */
:where(#loading) { background: var(--red); }
:where(.loading__embers) { inset: 0; }
:where(.loading-card) {
  left: 50%; top: 50%; translate: -50% -50%; width: min(34rem, 90vw);
  display: grid; justify-items: center; gap: 1.2rem; padding: 2rem; text-align: center;
}
:where(.loading__swirl) { position: absolute; width: 9rem; height: 9rem; right: -3rem; top: -3rem; z-index: -1; border-radius: 50%; }
:where(.loadbar) { position: relative; width: min(24rem, 100%); height: 1rem; overflow-x: clip; overflow-y: visible; }
:where(#load-bar) { position: absolute; inset: 0; display: block; width: 100%; transform-origin: 0 50%; }
:where(.walker) { position: absolute; right: 0; bottom: 100%; }

/* ---------------------------------------------------------------- title (3.2): one column (lx = 4.5vw, 34rem wide; its
   items centred on lx + 17rem), the now-playing card at Aisu's feet (right edge 1.5rem inside the title safe line, the
   bichito on its top edge), the footer chips on lx. The lanterns end before the MV. */
:where(.title-crowd) { left: 0; bottom: 0; width: 46vw; height: 24vh; }
:where(.title-lanterns) { left: 0; top: 0; width: calc(var(--mv-title-l) - 1rem); height: 13vh; }
:where(.title-fireworks) { left: 0; top: 0; width: calc(var(--safe-title-r) - 4rem); height: 40vh; }
:where(#title-logo) { left: var(--lx); top: var(--ly); width: 34rem; height: 22rem; }
:where(#title .tagline) { left: calc(var(--lx) + 17rem); top: calc(var(--ly) + 22.4rem); translate: -50% 0; }
:where(#btn-start) { left: calc(var(--lx) + 5.5rem); top: calc(var(--ly) + 26.5rem); width: 23rem; height: 4.4rem; }
:where(#title .prompt-alt) { left: calc(var(--lx) + 5.5rem); top: calc(var(--ly) + 31.9rem); width: 23rem; }
:where(#title .np) { left: calc(var(--safe-title-r) - 1.5rem - 24rem); bottom: 2.5vh; width: 24rem; }
:where(#title .mascot-anchor) { left: calc(var(--safe-title-r) - 25.5rem + 1.2rem); bottom: calc(2.5vh + 7.4rem); width: 6.5rem; height: 8rem; }
:where(.title-foot) { left: var(--lx); bottom: 2.5vh; max-width: 30rem; display: flex; flex-wrap: wrap; gap: .5rem; }

/* ---------------------------------------------------------------- the stall (3.5): frame in #backdrop, content in each section */
:where(#stall) { position: absolute; left: var(--stall-l); right: var(--stall-r); top: var(--stall-t); bottom: var(--stall-b); }
:where(.stall__roof) { position: absolute; left: 0; right: 0; top: 0; height: var(--roof-h); }   /* flush with the panel */
:where(.stall__stripes) { position: absolute; inset: 0; }
:where(.stall__lanterns) { position: absolute; left: 0; right: 0; top: var(--roof-h); height: 0; }
:where(.stall__panel) { position: absolute; left: 0; right: 0; top: var(--roof-h); bottom: 0; }
/* bichito: feet on the roof top at its right end (right edge 98.5vw - 1.5rem, bottom 49vh + .4rem, 6rem tall) */
:where(#stall .mascot-anchor, .screen > .mascot-anchor[data-mascot-anchor="stall"]) { width: 7rem; height: 6rem; }
:where(#stall .mascot-anchor) { right: 1.5rem; top: calc(.4rem - 6rem); }
:where(.screen > .mascot-anchor[data-mascot-anchor="stall"]) { right: calc(var(--stall-r) + 1.5rem); top: calc(var(--stall-t) + .4rem - 6rem); }

/* section side: the sign hangs on the roof's left (bottom 1rem below the roof), the body covers the panel */
:where(.stall__sign) {
  left: calc(var(--stall-l) + 1.25rem); bottom: calc(100vh - var(--stall-body-t) - 1rem);
  max-width: calc(var(--stall-w) - 12rem); display: flex; align-items: center; gap: .6rem;
  z-index: 1;   /* above the section's own body / ema / notice, which come later in the DOM */
}
:where(.stall__body) { left: var(--stall-l); right: var(--stall-r); top: var(--stall-body-t); bottom: var(--stall-b); }
:where(.stall__body) {
  padding: calc(1rem + var(--ow-l)) calc(1.25rem + var(--ow-l));
  overflow-y: auto; scrollbar-gutter: stable; container-type: inline-size;
}
:where(.select-body, .settings-body, .calibrate-body, .board-body) { position: relative; }
/* top-left above Aisu's head: logo + profile chip (select) */
:where(.menu-top) { left: 1.5vw; top: 2vh; height: 2.6rem; display: flex; align-items: center; gap: .8rem; }

/* hint bars (2.16): no panel. Menu shot: under the stall. Title shot (welcome, code): bottom-left */
:where(.hintbar) { height: var(--hint-h); display: flex; align-items: center; gap: 1.1rem; container-type: inline-size; }
:where(#welcome, #code) > :where(.hintbar) { left: 5vw; bottom: 2vh; width: min(30rem, var(--safe-title-r) - 5vw); }
:where(#select, #board, #settings, #calibrate) > :where(.hintbar),
:where(body[data-shot="menu"]) :where(#welcome, #code) > :where(.hintbar) { left: var(--stall-l); right: var(--stall-r); bottom: 1vh; width: auto; }

/* ---------------------------------------------------------------- welcome (3.3), title shot: the ema plaque */
:where(#welcome .ema) {
  left: 5vw; top: max(6vh, 4rem); width: min(42rem, var(--safe-title-r) - 5vw - 1rem);
  container-type: inline-size;
}
:where(.ema__paper) { position: relative; max-height: min(33rem, 100vh - max(6vh, 4rem) - 2vh - var(--hint-h) - 2rem); overflow-y: auto; scrollbar-gutter: stable; }
:where(.ema__cord, .ema__ink, .ema__roof) { position: absolute; }
:where(.ema .mascot-anchor) { left: 4rem; top: -3.5rem; width: 5.8rem; height: 5rem; }
:where(#aisu-say) { left: calc(var(--safe-title-r) - 16rem); top: 1.5vh; width: 16rem; min-height: 4rem; }
/* menu shot: the ema's own roof, cord and outline go; its content fills the stall body */
:where(body[data-shot="menu"]) :where(.ema__cord, .ema__ink, .ema__roof) { display: none; }
:where(body[data-shot="menu"]) :where(.ema__paper, .notice__paper) {
  height: 100%; max-height: none; width: auto; overflow-y: auto;
  padding: calc(1rem + var(--ow-l)) calc(1.25rem + var(--ow-l));
  background: none; border: 0; box-shadow: none;
}

/* ---------------------------------------------------------------- code (3.4), title shot: the notice card */
:where(#code .notice) { left: 5vw; top: 12vh; width: min(40rem, var(--safe-title-r) - 5vw - 1rem); container-type: inline-size; }
:where(.notice__paper) { position: relative; max-height: calc(100vh - 12vh - 2vh - var(--hint-h) - 1.5rem); overflow-y: auto; }
:where(.notice__ink, .notice__bunting) { position: absolute; }
:where(.notice .mascot-anchor) { left: 36rem; top: 22rem; width: 6rem; height: 7rem; }
:where(body[data-shot="menu"]) :where(.notice__ink, .notice__bunting) { display: none; }
/* menu shot (welcome / code opened from Settings): the plaque or card content fills the stall body */
:where(body[data-shot="menu"]) :where(#welcome .ema, #code .notice) {
  left: var(--stall-l); right: var(--stall-r); top: var(--stall-body-t); bottom: var(--stall-b); width: auto;
}
:where(body[data-shot="menu"]) :where(.ema .mascot-anchor, .notice .mascot-anchor) { display: none; }

/* ---------------------------------------------------------------- select (3.6): grid inside the stall body */
:where(.select-body) {
  display: grid; grid-template-columns: 12.5rem minmax(0, 1fr); grid-template-rows: 6.2rem 5.8rem 4.4rem;
  column-gap: 1.25rem; row-gap: 1.4rem; align-content: start;
}
:where(.select-body > #song-list) { grid-row: 1 / span 3; display: flex; flex-direction: column; gap: .4rem; min-width: 0; }
:where(.song-head) { display: grid; grid-template-columns: 6.2rem minmax(0, 1fr); gap: 1rem; min-width: 0; }
:where(.cover-wrap) { position: relative; width: 6.2rem; height: 6.2rem; }
:where(#sd-cover) { display: block; width: 100%; height: 100%; object-fit: cover; }
:where(.eq) { position: absolute; left: .35rem; bottom: .35rem; height: 1.6rem; display: flex; align-items: flex-end; gap: .12rem; }
:where(.eq i) { display: block; width: .28rem; height: 100%; transform-origin: 50% 100%; }
:where(.song-info) { min-width: 0; display: grid; align-content: start; gap: .3rem; }
:where(.dif-field) { display: grid; grid-template-rows: 1.1rem 4.7rem; gap: 0; min-width: 0; }
:where(#difficulty) { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .6rem; }
:where(.controls-row) { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: .9rem; min-width: 0; }
:where(#modes) { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; min-width: 0; }

/* ---------------------------------------------------------------- board (3.7) */
:where(.board-body) { display: flex; flex-direction: column; height: 100%; min-height: 0; }
:where(#board-tabs) { flex: none; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .5rem; height: 2.6rem; }
:where(.board-row) { display: grid; grid-template-columns: 3rem minmax(0, 1fr) 4.5rem 6rem 3.5rem 6.5rem; gap: .5rem; align-items: center; }
:where(.board-row.head) { flex: none; height: 1.4rem; margin-top: .5rem; }
:where(#board-list) { flex: 1 1 auto; min-height: 0; overflow-y: auto; scrollbar-gutter: stable; }
:where(#board-status) { flex: none; min-height: 1.3rem; }
@container (max-width: 50rem) {
  :where(.board-row) { grid-template-columns: 2.6rem minmax(0, 1fr) 5rem 3.2rem 6rem; }
  :where(.board-row > :nth-child(3)) { display: none; }
}

/* ---------------------------------------------------------------- settings (3.8): 3 columns, 2 below 50rem, 1 below 34rem */
:where(.settings-body) { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: 1rem; align-items: start; }
:where(.settings-col) { display: grid; gap: .8rem; min-width: 0; }

/* ---------------------------------------------------------------- calibrate (3.9) */
:where(.calibrate-body) { display: grid; grid-template-columns: 12rem minmax(0, 1fr); gap: 1.25rem; align-items: center; }
:where(.metro) { display: grid; place-items: center; height: 10rem; }
:where(#metro-dot) { display: block; width: 9rem; height: 9rem; border-radius: 50%; }

/* ---------------------------------------------------------------- playing (3.10): the HUD regions */
:where(#hud) > :where(*) { position: absolute; }
:where(#edge-glow) { inset: 0; }
:where(#edge-glow i) { position: absolute; top: 0; bottom: 0; width: 1.2vw; }
:where(#edge-glow i:first-child) { left: 0; }
:where(#edge-glow i:last-child) { right: 0; }
:where(.song-plate) { left: 1.5vw; top: 1.5vh; width: 17rem; min-height: 7.9vh; }
:where(.lyrics) { left: 50%; translate: -50% 0; top: 1.5vh; height: 4.6rem; width: min(38rem, 97vw - 40rem); }
:where(#section-toast) { right: 1.5vw; top: 0; width: 11rem; min-height: 10.5vh; }
:where(#endcap) { left: 50%; top: 7vh; translate: -50% -50%; }
:where(.rock) { left: 1rem; top: 12.5vh; width: 6.5rem; height: calc(57.5vh + 3.4rem); --tube-h: 52vh; }
:where(.rock__cap, .rock__chip, .rock__tube, .rock__bulb) { position: absolute; left: 0; }
:where(.rock__cap) { top: 0; }
:where(.rock__chip) { top: 2.5vh; }
:where(.rock__tube) { top: 5.5vh; width: 2.9rem; height: var(--tube-h); overflow: hidden; }
:where(.rock__bulb) { top: calc(5.5vh + var(--tube-h)); left: -.25rem; width: 3.4rem; height: 3.4rem; }
:where(#rock-fill) { position: absolute; inset: 0; overflow: clip; transform: translateY(calc((1 - var(--rock, .5)) * 100%)); }
:where(#rock-fill > i) { position: absolute; inset: 0; transform: translateY(calc((var(--rock, .5) - 1) * 100%)); }
:where(.rock__line) { position: absolute; left: 0; right: 0; }
:where(.rock__line--fail) { bottom: 25%; }
:where(.rock__line--fire) { bottom: 75%; }
:where(#rock-needle) { position: absolute; left: 50%; bottom: 0; translate: -50% calc(50% - var(--rock, .5) * var(--tube-h)); }
:where(#hud > .mascot-anchor[data-mascot-anchor="hud"]) { left: 1rem; bottom: 1.5vh; width: 6.4rem; height: 5.5rem; }
:where(.dock) { right: 1.5vw; bottom: 1.5vh; width: var(--dock-w); height: var(--dock-h); container-type: inline-size; }
:where(.dock > .mascot-anchor) { display: none; left: 1rem; top: -7.5rem; width: 6.4rem; height: 5.5rem; }
:where(.dock__plate) { position: absolute; left: 1rem; top: -2.2rem; width: 13rem; height: 3rem; }
:where(#combo) { right: 1.5vw; top: calc(var(--dock-t) - 6.4rem); max-width: 19rem; min-height: 3.8rem; }
:where(#judge-host) { left: 0; top: 73vh; width: 100%; height: 0; }
:where(.judge) { position: absolute; left: var(--jx, 50vw); top: 0; translate: -50% -50%; white-space: nowrap; }
:where(#timing) { left: var(--jx, 50vw); top: 77.5vh; translate: -50% -50%; }
:where(#countdown) { left: 50%; top: 22vh; translate: -50% -50%; width: 8rem; height: 8rem; display: grid; place-items: center; }
/* narrow HUD (aspect < 1.5): the left strip vanishes; the gauge lies under the song plate, the bichito sits on the dock */
@media (max-aspect-ratio: 149/100) {
  :where(.rock) { left: 1.5vw; top: 9.9vh; width: 17rem; height: 2.5vh; --tube-h: 14rem; }
  :where(.rock__cap, .rock__chip, .rock__bulb) { display: none; }
  :where(.rock__tube) { top: 0; width: 14rem; height: 1.4rem; }
  :where(#rock-fill) { transform: translateX(calc((var(--rock, .5) - 1) * 100%)); }
  :where(#rock-fill > i) { transform: translateX(calc((1 - var(--rock, .5)) * 100%)); }
  :where(#rock-needle) { left: 0; bottom: 50%; translate: calc(var(--rock, .5) * var(--tube-h) - 50%) 50%; }
  :where(#hud > .mascot-anchor[data-mascot-anchor="hud"]) { display: none; }
  :where(.dock > .mascot-anchor) { display: block; }
}

/* ---------------------------------------------------------------- paused (3.11): HUD stays, the dock leaves, the card takes its place */
:where(.dock) { transition: transform var(--t-base) var(--ease-in), opacity var(--t-base) var(--ease-in); }
:where(body[data-screen="paused"]) :where(.dock) { transform: translateX(110%); opacity: 0; }
:where(body[data-screen="paused"]) :where(#hud) > :where(:not(.dock, #edge-glow)) { opacity: .6; }
:where(.pause-sheet) { right: 1.5vw; bottom: 1.5vh; top: 55vh; width: max(15rem, var(--dock-w)); overflow-y: auto; }

/* ---------------------------------------------------------------- results (3.12): the board in the left field */
:where(.results-board) {
  left: 2.5vw; top: 3vh; width: var(--res-w); height: 94vh; overflow-y: auto; scrollbar-gutter: stable;
  container-type: inline-size; display: flex; flex-direction: column; gap: .9rem;
}
:where(#results > .mascot-anchor) { left: calc(2.5vw + var(--res-w) - 6rem); top: calc(97vh - 7.5rem); width: 6.5rem; height: 8rem; }
:where(#res-field) { position: absolute; inset: 0; }
:where(#res-field > i) { position: absolute; inset: 0; }

/* ---------------------------------------------------------------- error toast placement by context (3.13) */
:where(#error) { left: 50%; translate: -50% 0; bottom: 6vh; width: min(32rem, 90vw); }
:where(body:is([data-screen="title"], [data-screen="welcome"], [data-screen="code"], [data-screen="results"])) :where(#error) { left: 2vw; translate: none; }
:where(body:is([data-screen="select"], [data-screen="board"], [data-screen="settings"], [data-screen="calibrate"]), body[data-shot="menu"]) :where(#error) { left: 1.5vw; translate: none; top: calc(2vh + 3.2rem); bottom: auto; }
:where(body:is([data-screen="playing"], [data-screen="paused"])) :where(#error) { left: 50%; translate: -50% 0; top: 1.5vh; bottom: auto; }
:where(.narrow-pill) { left: 50%; translate: -50% 0; top: 1vh; }

/* ---------------------------------------------------------------- #fx defaults: invisible until their owners drive them (WP1 / WP2) */
:where(#wipe, #curtain) { position: absolute; inset: 0; display: none; }
:where(#bichito) { position: absolute; left: 0; top: 0; opacity: 0; }
:where(#bichito .sprite__pose) { position: absolute; left: 0; bottom: 0; height: 6rem; width: auto; opacity: 0; }
:where(#bichito .say:empty) { display: none; }
:where(#cursor) { position: absolute; left: 0; top: 0; opacity: 0; }

/* ============================================================================================= C. SCAFFOLD
   Minimal G0 look: legible and clickable, nothing more. Zero specificity, overridden by components.css / screens. */

/* surfaces */
:where(.panel) { background: var(--grad-ivory); color: var(--ink); border: var(--ow-l) solid var(--ink); border-radius: var(--r-l); }
:where(.panel--night) { background: var(--grad-night); color: var(--ivory); }
:where(.sheet) { padding: 1.1rem 1.3rem; display: grid; gap: .7rem; align-content: start; }
:where(.stall__stripes--a) { background: repeating-linear-gradient(90deg, var(--roof-a, var(--red)) 0 2.2rem, var(--roof-b, var(--ivory)) 0 4.4rem); border: var(--ow-l) solid var(--ink); border-radius: var(--r-m) var(--r-m) 0 0; }
:where(#stall) { --roof-a: var(--red); --roof-b: var(--ivory); }
:where(body[data-screen="board"]) :where(#stall) { --roof-a: var(--cobalt); }
:where(body:is([data-screen="settings"], [data-screen="calibrate"])) :where(#stall) { --roof-a: var(--night-3); }
:where(.stall__body, .ema__paper, .notice__paper, .results-board, .pause-sheet) { color: var(--ink); }
:where(.band) { background: var(--red); color: var(--ivory); padding: .5rem 1rem; border-radius: var(--r-m); }
:where(.band--cobalt) { background: var(--cobalt); }

/* type */
:where(.stall-title, .band h2, .notice__paper h2) { font-size: var(--fs-h2); }
:where(.stall__sign .stall-title) { --tk-fill: var(--ivory); }
:where(.label) { font-size: var(--fs-small); font-weight: 900; text-transform: uppercase; letter-spacing: .1em; display: flex; align-items: center; gap: .6rem; }
:where(.label small) { text-transform: none; letter-spacing: 0; font-weight: 800; color: var(--ink-2); }
:where(.body, .status, .form-msg, .field-help, .tip) { font-size: var(--fs-small); }
:where(.form-msg) { min-height: 1.3em; }
:where(.form-msg.err) { color: var(--red-deep); }
:where(.pill) { display: inline-flex; align-items: center; min-height: 1.5rem; padding: 0 .6rem; border-radius: var(--r-pill); border: var(--ow-s) solid var(--ink); background: var(--night); color: var(--ivory); font-size: var(--fs-small); font-weight: 900; text-transform: uppercase; letter-spacing: .06em; white-space: nowrap; }
:where(.pill--red) { background: var(--red); }
:where(.pill:empty) { display: none; }
:where(.notice__kicker) { justify-self: start; }

/* keys and buttons */
:where(kbd) { display: inline-grid; place-items: center; min-width: 1.6rem; height: 1.5rem; padding: 0 .4rem; margin-inline: .15rem; border: var(--ow-s) solid var(--ink); border-radius: var(--r-xs); background: var(--paper); color: var(--ink); font: 900 var(--fs-small)/1 var(--font-body); box-shadow: 0 .18rem 0 var(--ink); vertical-align: middle; }
:where(button) { display: inline-flex; align-items: center; justify-content: center; gap: .5rem; min-height: 2.4rem; padding: .3rem 1rem; border: var(--ow) solid var(--ink); border-radius: var(--r-pill); background: var(--paper); color: var(--ink); font-family: var(--font-display); font-weight: 700; font-stretch: 85%; font-size: var(--fs-btn); box-shadow: var(--drop); }
:where(button.primary, .play, .prompt, #btn-resume, #btn-again) { background: var(--grad-fire-btn); color: var(--paper); }
:where(.ghost) { background: transparent; box-shadow: none; min-height: 2.2rem; }
:where(.ghost.danger) { border-color: var(--red); color: var(--red-deep); }
:where(.confirm) { background: var(--red); color: var(--ivory); }
:where(.link) { border: 0; background: none; box-shadow: none; padding: 0; min-height: 0; color: var(--cobalt-deep); font-family: var(--font-body); font-weight: 900; font-size: var(--fs-small); text-decoration: underline; text-underline-offset: .2em; }
:where(.row) { display: flex; align-items: center; justify-content: space-between; gap: .8rem; flex-wrap: wrap; }
:where(.menu) { display: grid; gap: .5rem; }
:where(.menu button) { justify-content: space-between; min-height: 2.8rem; }
:where(.ghost.wide) { width: 100%; }
:where(#btn-start) { font-size: 1.3rem; }
:where(#btn-play) { min-height: 4.4rem; padding-inline: 1.4rem; font-size: var(--fs-play); }
:where(#btn-play .tk) { font-size: var(--fs-play); --tk-fill: var(--ivory); }
:where(.prompt-alt, .tagline) { font-size: var(--fs-small); text-transform: uppercase; letter-spacing: .1em; color: var(--ivory-2); }
:where(.tagline) { font-size: 1.2rem; text-transform: none; letter-spacing: .02em; color: var(--ivory); }

/* hint bar: ivory text with the hint shadow, no panel */
:where(.hintbar) { color: var(--ivory); text-shadow: var(--hint-shadow); font-size: var(--fs-small); font-weight: 900; text-transform: uppercase; letter-spacing: .06em; white-space: nowrap; }
:where(.hintbar .hint) { display: inline-flex; align-items: center; gap: .3rem; }   /* scoped: #section-toast.hint (ui.hint) is not a hint-bar item */
:where(.hint-btn) { height: 100%; min-height: 0; padding: 0 .2rem; border: 0; border-radius: var(--r-s); background: none; box-shadow: none; color: inherit; font: inherit; text-shadow: inherit; text-transform: inherit; letter-spacing: inherit; }
:where(.hint--go .hint__label) { color: var(--f2); }
:where(.hint--note) { text-transform: none; letter-spacing: .02em; color: var(--ivory-2); }
/* 2.16: low-priority items (Controls, Title) drop out when the bar is narrow */
@container (max-width: 40rem) { :where(.hintbar [data-prio="2"]) { display: none; } }
/* 3.6 compact select (stall body < 50rem): the same items drop out earlier */
@container (max-width: 50rem) { :where(#select > .hintbar [data-prio="2"]) { display: none; } }
:where(.hintbar kbd) { margin-inline: .05rem; }

/* form fields */
:where(.field-text) { position: relative; display: grid; gap: .25rem; font-size: var(--fs-small); font-weight: 900; }
:where(.field-text small) { font-weight: 800; color: var(--ink-2); }
:where(.field-text input) { min-width: 0; height: 3rem; padding: 0 .9rem; border: var(--ow) solid var(--ink); border-radius: var(--r-s); background: var(--paper); color: var(--ink); font: 800 var(--fs-btn) var(--font-body); caret-color: var(--red); }
:where(.field-text input[aria-invalid="true"]) { border-color: var(--red); }
:where(.mono, .code-value) { font-family: var(--font-mono); font-weight: 700; letter-spacing: .08em; }
:where(.field-row) { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
:where(.field) { display: grid; gap: .25rem; min-width: 0; }
:where(.field-ok) { display: none; }
:where(.preview) { display: grid; gap: .25rem; }
:where(.preview__label) { font-size: var(--fs-small); font-weight: 900; text-transform: uppercase; letter-spacing: .1em; }
:where(.plate) { display: inline-flex; align-items: center; gap: .5rem; min-width: 0; padding: .3rem .8rem .3rem .3rem; border: var(--ow) solid var(--ink); border-radius: 1.4rem .4rem 1.4rem .4rem; background: var(--paper); color: var(--ink); }
:where(.plate--night) { background: var(--night); color: var(--ivory); }
:where(.plate__name, .chip-name, #hud-name) { max-width: 14ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; unicode-bidi: isolate; }
:where(.avatar) { display: inline-grid; place-items: center; flex: none; width: 2rem; height: 2rem; border-radius: 50%; border: var(--ow-s) solid var(--ink); background: var(--red); color: var(--ivory); font: 700 var(--fs-btn)/1 var(--font-display); }
:where(#btn-profile) { flex: none; min-height: 2.6rem; padding-block: 0; border-radius: 1.4rem .4rem 1.4rem .4rem; font-family: var(--font-body); font-weight: 900; font-size: var(--fs-body); }

/* switch: the native checkbox stays on top of the track at full size (visible and clickable for Playwright) */
:where(.switch) { position: relative; display: inline-flex; align-items: center; gap: .6rem; font-size: var(--fs-small); font-weight: 900; cursor: pointer; }
:where(.switch input) { position: absolute; left: 0; top: 50%; translate: 0 -50%; width: 2.8rem; height: 1.6rem; margin: 0; opacity: 0; cursor: pointer; z-index: 1; }
:where(.switch .track) { position: relative; flex: none; width: 2.8rem; height: 1.6rem; border-radius: var(--r-pill); background: var(--ink); border: var(--ow-s) solid var(--ink); }
:where(.switch .track)::after { content: ''; position: absolute; left: .1rem; top: 50%; translate: 0 -50%; width: 1.2rem; height: 1.2rem; border-radius: 50%; background: var(--ivory); transition: transform var(--t-base) var(--ease-out); }
:where(.switch input:checked + .track) { background: var(--grad-fire-btn); }
:where(.switch input:checked + .track)::after { transform: translateX(1.2rem); }
:where(.switch input:focus-visible + .track) { outline: 3px solid var(--focus); outline-offset: 2px; }

/* sliders */
:where(.slider) { display: grid; grid-template-columns: 6.5rem minmax(0, 1fr) 4.2rem; align-items: center; gap: .6rem; font-size: var(--fs-small); font-weight: 900; }
:where(.slider input[type="range"]) { width: 100%; margin: 0; accent-color: var(--f3); }
:where(.slider output) { justify-self: end; font-family: var(--font-num); }

/* select scaffold */
:where(.song-thumb) { justify-content: flex-start; gap: .5rem; width: 100%; height: 3.5rem; min-height: 0; padding: .25rem; border-radius: var(--r-m); box-shadow: var(--drop-s); overflow: hidden; }
:where(.song-thumb img) { height: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--r-s); }
:where(.song-thumb[aria-selected="true"]) { background: var(--f2); }
:where(.song-thumb.locked) { display: flex; align-items: center; gap: .5rem; padding: 0 .7rem; border: var(--ow) solid var(--ink); background: var(--night-3); color: var(--ivory-3); font-size: var(--fs-small); }
:where(.song-thumb.locked svg) { flex: none; width: 1rem; height: 1rem; }
:where(#sd-title) { max-width: 100%; overflow: hidden; text-overflow: ellipsis; font-size: var(--fs-h2); }
:where(.stats) { display: flex; flex-wrap: wrap; gap: .2rem 1rem; font-size: var(--fs-small); }
:where(.stats dt) { text-transform: uppercase; letter-spacing: .1em; color: var(--ink-2); }
:where(.best) { font-size: var(--fs-small); min-height: 1.3em; }
:where(.eq i) { background: var(--ivory); box-shadow: 0 0 0 1px var(--ink); }
:where(.seg button) { flex-direction: column; align-items: flex-start; justify-content: center; gap: .1rem; min-width: 0; height: 100%; padding: .3rem .7rem; border-radius: var(--r-m); box-shadow: var(--drop-s); text-align: left; }
:where(.seg button b) { font-size: var(--fs-btn); }
:where(.seg button small) { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-body); font-weight: 800; font-size: var(--fs-small); }
:where(.seg button[aria-checked="true"]) { background: var(--dif-color, var(--night-2)); color: var(--ivory); }
:where(#modes button[aria-checked="true"]) { background: var(--night-2); color: var(--ivory); }
:where(.pips) { display: flex; gap: .15rem; }
:where(.pips i) { width: .5rem; height: .5rem; border-radius: 50%; background: var(--ivory-3); }
:where(.pips i.on) { background: var(--f4); }
:where(.hint-keys) { display: inline-flex; }

/* board scaffold */
:where(#board-tabs button) { min-height: 0; height: 100%; box-shadow: var(--drop-s); }
:where(#board-tabs button[aria-selected="true"]) { background: var(--dif-color, var(--red)); color: var(--ivory); }
:where(.board-row) { padding: .25rem .5rem; min-height: 2rem; font-size: var(--fs-body); }
:where(.board-row.head) { font-size: var(--fs-small); text-transform: uppercase; letter-spacing: .1em; color: var(--ink-2); }
:where(.board-list .board-row:nth-child(even)) { background: var(--ivory-2); }
:where(.board-list .board-row.me) { position: sticky; top: 0; bottom: 0; background: var(--f2); }
:where(.board-row .who) { display: flex; flex-direction: column; min-width: 0; }
:where(.board-row .who b) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; unicode-bidi: isolate; }
:where(.board-row .who a) { font-size: var(--fs-small); color: var(--cobalt); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
:where(.board-row .num) { text-align: right; font-weight: 900; font-variant-numeric: tabular-nums; }
:where(.board-row .st) { color: var(--red); white-space: nowrap; }
:where(.board-row .st.gold, .best .st.gold) { color: var(--gold-deep); }
:where(.board-gap) { text-align: center; font-family: var(--font-symbols); }
:where(.board-song) { margin-top: .2rem; }

/* settings scaffold */
:where(.group) { display: grid; gap: .45rem; }
:where(.profile-form) { display: grid; gap: .45rem; }
:where(.profile-form .field-text input, .settings-body .field-text input) { height: 2.6rem; }
:where(.form-row) { display: flex; align-items: center; justify-content: space-between; gap: .6rem; }
:where(.profile-actions) { display: flex; flex-wrap: wrap; gap: .4rem; }
:where(.profile-actions button) { min-height: 2rem; padding: .1rem .7rem; font-size: var(--fs-small); box-shadow: var(--drop-s); }
:where(#settings .field-text input) { height: 2.4rem; }
:where(#profile-form) { display: grid; gap: .4rem; }
:where(.keys) { display: flex; flex-wrap: wrap; gap: .4rem; }
:where(.keys button) { min-width: 2.4rem; height: 2.4rem; min-height: 0; padding: 0 .5rem; border-radius: var(--r-s); border-top: .5rem solid var(--lane, var(--ink)); box-shadow: var(--drop-s); }
:where(.keys button.strum) { background: var(--night-3); color: var(--ivory); }
:where(.keys button.star) { background: var(--cobalt); color: var(--ivory); }
:where(.keys .sep) { width: 1rem; border-left: 2px dashed var(--ink-2); }

/* calibrate scaffold */
:where(#metro-dot) { background: var(--ivory-2); border: var(--ow-l) solid var(--ink); }
:where(#metro-dot.on) { background: var(--red); transform: scale(.94); }
:where(.cal-info) { display: grid; gap: .6rem; }
:where(#cal-status) { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h3); }
:where(.cal-dots) { display: flex; gap: .3rem; }
:where(.cal-dots li) { width: .7rem; height: .7rem; border-radius: 50%; border: var(--ow-s) solid var(--ink); }

/* title / loading scaffold */
:where(.lockup) { display: flex; flex-direction: column; align-items: flex-start; line-height: 1; }
/* the owner's AISU and HERO marks (docs/assets-originales/aisu-logo.png, hero-logo.png), side by side, HERO sitting low */
:where(.lockup__mark) { display: block; height: 2.7rem; width: auto; user-select: none; -webkit-user-drag: none; }
:where(.lockup__mark--hero) { height: 1.55rem; align-self: flex-end; margin-bottom: .2rem; rotate: -3deg; }
:where(.lockup--sm) { flex-direction: row; align-items: center; gap: .3rem; }
:where(.loading-card .status) { font-size: var(--fs-body); font-weight: 900; }
:where(.loading-card .tip) { color: var(--ink-2); }
:where(.tip__star) { color: var(--gold-deep); }
:where(.loadbar) { border: var(--ow-s) solid var(--ink); border-radius: var(--r-pill); background: var(--ivory-2); }
:where(#load-bar) { background: var(--grad-fire); border-radius: inherit; }
:where(.title-foot__chip) { padding: .15rem .6rem; border-radius: var(--r-pill); background: var(--night); color: var(--ivory-2); font-size: var(--fs-small); }

/* code ticket */
:where(.ticket__in) { display: flex; align-items: center; justify-content: space-between; gap: .8rem; padding: .7rem 1rem; border: var(--ow) solid var(--ink); border-radius: var(--r-m); background: var(--paper); }
:where(.code-value) { font-size: 1.6rem; letter-spacing: .1em; user-select: all; -webkit-user-select: all; overflow-wrap: anywhere; }
:where(.ticket__stub) { font-size: var(--fs-small); font-weight: 900; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-2); }

/* HUD scaffold: readable on the dark stage */
:where(.song-plate) { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: center; column-gap: .5rem; padding: .3rem .6rem; border: var(--ow) solid var(--ink); border-radius: var(--r-m); background: var(--paper); color: var(--ink); }
:where(#hud-song) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-display); font-weight: 700; font-stretch: 75%; font-size: var(--fs-h3); }
:where(.song-plate__meta) { grid-column: 1 / -1; display: flex; gap: .4rem; align-items: center; font-size: var(--fs-small); }
:where(.lyrics) { display: grid; align-content: center; justify-items: center; padding: 0 1rem; border: var(--ow) solid var(--ink); border-radius: var(--r-pill); background: rgb(13 11 22 / .92); text-align: center; }
:where(.lyric-now) { max-width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-family: var(--font-display); font-weight: 700; font-stretch: 75%; font-size: var(--fs-lyric); color: var(--ivory); }
:where(.lyric-next) { max-width: 100%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: var(--fs-small); color: var(--ivory-3); }
:where(#section-toast) { opacity: 0; padding: .4rem .7rem; background: var(--paper); color: var(--ink); border: var(--ow) solid var(--ink); border-radius: 0 0 var(--r-m) var(--r-m); font-size: var(--fs-small); transition: opacity var(--t-base) linear; }
:where(#section-toast.on) { opacity: 1; }
:where(.rock__cap, .rock__chip) { font-size: var(--fs-small); font-weight: 900; text-transform: uppercase; letter-spacing: .06em; text-shadow: var(--hint-shadow); }
:where(.rock__tube) { border: var(--ow) solid var(--ink); border-radius: var(--r-pill); background: var(--night); }
:where(#rock-fill > i) { background: linear-gradient(0deg, var(--red) 0 25%, var(--ember) 25% 50%, var(--f3) 50% 75%, var(--gold) 75%); }
:where(.rock__line) { border-top: 2px dashed var(--ivory); }
:where(#rock-needle) { width: 1.4rem; height: 1.4rem; border-radius: 50%; background: var(--ivory); border: var(--ow-s) solid var(--ink); }
:where(.rock__bulb) { border-radius: 50%; background: var(--ivory); border: var(--ow) solid var(--ink); }
:where(.dock) { display: grid; grid-template-rows: auto auto auto auto; align-content: space-between; padding: 1rem; }
:where(.dock__score .label) { color: var(--ivory-3); }
:where(.score, #hud-streak) { font-family: var(--font-num); font-weight: 700; font-size: var(--fs-score); line-height: 1.1; color: var(--ivory); }
:where(#hud-delta, #hud-streak-best) { font-size: var(--fs-small); color: var(--ivory-3); }
:where(.dock__streak) { display: flex; align-items: center; gap: .8rem; }
:where(.mult) { position: relative; width: 4.6rem; height: 4.6rem; display: grid; place-items: center; flex: none; }
:where(.mult svg) { position: absolute; inset: 0; width: 100%; height: 100%; rotate: -90deg; }
:where(.mult .ring-bg) { fill: none; stroke: rgb(246 240 228 / .2); stroke-width: 3; }
:where(.mult .ring) { fill: none; stroke-width: 3; stroke-dasharray: 0 100; }
:where(#hud-streak) { font-size: 1.4rem; }
:where(#hud-mult) { position: absolute; left: -.4rem; bottom: -.4rem; font-family: var(--font-num); font-weight: 700; font-size: var(--fs-small); padding: 0 .3rem; border-radius: var(--r-xs); background: var(--red); color: var(--ivory); }
:where(.mult__max) { display: none; }
:where(.dock__star) { display: flex; align-items: center; gap: .6rem; }
:where(.starbar) { display: grid; grid-template-columns: repeat(4, 1.6rem); gap: .3rem; }
:where(.starbar i) { position: relative; height: 1.8rem; overflow: clip; border: var(--ow-s) solid var(--ink); border-radius: 45% / 40%; background: var(--night-3); }
:where(.starbar i)::before { content: ''; position: absolute; inset: 0; background: var(--grad-blue); transform: translateY(calc(100% - var(--f, 0%))); }
:where(.star-hint) { font-size: var(--fs-small); color: var(--cobalt-hi); }
:where(.dock__rope) { display: grid; gap: .25rem; }
:where(.rope) { position: relative; height: 1rem; overflow-x: clip; border: var(--ow-s) solid var(--ink); border-radius: var(--r-pill); background: var(--ivory-2); }
:where(#hud-progress, #pause-bar) { position: absolute; inset: 0; display: block; width: 100%; background: var(--grad-fire); }
:where(#hud-time) { font-size: var(--fs-small); color: var(--ivory-3); }
:where(.dock__plate) { padding-block: 0; font-size: var(--fs-small); }
:where(#combo) { opacity: 0; padding: .4rem .9rem; border: var(--ow) solid var(--ink); border-radius: var(--r-m); background: var(--paper); color: var(--ink); font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h3); }
:where(#combo.pop) { animation: ff-slide-r 320ms var(--spring-soft) backwards, ff-fade-out 200ms linear 1.72s forwards; opacity: 1; }
:where(.judge) { font-family: var(--font-display); font-weight: 700; font-stretch: 100%; font-size: var(--fs-judge); }
/* G0 stopgap (wp0b-requests 1): ui.judge() adds .on and moves the node, which restarts this one-shot; it ends invisible.
   WP9 (screens/hud.css) replaces it with the per-kind treatment of SPEC 2.13. */
:where(.judge) { opacity: 0; }
:where(.judge.on) { opacity: 1; animation: ff-judge 300ms var(--spring-pop) backwards, ff-fade-out 160ms linear 380ms forwards; }
@media (prefers-reduced-motion: reduce) {
  :where(.judge.on) { animation: ff-fade 80ms linear backwards, ff-fade-out 160ms linear 380ms forwards; }
}
:where(#timing) { opacity: 0; padding: 0 .6rem; border-radius: var(--r-pill); border: var(--ow-s) solid var(--ink); font-size: var(--fs-small); font-weight: 900; text-transform: uppercase; color: var(--ink); background: var(--early); }
:where(#timing.late) { background: var(--late); }
:where(#timing.on) { opacity: 1; }
:where(#countdown) { font-size: var(--fs-count); }
:where(#countdown:empty, #endcap:empty) { display: none; }
:where(#endcap) { font-size: var(--fs-verdict); }

/* pause scaffold */
:where(.pause-sheet) { padding: 0 0 1rem; overflow: hidden auto; }
:where(.pause-sheet) > :where(:not(.band)) { margin-inline: 1rem; }
:where(.pause-sheet .band) { border-radius: 0; }
:where(.pause-sheet .rope) { overflow: clip; }

/* results scaffold */
:where(.results-board) { padding: 1rem 1.5rem; }
:where(.res-skip, .res-fail) { display: none; }
:where(.res-head) { display: grid; place-items: center; min-height: 5rem; }
:where(#res-verdict) { font-size: var(--fs-verdict); --tk-gradient: var(--grad-fire); }
:where(.res-side) { display: flex; align-items: center; gap: 1rem; }
:where(.res-cover-wrap) { position: relative; flex: none; width: 5rem; height: 5rem; }
:where(#res-cover) { width: 100%; height: 100%; object-fit: cover; border-radius: var(--r-s); border: var(--ow-s) solid var(--ink); }
:where(.res-song-info) { display: grid; justify-items: start; gap: .3rem; min-width: 0; }
:where(.res-song) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-family: var(--font-display); font-weight: 700; font-stretch: 75%; font-size: var(--fs-h2); }
:where(.res-crown) { margin-left: auto; font-size: var(--fs-small); }
:where(.res-score-row) { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
:where(.res-score-box) { display: flex; align-items: baseline; gap: .8rem; padding: .3rem 1rem; border: var(--ow-l) solid var(--ink); border-radius: var(--r-pill); background: var(--grad-gold); }
:where(.res-score-box__label) { font-size: var(--fs-small); font-weight: 900; text-transform: uppercase; letter-spacing: .1em; }
:where(.res-score) { font-family: var(--font-num); font-weight: 700; font-size: var(--fs-score-res); line-height: 1.1; }
:where(.badge-new) { padding: .1rem .7rem; border-radius: var(--r-s); background: var(--gold); border: var(--ow-s) solid var(--ink); font-size: var(--fs-small); font-weight: 900; }
:where(.stars) { font-family: var(--font-num); font-size: 2.2rem; letter-spacing: .1em; color: var(--ivory-3); min-height: 1.2em; }
:where(.stars span.on) { color: var(--red); }
:where(.stars.gold span.on) { color: var(--gold-deep); }
:where(.res-mid) { display: grid; gap: .8rem; }
:where(.breakdown) { display: flex; height: 1.4rem; overflow: hidden; border: var(--ow-s) solid var(--ink); border-radius: var(--r-pill); background: var(--ivory-2); }
:where(.breakdown i) { display: block; height: 100%; width: 0; transform-origin: 0 50%; }
:where(.b-perfect) { background: var(--gold); }
:where(.b-great) { background: var(--cobalt-hi); }
:where(.b-good) { background: var(--ivory-3); }
:where(.b-miss) { background: var(--miss); }
:where(.res-grid) { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .6rem 1rem; }
:where(.res-grid dt) { display: flex; align-items: center; gap: .35rem; font-size: var(--fs-small); text-transform: uppercase; letter-spacing: .06em; color: var(--ink-2); }
:where(.res-grid dd) { font-family: var(--font-num); font-weight: 700; font-size: var(--fs-h2); }
:where(.dot) { display: inline-block; width: .7rem; height: .7rem; border-radius: 50%; border: 1.5px solid var(--ink); }
:where(.res-ring) { display: none; }
:where(.res-timing-row) { display: flex; align-items: center; gap: 1rem; }
:where(.res-meter) { display: flex; align-items: center; gap: .4rem; font-size: var(--fs-small); text-transform: uppercase; color: var(--ink-2); }
:where(.res-meter__track) { position: relative; width: 8rem; height: .5rem; border-radius: var(--r-pill); background: var(--ivory-3); }
:where(.res-meter__mark) { position: absolute; left: 50%; top: 50%; width: .8rem; height: .8rem; translate: -50% -50%; border-radius: 50%; background: var(--ink); }
:where(.res-timing, .res-note, .res-rank) { font-size: var(--fs-small); }
:where(.res-rank) { display: flex; align-items: center; flex-wrap: wrap; gap: .3rem .8rem; min-height: 1.5em; }
:where(.res-rank:empty) { display: none; }
:where(.res-actions) { margin-top: auto; flex-wrap: nowrap; }
:where(.res-actions button) { flex: 1 1 0; min-height: 3.6rem; justify-content: space-between; }
:where(#btn-again) { flex-grow: 1.4; }
:where(#res-field) { background: radial-gradient(60rem 50rem at calc(2.5vw + var(--res-w) / 2) 50%, rgb(232 32 47 / .35), rgb(13 11 22 / .85)); -webkit-mask: linear-gradient(90deg, #000 0 calc(var(--safe-title-r) - 8rem), transparent var(--safe-title-r)); mask: linear-gradient(90deg, #000 0 calc(var(--safe-title-r) - 8rem), transparent var(--safe-title-r)); }

/* messages, toasts */
:where(.toast) { padding: .6rem 1rem; border: var(--ow) solid var(--ink); border-radius: var(--r-m); background: var(--paper); color: var(--ink); font-size: var(--fs-body); }
:where(#error)::before { content: 'Oops! '; color: var(--red); font-family: var(--font-display); font-weight: 700; }
:where(.narrow-pill) { padding: .2rem .9rem; border-radius: var(--r-pill); font-size: var(--fs-small); }
:where(.bubble) { padding: .5rem .8rem; border: var(--ow) solid var(--ink); border-radius: var(--r-m); background: var(--paper); color: var(--ink); font-size: var(--fs-body); }
:where(.note) { padding: .4rem .7rem; border-radius: var(--r-s); background: var(--ivory-2); }
:where(.warn-note) { background: var(--f2); color: var(--ink); }

/* focus fallback until the global cursor (WP1) exists */
:where(:focus-visible) { outline: 3px solid var(--focus); outline-offset: 3px; }
