/* SIDES — neon geometry on the void. Mobile-first, 44px+ targets. */

* { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

:root {
  /* Playtest 29 — ANGULAR HIG. One notch for every container that used to be
     a rounded card: Apple's structure (grouped lists, sheets, materials) in the
     game's own shape language. clip-path CLIPS borders and outer glows, so a
     clipped element carries its line as an INSET ring (the .form-chip idiom). */
  --notch: 12px;
  --bg: #05060f;
  --bg2: #0a0d1c;
  --panel: #10142a;
  --line: rgba(83, 232, 255, 0.16);
  --text: #eaf6ff;
  --dim: #8b96b8;
  --cyan: #53e8ff;
  --violet: #b78aff;
  --gold: #ffd166;
  --red: #ff5d5d;
  --pink: #ff6b9d;
}

html, body {
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  overscroll-behavior: none;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  overflow: hidden;
}

/* Playtest 29: --app-h is set by main.js ONLY when a home-screen web app's
   layout viewport comes up short of the screen (the iOS 26 toolbar-gap bug);
   otherwise the dynamic viewport is the truth, as before. */
#app { height: var(--app-h, 100dvh); max-width: 560px; margin: 0 auto; position: relative; }

.screen { position: absolute; inset: 0; display: none; }
.screen.active { display: block; }

/* Playtest 31 (art-director, third read): a custom property that references
   another is resolved ONCE, on the element that declares it — so a root-level
   `--clip-notch: polygon(var(--notch) …)` baked in 12px and every per-element
   `--notch` was inert: cards, buttons, tags and the switch all clipped at 12px
   whatever they asked for (measured). Declaring the polygon on EVERY element
   makes it compute against that element's own --notch. */
*, *::before, *::after {
  --clip-notch: polygon(var(--notch) 0, 100% 0, 100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%, 0 100%, 0 var(--notch));
}

/* Visually-hidden but screen-reader-available (labels/units for icon-only UI). */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* Stroked-SVG upgrade/weapon/tier icons — inherit currentColor, faint neon halo. */
.ico { display: block; filter: drop-shadow(0 0 4px currentColor); }

/* --- The Ascent (start + meta) --------------------------------------------- */
/* Deliberately NOT a stat-panel-and-cards screen. An immersive vertical climb:
   a fixed ladder-to-infinity backdrop the content scrolls up over, angular
   clip-path controls, and a spine-rail chart of the shapes to become. */
#ladder {
  /* Art pass: solid void by ~52% — the economy cards sit on clean ground
     instead of fighting the fixed backdrop's bright nodes while scrolling. */
  background:
    linear-gradient(to bottom, rgba(5,6,15,0) 0%, rgba(5,6,15,0.15) 30%, var(--bg) 52%, var(--bg) 100%),
    url('../assets/bg/ascent.png') top center / cover no-repeat,
    var(--bg);
}
/* --- The APP SHELL: fixed top bar · independent tab panes · bottom tab bar -- */
.app-top {
  position: absolute; top: 0; left: 0; right: 0; z-index: 10;
  display: flex; align-items: center; gap: 10px;
  padding: calc(6px + env(safe-area-inset-top)) 6px 6px 14px;
  /* Playtest 28 (Shai: "the app doesn't take up the whole screen on my
     iphone, specifically towards the bottom"): the bars are translucent
     MATERIALS now — the pane runs the full height and scrolls UNDER them,
     blurred, the way an iOS navigation/tab bar behaves. The bar no longer
     reads as a slab the app stops at. */
  background: rgba(5, 6, 15, 0.86);
  backdrop-filter: blur(20px) saturate(140%); -webkit-backdrop-filter: blur(20px) saturate(140%);
  border-bottom: 1px solid var(--line);
}
/* Art-director pass on v56: at 0.66 the content read SHARP through the bars —
   a material is ~0.86 effective and always paired with a scrim, so what
   scrolls under fades into the bar instead of being guillotined by the rule. */
.app-top::after, .tab-bar::before {
  content: ''; position: absolute; left: 0; right: 0; height: 22px; pointer-events: none;
}
.app-top::after { top: 100%; background: linear-gradient(to bottom, rgba(5, 6, 15, 0.8), rgba(5, 6, 15, 0)); }
.tab-bar::before { bottom: 100%; background: linear-gradient(to top, rgba(5, 6, 15, 0.8), rgba(5, 6, 15, 0)); }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .app-top, .tab-bar { background: rgba(5, 6, 15, 0.97); }
}
.app-logo { /* semantic <h1>, worn small — the tab is the identity now */
  margin: 0; font-size: 15px; font-weight: 900; letter-spacing: 0.3em; text-indent: 0.3em;
  color: var(--text); text-shadow: 0 0 12px rgba(83, 232, 255, 0.65);
}
.app-cur { margin-left: auto; display: flex; gap: 12px; font-variant-numeric: tabular-nums; align-items: center; }
.cur { font-size: 13.5px; font-weight: 800; }
.cur-flux { color: var(--gold); text-shadow: 0 0 10px rgba(255, 209, 102, 0.35); }
.cur-tok { color: var(--violet); text-shadow: 0 0 10px rgba(183, 138, 255, 0.35); }
.mute-btn {
  background: none; border: none; font-size: 18px; min-width: 44px; min-height: 44px;
  cursor: pointer; color: var(--text);
}

.pane {
  position: absolute; left: 0; right: 0;
  /* Playtest 28: the pane spans the FULL height and pads its content past both
     bars (57px each: 6 + 44 + 6 + the 1px rule) plus the safe-area insets — so
     rows scroll clear of the home indicator instead of the pane stopping
     above it (The Long Descent's build-21 dead-bar lesson, ported). It used to
     start at 50px + inset while the bar is 57px tall, so the first 7px of every
     pane were hidden under the bar. */
  top: 0; bottom: 0;
  overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
  padding: calc(57px + env(safe-area-inset-top) + 14px) 16px calc(57px + env(safe-area-inset-bottom) + 24px);
  display: none; background: var(--bg);
}
.pane.active { display: block; }
.pane-climb { background: transparent; }   /* the ascent backdrop reads through */

.tab-bar {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 10;
  display: flex;
  padding-bottom: env(safe-area-inset-bottom);
  /* Playtest 28: a material, not a slab (see .app-top). The bar still owns
     the home-indicator inset — that is where iOS puts a tab bar — but the
     content blurs through it, so the screen reads as one surface. */
  background: rgba(5, 6, 15, 0.86);
  backdrop-filter: blur(20px) saturate(140%); -webkit-backdrop-filter: blur(20px) saturate(140%);
  border-top: 1px solid var(--line);
}
.tab {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; min-height: 56px; background: none; border: none; cursor: pointer;
  color: var(--dim);
}
.tab-i { font-size: 17px; line-height: 1; display: block; }
.tab-i svg { display: block; }
.tab-t { font-size: 10.5px; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; }
.tab.active { color: var(--cyan); }
.tab.active .tab-i { text-shadow: 0 0 12px rgba(83, 232, 255, 0.8); }
.tab:focus-visible { outline: none; box-shadow: inset 0 0 0 3px var(--gold); }

/* Hero zone — pure backdrop; the ascent image reads through here. */
/* Playtest 15: this was a flex ROW holding two stacked children, so playtest
   13's YOUR RECORD strip rendered BESIDE the best-line — both crushed into
   narrow columns, and at real record numbers the best-line clipped off the
   left screen edge. The record-row's own rule always described a "strip under
   the best-line"; the container just never got its axis. Column: bottom-
   aligned (was align-items:flex-end), horizontally centred (was justify). */
.hero-zone {
  height: 32vh; min-height: 180px; display: flex; flex-direction: column;
  align-items: center; justify-content: flex-end; padding-bottom: 8px;
}
.best-line {
  text-align: center; color: var(--cyan); font-size: 13px; letter-spacing: 0.05em;
  font-weight: 600; text-shadow: 0 1px 10px rgba(0,0,0,0.9);
}

/* Descend — the single hexagon-cut CTA. */
.descend {
  display: block; width: 100%; margin: 4px 0 26px;
  clip-path: polygon(3% 0, 97% 0, 100% 50%, 97% 100%, 3% 100%, 0 50%);
  background: var(--cyan); color: #04222b; border: none;
  font-size: 18px; font-weight: 900; letter-spacing: 0.18em; padding: 20px 12px;
  cursor: pointer; text-transform: uppercase;
  box-shadow: 0 0 26px rgba(83, 232, 255, 0.45), inset 0 0 0 1px rgba(255,255,255,0.25);
}
.descend:active { transform: scale(0.98); }
/* Playtest 30: the threat you are about to climb, on the button itself. */
.descend-sub {
  display: block; margin-top: 3px; font-size: 11px; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; opacity: 0.72;
}
.descend-i { display: inline-block; margin-right: 6px; transform: translateY(1px); }

/* --- Juice (all neutralized under prefers-reduced-motion, see bottom) ------- */
/* The CTA breathes — a slow neon inhale on its existing cyan glow. */
@keyframes descendBreathe {
  0%, 100% { box-shadow: 0 0 26px rgba(83, 232, 255, 0.45), inset 0 0 0 1px rgba(255,255,255,0.25); }
  50%      { box-shadow: 0 0 42px rgba(83, 232, 255, 0.8),  inset 0 0 0 1px rgba(255,255,255,0.45); }
}
/* Playtest 29 (HIG · deference): the CTA no longer breathes — motion answers a
   touch, it does not run in a loop while you read. The glow stays, static. */

