/* ============================================================================
   TeamKeys — shell chrome (TELAIO). Every value is a token from
   app/design/tokens.css or a structural measure from the approved baseline
   (app/_baseline/TeamKeys.dc.html, cited [b:NN]) — the same convention as
   ATELIER's screen.css and card-anatomy.html, which this file follows.

   No --tk-state-* colour appears anywhere in the shell today: the shell shows
   scores and availability, which are data, not outcomes. State colour lives
   inside the exercises' own outcome surfaces (§14 of tokens.css), where D-021
   marking applies. The DEV banner carries its meaning as WORDS.
   ============================================================================ */

html,body{height:100%}
/* F10 (fixl2, dall'L2 dell'umano): the page is an app, not a document — no
   pinch-zoom, no double-tap zoom, no rubber-band. Without this the browser
   holds every tap ~300ms deciding if it is a double-tap, and EATS the second
   tap on Next as a zoom gesture (the observed multi-tap bug). A11y trade-off
   (pinch-zoom off) declared in L3: the frame already scales itself (R7). */
html,body{touch-action:manipulation;overscroll-behavior:none}
/* overflow hidden: the frame scales to the viewport (R7) — the page itself
   never scrolls, every scroll lives inside the glass */
body{margin:0;overflow:hidden;display:flex;align-items:center;justify-content:center;
     padding:8px;background:var(--tk-surface-void-field), var(--tk-surface-void);
     font-family:var(--tk-font-sans);color:var(--tk-ink-primary);
     -webkit-font-smoothing:antialiased}

/* D-044 package (d): THE SHELL IS THE GLASS WORLD — declared here, not
   inherited (C-5y: every screen with the mark reads its world off this
   line). The one dark room left is the run itself: games keep their world
   and the ≤480ms worldshift veil is the door. Ink follows the immediate
   surface, not the world — so the dark card faces and the run chrome keep
   their light ink below. */
/* E-006: flex:0 0 auto — the frame is a flex child of body and its DECLARED
   390 was being shrunk to 344 at 360w / 374 at 390w (measured). The width
   contract is layout; fitting small viewports is the R7 transform's job. */
.frame{width:390px;height:844px;position:relative;overflow:hidden;flex:0 0 auto;
     border-radius:var(--tk-radius-frame);background:var(--tk-bg-field);
     color:var(--tk-glass-ink-primary);
     box-shadow:var(--tk-shadow-frame),var(--tk-shadow-hairline);
     display:flex;flex-direction:column}
.frame[data-screen="play"]{background:var(--tk-surface-frame);color:var(--tk-ink-primary)}
.frame .glow{position:absolute;inset:0;pointer-events:none;z-index:1;
     background:radial-gradient(80% 40% at 50% 22%,var(--tk-accent-glow) 0%,transparent 70%)}

/* --- status bar [b:25-31] ------------------------------------------------- */
.status{display:flex;align-items:center;justify-content:space-between;height:54px;
     padding:0 var(--tk-gutter);position:relative;z-index:3;flex:0 0 auto;
     font:var(--tk-weight-medium) var(--tk-text-mono) var(--tk-font-mono);
     color:var(--tk-glass-ink-primary)}
.status .right{display:flex;gap:var(--tk-space-2);align-items:center}
.status .cell{width:16px;height:9px;border-radius:var(--tk-radius-xs);
     border:1px solid var(--tk-glass-ink-secondary)}
.status .batt{width:22px;height:10px;border-radius:var(--tk-radius-sm);
     border:1px solid var(--tk-glass-ink-secondary);position:relative}
.status .batt i{position:absolute;inset:1.5px;right:5px;background:var(--tk-glass-ink-primary);
     border-radius:1px}
/* the run keeps the dark chrome: ink follows the immediate surface */
.frame[data-screen="play"] .status{color:var(--tk-ink-strong)}
/* exit affordance during a run — shell furniture, outside the engine's mount */
.status .exit{display:none;align-items:center;gap:var(--tk-space-2);
     min-height:var(--tk-target-min);padding:0 var(--tk-space-3);margin-right:calc(0px - var(--tk-space-3));
     background:none;border:0;cursor:pointer;touch-action:manipulation;
     font:var(--tk-weight-medium) var(--tk-text-mono) var(--tk-font-mono);
     letter-spacing:var(--tk-tracking-wide);color:var(--tk-ink-secondary)}
.frame[data-screen="play"] .status .exit{display:flex}
.frame[data-screen="play"] .status .right{display:none}

/* --- screen area ---------------------------------------------------------- */
/* No padding here: the play screen hands the FULL 390×712 to the engine
   (contract mountEl). Every other screen applies .pad itself. */
#screen{flex:1;position:relative;z-index:2;display:flex;flex-direction:column;
     overflow:hidden;min-height:0}
.pad{padding-left:var(--tk-gutter);padding-right:var(--tk-gutter)}
.scroll{overflow-y:auto;min-height:0}
/* The frame simulates a phone: a desktop scrollbar inside the glass breaks
   the illusion. Scroll stays (wheel, drag, touch); the bar never shows —
   frame-wide, so any scrolling surface now or later is covered. */
.frame *{scrollbar-width:none}               /* Firefox */
.frame *::-webkit-scrollbar{display:none}    /* Chrome / Edge */

/* --- nav [b:64-70] -------------------------------------------------------- */
/* glass chrome per screen.css (package d): one recipe, the shell is one
   world now. Inactive inks are the glass steps the reference measured:
   label 6.81:1, active 15.09:1, marker on the faint step (C-5q). */