/* "You are here, climbing" — the current rung's node gently pulses. */
@keyframes hereGlow {
  0%, 100% { box-shadow: inset 0 0 0 2px var(--cyan), 0 0 12px rgba(83, 232, 255, 0.35); }
  50%      { box-shadow: inset 0 0 0 2px var(--cyan), 0 0 24px rgba(83, 232, 255, 0.8); }
}
/* Playtest 29: the "you are here" node holds a static glow (was a 2.8s loop). */

/* Resonance purchase — a quick pop + gold flash (ui.js adds .bought, one-shot). */
@keyframes nodePop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.12); box-shadow: inset 0 0 0 2px var(--gold), 0 0 24px rgba(255, 209, 102, 0.65); }
  100% { transform: scale(1); }
}
.node.bought { animation: nodePop 0.45s ease-out; }

/* Wordmark — a one-shot neon flicker-ignite on load. Ends at full glow. */
@keyframes wordmarkIgnite {
  0%       { opacity: 0.1; text-shadow: none; }
  10%      { opacity: 1;   text-shadow: 0 0 18px rgba(83, 232, 255, 0.7); }
  14%      { opacity: 0.25; text-shadow: none; }
  22%      { opacity: 1;   text-shadow: 0 0 22px rgba(83, 232, 255, 0.9); }
  30%      { opacity: 0.4; text-shadow: none; }
  42%, 100% { opacity: 1;  text-shadow: 0 0 18px rgba(83, 232, 255, 0.7); }
}
/* Playtest 29: the wordmark no longer flickers on load. */

/* Lair blocks — angular section headers, no rounded cards. */
.lair-block { margin-bottom: 24px; }
.lair-h { /* semantic <h2>; reset UA heading top-margin */
  font-size: 11px; font-weight: 800; letter-spacing: 0.22em; text-transform: uppercase;
  color: var(--text); padding-left: 12px; margin: 0 0 12px; position: relative;
}
.lair-h::before {
  content: ''; position: absolute; left: 0; top: 1px; bottom: 1px; width: 3px;
  background: var(--cyan); box-shadow: 0 0 8px var(--cyan);
}
.lair-h .dim { color: var(--dim); font-weight: 500; letter-spacing: 0.04em; text-transform: none; }