/* E-006: box-sizing border-box — in content-box this bar RENDERED 93px
   (78 + 14 padding + 1 border) and the 15px came out of #screen's 712,
   clipping every engine's bottom edge (measured at four widths: screen
   697, elementFromPoint at the mount's bottom answered the NAV). The
   844 = 54 + 712 + 78 budget only closes if 78 is the RENDERED height. */
.nav{display:flex;justify-content:center;gap:74px;align-items:center;height:78px;
     box-sizing:border-box;
     padding:0 14px 14px;border-top:1px solid var(--tk-glass-border);
     background:var(--tk-glass-paint);backdrop-filter:blur(var(--tk-glass-blur));
     position:relative;z-index:3;flex:0 0 auto}
.nav .item{display:flex;flex-direction:column;align-items:center;gap:5px;padding-top:12px;
     min-width:var(--tk-target-min);min-height:var(--tk-target-min);
     background:none;border:0;cursor:pointer;color:inherit}
/* the 44px column target is the button itself (min-width/height below):
   visual stays 20px, the hit area is transparent — the vault-index pattern. */
.nav .item .mark{width:20px;height:20px;border:1.5px solid var(--tk-glass-mark-rest);
     background:transparent;display:block}
.nav .item .mark.sq{border-radius:var(--tk-radius-md)}
.nav .item .mark.rd{border-radius:var(--tk-radius-round)}
.nav .item span{font:var(--tk-weight-medium) var(--tk-text-micro) var(--tk-font-mono);
     letter-spacing:var(--tk-tracking-wide);color:var(--tk-glass-ink-secondary)}
.nav .item.active .mark{border-color:var(--tk-glass-ink-primary);background:var(--tk-glass-surface)}
.nav .item.active span{color:var(--tk-glass-ink-primary)}
/* during a run the nav is inert: leaving an exercise goes through EXIT,
   which destroys the engine — never through a tab that leaks a half-run */
.frame[data-screen="play"] .nav .item{pointer-events:none;opacity:var(--tk-pulse-min)}
/* …and OPAQUE-DARK (咖啡's reference, D-059 round): the glass paint
   composites to #918f95 over a dark run — a light 78px band under every
   dark room. Declared in the reference, not a silent restyle. Specificity
   0,2,1 also beats the C-5v guard fallbacks, correctly: an opaque value
   needs no fallback. */
.frame[data-screen="play"] .nav{background:var(--tk-surface-nav-opaque)}
/* f5nav (fixl2, dall'L2 dell'umano): during ONBOARDING (name capture and
   the 18 items) there is no profile to navigate yet — a nav that leads
   away from a half-done registration is dead weight or a temptation.
   display:none is ABSENT for the screen reader too (no tab stops on
   buttons that must not exist there); it returns from the first post-gate
   screen. The D-045 gate walls stay untouched underneath — this is the
   visual layer, never the guard. DECLARED: the 78px the nav frees flow to
   the content (flex does it), which is exactly what the 18-item screen
   wants; the 712 mount contract lives on play, where the nav stands. */
.frame[data-screen="intro"] .nav,
.frame[data-screen="questionnaire"] .nav{display:none}

/* C-5v: whoever blurs answers BOTH ways — @supports covers "the engine
   cannot", prefers-reduced-transparency covers "the reader asked me not
   to". The opaque is the composite over the lightest thing that can
   scroll beneath (tokens §1); translucent-without-fallback was a baseline
   defect, not a cosmetic choice. Pinned by translucency.test.js. */
@supports not (backdrop-filter: blur(1px)){
  .nav{background:var(--tk-glass-surface)}
  .dev-banner{background:var(--tk-glass-surface)}
  .btn.secondary{background:var(--tk-glass-surface);
       box-shadow:inset 0 0 0 1px var(--tk-glass-border-strong),var(--tk-shadow-card)}
  .panel{background:var(--tk-glass-surface)}
}
@media (prefers-reduced-transparency: reduce){
  .nav{background:var(--tk-glass-surface);backdrop-filter:none}
  .dev-banner{background:var(--tk-glass-surface);backdrop-filter:none}
  .btn.secondary{background:var(--tk-glass-surface);backdrop-filter:none;
       box-shadow:inset 0 0 0 1px var(--tk-glass-border-strong),var(--tk-shadow-card)}
  .panel{background:var(--tk-glass-surface);backdrop-filter:none}
  /* r16bg: the still equivalent — no blur, the mask's fade alone keeps the
     band soft; every value stays a canonical token */
  .stage-backdrop .fill{filter:none}
}

/* --- shared type roles (screen.css contract) ------------------------------ */
.h-display{font:var(--tk-weight-semibold) var(--tk-text-display)/var(--tk-leading-tight) var(--tk-font-sans);
     letter-spacing:var(--tk-tracking-tight)}
.h-title{font:var(--tk-weight-semibold) var(--tk-text-title)/var(--tk-leading-snug) var(--tk-font-sans)}
.kicker{font:var(--tk-weight-medium) var(--tk-text-micro) var(--tk-font-mono);
     letter-spacing:var(--tk-tracking-wider);text-transform:uppercase;
     color:var(--tk-glass-ink-secondary)}
.body-copy{font:var(--tk-weight-regular) var(--tk-text-body)/var(--tk-leading-body) var(--tk-font-sans);
     color:var(--tk-glass-ink-secondary)}
.mono{font:var(--tk-weight-medium) var(--tk-text-mono) var(--tk-font-mono)}

/* --- the button system (D-044 package b, screens/buttons.html) ------------ */
/* Three ranks, five states, every state on a non-colour channel (D-008):
   hover lifts, press sinks (geometry), focus adds a ring that is INK — the
   measurement talking, accent-on-accent is 1.00:1 — disabled goes flat AND
   dim. Primary fill is --tk-accent-strong, NEVER the brand value.
   Rank mapping in this shell (declared): primary = forward CTAs;
   secondary (glass) = back/neutral — its white paint stays readable even
   over the still-dark screens; ghost is PARKED until the screen world turns
   glass: transparent + dark ink on the dark frame would be invisible. */
.btn{display:inline-flex;align-items:center;justify-content:center;width:100%;
     min-height:var(--tk-btn-h);padding:0 var(--tk-btn-pad-x);
     border-radius:var(--tk-radius-pill);border:0;cursor:pointer;
     font:var(--tk-weight-semibold) var(--tk-text-body) var(--tk-font-sans);
     transition:transform var(--tk-duration-feedback) var(--tk-ease-screen),
                box-shadow var(--tk-duration-feedback) var(--tk-ease-screen)}
/* F11 (fixl2): the primary carried --tk-shadow-card — a DARK-WORLD value
   (0 24px 50px black .6) that on the light glass world painted a squared,
   off-centre smudge under the quiz CTA. The human ordered fix-or-remove;
   removed: on glass the pill needs no pedestal. */
.btn.primary{background:var(--tk-btn-primary-fill);color:var(--tk-btn-primary-ink)}
.btn.secondary{background:var(--tk-glass-paint);color:var(--tk-btn-secondary-ink);
     backdrop-filter:blur(var(--tk-glass-blur));
     box-shadow:inset 0 0 0 1px var(--tk-glass-border),var(--tk-shadow-card)}
.btn.ghost{background:transparent;color:var(--tk-btn-ghost-ink);
     box-shadow:inset 0 0 0 1px var(--tk-btn-ghost-border)}
.btn.primary:hover{box-shadow:0 6px 18px rgba(148,24,255,.28)}
.btn.secondary:hover,.btn.ghost:hover{box-shadow:inset 0 0 0 1px var(--tk-glass-border-strong),var(--tk-shadow-card)}
.btn:active{transform:translateY(var(--tk-btn-press-shift));box-shadow:none}
.btn:focus-visible{outline:var(--tk-btn-focus-ring-w) solid var(--tk-btn-focus-ring);
     outline-offset:var(--tk-btn-focus-ring-gap)}
.btn:disabled{cursor:not-allowed;box-shadow:none;transform:none}
.btn.primary:disabled{background:color-mix(in srgb, var(--tk-btn-primary-fill) 45%, transparent);
     color:var(--tk-glass-ink-primary)}
.btn.secondary:disabled,.btn.ghost:disabled{opacity:.55;
     box-shadow:inset 0 0 0 1px var(--tk-glass-border-strong)}

/* --- DEV banner (D-024) — meaning carried by its words -------------------- */
/* F3 (fixl2): the pill lives INSIDE the status strip (its middle is empty
   on every screen: time left, battery right, EXIT left on play) — it no
   longer sits on the screens' kickers. */
.dev-banner{position:absolute;left:50%;top:12px;transform:translateX(-50%);z-index:4;
     padding:var(--tk-space-1) var(--tk-space-3);border-radius:var(--tk-radius-pill);
     border:1px solid var(--tk-glass-border-strong);background:var(--tk-glass-paint);
     backdrop-filter:blur(var(--tk-glass-blur));white-space:nowrap;
     font:var(--tk-weight-medium) var(--tk-text-micro) var(--tk-font-mono);
     letter-spacing:var(--tk-tracking-wide);color:var(--tk-glass-ink-primary)}

/* --- idle hint (D-031, placement per 老干妈's finding) --------------------- */
/* The hint lives ADJACENT to the control it explains — in pixels AND in DOM
   order (a screen reader must meet it beside the answers, not after the
   nav). Each hinting screen reserves a one-line slot in flow, so the text
   fades in without shifting the layout; aria-live announces it to the ear
   at the same moment the eye gets it. */
.hint-slot{min-height:calc(var(--tk-text-body) * var(--tk-leading-body));
     margin-top:var(--tk-space-3);text-align:center;flex:0 0 auto}
.hint{opacity:0;transition:opacity var(--tk-duration-swap);
     font:var(--tk-weight-regular) var(--tk-text-body)/var(--tk-leading-body) var(--tk-font-sans);
     color:var(--tk-glass-ink-secondary)}
.hint.show{opacity:1}

/* --- VAULT: logo + carousel [b:37-53, D-042] ------------------------------ */
/* [home] geometry (D-049, 咖啡's measured budget — sums to 712.00 exact):
   26 border→mark (--tk-gutter) · 47.81 mark (--tk-logo-w at 2011:707) ·
   460 stage FIXED · 12 hint margin · 20.93 hint line · 20+worst-case+12
   caption · 8.41 rest. STRUCTURAL: the stage is FIXED and the caption
   absorbs the remainder — the card can never jump height between a
   one-line and a two-line tagline. The rendered-px pin judges. */
.vault-title{padding:var(--tk-gutter) var(--tk-gutter) 0;flex:0 0 auto;
     display:flex;justify-content:center}