/* Starting-form picker — angular chips. */
.form-row { display: flex; gap: 10px; }
.form-chip {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 4px;
  clip-path: polygon(10% 0, 100% 0, 100% 90%, 90% 100%, 0 100%, 0 10%);
  background: var(--panel); border: none; padding: 14px 6px 11px; cursor: pointer;
  color: var(--text); box-shadow: inset 0 0 0 1px var(--line); min-height: 92px;
}
.form-chip.locked { opacity: 0.6; } /* 0.6 keeps name/cost above AA contrast while still reading "locked" */
.form-chip.sel { box-shadow: inset 0 0 0 2px var(--cyan), 0 0 16px rgba(83,232,255,0.3); background: #12203a; }
.form-name { font-size: 13px; font-weight: 700; }
.form-cost { font-size: 11px; color: var(--gold); font-weight: 700; }
.form-chip.sel .form-cost { color: var(--cyan); }

/* Threat (difficulty) picker — same angular chip language as the forms. */
.diff-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.diff-chip {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  clip-path: polygon(10% 0, 100% 0, 100% 90%, 90% 100%, 0 100%, 0 10%);
  background: var(--panel); border: none; padding: 12px 4px 10px; cursor: pointer;
  color: var(--text); box-shadow: inset 0 0 0 1px var(--line); min-height: 74px;
}
.diff-chip.sel { box-shadow: inset 0 0 0 2px var(--cyan), 0 0 16px rgba(83,232,255,0.3); background: #12203a; }
.diff-chip.diff-hard.sel { box-shadow: inset 0 0 0 2px var(--gold), 0 0 16px rgba(255,209,102,0.3); }
.diff-chip.diff-insane.sel { box-shadow: inset 0 0 0 2px var(--red), 0 0 16px rgba(255,93,93,0.35); }
.diff-name { font-size: 13px; font-weight: 800; letter-spacing: 0.04em; }
.diff-desc { font-size: 10px; color: var(--dim); text-align: center; line-height: 1.2; }
.diff-flux { font-size: 11px; color: var(--gold); font-weight: 700; }

/* P3: arena picker + the Insanity dare (inside the Threat block). */
.arena-row { margin-top: 8px; display: flex; flex-direction: column; gap: 8px; }
.map-chips { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.map-chip.sel { box-shadow: inset 0 0 0 2px var(--violet), 0 0 16px rgba(183,138,255,0.3); }
.insanity-chip {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  clip-path: polygon(2% 0, 98% 0, 100% 50%, 98% 100%, 2% 100%, 0 50%);
  background: var(--panel); border: none; padding: 12px 8px; cursor: pointer;
  color: var(--dim); box-shadow: inset 0 0 0 1px var(--line); min-height: 56px;
}
.insanity-chip .diff-name { color: inherit; }
.insanity-chip.on {
  color: var(--text);
  box-shadow: inset 0 0 0 2px var(--red), 0 0 20px rgba(255, 93, 93, 0.4);
  background: #2a1020;
}
.insanity-chip.on .diff-name { color: var(--red); text-shadow: 0 0 10px rgba(255,93,93,0.6); }

/* Bounty round: the WANTED ladder — a rung rail that only surfaces on Insane.
   Locked rungs stay visible (the collection psychology IS the tease). */
.wanted-row { display: flex; flex-direction: column; gap: 7px; }
.wanted-head { font-size: 11px; font-weight: 800; letter-spacing: 0.14em; color: var(--red); }
.wanted-head .dim { font-weight: 600; letter-spacing: 0.02em; margin-left: 6px; color: var(--dim); }
.wanted-chips { display: flex; flex-direction: column; gap: 6px; }
.wanted-chip {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 10px;
  min-height: 44px; padding: 8px 12px; cursor: pointer; text-align: left;
  clip-path: polygon(1.5% 0, 100% 0, 100% 60%, 98.5% 100%, 0 100%, 0 40%);
  background: var(--panel); border: none; color: var(--text);
  box-shadow: inset 0 0 0 1px var(--line);
}
.wanted-chip b { font-size: 13px; font-weight: 800; letter-spacing: 0.08em; }
.wanted-chip i { font-style: normal; font-size: 11.5px; color: var(--dim); }
.wanted-chip span { font-size: 11.5px; color: var(--gold); font-weight: 700; }
/* 0.65: locked weight, but the tease copy stays readable (crew-pass call —
   the rung DESCRIPTIONS are the collection hook, disabled-exempt or not). */
.wanted-chip.locked { opacity: 0.65; cursor: not-allowed; }
.wanted-chip.sel {
  box-shadow: inset 0 0 0 2px var(--red), 0 0 16px rgba(255, 93, 93, 0.35);
  background: #2a1020;
}
.wanted-chip.sel b { color: var(--red); }

/* Resonance — hexagonal upgrade nodes in a triad grid. */
.node-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.node {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  clip-path: polygon(50% 0, 100% 20%, 100% 80%, 50% 100%, 0 80%, 0 20%);
  background: var(--panel); border: none; padding: 16px 6px 14px; cursor: pointer;
  color: var(--text); box-shadow: inset 0 0 0 1px var(--line);
  opacity: 0.6; transition: opacity 0.15s, box-shadow 0.15s; min-height: 132px;
}
.node.afford { opacity: 1; box-shadow: inset 0 0 0 1px rgba(83,232,255,0.55), 0 0 14px rgba(83,232,255,0.22); }
.node.maxed { opacity: 0.85; box-shadow: inset 0 0 0 1px rgba(255,209,102,0.45); }
.node:disabled { cursor: default; }
.node-hex { font-size: 22px; color: var(--cyan); line-height: 1; }
.node.maxed .node-hex { color: var(--gold); }
.node-name { font-size: 12px; font-weight: 700; text-align: center; line-height: 1.15; }
/* Playtest 29: the effect, on the node. It used to live only in aria-label. */
.node-fx { font-size: 10px; color: var(--dim); text-align: center; line-height: 1.2; max-width: 92px; }
.node-lv { font-size: 10px; letter-spacing: 1px; color: var(--cyan); }
.node-cost { font-size: 11px; font-weight: 700; color: var(--gold); }

/* The Ladder — a vertical spine you climb, current rung lit. */
.ascent-rail { position: relative; padding-left: 6px; }
.rail-rung {
  display: flex; align-items: center; gap: 12px; padding: 7px 0; position: relative;
}
.rail-rung::before {
  content: ''; position: absolute; left: 19px; top: 0; bottom: 0; width: 2px;
  background: var(--line);
}
.rail-rung:first-child::before { top: 50%; }
.rail-rung:last-child::before { bottom: 50%; }
.rail-rung.reached::before { background: rgba(83, 232, 255, 0.4); }
.rail-node {
  position: relative; z-index: 1; width: 40px; height: 40px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg2); border-radius: 50%; box-shadow: inset 0 0 0 1px var(--line);
}
.rail-rung.current .rail-node {
  box-shadow: inset 0 0 0 2px var(--cyan), 0 0 16px rgba(83, 232, 255, 0.5);
  background: #0d2438;
}
.rail-node.mystery { font-size: 20px; color: var(--violet); }
.rail-txt { display: flex; flex-direction: column; }
.rail-txt b { font-size: 15px; font-weight: 700; }
.rail-txt i { font-size: 12px; color: var(--dim); font-style: normal; }
.rail-rung.current .rail-txt b { color: var(--cyan); }
.rail-rung:not(.reached):not(.locked) .rail-txt b { color: var(--dim); }
.rail-rung.locked .rail-txt b { color: var(--violet); }

.btn {
  --notch: 8px; clip-path: var(--clip-notch);
  border: none; box-shadow: inset 0 0 0 1px var(--line); background: var(--panel);
  color: var(--text); font-size: 15px; font-weight: 800; padding: 15px 12px;
  cursor: pointer; min-height: 52px;
}
.btn.primary { background: var(--cyan); box-shadow: inset 0 0 0 1px var(--cyan); color: #04222b; }

/* A11y (SC 2.4.7): every angular control is clip-path'd, which CLIPS the UA
   outline — an INSET ring survives the clip. Gold, and allowed to override
   selection glows: seeing where you are beats seeing what's selected. */
.descend:focus-visible, .form-chip:focus-visible, .diff-chip:focus-visible,
.map-chip:focus-visible, .insanity-chip:focus-visible, .node:focus-visible,
.day-chip:focus-visible, .skin-chip:focus-visible, .emph-chip:focus-visible,
.mode-chip:focus-visible, .wanted-chip:focus-visible,
/* playtest 6 (a11y audit #6): the new controls join the studio ring instead
   of the UA's amber outline:auto */
.menu-row:focus-visible, .vault-card:focus-visible, .vault-restore:focus-visible,
.btn:focus-visible, .draft-reroll:focus-visible, .ability-card:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 3px var(--gold) !important;
}

/* The ascent rail's collapsed ??? run (art pass). */
.rail-rung.summary .rail-node { color: var(--dim); font-size: 16px; }
.rail-rung.summary .rail-txt b { color: var(--dim); }

/* Compact shop (art pass): one browse button; the grid lives in a sheet. */

/* --- Run ------------------------------------------------------------------ */
.run { background: var(--bg); }
#runCanvas { position: absolute; inset: 0; width: 100%; height: 100%; touch-action: none; }

.hud {
  position: absolute; top: 0; left: 0; right: 0;
  padding: calc(10px + env(safe-area-inset-top)) 14px 0;
  pointer-events: none;
}
.hud-row {
  display: flex; align-items: baseline; gap: 12px;
  font-weight: 800; font-size: 15px; margin-bottom: 6px;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.9); /* a11y: scrim vs bright canvas moments */
}
.hud-timer { color: var(--gold); font-variant-numeric: tabular-nums; margin-left: auto; }
.hud-shape { color: var(--cyan); font-size: 16px; }
.hp-track { height: 6px; border-radius: 3px; background: rgba(0,0,0,0.55); overflow: hidden; }
.hp-fill { height: 100%; width: 100%; background: var(--cyan); transition: width 0.12s; }

.boss-track {
  height: 8px; border-radius: 4px; background: rgba(0,0,0,0.6); overflow: hidden;
  margin-top: 8px; display: none; position: relative;
}
.boss-track.show { display: block; }
.boss-fill { height: 100%; width: 100%; background: var(--pink); transition: width 0.12s; }
.boss-label {
  position: absolute; top: 12px; left: 0; right: 0; text-align: center;
  font-size: 12px; color: var(--pink); font-weight: 700; letter-spacing: 0.06em;
}

/* Playtest 28: this was `bottom: 0; height: calc(5px + inset); background:
   rgba(0,0,0,0.6)` — a 39px dark band across the bottom of the arena on an
   iPhone, painted INTO the home-indicator zone, which is exactly the "dead bar
   above the home indicator" The Long Descent already paid for (build 21). The
   canvas paints to the physical edge of the glass now; the XP bar is a 5px
   line sitting just above the indicator. */
.xp-track {
  position: absolute; left: 0; right: 0; bottom: env(safe-area-inset-bottom);
  height: 5px; background: rgba(0,0,0,0.45);
}
.xp-fill { height: 5px; width: 0%; background: var(--gold); transition: width 0.15s; }

/* Playtest 3: the ability trigger — bottom-left thumb, radial cooldown sweep. */
.ability-btn {
  position: absolute; left: 10px; bottom: calc(16px + env(safe-area-inset-bottom));
  width: 58px; height: 58px; z-index: 6; cursor: pointer;
  background: rgba(10, 13, 28, 0.6); box-shadow: inset 0 0 0 1px var(--line); border: none;
  --notch: 10px; clip-path: var(--clip-notch);
  display: flex; align-items: center; justify-content: center; overflow: hidden;
  color: var(--dim);
}
.ability-btn[hidden] { display: none; }   /* display:flex beats the hidden attr otherwise */
.ability-btn.ready {   /* a clipped element's glow is a FILTER, not a box-shadow */
  color: var(--cyan); box-shadow: inset 0 0 0 2px var(--cyan); background: rgba(18, 32, 58, 0.8);
  filter: drop-shadow(0 0 8px rgba(83, 232, 255, 0.5));
}
.ability-btn:active { transform: scale(0.94); }
.ability-glyph { font-size: 24px; line-height: 1; position: relative; z-index: 1; }
.ability-cd {
  position: absolute; inset: 0;
  background: conic-gradient(rgba(5, 6, 15, 0.78) var(--cd, 0deg), transparent 0);
}

/* Abilities on the Power tab — wide cards, one equipped. */
.ability-row { display: flex; flex-direction: column; gap: 9px; }
.ability-card {
  display: grid; grid-template-columns: 44px 1fr auto; align-items: center; column-gap: 10px;
  clip-path: polygon(2% 0, 98% 0, 100% 50%, 98% 100%, 2% 100%, 0 50%);
  background: var(--panel); border: none; padding: 13px 16px; cursor: pointer;
  color: var(--text); box-shadow: inset 0 0 0 1px var(--line); min-height: 64px; text-align: left;
}
.ability-card.locked { opacity: 0.6; }
.ability-card.sel { box-shadow: inset 0 0 0 2px var(--cyan), 0 0 16px rgba(83, 232, 255, 0.3); background: #12203a; }
.ability-card-glyph { font-size: 24px; color: var(--cyan); text-align: center; }
.ability-card-txt { display: flex; flex-direction: column; gap: 2px; }
.ability-card-txt b { font-size: 15px; font-weight: 800; }
.ability-card-txt i { font-size: 12px; color: var(--dim); font-style: normal; line-height: 1.35; }
.ability-card-cost { font-size: 11.5px; font-weight: 800; color: var(--gold); }
.ability-card.sel .ability-card-cost { color: var(--cyan); }
.ability-card:focus-visible { outline: none; box-shadow: inset 0 0 0 3px var(--gold) !important; }

/* Pause — bottom-right, clear of the HUD stack and the action's center. */
.pause-btn {
  position: absolute; right: 10px; bottom: calc(16px + env(safe-area-inset-bottom));
  width: 46px; height: 46px; z-index: 6; cursor: pointer;
  background: rgba(10, 13, 28, 0.6); box-shadow: inset 0 0 0 1px var(--line); border: none;
  --notch: 8px; clip-path: var(--clip-notch);
  color: var(--dim); font-size: 13px; font-weight: 800; letter-spacing: 1px;
  display: flex; align-items: center; justify-content: center;
}
.pause-btn:active { color: var(--cyan); box-shadow: inset 0 0 0 1px var(--cyan); }
.pause-note { color: var(--dim); font-size: 13px; line-height: 1.4; margin-bottom: 16px; }

/* Playtest 12: YOUR BUILD — the pause sheet's reviewable loadout. Read-only
   rows; the panel scrolls so a deep run never pushes Resume off-screen. */
.pause-card { max-height: 86vh; display: flex; flex-direction: column; }
.pause-card .death-actions { margin-top: auto; }
.build-panel {
  text-align: left; overflow-y: auto; -webkit-overflow-scrolling: touch;
  max-height: 44vh; margin: 2px 0 12px; padding: 0 6px 14px 0;
  border-top: 1px solid rgba(83, 232, 255, 0.14);
  -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 calc(100% - 14px), transparent);
  mask-image: linear-gradient(to bottom, #000 0, #000 calc(100% - 14px), transparent);
}
.build-sec {
  color: var(--gold, #ffd166); font-size: 11px; letter-spacing: 0.14em;
  margin: 10px 0 4px; opacity: 0.85;
}
.build-row { display: flex; gap: 8px; align-items: flex-start; padding: 3px 0; }
.build-glyph { flex: 0 0 22px; text-align: center; font-size: 15px; line-height: 1.2; }
.build-row svg { vertical-align: -3px; }
.build-txt { flex: 1; min-width: 0; }
.build-txt b { display: block; font-size: 13.5px; line-height: 1.25; }
.build-txt b i { font-style: normal; color: var(--gold, #ffd166); font-size: 10px; letter-spacing: 0.06em; }
.build-txt small { display: block; color: var(--dim); font-size: 12px; line-height: 1.35; }

/* Playtest 13: YOUR RECORD — lifetime stats strip under the best-line. */
.record-row {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px;
  margin: 10px 2px 0; align-self: stretch;
}
/* Playtest 15: `display:grid` beat the UA `[hidden]{display:none}`, so a fresh
   save still laid out an empty 5-column strip (the same trap .mode-row and
   .ability-btn already guard against). It only looked inert because the hero
   zone was a row; making that a column would have exposed it. */
.record-row[hidden] { display: none; }
.record-tile { text-align: center; padding: 7px 2px 6px; background: rgba(83, 232, 255, 0.05);
  box-shadow: inset 0 0 0 1px rgba(83, 232, 255, 0.12); --notch: 6px; clip-path: var(--clip-notch); }
.record-tile span { display: block; font-size: 17px; font-weight: 700; color: #eaffff; line-height: 1.1; }
.record-tile label { display: block; margin-top: 2px; font-size: 10px; letter-spacing: 0.04em; line-height: 1.15;
  min-height: 2.3em; text-transform: uppercase; color: var(--dim); }

/* Playtest 13: facet cards — violet FORM TRAIT identity, never gold EVOLVE. */
.draft-note { color: var(--dim); font-size: 12.5px; line-height: 1.4; margin: -4px 0 10px; }
.draft-opt.facet-opt { box-shadow: inset 0 0 0 1px rgba(183, 138, 255, 0.65); }
.facet-tag {
  font-style: normal; font-size: 9px; letter-spacing: 0.1em; padding: 2px 6px;
  border-radius: 6px; background: rgba(183, 138, 255, 0.18); color: #b78aff;
  border: 1px solid rgba(183, 138, 255, 0.4); vertical-align: 1px;
}

/* Playtest 14b: ONE forward line per card — the recipe (cyan-white) or the
   tier teaser (gold), never both. grid-column 2 like .tier-next, or the grid
   auto-places it into the 44px icon column and wraps word-per-word. */
.fuse-next {
  grid-column: 2; font-size: 11px; font-weight: 600; line-height: 1.3;
  margin-top: 3px; color: rgba(159, 243, 255, 0.8);
}

.drag-hint {
  position: absolute; bottom: calc(22px + env(safe-area-inset-bottom)); width: 100%;
  text-align: center; color: var(--dim); font-size: 13px; pointer-events: none;
  animation: fadeHint 5s forwards;
}
@keyframes fadeHint { 0%, 70% { opacity: 1; } 100% { opacity: 0; } }

/* --- Overlays (draft / death) ---------------------------------------------- */
.overlay {
  /* Playtest 29: absolute inside #app, not fixed to the viewport — a fixed
     overlay stops at the (possibly wrong) viewport edge and leaves the fitted
     band below it undimmed. #app is the one box that is always the screen. */
  position: absolute; inset: 0; z-index: 50; background: rgba(3, 4, 10, 0.9);
  display: none; align-items: center; justify-content: center;
  /* Playtest 28 (art-director): flat 22px let the tallest sheet tuck under the
     notch and the home indicator. */
  padding: calc(22px + env(safe-area-inset-top)) 22px calc(22px + env(safe-area-inset-bottom));
  /* NO backdrop-filter here: iOS Safari fails to paint the children of a
     backdrop-filtered overlay when other backdrop-filtered layers (the app
     top/tab bars) are live underneath — the user saw the blur with no card.
     A deeper solid dim replaces the decorative blur. */
}
.overlay.open { display: flex; }

.draft-card, .death-card {
  background: var(--bg2); box-shadow: inset 0 0 0 1px var(--line);
  /* Art-director, second read: for a 45° cut, inner = outer − padding, so a
     26px card notch and 8px button/option notches are CONCENTRIC. And the
     property INHERITS — every clipped child sets its own, or it wears the
     card's corner (the sheets' row containers were rendering at 18px). */
  --notch: 26px; clip-path: var(--clip-notch);
  padding: 22px 18px; width: 100%; max-width: 360px; text-align: center;
}
.draft-kicker { color: var(--gold); font-size: 11px; letter-spacing: 0.3em; margin-bottom: 4px; }
.draft-card h2, .death-card h2 { font-size: 19px; margin-bottom: 16px; }
.draft-opts { display: flex; flex-direction: column; gap: 9px; }
.draft-opt {
  display: grid; grid-template-columns: 44px 1fr; grid-template-rows: auto auto auto;
  column-gap: 10px; align-items: center; text-align: left;
  background: var(--panel); box-shadow: inset 0 0 0 1px var(--line); border: none;
  --notch: 8px; clip-path: var(--clip-notch);
  padding: 12px 14px; cursor: pointer; color: var(--text); min-height: 64px;
}
.draft-opt:active { box-shadow: inset 0 0 0 1px var(--cyan); }
.draft-icon { grid-row: span 3; font-size: 22px; text-align: center; color: var(--cyan); }
.draft-name { font-weight: 800; font-size: 15px; }
.draft-desc { color: var(--dim); font-size: 13px; line-height: 1.35; }
/* Level story (playtest 2): pips + "Lv n → n+1" — NEW is a tag, not the name. */
.draft-lvl { grid-column: 2; display: flex; align-items: center; gap: 7px; font-size: 11px; font-weight: 700; color: var(--dim); margin-top: 2px; }
.draft-lvl .pips { font-style: normal; font-size: 8px; letter-spacing: 1.5px; color: var(--cyan); }
.new-tag {
  font-style: normal; font-size: 9px; font-weight: 800; letter-spacing: 0.16em;
  color: #04222b; background: var(--cyan); border-radius: 4px;
  padding: 1px 5px; margin-left: 6px; vertical-align: 2px;
}

/* Evolution offers — a maxed weapon + passive fusing. Gold marks the moment. */
.draft-opt.evolved { box-shadow: inset 0 0 0 2px var(--gold); filter: drop-shadow(0 0 9px rgba(255, 209, 102, 0.4)); }
.draft-opt.evolved .draft-icon,
.draft-opt.evolved .draft-name { color: var(--gold); }
.evo-tag {
  font-style: normal; font-size: 9px; font-weight: 800; letter-spacing: 0.18em;
  color: #04222b; background: var(--gold); border-radius: 4px;
  padding: 1px 5px; margin-left: 6px; vertical-align: 2px;
}
/* Playtest 10: weapon ascension — the tier chip + the next-threshold teaser. */
.tier-chip {
  font-style: normal; font-size: 8.5px; font-weight: 800; letter-spacing: 0.14em;
  color: var(--cyan); border: 1px solid rgba(83, 232, 255, 0.5); border-radius: 4px;
  padding: 1px 5px; margin-left: 6px; vertical-align: 2px;
}
.tier-next {
  grid-column: 2; font-size: 11px; font-weight: 600; color: rgba(255, 209, 102, 0.75);
  line-height: 1.3; margin-top: 3px;
}

/* Bounty round: the reroll die (also the chest's Refuse) — a quiet footer
   action under the cards, never competing with them. 44px touch floor. */
.draft-reroll {
  margin-top: 10px; width: 100%; min-height: 44px; cursor: pointer;
  background: none; border: none; box-shadow: inset 0 0 0 1px var(--line); --notch: 10px; clip-path: var(--clip-notch);
  color: var(--dim); font-size: 13.5px; font-weight: 700; letter-spacing: 0.04em;
}
.draft-reroll:active { color: var(--cyan); border-color: var(--cyan); }
.draft-reroll[hidden] { display: none; }

/* Relic chest cards — the gain and the price both read before the tap. */
.relic-kicker { color: var(--violet); }
.relic-glyph { color: var(--gold); font-size: 24px; }
.relic-opt { box-shadow: inset 0 0 0 1px rgba(255, 209, 102, 0.45); }
.relic-up, .relic-down { grid-column: 2; font-size: 13px; line-height: 1.35; font-weight: 600; }
.relic-up { color: #7fe8a8; }
.relic-down { color: var(--red); }

.death-stats { display: flex; justify-content: center; gap: 22px; margin-bottom: 12px; }
.death-stats div { display: flex; flex-direction: column; }
.death-stats span { font-size: 22px; font-weight: 800; }
.death-stats label { font-size: 11.5px; color: var(--dim); letter-spacing: 0.06em; }
.death-score { color: var(--gold); font-weight: 700; margin-bottom: 16px; }
.death-score b { color: var(--cyan); }
/* Bounty round: the run's relic string + progression stamps on the report. */
.death-relics { display: flex; justify-content: center; gap: 8px; margin-bottom: 10px; }
.death-relic { color: var(--gold); font-size: 17px; }
.death-prog { color: var(--gold); margin-bottom: 12px; }
.death-actions { display: flex; gap: 9px; }
.death-actions .btn { flex: 1; }

/* --- Playtest 6: the ☰ menu sheet ------------------------------------------ */
/* Playtest 28 (Shai: "a cleaner menu"): the flat stack of rounded buttons is
   an INSET GROUPED LIST now — the iOS Settings idiom. Titled groups, rows
   separated by hairlines inside one rounded container, a chevron on every row
   that opens a sheet, a real switch on the toggle. The row ids (muteBtn,
   menuNewsBtn, menuResetBtn…) are unchanged — every suite that drives the
   menu still finds them. */
.menu-btn { font-size: 20px; line-height: 1; }
.menu-card { text-align: left; }
.menu-card h2 { text-align: center; font-size: 22px; letter-spacing: 0.12em; }
.menu-sub { text-align: center; color: var(--dim); font-size: 12.5px; margin: -10px 0 12px; }
/* Art-director pass: the list cut a row mid-glyph with no affordance — a fade
   at the bottom says "there is more"; dvh so the URL bar can't push it under. */
.menu-scroll {
  max-height: min(58dvh, 520px); overflow-y: auto; -webkit-overflow-scrolling: touch;
  margin: 0 -4px 12px; padding: 0 4px 14px;
  -webkit-mask-image: linear-gradient(to bottom, #000 0, #000 calc(100% - 14px), transparent);
  mask-image: linear-gradient(to bottom, #000 0, #000 calc(100% - 14px), transparent);
}
/* Dismissal is never the primary action (HIG) — Close/Back are quiet pills;
   cyan stays the game's "go". */
.menu-card .death-actions .btn.primary { background: var(--panel); box-shadow: inset 0 0 0 1px var(--line); color: var(--text); }
.menu-group { margin-bottom: 12px; }
.menu-group-h {   /* an <h3> since the a11y audit — reset the UA heading look */
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--dim); margin: 0 0 6px 2px; padding-left: 11px; position: relative;
}
.menu-group-h::before {   /* the .lair-h tick — one section language on both screens */
  content: ''; position: absolute; left: 0; top: 1px; bottom: 1px; width: 3px;
  background: var(--cyan); box-shadow: 0 0 8px var(--cyan);
}
.menu-rows {
  display: flex; flex-direction: column; margin: 0;
  background: var(--panel); box-shadow: inset 0 0 0 1px var(--line); --notch: 10px; clip-path: var(--clip-notch); overflow: hidden;
}
.menu-row {
  display: grid; grid-template-columns: 30px 1fr auto; align-items: center; gap: 10px;
  min-height: 56px; padding: 9px 12px; cursor: pointer; text-align: left;
  background: none; border: none; color: var(--text);
}
.menu-row + .menu-row { border-top: 1px solid rgba(83, 232, 255, 0.10); }
.menu-row:active { background: rgba(83, 232, 255, 0.06); }
.menu-row-glyph { font-size: 19px; display: grid; place-items: center; color: var(--cyan); }
.menu-row-glyph svg, .menu-row-glyph .ico { width: 22px; height: 22px; }
.menu-row-txt { min-width: 0; }
.menu-row-txt b { display: block; font-size: 15px; }
.menu-row-txt i { font-style: normal; font-size: 12px; color: var(--dim); display: block; line-height: 1.3; }
.menu-row-end {
  display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700;
  color: var(--dim); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.menu-row-end .chev { font-size: 18px; line-height: 1; color: #7b87a8; font-weight: 400; }   /* 5.08:1 */
/* The switch — the one control on the sheet that is a state, not a door. */
.switch {
  width: 46px; height: 24px; background: #5a6490; position: relative;   /* 3.17:1 boundary */
  --notch: 4px; clip-path: var(--clip-notch);   /* the 6px cut used to eat the knob's corner at .on */
  transition: background 0.2s; flex-shrink: 0;
}
.switch i {   /* a hexagon, not a circle — the Resonance node's silhouette */
  position: absolute; top: 3px; left: 3px; width: 18px; height: 18px;
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
  background: #eaf6ff; transition: transform 0.2s; box-shadow: 0 1px 3px rgba(0,0,0,0.5);
}
.switch.on { background: var(--cyan); }
.switch.on i { transform: translateX(22px); }
.menu-row:focus-visible { box-shadow: inset 0 0 0 3px var(--gold) !important; outline: none; }

/* Stats sheet — label left, value right, tabular numerals. */
.stat-rows {
  display: flex; flex-direction: column;
  background: var(--panel); box-shadow: inset 0 0 0 1px var(--line); --notch: 10px; clip-path: var(--clip-notch); overflow: hidden;
}
.stat-row {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  min-height: 44px; padding: 8px 12px; font-size: 13.5px;
}
.stat-row + .stat-row { border-top: 1px solid rgba(83, 232, 255, 0.10); }
.stat-row span { color: var(--dim); }
.stat-row b { font-variant-numeric: tabular-nums; text-align: right; }

/* Achievements sheet — glyph · name/desc/progress · when. */
.ach-rows {
  display: flex; flex-direction: column;
  background: var(--panel); box-shadow: inset 0 0 0 1px var(--line); --notch: 10px; clip-path: var(--clip-notch); overflow: hidden;
}
.ach-row {
  display: grid; grid-template-columns: 32px 1fr auto; align-items: center; gap: 10px;
  min-height: 54px; padding: 9px 12px;
}
.ach-row + .ach-row { border-top: 1px solid rgba(83, 232, 255, 0.10); }
.ach-glyph { font-size: 20px; text-align: center; color: var(--gold); text-shadow: 0 0 10px rgba(255, 209, 102, 0.45); }
.ach-row.locked .ach-glyph { color: #7a86ad; text-shadow: none; }   /* 5.05:1 (a11y audit) */
.ach-txt { min-width: 0; }
.ach-txt b { display: block; font-size: 13.5px; }
.ach-row.locked .ach-txt b { color: #b8c2dc; }
.ach-txt i { display: block; font-style: normal; font-size: 11.5px; color: var(--dim); line-height: 1.3; }
.ach-bar { display: block; height: 3px; border-radius: 2px; background: rgba(0,0,0,0.5); margin-top: 5px; overflow: hidden; }
.ach-bar b { display: block; height: 100%; background: var(--cyan); }
.ach-when { font-size: 10px; color: var(--dim); text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.ach-row.unlocked .ach-when { color: var(--gold); }
/* The death card's line for what this climb unlocked. */
.death-ach { color: #b8c2dc; font-size: 11.5px; margin: -6px 0 12px; line-height: 1.4; }
.death-ach b { color: var(--gold); }
.menu-row.danger b { color: var(--red); }
/* The destructive row reads red end-to-end — the icon joins the semantic. */
.menu-row.danger .menu-row-glyph { color: var(--red); }
.menu-row.danger.armed { box-shadow: inset 0 0 0 2px var(--red); background: #2a1020; }
.menu-about {
  color: var(--dim); font-size: 11.5px; letter-spacing: 0.06em; line-height: 1.5;
  padding-top: 10px; margin-bottom: 14px;
  border-top: 1px solid rgba(83, 232, 255, 0.10);   /* P34 (art): a footer, not orphaned copy */
  font-variant-numeric: tabular-nums;               /* it is telemetry — let the digits column */
}

/* --- Playtest 23: the endgame rung lists all four branches ------------------ */
.eg-row { display: flex; flex-wrap: wrap; gap: 4px 9px; margin-top: 4px; }
.eg-got { color: var(--cyan); font-weight: 700; font-size: 11.5px; letter-spacing: 0.04em; }
.eg-tease { color: #6b7794; font-size: 11.5px; letter-spacing: 0.04em; }   /* 4.51:1 (a11y audit) */

/* --- Playtest 18: WHAT'S NEW ------------------------------------------------
   A shipped build used to be invisible — the PWA swaps itself in silently. The
   ☰ wears a dot until you have read the current build's notes. */
.menu-btn { position: relative; }
.menu-btn.has-news::after {
  content: ''; position: absolute; top: 3px; right: 3px;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--gold); box-shadow: 0 0 8px rgba(255, 209, 102, 0.9);
}
.menu-row.news b { color: var(--gold); }
.menu-row.news .menu-row-glyph { color: var(--gold); }
.menu-row.news { box-shadow: inset 3px 0 0 var(--gold); }   /* a gold edge, the way iOS marks the unread */
/* The list is the only part that scrolls — the title and Back stay put, so a
   long history can never push the way out off a phone screen. */
.log-scroll {
  max-height: min(52vh, 420px); overflow-y: auto; -webkit-overflow-scrolling: touch;
  margin-bottom: 12px; padding-right: 4px; text-align: left;
}
.log-build { margin-bottom: 16px; }
.log-build h3 {
  display: flex; align-items: center; gap: 8px; margin-bottom: 3px;
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim);
}
.log-build h3 b { color: var(--cyan); font-size: 13px; letter-spacing: 0.08em; }
.log-now {
  font-size: 9.5px; letter-spacing: 0.1em; color: var(--gold);
  box-shadow: inset 0 0 0 1px rgba(255, 209, 102, 0.45); --notch: 4px; clip-path: var(--clip-notch); padding: 1px 7px;
}
.log-title { font-size: 14px; color: var(--text); margin-bottom: 7px; }
.log-build ul { list-style: none; display: flex; flex-direction: column; gap: 6px; }
.log-build li {
  position: relative; padding-left: 13px;
  font-size: 12.5px; line-height: 1.5; color: var(--dim);
}
.log-build li::before {
  content: '·'; position: absolute; left: 3px; top: -1px;
  color: var(--cyan); font-size: 14px;
}

/* --- Playtest 6: THE VAULT (real-money TEST store) -------------------------- */
.vault-note {
  color: var(--dim); font-size: 12px; line-height: 1.45; margin-bottom: 12px;
  box-shadow: inset 0 0 0 1px rgba(255, 209, 102, 0.4); --notch: 10px; clip-path: var(--clip-notch); padding: 8px 10px;
}
.vault-grid { display: flex; flex-direction: column; gap: 9px; }
.vault-card {
  position: relative; display: grid; grid-template-columns: 40px 1fr auto;
  align-items: center; gap: 10px; min-height: 64px; padding: 12px;
  text-align: left; cursor: pointer; color: var(--text);
  background: var(--panel); box-shadow: inset 0 0 0 1px rgba(255, 209, 102, 0.35); border: none;
  --notch: 12px; clip-path: var(--clip-notch);
}
.vault-card:active { box-shadow: inset 0 0 0 1px var(--gold); }
/* 0.85 (a11y audit #7): disabled-exempt, but the description stays useful. */
.vault-card.owned { opacity: 0.85; cursor: default; box-shadow: inset 0 0 0 1px rgba(255, 209, 102, 0.18); }
.vault-glyph { font-size: 22px; color: var(--gold); text-align: center; }
.vault-txt b { display: block; font-size: 15px; }
.vault-txt i { font-style: normal; font-size: 12px; color: var(--dim); line-height: 1.35; }
.vault-price {
  font-size: 13.5px; font-weight: 800; color: #04222b; background: var(--gold);
  --notch: 4px; clip-path: var(--clip-notch); padding: 7px 11px; white-space: nowrap;
}
.vault-card.owned .vault-price { background: none; color: var(--gold); padding: 0; }
.vault-tag {   /* Playtest 29: an inline chip after the name — it used to hang 7px above
                  the card edge, which the notch cuts, and inside the card it collided
                  with the price. */
  display: inline-block; vertical-align: 2px; margin-left: 4px;
  font-size: 9px; font-weight: 800; letter-spacing: 0.14em;
  color: #04222b; background: var(--cyan); --notch: 3px; clip-path: var(--clip-notch); padding: 1px 5px;
}
.vault-restore {
  margin-top: 10px; width: 100%; min-height: 44px; cursor: pointer;
  background: none; border: none; box-shadow: inset 0 0 0 1px var(--line); --notch: 10px; clip-path: var(--clip-notch);
  color: var(--dim); font-size: 13px; font-weight: 700;
}
/* Vault-exclusive skins wear their own rarity chip color in the grid. */
.skin-chip.rar-vault .skin-rar { color: var(--gold); }

/* --- Toasts ---------------------------------------------------------------- */
.toasts {
  /* P34 (art): the lane starts BELOW the top bar (6 + 44 + 6 + 1px rule +
     10). A "+503 flux" toast used to cover the flux counter it changed. */
  position: absolute; top: calc(67px + env(safe-area-inset-top)); left: 0; right: 0;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  pointer-events: none; z-index: 70;
}
.toast {
  background: rgba(16, 20, 42, 0.95); box-shadow: inset 0 0 0 1px var(--line);
  --notch: 8px; clip-path: var(--clip-notch);
  color: var(--text); font-size: 14px; padding: 9px 16px;
  max-width: 86%; text-align: center; opacity: 0; transform: translateY(-8px);
  transition: opacity 0.3s, transform 0.3s;
}
.toast.show { opacity: 1; transform: translateY(0); }

/* --- 2A: start-mode toggle (checkpoint resume) ------------------------------ */
.mode-row { display: flex; gap: 8px; margin: 0 0 10px; }
.mode-row[hidden] { display: none; }
.mode-chip {
  flex: 1; min-height: 44px; padding: 10px 8px; cursor: pointer;
  --notch: 10px; clip-path: var(--clip-notch);
  background: var(--panel); border: none; color: var(--dim);
  box-shadow: inset 0 0 0 1px var(--line);
  font-size: 12px; font-weight: 700; letter-spacing: 0.03em;
}
.mode-chip.sel {   /* Playtest 29: selected is CYAN everywhere; gold means currency */
  color: var(--text); background: #12203a;
  box-shadow: inset 0 0 0 2px var(--cyan);
}

/* --- 2A: timed-buff chips (under the HP track, inside the inert HUD) -------- */
/* Playtest 15: no wrap — a full relic set (the design plans for all 10) plus
   Overdrive and Stasis measured a 369px row, so the last chip's timer bar was
   clipped off the right edge on 375pt phones (body is overflow:hidden, so
   there was no way to see it). Let the row wrap onto a second line. */
.buff-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 5px; pointer-events: none; }
.buff-chips:empty { display: none; }
/* Art pass: glyph + thin ring of bar — the chips whisper over the arena. */
.buff-chip {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12px; font-weight: 800; line-height: 1;
  background: rgba(10, 13, 28, 0.55); box-shadow: inset 0 0 0 1px var(--line);
  --notch: 4px; clip-path: var(--clip-notch); padding: 2px 5px;
}
.buff-chip .buff-bar {
  width: 22px; height: 3px; border-radius: 2px;
  background: rgba(0, 0, 0, 0.6); overflow: hidden; font-style: normal;
}
.buff-chip .buff-bar b { display: block; height: 100%; width: 100%; }
.buff-overdrive { color: #eaffff; }
.buff-overdrive .buff-bar b { background: var(--cyan); }
.buff-stasis { color: var(--violet); }
.buff-stasis .buff-bar b { background: var(--violet); }
/* Bounty round: taken relics — permanent gold glyphs, no timer bar. */
.buff-relic { color: var(--gold); border-color: rgba(255, 209, 102, 0.4); }

/* --- 2A: Second Wind / TEST-AD placeholder ---------------------------------- */
.revive-actions { flex-direction: column; }
.test-ad { border: 2px dashed var(--gold); }
.test-ad-tag {
  display: inline-block; background: var(--gold); color: #04222b;
  font-size: 10px; font-weight: 900; letter-spacing: 0.16em;
  border-radius: 4px; padding: 3px 8px; margin-bottom: 10px;
}
.ad-bar {
  height: 8px; border-radius: 4px; background: rgba(0, 0, 0, 0.55);
  overflow: hidden; margin: 6px 0 10px;
}
.ad-bar b { display: block; height: 100%; width: 0%; background: var(--gold); }
.ad-count { color: var(--gold); font-weight: 800; font-size: 18px; }

/* --- Reduced motion -------------------------------------------------------- */
/* Honor prefers-reduced-motion (WCAG 2.3.3; studio mandate — our games lean on
   shake/particles/scroll). Neutralize CSS animations + transitions. NOTE: this
   only covers DOM/CSS motion; canvas-drawn run FX (particles, damage flash,
   screen shake in js/run.js) still need their own guard — see audit notes.
   The drag hint animates to opacity:0; without the animation we pin it visible
   so the "drag anywhere to move" instruction survives instead of vanishing. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .drag-hint { animation: none !important; opacity: 1 !important; }
  /* Juice pass: kill the loops outright (their 100% frames equal the resting
     style, so `animation: none` leaves the base look intact). */
  .descend, .rail-rung.current .rail-node, .app-logo, .node.bought {
    animation: none !important;
  }
}

/* =========================================================================== 2B
   Home economy — event banner · Daily Signal · Prism Shop · Leaderboard ·
   The Gauntlet. Same angular lair-block language as the rest of the Ascent.
============================================================================== */

/* --- Holiday event banner --------------------------------------------------- */
.evt-banner {
  position: relative; overflow: hidden; min-height: 92px;
  clip-path: polygon(2% 0, 100% 0, 98% 100%, 0 100%);
  background: var(--panel); box-shadow: inset 0 0 0 1px var(--evt, var(--cyan));
  display: flex; align-items: stretch;
}
.evt-art {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; opacity: 0.6;
}
.evt-txt {
  position: relative; z-index: 1; display: flex; flex-direction: column; gap: 3px;
  justify-content: center; padding: 12px 14px;
  /* A11y/art: hold the dark scrim further right so text clears even the
     brightest event art (Solstice/Ascension) at 4.5:1. */
  background: linear-gradient(to right, rgba(5,6,15,0.9) 55%, rgba(5,6,15,0.45));
  width: 100%;
}
.evt-name { font-size: 14px; font-weight: 900; letter-spacing: 0.12em; text-transform: uppercase; color: var(--evt, var(--cyan)); text-shadow: 0 0 12px var(--evt, var(--cyan)); }
.evt-blurb { font-size: 12.5px; color: var(--text); opacity: 0.9; }
.evt-meta { font-size: 12px; font-weight: 700; color: var(--text); } /* art: not gold-on-gold-art */
.evt-mult { font-style: normal; color: var(--violet); font-weight: 800; }

/* --- Daily Signal ------------------------------------------------------------ */
.daily-wrap { position: relative; }
.daily-chest {
  position: absolute; top: -46px; right: 2px; width: 40px; height: 40px;
  filter: drop-shadow(0 0 8px rgba(83,232,255,0.35)); pointer-events: none;
}
.day-chips { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; }
.day-chip {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  clip-path: polygon(15% 0, 100% 0, 100% 85%, 85% 100%, 0 100%, 0 15%);
  background: var(--panel); border: none; padding: 8px 2px; cursor: default;
  color: var(--text); box-shadow: inset 0 0 0 1px var(--line); min-height: 56px;
}
.day-chip .day-n { font-size: 11px; font-weight: 800; color: var(--dim); letter-spacing: 0.04em; }
.day-chip .day-r { font-size: 10.5px; font-weight: 700; color: var(--gold); }
.day-chip .day-t { font-size: 10px; font-weight: 800; color: var(--violet); }
.day-chip.done { opacity: 0.75; box-shadow: inset 0 0 0 1px rgba(83,232,255,0.5); }
.day-chip.done .day-n { color: var(--cyan); }
.day-chip.future { opacity: 0.55; }
.day-chip.today {
  cursor: pointer; opacity: 1;
  box-shadow: inset 0 0 0 2px var(--gold), 0 0 14px rgba(255,209,102,0.35);
}
.day-chip.today .day-n { color: var(--gold); }
@keyframes todayBeckon {
  0%, 100% { box-shadow: inset 0 0 0 2px var(--gold), 0 0 10px rgba(255,209,102,0.25); }
  50%      { box-shadow: inset 0 0 0 2px var(--gold), 0 0 22px rgba(255,209,102,0.6); }
}
/* Playtest 29: today's chip holds its gold ring (was a 2.2s beckon loop). */
@keyframes claimPop {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.18); box-shadow: inset 0 0 0 2px var(--gold), 0 0 30px rgba(255,209,102,0.9); }
  100% { transform: scale(1); }
}
.claim-pop { animation: claimPop 0.5s ease-out; }
.daily-double {
  width: 100%; margin-top: 10px; color: var(--gold); box-shadow: inset 0 0 0 1px rgba(255,209,102,0.4);
  font-size: 13px; letter-spacing: 0.06em;
}
.daily-note { color: var(--dim); font-size: 12.5px; margin-top: 8px; text-align: center; }

/* --- TEST AD placeholder ----------------------------------------------------- */
.ad-tag {
  display: inline-block; background: var(--gold); color: #04222b;
  font-size: 10px; font-weight: 900; letter-spacing: 0.22em; padding: 3px 10px;
  border-radius: 4px; margin-bottom: 10px;
}
.ad-body { color: var(--dim); font-size: 13.5px; line-height: 1.45; margin-bottom: 14px; }
.ad-track { height: 8px; border-radius: 4px; background: rgba(0,0,0,0.6); overflow: hidden; margin-bottom: 16px; }
.ad-fill { height: 100%; width: 0%; background: var(--gold); transition: width linear; }

/* --- Prism Shop -------------------------------------------------------------- */
.shop-banner {
  display: block; width: 100%; height: 74px; object-fit: cover; margin-bottom: 10px;
  clip-path: polygon(2% 0, 100% 0, 98% 100%, 0 100%);
  box-shadow: inset 0 0 0 1px var(--line);
}
.shop-bal { display: flex; justify-content: space-between; margin-bottom: 10px; font-variant-numeric: tabular-nums; }
.bal-flux { color: var(--gold); font-weight: 800; font-size: 13px; }
.bal-tok { color: var(--violet); font-weight: 800; font-size: 13px; }
.bal-tok i { font-style: normal; font-weight: 600; font-size: 10px; color: var(--dim); }
.skin-preview {
  display: flex; align-items: center; gap: 12px; padding: 10px 12px; margin-bottom: 10px;
  background: var(--bg2); box-shadow: inset 0 0 0 1px var(--line);
  --notch: 14px; clip-path: var(--clip-notch);   /* a % notch shears on a wide box */
}
.skin-preview-shape { filter: drop-shadow(0 0 10px var(--skglow, var(--cyan))); line-height: 0; }
.skin-preview-txt { display: flex; flex-direction: column; gap: 3px; }
.skin-preview-txt b { font-size: 15px; }
.skin-sw { display: flex; gap: 4px; }
.skin-sw i { width: 14px; height: 8px; border-radius: 2px; display: inline-block; }
.skin-eq-tag { font-size: 11px; color: var(--cyan); font-weight: 700; letter-spacing: 0.05em; }
.skin-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.skin-chip {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  --notch: 12px; clip-path: var(--clip-notch);   /* P34 (art): was a % polygon — it sheared to a 29° bevel on a wide tile */
  background: var(--panel); border: none; padding: 10px 4px 9px; cursor: pointer;
  color: var(--text); box-shadow: inset 0 0 0 1px var(--line); min-height: 88px;
}
/* A11y (SC 1.4.3): `opacity: .6` blended the rarity label to 2.88:1 (common)
   and 3.17:1 (epic) — axe, serious, 4 nodes. Dim the art and the name; the
   rarity and the price stay legible. */
.skin-chip.locked svg, .skin-chip.locked .skin-name { opacity: 0.55; }
.skin-chip.locked .skin-rar { opacity: 0.85; }
.skin-chip.locked .skin-cost { color: var(--dim); }
.skin-chip.sel { box-shadow: inset 0 0 0 2px var(--cyan), 0 0 14px rgba(83,232,255,0.3); background: #12203a; }
.skin-chip.armed { box-shadow: inset 0 0 0 2px var(--gold), 0 0 16px rgba(255,209,102,0.4); }
.skin-name { font-size: 12px; font-weight: 700; text-align: center; line-height: 1.15; }
.skin-rar { font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase; font-weight: 800; }
.rar-common .skin-rar { color: var(--dim); }
.rar-rare .skin-rar { color: var(--cyan); }
.rar-epic .skin-rar { color: var(--violet); }
.rar-seasonal .skin-rar { color: var(--gold); }
.skin-cost { font-size: 11px; color: var(--gold); font-weight: 700; text-align: center; }
.skin-chip.sel .skin-cost { color: var(--cyan); }

/* --- Leaderboard -------------------------------------------------------------- */
.lb-empty { color: var(--dim); font-size: 13.5px; padding: 6px 2px; }
.lb-rows { list-style: none; display: flex; flex-direction: column; gap: 4px; }
.lb-row {
  display: grid; grid-template-columns: 22px 1fr auto 22px 52px; gap: 8px; align-items: center;
  background: var(--panel); box-shadow: inset 0 0 0 1px var(--line);
  clip-path: polygon(1.5% 0, 100% 0, 98.5% 100%, 0 100%);
  padding: 7px 10px; font-size: 13px; min-height: 34px;
}
.lb-row.best {
  box-shadow: inset 0 0 0 1px rgba(255,209,102,0.55), 0 0 12px rgba(255,209,102,0.18);
  background: #171a2e;
}
.lb-rank { color: var(--dim); font-weight: 800; font-size: 12px; }
.lb-row.best .lb-rank { color: var(--gold); }
.lb-score { font-weight: 800; font-variant-numeric: tabular-nums; }
.lb-meta { color: var(--dim); font-size: 11.5px; }
.lb-diff {
  width: 18px; height: 18px; display: flex; align-items: center; justify-content: center;
  font-size: 9.5px; font-weight: 900; border-radius: 4px; box-shadow: inset 0 0 0 1px var(--line);
}
.lbd-easy { color: var(--dim); }
.lbd-normal { color: var(--cyan); }
.lbd-hard { color: var(--gold); box-shadow: inset 0 0 0 1px rgba(255,209,102,0.5); }
.lbd-insane { color: var(--red); box-shadow: inset 0 0 0 1px rgba(255,93,93,0.5); }
.lb-date { color: var(--dim); font-size: 11px; text-align: right; }

/* --- The Gauntlet -------------------------------------------------------------- */
.gaunt-head { display: flex; gap: 12px; align-items: center; margin-bottom: 10px; }
.gaunt-emblem { /* art: the near-white asset needs a push to read as finished */
  width: 56px; height: 56px; flex-shrink: 0;
  filter: brightness(1.8) drop-shadow(0 0 8px rgba(183, 138, 255, 0.55));
}
.gaunt-rank { flex: 1; display: flex; flex-direction: column; gap: 3px; }
.rank-name { font-size: 17px; font-weight: 900; letter-spacing: 0.14em; text-transform: uppercase; text-shadow: 0 0 12px currentColor; }
.rank-pts { font-size: 12px; color: var(--dim); font-variant-numeric: tabular-nums; }
.rank-track { height: 6px; border-radius: 3px; background: rgba(0,0,0,0.55); overflow: hidden; }
.rank-fill { height: 100%; transition: width 0.3s; }
.gaunt-record { font-size: 11.5px; color: var(--dim); font-weight: 700; }
.champ-sum {
  display: flex; gap: 12px; align-items: center; padding: 9px 12px; margin-bottom: 10px;
  background: var(--bg2); box-shadow: inset 0 0 0 1px var(--line);
  --notch: 14px; clip-path: var(--clip-notch);
}
.champ-shape { line-height: 0; filter: drop-shadow(0 0 8px rgba(83,232,255,0.4)); }
.champ-txt { display: flex; flex-direction: column; gap: 2px; }
.champ-txt b { font-size: 14px; }
.champ-build { font-size: 11.5px; color: var(--cyan); letter-spacing: 0.03em; }
.champ-stats { font-size: 11.5px; color: var(--dim); }

/* Arena 2.0 — the champion card, the online line, the inbox and the global board. */
.champ-name { font-size: 14px; font-weight: 800; }
.champ-meta { font-size: 11.5px; color: var(--dim); }
.arena-line { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--dim); margin: 0 0 10px; }
.arena-dot { width: 8px; height: 8px; clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%); background: #4a5570; }
.arena-line.on .arena-dot { background: var(--cyan); filter: drop-shadow(0 0 4px rgba(83, 232, 255, 0.8)); }
.arena-line.on { color: var(--text); }
.inbox-rows { display: flex; flex-direction: column; gap: 4px; margin-top: 10px; }
.inbox-row {
  display: grid; grid-template-columns: 1fr auto; gap: 8px; align-items: center;
  background: var(--panel); box-shadow: inset 0 0 0 1px var(--line); --notch: 6px; clip-path: var(--clip-notch);
  padding: 7px 10px; font-size: 12px; min-height: 34px;
}
.inbox-row i { font-style: normal; color: var(--dim); font-size: 11px; }
.inbox-row.held b { color: var(--cyan); }
.inbox-row.fell b { color: var(--red); }
.board-h { font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase; color: var(--dim); margin: 12px 0 6px; }
.lb-row.you { box-shadow: inset 0 0 0 1px rgba(83, 232, 255, 0.55); }
.bout-tag {
  display: inline-block; font-size: 10.5px; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase;
  padding: 3px 8px; --notch: 3px; clip-path: var(--clip-notch); margin-bottom: 8px;
}
.bout-tag.real { color: var(--cyan); background: rgba(83, 232, 255, 0.12); box-shadow: inset 0 0 0 1px rgba(83, 232, 255, 0.55); }
.bout-tag.offline { color: var(--dim); background: rgba(255, 255, 255, 0.04); box-shadow: inset 0 0 0 1px var(--line); }
.fight-rival { font-size: 11.5px; color: var(--dim); margin: -8px 0 10px; }

/* Forge sheet */
.forge-card { max-width: 380px; text-align: left; }
.forge-card h2 { text-align: center; }
.forge-note { color: var(--dim); font-size: 12.5px; text-align: center; margin-bottom: 12px; }
.forge-forms { display: flex; gap: 8px; margin-bottom: 12px; }
.forge-form { min-height: 74px; padding: 10px 4px 8px; }
/* 2.0: the forged name (re-roll is free) and the champion's derived size. */
.forge-id {
  display: grid; grid-template-columns: 44px 1fr auto; gap: 10px; align-items: center;
  background: var(--bg2); box-shadow: inset 0 0 0 1px var(--line); --notch: 10px; clip-path: var(--clip-notch);
  padding: 8px 10px; margin-bottom: 12px;
}
.forge-id-txt b { display: block; font-size: 14px; }
.forge-id-txt i { display: block; font-style: normal; font-size: 11px; color: var(--dim); }
.forge-reroll {
  min-width: 44px; min-height: 44px; background: none; border: none; color: var(--cyan); cursor: pointer;
  font-size: 12px; font-weight: 800; letter-spacing: 0.06em;
}
.forge-slots { font-size: 11px; color: var(--dim); margin: -6px 0 8px; text-align: center; }
.forge-emph {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-bottom: 14px;
  max-height: min(46dvh, 420px); overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 12px 2px 14px;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 10px, #000 calc(100% - 14px), transparent);
  mask-image: linear-gradient(to bottom, transparent 0, #000 10px, #000 calc(100% - 14px), transparent);
}
.emph-chip {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  --notch: 8px; clip-path: var(--clip-notch);
  background: var(--panel); border: none; padding: 9px 4px 8px; cursor: pointer;
  color: var(--text); box-shadow: inset 0 0 0 1px var(--line); min-height: 76px;
  opacity: 0.8;   /* 0.65 pushed --dim under 4.5:1 */
}
.emph-chip.afford { opacity: 1; box-shadow: inset 0 0 0 1px rgba(83,232,255,0.18); }
.emph-chip.picked { opacity: 1; background: rgba(83,232,255,0.07); box-shadow: inset 0 0 0 2px var(--cyan); filter: drop-shadow(0 0 6px rgba(83,232,255,0.3)); }
.forge-emph > :last-child:nth-child(3n + 1) { grid-column: 2; }   /* the tenth chip sits centred, not orphaned left */
.emph-chip:disabled { cursor: default; }
.emph-glyph { font-size: 16px; color: var(--cyan); }
.emph-name { font-size: 11px; font-weight: 800; }
.emph-pips { font-size: 10.5px; letter-spacing: 2px; color: rgba(83,232,255,0.35); }
.emph-chip.picked .emph-pips { color: var(--cyan); }
.emph-cost { font-size: 10.5px; color: var(--gold); font-weight: 700; }
/* P34 (art): gold is CURRENCY. 'pick' / 'MAX' / '—' are states — nine gold
   ones made the sheet's only real price read as decoration. */
.emph-cost.state { color: var(--dim); }
.emph-chip.picked .emph-cost.state { color: var(--cyan); }

/* Fight result */
.fight-card { max-width: 380px; }
.fight-vs { font-size: 17px; }
.fight-vs i { font-style: normal; color: var(--dim); font-size: 12px; padding: 0 4px; }
.fight-log {
  text-align: left; background: rgba(0,0,0,0.35); box-shadow: inset 0 0 0 1px var(--line);
  --notch: 8px; clip-path: var(--clip-notch); padding: 10px 12px; min-height: 120px; max-height: min(34dvh, 240px);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 12px, #000 calc(100% - 12px), transparent);
  mask-image: linear-gradient(to bottom, transparent 0, #000 12px, #000 calc(100% - 12px), transparent);
  overflow-y: auto; margin-bottom: 12px;
}
.fight-log p { color: var(--dim); font-size: 12.5px; line-height: 1.5; margin: 0 0 4px; }
.fight-log p:first-child { color: var(--text); }
.fight-log p:last-child { color: var(--text); }
.fight-verdict { display: flex; flex-direction: column; gap: 3px; margin-bottom: 14px; min-height: 44px; }
.fight-verdict[hidden] { display: flex; visibility: hidden; }   /* reserve the space — the buttons must not jump */
.fight-verdict b { font-size: 17px; letter-spacing: 0.12em; }
.fight-verdict.won b { color: var(--cyan); text-shadow: 0 0 14px rgba(83,232,255,0.7); }
.fight-verdict.lost b { color: var(--red); }
.fight-verdict span { font-size: 13px; color: var(--gold); font-weight: 700; }
@keyframes rankUpGlow {
  0%   { transform: scale(0.9); filter: brightness(0.8); }
  40%  { transform: scale(1.08); filter: brightness(1.6); }
  100% { transform: scale(1); filter: brightness(1); }
}
.fight-verdict.rank-up { animation: rankUpGlow 0.7s ease-out; }
.rank-up-line { font-size: 13px; font-weight: 900; letter-spacing: 0.18em; text-shadow: 0 0 14px currentColor; }

/* 2B reduced-motion: kill the new loops/one-shots outright (base = rest look). */
@media (prefers-reduced-motion: reduce) {
  .day-chip.today, .claim-pop, .fight-verdict.rank-up { animation: none !important; }
}

/* Playtest 33/34: the Shop's "watch an ad" offer — one card above the skins,
   in the VAULT's clothes (gold ring, 12px notch), because it is flux-for-
   attention and not a skin. Gold is currency: it belongs on the reward, never
   on the play mark. */
.ad-offer {
  display: flex; align-items: center; gap: 12px; margin: 0 0 14px;
  background: var(--panel); box-shadow: inset 0 0 0 1px rgba(255, 209, 102, 0.35);
  --notch: 12px; clip-path: var(--clip-notch);
  padding: 12px 14px; min-height: 64px;
}
.ad-offer-glyph { color: var(--dim); flex: 0 0 auto; width: 22px; display: grid; place-items: center; }
.ad-offer-glyph svg { display: block; }
.ad-offer-txt { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ad-offer-txt b { font-size: 15px; }
.ad-offer-txt b em { font-style: normal; color: var(--gold); white-space: nowrap; }
.ad-offer-txt i { font-style: normal; color: var(--dim); font-size: 12.5px; }
.ad-offer .btn { flex: 0 0 auto; min-height: 44px; padding: 0 14px; white-space: nowrap; }
/* Spent (art + a11y, SC 1.4.3): 0.7 on the whole card put --dim at 3.65:1 and
   left a dead button wearing the loudest fill on the page. The COPY stays
   readable; the glyph dims; only the CTA gives up its accent. */
.ad-offer.spent .ad-offer-glyph { color: #5a6490; }
.ad-offer.spent .ad-offer-txt b { color: var(--dim); }
.ad-offer .btn.primary:disabled {
  background: none; box-shadow: inset 0 0 0 1px var(--line); color: var(--dim); cursor: default;
}
/* A drawn mark inside a text button (Second Wind, the Daily Double). */
.btn > svg { vertical-align: -0.18em; margin-right: 6px; }

/* v66: the save-code box (☰ → Copy / Load a save code) */
.save-code {
  width: 100%; box-sizing: border-box; margin: 10px 0 4px; padding: 10px 12px;
  font: 12px/1.45 ui-monospace, Menlo, monospace; word-break: break-all;
  color: var(--text, #eaf6ff); background: rgba(83, 232, 255, 0.06);
  border: 1px solid var(--line, rgba(83, 232, 255, 0.25)); border-radius: 6px; resize: vertical;
}

/* v66: "Share this climb" under the shatter report's two buttons */
.death-share {
  display: flex; align-items: center; justify-content: center; gap: 8px; margin: 14px auto 0;
  padding: 10px 14px; min-height: 44px; background: none; border: none; cursor: pointer;
  color: var(--cyan, #53e8ff); font: 700 13px/1 inherit; letter-spacing: 0.08em; text-transform: uppercase;
}
.death-share:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--gold, #ffd166); border-radius: 6px; }

/* v67: the web trial's card (Shop tab, and the report when the gate ends a climb) */
.trial-card { margin: 12px 0; padding: 16px 16px 18px; border: 1px solid var(--line, rgba(83,232,255,.25));
  border-radius: 10px; background: rgba(83, 232, 255, 0.05); text-align: left; }
.trial-card h3 { margin: 0 0 6px; font-size: 16px; letter-spacing: 0.04em; color: var(--cyan, #53e8ff); }
.trial-card p { margin: 0 0 8px; font-size: 13px; color: var(--dim, #a9b8cc); }
.trial-card ul { margin: 0 0 14px; padding-left: 18px; font-size: 13px; line-height: 1.5; }
.trial-cta { display: block; text-align: center; text-decoration: none; }