/* C-5y: every shell screen that shows the mark (vault, ME, splash) sits in
   the glass world — declared on .frame's background above, dark only behind
   [data-screen="play"], which never shows the mark. The mark takes ITS
   world's ink; the old dark-frame stopgap died with the dark frame. */
.logo{display:block;color:var(--tk-logo-ink)}
.vault-title .logo{width:var(--tk-logo-w);height:auto}
.me-head .logo{width:var(--tk-logo-w-compact);height:auto;flex:0 0 auto}
/* ME header: the compact logo BESIDE the screen's own title (tokens §18) */
.me-head{display:flex;justify-content:space-between;align-items:flex-start;
     gap:var(--tk-space-3)}
/* package (d): ring, horizon and edge masks were the DARK vault's dressing —
   the glass reference (vault.html) draws none of them; depth is the cards'
   own transform, opacity and blur. Gone with their world. */
/* r16bg (D-112) · the stage backdrop: 咖啡's ramp BEHIND the cards, never
   behind text. Outer layer clips (overflow) and fades (mask, the canonical
   fade token top AND bottom) so the inner 22px blur can never leak past
   the stage into the caption or the title. pointer-events none: scenery,
   not surface. The colour itself is set inline by the vault from the
   registry's declared map. */
.stage-backdrop{position:absolute;inset:0;overflow:hidden;pointer-events:none;
     -webkit-mask-image:linear-gradient(to bottom,
       transparent 0,#000 var(--tk-stage-backdrop-fade),
       #000 calc(100% - var(--tk-stage-backdrop-fade)),transparent 100%);
     mask-image:linear-gradient(to bottom,
       transparent 0,#000 var(--tk-stage-backdrop-fade),
       #000 calc(100% - var(--tk-stage-backdrop-fade)),transparent 100%)}
.stage-backdrop .fill{position:absolute;inset:0;
     filter:blur(var(--tk-stage-backdrop-blur));
     transition:background-color .45s ease}
/* the reduced-motion and reduced-transparency answers live in the ONE
   canonical media block each (the C-5r/C-5v guards read the FIRST block as
   THE block — a second block would blind them, measured) */
.stage{position:relative;height:460px;margin-top:0;flex:0 0 auto;
     touch-action:pan-y;user-select:none;cursor:grab}
.stage .track{position:absolute;inset:0;
     perspective:var(--tk-perspective);perspective-origin:50% 50%}

/* THE INDEX ROW IS GONE (D-042 R2): played-state lives on the caption
   kicker (D-037 strings), position on the card's own numeral, navigation on
   the swipe and on the cards' keyboard door. The kicker's load-bearing
   condition — the vault returns to the card just played — is still the
   shell's to keep. */

.vault-caption{padding:var(--tk-space-5) var(--tk-gutter) var(--tk-space-3);
     flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column}
.vault-caption .h-title{display:flex;align-items:center;justify-content:space-between}
.vault-caption .body-copy{margin-top:var(--tk-space-2)}
/* D-045: the leaderboard door beside the game name — 咖啡's podium glyph
   in the chip; the hit area is the 44px the finger needs. */
.lb-door{background:none;cursor:pointer;display:inline-flex;
     align-items:center;justify-content:center;
     border:1px solid var(--tk-field-border-strong);border-radius:var(--tk-radius-pill);
     padding:var(--tk-space-1) var(--tk-space-3);min-height:var(--tk-target-min);
     color:var(--tk-glass-ink-secondary)}
.lb-door svg{width:20px;height:20px;display:block;
     stroke-width:var(--tk-card-glyph-stroke)}
.lb-door:focus-visible{outline:var(--tk-btn-focus-ring-w) solid var(--tk-btn-focus-ring);
     outline-offset:var(--tk-btn-focus-ring-gap)}

/* the fake 9:41 doubles the OS bar on a real phone (playtest): the strip
   stays — it hosts EXIT and holds the 54px the mount contract counts on —
   the decorations go */
@media (pointer: coarse) and (max-width: 430px){
  .status > span:first-child, .status .right{visibility:hidden}
}

/* --- mob [fullbleed] (D-059 round): on a REAL phone the phone IS the
   frame. The drawn bezel (radius, frame shadow, desk void behind it) is a
   desktop mockup — on a phone viewport it reads «an app inside an app»
   (the human's own words, verbatim in the brief). The 390×844 LAYOUT and
   the R7 fit transform are untouched: geometry contracts stay; only the
   desk chrome dies. The desk becomes the field, so any letterboxing from
   the fit-scale sits on the app's own colour, not on a void. ------------- */
@media (pointer: coarse) and (max-width: 430px){
  body{padding:0;background:var(--tk-bg-field)}
  .frame{border-radius:0;box-shadow:none}
}
/* installed (standalone) on a notched phone: the nav must not sit under
   the home indicator. The inset pads the BODY, never the nav — growing
   the nav would squeeze #screen under its 712 contract (E-006). The frame
   stays 844; the R7 fit absorbs the slightly smaller room and the inset
   strip shows the app's own field colour. */
@media (display-mode: standalone) and (pointer: coarse){
  body{padding-bottom:env(safe-area-inset-bottom, 0px)}
}

/* --- game card, anatomy per app/design/card-anatomy.html ------------------ */
/* D-042: enlarged card, single face for all seven (the hue septet is dead —
   measured ΔEok .028/.009 against JND ~.02: it was never seven identities).
   Identity lives on glyph + numeral + preview; the face is one token. */
.card{position:absolute;left:50%;top:50%;width:272px;height:408px;
     margin:-204px 0 0 -136px;border-radius:var(--tk-radius-lg);overflow:hidden;
     will-change:transform,filter,opacity}         /* [D-042 · D-049: median 230,
                                                       26 above and below in the
                                                       fixed 460 stage] */
.card .bg{position:absolute;inset:0;border-radius:var(--tk-radius-lg);
     background:var(--tk-card-face);
     box-shadow:var(--tk-shadow-card),var(--tk-shadow-inset-top)}
.card .edge{position:absolute;inset:0;border-radius:var(--tk-radius-lg);
     border:1px solid var(--tk-line-border)}
.card .sheen{position:absolute;left:-30%;top:-40%;width:160%;height:80%;
     background:linear-gradient(105deg,var(--tk-fill-dim),transparent 60%);
     transform:rotate(-14deg)}
.card .glyph{position:absolute;left:var(--tk-space-4);top:var(--tk-space-4);
     width:var(--tk-card-glyph-size);height:var(--tk-card-glyph-size);
     color:var(--tk-ink-strong)}
.card .glyph svg{width:100%;height:100%;stroke-width:var(--tk-card-glyph-stroke)}
.card .index{position:absolute;right:var(--tk-space-4);top:var(--tk-space-5);
     font:var(--tk-weight-medium) var(--tk-text-mono) var(--tk-font-mono);
     letter-spacing:var(--tk-tracking-wider);color:var(--tk-ink-strong)}
.card .index small{font-size:var(--tk-text-micro);color:var(--tk-ink-strong);
     letter-spacing:var(--tk-tracking-wider)}
     /* D-094: the denominator joins its numerator at .85 — the last .55 ink on the
        card face capped every per-game backdrop at near-black (咖啡's measured
        budget: with .55 the r10fx mandate is unsatisfiable, with .85 the worst
        corner is 5.19:1). Size still carries the hierarchy. */
.card .name{position:absolute;left:var(--tk-space-4);right:var(--tk-space-4);bottom:44px;
     font:var(--tk-weight-semibold) var(--tk-text-heading)/var(--tk-leading-tight) var(--tk-font-sans);
     letter-spacing:var(--tk-tracking-tight);color:var(--tk-ink-primary)}
.card .segs{position:absolute;left:var(--tk-space-4);right:var(--tk-space-4);bottom:var(--tk-space-5);
     display:flex;gap:var(--tk-space-1)}
.card .segs i{flex:1;height:14px;border-radius:1px;background:var(--tk-fill-dim)}
.card .segs i:nth-child(3n+1){background:var(--tk-fill-mid)}
/* D-032: the game preview — ONE node in the whole shell, re-parented onto
   the front card (the animations bind to the symbol originals, so gating
   which card animates = gating which card HOSTS the instance). Sits under
   the glyph, above the name; ink from the card (currentColor contract). */
.card .preview{position:absolute;left:50%;
     top:calc(var(--tk-space-4) + var(--tk-card-glyph-size) + var(--tk-space-4));
     width:var(--tk-card-preview-w);height:var(--tk-card-preview-h);
     margin-left:calc(var(--tk-card-preview-w) / -2);
     color:var(--tk-ink-primary);pointer-events:none}
.card .preview svg{width:100%;height:100%;display:block}

/* --- questionnaire (reference: design/screens/questionnaire-item.html) ---- */
.progress{margin-top:var(--tk-space-4)}
.progress .bar{height:3px;border-radius:var(--tk-radius-xs);background:var(--tk-glass-border-strong);
     margin-top:var(--tk-space-2);position:relative;overflow:hidden}
.progress .bar i{position:absolute;left:0;top:0;bottom:0;
     background:var(--tk-accent);border-radius:var(--tk-radius-xs)}
.q-item{margin-top:var(--tk-space-6);
     font:var(--tk-weight-medium) var(--tk-text-item)/var(--tk-leading-item) var(--tk-font-sans)}
.options{display:flex;flex-direction:column;gap:var(--tk-space-3);margin-top:var(--tk-space-6)}
.opt{display:flex;align-items:center;gap:var(--tk-space-3);text-align:left;
     min-height:var(--tk-target-min);padding:var(--tk-space-3) var(--tk-space-4);
     border-radius:var(--tk-radius-lg);border:1px solid var(--tk-field-border-strong);
     background:none;cursor:pointer;
     font:var(--tk-weight-regular) var(--tk-text-item)/var(--tk-leading-item) var(--tk-font-sans);
     color:var(--tk-field-ink-primary)}
.opt .ring{flex:0 0 auto;width:20px;height:20px;border-radius:var(--tk-radius-round);
     border:1.5px solid var(--tk-field-mark-rest);position:relative}
.opt.selected{border-color:var(--tk-field-mark-chosen);
     box-shadow:inset 0 0 0 1px var(--tk-field-mark-chosen);color:var(--tk-glass-ink-primary)}
     /* D-105: --tk-accent-line is a decorative horizon rule (1.39:1 on the field) —
        borrowed as a STATE boundary it was the worst of the four E-011 cases.
        The chosen-state mark already exists, measured on this ground. */
.opt.selected .ring{border-color:var(--tk-field-mark-chosen)}
.opt.selected .ring::after{content:"";position:absolute;inset:4px;
     border-radius:var(--tk-radius-round);background:var(--tk-field-mark-chosen)}
.likert{display:flex;gap:var(--tk-space-2);margin-top:var(--tk-space-6)}
.lk{flex:1;display:flex;align-items:center;justify-content:center;
     min-height:var(--tk-target-min);border-radius:var(--tk-radius-md);
     border:1px solid var(--tk-field-border-strong);background:none;cursor:pointer;
     font:var(--tk-weight-medium) var(--tk-text-mono) var(--tk-font-mono);
     color:var(--tk-field-ink-primary)}
.lk.selected{border-color:var(--tk-accent);box-shadow:inset 0 0 0 1px var(--tk-accent);
     color:var(--tk-glass-ink-primary)}
.anchors{display:flex;justify-content:space-between;margin-top:var(--tk-space-2);
     font:var(--tk-weight-regular) var(--tk-text-body)/var(--tk-leading-body) var(--tk-font-sans);
     color:var(--tk-glass-ink-secondary)}
.cta{margin-top:auto;margin-bottom:var(--tk-space-5);display:flex;flex-direction:column;gap:var(--tk-space-3)}

/* --- player selector (D-044) ---------------------------------------------- */
/* D-045: the profile door carries its disclosure chevron (me.html .door):
   the whole row is the target, the shape says «this opens» */
.profile-btn{background:none;border:0;padding:0;cursor:pointer;text-align:left;
     color:inherit;min-height:var(--tk-target-min);
     display:flex;align-items:center;gap:6px}
.profile-btn .ch{width:18px;height:18px;flex:0 0 auto;color:var(--tk-glass-ink-secondary)}
.profile-btn .ch svg{width:100%;height:100%;stroke-width:var(--tk-card-glyph-stroke)}
/* D-049 [nome]: the rename door and its in-place editor. Errors are words
   in flow (aria-live) — never colour-only (D-008). */
.name-edit-door{background:none;cursor:pointer;
     border:1px solid var(--tk-field-border-strong);border-radius:var(--tk-radius-pill);
     padding:var(--tk-space-1) var(--tk-space-3);min-height:var(--tk-target-min);
     font:var(--tk-weight-medium) var(--tk-text-micro) var(--tk-font-mono);
     letter-spacing:var(--tk-tracking-wider);text-transform:uppercase;
     color:var(--tk-glass-ink-secondary)}
.name-edit-door:focus-visible{outline:var(--tk-btn-focus-ring-w) solid var(--tk-btn-focus-ring);
     outline-offset:var(--tk-btn-focus-ring-gap)}
.field-error{min-height:calc(var(--tk-text-body) * var(--tk-leading-body));
     font:var(--tk-weight-regular) var(--tk-text-body)/var(--tk-leading-body) var(--tk-font-sans);
     color:var(--tk-glass-ink-primary)}
.name-edit-cta{margin-top:var(--tk-space-2);margin-bottom:0}
.profile-list{margin-top:var(--tk-space-5);display:flex;flex-direction:column}
.profile-row{display:flex;align-items:center;justify-content:space-between;width:100%;
     min-height:var(--tk-target-min);padding:var(--tk-space-3) 0;text-align:left;
     background:none;border:0;cursor:pointer;
     border-top:1px solid var(--tk-field-border-strong)}
.profile-list [role="listitem"]:last-child .profile-row{border-bottom:1px solid var(--tk-field-border-strong)}
.profile-row .n{font:var(--tk-weight-medium) var(--tk-text-item)/var(--tk-leading-item) var(--tk-font-sans);
     color:var(--tk-glass-ink-primary);display:block}
.profile-row .t{font:var(--tk-weight-regular) var(--tk-text-micro) var(--tk-font-sans);
     color:var(--tk-glass-ink-secondary);display:block}
.profile-row .v{font:var(--tk-weight-medium) var(--tk-text-micro) var(--tk-font-mono);
     letter-spacing:var(--tk-tracking-wide);text-transform:uppercase;
     color:var(--tk-glass-ink-secondary)}
.profile-row.current .n{color:var(--tk-glass-ink-primary)}

/* --- splash (D-044): first paint, never a blocker -------------------------- */
/* Dressing from 咖啡's reference (screens/splash.html), rules mirrored;
   the phase machine (splash.js) owns the timing, this owns the light. */
#splash{position:absolute;inset:0;z-index:5;overflow:hidden;
     background:var(--tk-bg-field);
     display:flex;flex-direction:column;align-items:center;justify-content:center;
     opacity:1;transition:opacity var(--tk-splash-fade, 700ms)}
#splash[data-phase="out"]{opacity:0;pointer-events:none}
#splash .splash-scene{position:absolute;inset:0;display:flex;flex-direction:column;
     align-items:center;justify-content:center}
.sp-flash{position:absolute;inset:0;background:#fff;opacity:0;
     animation:sp-flash var(--tk-splash-flash) ease-out 1}
@keyframes sp-flash{0%{opacity:.85}100%{opacity:0}}
.sp-horizon{position:absolute;left:0;right:0;top:46%;height:1px;
     background:var(--tk-splash-line)}
.sp-glow{position:absolute;left:50%;top:46%;width:300px;height:150px;
     transform:translate(-50%,-50%);pointer-events:none;
     background:radial-gradient(50% 50% at 50% 50%, rgba(148,24,255,.20) 0%, rgba(148,24,255,0) 70%);
     animation:sp-breathe var(--tk-splash-breathe) ease-in-out infinite}
@keyframes sp-breathe{0%,100%{opacity:.55;transform:translate(-50%,-50%) scale(1)}
                      50%{opacity:1;transform:translate(-50%,-50%) scale(1.08)}}
.sp-p{position:absolute;width:var(--tk-splash-particle);height:var(--tk-splash-particle);
     border-radius:var(--tk-radius-round);background:var(--tk-accent-strong);opacity:.5}
.sp-p.p1{left:22%;top:calc(46% - 26px);animation:sp-drift 4200ms ease-in-out infinite}
.sp-p.p2{left:63%;top:calc(46% - 12px);animation:sp-drift 5200ms ease-in-out infinite reverse}
.sp-p.p3{left:79%;top:calc(46% + 18px);animation:sp-drift 4700ms ease-in-out infinite}
@keyframes sp-drift{0%,100%{transform:translateY(0);opacity:.5}
                    50%{transform:translateY(-9px);opacity:.9}}
.sp-logo{position:relative;z-index:2;display:flex;flex-direction:column;
     align-items:center;margin-top:-6%}
.sp-logo svg{width:var(--tk-splash-logo-w);height:auto;display:block;
     color:var(--tk-logo-ink)}
.sp-tag{margin-top:14px;
     font:var(--tk-weight-medium) var(--tk-text-micro) var(--tk-font-mono);
     letter-spacing:var(--tk-tracking-wider);text-transform:uppercase;
     color:var(--tk-splash-tagline-ink)}
.sp-tick{position:absolute;width:18px;height:18px;
     border-color:var(--tk-glass-border-strong);border-style:solid;border-width:0}
.sp-tick.tl{left:24px;top:24px;border-left-width:1px;border-top-width:1px}
.sp-tick.tr{right:24px;top:24px;border-right-width:1px;border-top-width:1px}
.sp-tick.bl{left:24px;bottom:24px;border-left-width:1px;border-bottom-width:1px}
.sp-tick.br{right:24px;bottom:24px;border-right-width:1px;border-bottom-width:1px}
/* the inline failsafe's escape hatch — independent of the machine */
#splash.gone{opacity:0;pointer-events:none}

/* --- player name capture (D-042 R3) --------------------------------------- */
.name-field{margin-top:var(--tk-space-6);display:flex;flex-direction:column;gap:var(--tk-space-2)}
.name-input{min-height:var(--tk-target-min);padding:var(--tk-space-3) var(--tk-space-4);
     border-radius:var(--tk-radius-lg);border:1px solid var(--tk-field-border-strong);
     background:transparent;color:var(--tk-field-ink-primary);
     font:var(--tk-weight-regular) var(--tk-text-item)/var(--tk-leading-item) var(--tk-font-sans)}
.name-input:focus{outline:none;border-color:var(--tk-btn-focus-ring);
     box-shadow:inset 0 0 0 1px var(--tk-btn-focus-ring)}
     /* D-105: a focus ring is the indicator keyboard navigation lives on —
        the borrowed horizon rule gave it 1.39:1; the house focus ring is
        11.26:1 on this field. */

/* --- briefing ------------------------------------------------------------- */
/* F1 (fixl2): the briefing's floor is RESERVED — the CTA is a sibling of
   the scroll region (the home's recipe), so a long biography scrolls under
   it instead of burying it. flex:0 0 auto: the floor never gets squeezed. */
.brief-cta{flex:0 0 auto}
.brief-head{display:flex;align-items:flex-start;justify-content:space-between;
     margin-top:var(--tk-space-6)}
.brief-head .glyph{width:var(--tk-card-glyph-size);height:var(--tk-card-glyph-size);
     color:var(--tk-glass-ink-primary)}
.brief-head .glyph svg{width:100%;height:100%;stroke-width:var(--tk-card-glyph-stroke)}
.brief-title{margin-top:var(--tk-space-4)}
.brief-copy{margin-top:var(--tk-space-4);display:flex;flex-direction:column;gap:var(--tk-space-3)}
.soon-chip{display:inline-flex;align-items:center;align-self:flex-start;
     padding:var(--tk-space-1) var(--tk-space-3);border-radius:var(--tk-radius-pill);
     border:1px solid var(--tk-field-border-strong);background:transparent;
     font:var(--tk-weight-medium) var(--tk-text-micro) var(--tk-font-mono);
     letter-spacing:var(--tk-tracking-wider);text-transform:uppercase;
     color:var(--tk-field-ink-secondary)}

/* --- play ----------------------------------------------------------------- */
.mount{width:390px;height:712px;position:relative;flex:0 0 auto}

/* --- outcome -------------------------------------------------------------- */
.score-line{display:flex;align-items:baseline;gap:var(--tk-space-2);margin-top:var(--tk-space-4)}
.score-line .value{font:var(--tk-weight-semibold) var(--tk-text-score)/1 var(--tk-font-mono)}
.score-line .of{font:var(--tk-weight-regular) var(--tk-text-body) var(--tk-font-sans);
     color:var(--tk-glass-ink-secondary)}
.indices{margin-top:var(--tk-space-4);display:flex;flex-direction:column}
.indices .row{display:flex;align-items:center;justify-content:space-between;
     min-height:var(--tk-target-min);border-top:1px solid var(--tk-glass-border-strong)}
.indices .row:last-child{border-bottom:1px solid var(--tk-glass-border-strong)}
.indices .row .n{font:var(--tk-weight-regular) var(--tk-text-body) var(--tk-font-sans);
     color:var(--tk-glass-ink-primary)}
.indices .row .d{font:var(--tk-weight-regular) var(--tk-text-micro) var(--tk-font-sans);
     color:var(--tk-glass-ink-secondary);display:block}
.indices .row .v{font:var(--tk-weight-medium) var(--tk-text-mono) var(--tk-font-mono)}

/* D-075 · the glass panel around the board — the reference's own recipe
   (screens/leaderboard.html): the --tk-glass-border-strong separators
   measure legal (3,49:1) ON this paint; on the bare gradient they sat at
   2,60:1, under the 3:1 non-text floor — at fifteen rows, fourteen
   illegal lines. (The reference's flex:1 1 280px is its three-column
   page layout, not the panel's identity — dropped here.) */
.panel{border-radius:var(--tk-radius-lg);padding:16px;
     background:var(--tk-glass-paint);backdrop-filter:blur(var(--tk-glass-blur));
     box-shadow:inset 0 0 0 1px var(--tk-glass-border),var(--tk-shadow-card)}
.panel .indices{margin-top:0}

/* D-075 · la riga tua. PRESENZA + LUMINOSITÀ, nessuna tinta: togli ogni
colore da questa schermata e ti trovi lo stesso. */
.lb .row{border-left:2px solid transparent;padding-left:8px}
.lb .row .n{color:var(--tk-glass-ink-secondary)}
.lb .row.own{border-left-color:var(--tk-glass-ink-primary)}
.lb .row.own .n,.lb .row.own .v{color:var(--tk-glass-ink-primary)}

/* --- ME ------------------------------------------------------------------- */
.me-head{margin-top:var(--tk-space-4)}
.me-sec{margin-top:var(--tk-space-5)}
.gauges{display:flex;gap:var(--tk-space-3);margin-top:var(--tk-space-5)}
.gauge{flex:1;display:flex;flex-direction:column;align-items:center;gap:var(--tk-space-2)}
.gauge svg{width:100%;height:auto;display:block}
.gauge .g-label{font:var(--tk-weight-medium) var(--tk-text-micro) var(--tk-font-mono);
     letter-spacing:var(--tk-tracking-wider);text-transform:uppercase;
     color:var(--tk-glass-ink-secondary)}
/* full-bleed row (R8): the side labels need the gutter's 26px per side —
   the radar escapes .pad and spans the frame's full 390 */
.radar-wrap{margin:var(--tk-space-5) calc(0px - var(--tk-gutter)) 0;
     display:flex;justify-content:center}
.radar-wrap svg{width:100%;max-width:390px;height:auto;display:block}
.me-games{margin-top:var(--tk-space-5);margin-bottom:var(--tk-space-6);
     display:flex;flex-direction:column}
.me-games .row{display:flex;align-items:center;justify-content:space-between;
     min-height:var(--tk-target-min);border-top:1px solid var(--tk-glass-border-strong)}
.me-games .row:last-child{border-bottom:1px solid var(--tk-glass-border-strong)}
.me-games .row .n{font:var(--tk-weight-regular) var(--tk-text-body) var(--tk-font-sans);
     color:var(--tk-glass-ink-primary)}
.me-games .row .t{font:var(--tk-weight-regular) var(--tk-text-micro) var(--tk-font-sans);
     color:var(--tk-glass-ink-secondary);display:block}
.me-games .row .v{font:var(--tk-weight-medium) var(--tk-text-mono) var(--tk-font-mono)}
.me-games .row .v.na{color:var(--tk-glass-ink-secondary)}

/* --- screen transitions (D-044 package b) --------------------------------- */
/* Every setScreen fades the new screen in on the motion tokens; ENTERING A
   RUN is different: the GNG junction must land DARK within 480ms — the
   worldshift veil starts opaque and reveals inside 甜筒's adaptation beat
   (480 + 720 = 1200 exact). The constraint belongs to the beat, never the
   reverse. */
#screen.screen-enter > *{animation:screen-in var(--tk-duration-swap) var(--tk-ease-screen)}
@keyframes screen-in{from{opacity:0}to{opacity:1}}
#screen.world-shift::after{content:"";position:absolute;inset:0;z-index:4;
     background:var(--tk-surface-frame-base);pointer-events:none;
     animation:world-in var(--tk-duration-worldshift) var(--tk-ease-screen) forwards}
@keyframes world-in{from{opacity:1}to{opacity:0}}

/* --- reduced motion (tokens.css §9 + C-5r: the shell covers its own) ------ */
/* Every selector that declares a transition above must be neutralised here —
   enforced by reduced-motion.test.js, which enumerates them by pattern.
   The carousel's inertia is gated in carousel.js (stepToward); the previews
   stop inside previews.svg's own style block; the splash scene keeps its
   light and loses its movement (reference's own rule, mirrored). */
@media (prefers-reduced-motion: reduce){
  .hint{transition:none}
  #splash{transition:none}
  .btn{transition:none}
  .stage-backdrop .fill{transition:none}   /* r16bg: instant swap, no fade */
  .card{will-change:auto}
  .sp-flash{display:none}
  /* the particles declare their animation at TWO classes (.sp-p.p1…): a
     one-class reset loses on specificity and they never stopped — found
     by the C-5r animation guard on its first run; the reference carries
     the same twin defect (reported) */
  .sp-glow,.sp-p,.sp-p.p1,.sp-p.p2,.sp-p.p3{animation:none}
  .sp-glow{opacity:.8;transform:translate(-50%,-50%)}
  #screen.screen-enter > *{animation:none}
  #screen.world-shift::after{animation:none;opacity:0}
}
