/* ============================================================
   STAR MINER — Triviagon chrome around a viewport into space
   ============================================================

   The page chrome (masthead, nav, cards, buttons) speaks Triviagon:
   amethyst, antique gold, Cinzel/Spectral/Plex Mono, rounded corners,
   soft shadows, light and dark themes. Tokens match mt.css exactly.

   The BOARD does not follow the page theme, on purpose. It is a
   viewport into space: its ground stays deep and its objects stay
   neon in both themes, the way a window at noon still shows a dark
   room behind it. Every board colour is therefore a --sm-* token
   defined once, not a theme token.
   ============================================================ */

:root{
  --bg:#EDEAF2; --surface:#FBFAFD; --surface-2:#E4DFEE; --sunken:#E9E5F1;
  --ink:#1C1526; --ink-soft:#5F5673; --ink-faint:#6D6380;
  --line:#D3CBE0; --line-soft:#E2DCEC;
  --accent:#6D3FBF; --accent-2:#8B62D9; --accent-soft:#EDE4FB; --accent-ink:#FFFFFF;
  --gold:#8F6B18; --gold-2:#B8912F; --gold-soft:#F6EED9;
  --good:#2C7350; --good-bg:#DEEFE6; --bad:#A5364A; --bad-bg:#F8E1E5; --warn:#8E6415; --warn-bg:#F5EAD6;
  --glow:rgba(109,63,191,.10);
  --shadow-sm:0 1px 2px rgba(28,21,38,.06);
  --shadow:0 2px 4px rgba(28,21,38,.05), 0 12px 32px rgba(28,21,38,.10);
  --shadow-lg:0 4px 8px rgba(28,21,38,.06), 0 24px 60px rgba(28,21,38,.16);
  --display:"Cinzel",Georgia,serif;
  --body:"Spectral",Georgia,"Times New Roman",serif;
  --mono:"IBM Plex Mono",ui-monospace,Consolas,monospace;

  /* the space viewport — one palette, both themes */
  --sm-void:#0A0E1C;         /* board ground */
  --sm-tile:#111A30;         /* tile face */
  --sm-tile-2:#16223E;       /* tile face, raised */
  --sm-spent:#05060E;        /* flipped face -- markedly darker than the live
                                tile face, so a sealed tile reads as a hole in
                                the field rather than a dimmer version of it */
  --sm-line:#233255;         /* tile hairline */
  --sm-line-2:#31456F;       /* tile hairline, lit */
  --sm-ink:#D7E6FF;          /* board text */
  --sm-dim:#7C93B8;          /* board text, secondary */
  --fuel-ink:#1A66B4;        /* the banked figure in the HUD -- page-side blue,
                                darker than the board's --sm-fuel so it holds up
                                against the light theme's lavender ground */
  --sm-cy:#66E0FF;           /* ship, previews */
  --sm-entry:#4FE08A;        /* landing invitation -- see the entry phase below */
  --sm-rock:#9FB6C6;         /* small rock */
  --sm-rock2:#D3E3EE;        /* big rock */
  --sm-crys:#7EF0D0;         /* crystal */
  --sm-fuel:#63B3FF;         /* fuel -- azure, deliberately apart from both the
                                antique gold of the page chrome and the icy
                                cyan of the ship, so "fuel things" (canister,
                                gauge, costs) read as their own family */
  --sm-gold:#FFD977;         /* the optimum route line in replays -- gold is
                                reserved for reward, never for fuel */
  --sm-bad:#FF5F6E;          /* bomb, danger */
  --sm-flux:#C99BFF;         /* portal, wormhole */
  --sm-slip:#7EF0A0;         /* slipstream */
  --sm-field:#FF7A45;        /* matterfield -- burnt orange-red: caution, not
                                reward. Its old amber sat one shade from the
                                canister and the two read as siblings, which
                                they are the opposite of */
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    --bg:#120E1A; --surface:#1C1628; --surface-2:#261E36; --sunken:#171223;
    --ink:#EFE9F6; --ink-soft:#A79CBC; --ink-faint:#877C9C;
    --line:#332942; --line-soft:#2A2138;
    --accent:#B48CF7; --accent-2:#C9AAFF; --accent-soft:#291F44; --accent-ink:#150F22;
    --gold:#E2BA5F; --gold-2:#F0D28E; --gold-soft:#2E2413;
    --fuel-ink:#7CC2FF;
    --good:#5DC694; --good-bg:#14301F; --bad:#E7768A; --bad-bg:#2E1720; --warn:#E0B45C; --warn-bg:#2E2413;
    --glow:rgba(180,140,247,.13);
    --shadow-sm:0 1px 2px rgba(0,0,0,.5);
    --shadow:0 2px 4px rgba(0,0,0,.4), 0 12px 32px rgba(0,0,0,.5);
    --shadow-lg:0 4px 8px rgba(0,0,0,.45), 0 24px 60px rgba(0,0,0,.6);
  }
}
:root[data-theme="dark"]{
  --bg:#120E1A; --surface:#1C1628; --surface-2:#261E36; --sunken:#171223;
  --ink:#EFE9F6; --ink-soft:#A79CBC; --ink-faint:#877C9C;
  --line:#332942; --line-soft:#2A2138;
  --accent:#B48CF7; --accent-2:#C9AAFF; --accent-soft:#291F44; --accent-ink:#150F22;
  --gold:#E2BA5F; --gold-2:#F0D28E; --gold-soft:#2E2413;
  --fuel-ink:#7CC2FF;
  --good:#5DC694; --good-bg:#14301F; --bad:#E7768A; --bad-bg:#2E1720; --warn:#E0B45C; --warn-bg:#2E2413;
  --glow:rgba(180,140,247,.13);
  --shadow-sm:0 1px 2px rgba(0,0,0,.5);
  --shadow:0 2px 4px rgba(0,0,0,.4), 0 12px 32px rgba(0,0,0,.5);
  --shadow-lg:0 4px 8px rgba(0,0,0,.45), 0 24px 60px rgba(0,0,0,.6);
}

*{box-sizing:border-box}
body{
  margin:0; min-height:100vh; background:var(--bg); color:var(--ink);
  font-family:var(--body); font-size:17px; line-height:1.6;
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
}
body::before{
  content:""; position:fixed; inset:0; z-index:-1; pointer-events:none;
  background:radial-gradient(130% 70% at 50% -8%, var(--glow) 0%, transparent 62%);
}
#app{max-width:56rem; margin:0 auto; padding:1.5rem 1.15rem 4.5rem; position:relative}
/* Tutorial view: widens the wrapper to fit its third column. */
#app.tutorial{max-width:68rem}
a{color:inherit}

/* ---------------- masthead (mirrors the trivia pages) ---------------- */
.masthead{text-align:center; padding:1.1rem 0 1rem; position:relative}
.crest{
  font-family:var(--display); font-weight:700; letter-spacing:.02em;
  font-size:clamp(1.35rem,5.6vw,2.1rem); line-height:1.12; margin:0; color:var(--ink); text-wrap:balance;
}
.crest a{text-decoration:none}
.crest .glyph{
  display:block; font-size:.62em; color:var(--gold); margin:0 auto .5rem;
  letter-spacing:.3em; text-indent:.3em; line-height:1;
}
.rule{display:flex; align-items:center; gap:.7rem; margin:.85rem auto 0; max-width:24rem; color:var(--line)}
.rule::before,.rule::after{content:""; flex:1; height:1px; background:currentColor}
.rule span{
  font-family:var(--mono); font-size:.6rem; letter-spacing:.2em; text-transform:uppercase;
  color:var(--ink-faint); white-space:nowrap;
}
.homebtn{
  position:absolute; top:.9rem; left:0; font-family:var(--mono); font-size:.6rem;
  letter-spacing:.12em; text-transform:uppercase; color:var(--ink-faint); text-decoration:none;
  background:transparent; border:1px solid var(--line); border-radius:999px;
  padding:.3rem .6rem; line-height:1; display:inline-block;
}
.homebtn:hover{color:var(--ink); border-color:var(--ink-soft)}
.homebtn:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.hdr-actions{position:absolute; top:.9rem; right:0; display:flex; align-items:center; gap:.35rem}
.sndbtn,.themebtn,.patbtn{
  font-family:var(--mono); font-size:.6rem; letter-spacing:.12em; text-transform:uppercase;
  color:var(--ink-faint); background:transparent; border:1px solid var(--line);
  border-radius:999px; padding:.3rem .6rem; cursor:pointer; line-height:1;
}
.sndbtn:hover,.themebtn:hover,.patbtn:hover{color:var(--ink); border-color:var(--ink-soft)}
.sndbtn:focus-visible,.themebtn:focus-visible,.patbtn:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.sndbtn[aria-pressed="true"]{color:var(--gold); border-color:var(--gold)}
.themebtn,.patbtn{min-width:1.9rem; text-align:center; font-size:.7rem; padding:.26rem .5rem}

.topnav{display:flex; justify-content:center; gap:.4rem; margin:1.1rem 0 .2rem; flex-wrap:wrap}
.topnav a{
  font-family:var(--display); font-size:.68rem; font-weight:600; letter-spacing:.16em;
  text-transform:uppercase; text-decoration:none; color:var(--ink-faint);
  padding:.42rem .95rem; border:1px solid var(--line); border-radius:999px;
  transition:color .18s ease, border-color .18s ease, background .18s ease;
}
.topnav a:hover{color:var(--ink); border-color:var(--ink-soft)}
.topnav a[aria-current="page"]{color:var(--accent); border-color:var(--accent); background:var(--accent-soft)}
.topnav a:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.topnav a .done{color:var(--good); margin-left:.3rem}

/* ---------------- play layout ---------------- */
.playwrap{display:grid; grid-template-columns:minmax(0,1fr) 15rem; gap:1.4rem; align-items:start; margin-top:1.4rem}
@media (max-width:46rem){ .playwrap{grid-template-columns:1fr} }

/* The tutorial adds a third column. Placement is explicit rather than relying
   on source order, because the DOM deliberately leads with the board: that way
   the phone stack (board, checklist, legend) needs no reordering and screen
   readers reach the game before its annotations. Below 62rem it folds to the
   two-column shape a daily puzzle uses, then to a single stack. */
.playwrap.tut{grid-template-columns:14.5rem minmax(0,1fr) 15rem}
.playwrap.tut > .boardcol{grid-column:2; grid-row:1}
.playwrap.tut > .side-left{grid-column:1; grid-row:1}
.playwrap.tut > .side:not(.side-left){grid-column:3; grid-row:1}
@media (max-width:62rem){
  .playwrap.tut{grid-template-columns:minmax(0,1fr) 15rem}
  .playwrap.tut > .boardcol{grid-column:1; grid-row:1}
  .playwrap.tut > .side-left{grid-column:2; grid-row:1}
  .playwrap.tut > .side:not(.side-left){grid-column:2; grid-row:2}
}
@media (max-width:46rem){
  .playwrap.tut{grid-template-columns:1fr}
  .playwrap.tut > .boardcol,
  .playwrap.tut > .side-left,
  .playwrap.tut > .side:not(.side-left){grid-column:1; grid-row:auto}
}

/* ---------------- HUD ---------------- */
.hud{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  margin:0 0 .8rem; flex-wrap:wrap;
}
.hud .day{font-family:var(--mono); font-size:.66rem; letter-spacing:.14em; text-transform:uppercase; color:var(--ink-faint)}
.hud .day b{color:var(--ink); font-weight:600}
.scorebox{display:flex; gap:1.4rem; align-items:baseline; position:relative}
.scorebox .lbl{font-family:var(--mono); font-size:.58rem; letter-spacing:.16em; text-transform:uppercase; color:var(--ink-faint); display:block}
.scorebox .val{font-family:var(--display); font-weight:700; font-size:1.5rem; color:var(--ink); font-variant-numeric:tabular-nums; line-height:1.1}
.scorebox .bank{
  font-family:var(--mono); font-weight:600; font-size:.92rem; color:var(--fuel-ink);
  margin-left:.32rem; font-variant-numeric:tabular-nums;
}
/* The score breakdown. Built rather than left to a title attribute, which
   waits a second before appearing, renders in OS chrome that ignores the
   page's palette, and cannot rule off the total. Shown on hover and on
   keyboard focus; right-aligned because the score sits at the row's end. */
.scoretip{
  position:absolute; top:100%; right:0; z-index:20; margin-top:.45rem;
  background:var(--surface); border:1px solid var(--line); border-radius:8px;
  box-shadow:var(--shadow); padding:.6rem .8rem;
  font-family:var(--mono); font-size:.68rem; line-height:1.7; letter-spacing:.03em;
  color:var(--ink-soft); white-space:nowrap; text-align:left; font-weight:400;
  opacity:0; pointer-events:none; transform:translateY(-4px);
  transition:opacity .16s ease, transform .16s ease;
}
.scorebox:hover .scoretip,
.scorebox:focus-visible .scoretip{opacity:1; transform:none}
.scoretip b{color:var(--ink); font-weight:600}
.scoretip .tot{
  display:block; margin-top:.4rem; padding-top:.4rem;
  border-top:1px solid var(--line-soft); color:var(--ink);
}
.scorebox:focus{outline:none}
.scorebox:focus-visible{outline:2px solid var(--accent); outline-offset:4px; border-radius:4px}

.fuelrow{display:flex; align-items:center; gap:.6rem; margin:0 0 .9rem}
.fuelrow .flbl{font-family:var(--mono); font-size:.6rem; letter-spacing:.16em; text-transform:uppercase; color:var(--ink-faint)}
.fuelbar{
  flex:1; height:.85rem; border-radius:999px; background:var(--sunken);
  border:1px solid var(--line); overflow:hidden; position:relative;
}
.fuelbar .fill{
  height:100%; border-radius:999px;
  background:linear-gradient(90deg, #4A9BE8, var(--sm-fuel));
  transition:width .35s cubic-bezier(.4,0,.2,1);
}
.fuelbar.low .fill{background:linear-gradient(90deg, var(--bad), var(--bad))}
.fuelnum{font-family:var(--mono); font-weight:600; font-size:.95rem; color:var(--ink); min-width:2.2rem; text-align:right; font-variant-numeric:tabular-nums}
.fuelbar.low + .fuelnum{color:var(--bad)}
@media (prefers-reduced-motion:no-preference){
  .fuelbar.low .fill{animation:fuelPulse 1s ease-in-out infinite}
  @keyframes fuelPulse{50%{opacity:.55}}
}

/* ---------------- the viewport ---------------- */
.boardshell{
  background:var(--sm-void); border:1px solid var(--line); border-radius:14px;
  padding:clamp(.6rem,2.2vw,1rem); box-shadow:var(--shadow-lg), inset 0 0 60px rgba(20,30,66,.55);
  position:relative;
}
.boardshell::before{                        /* starfield, pure CSS */
  content:""; position:absolute; inset:0; border-radius:inherit; pointer-events:none;
  background-image:
    radial-gradient(1px 1px at 12% 22%, rgba(215,230,255,.5) 50%, transparent 51%),
    radial-gradient(1px 1px at 78% 12%, rgba(215,230,255,.35) 50%, transparent 51%),
    radial-gradient(1.5px 1.5px at 55% 82%, rgba(126,240,208,.35) 50%, transparent 51%),
    radial-gradient(1px 1px at 33% 65%, rgba(215,230,255,.3) 50%, transparent 51%),
    radial-gradient(1px 1px at 90% 55%, rgba(201,155,255,.4) 50%, transparent 51%),
    radial-gradient(1.2px 1.2px at 8% 88%, rgba(215,230,255,.4) 50%, transparent 51%),
    radial-gradient(1px 1px at 66% 38%, rgba(102,224,255,.3) 50%, transparent 51%);
}
.boardwrap{position:relative}
.grid{
  display:grid; gap:clamp(4px,1vw,7px); position:relative; z-index:1;
  touch-action:manipulation;
}
#fx{position:absolute; inset:0; z-index:3; pointer-events:none}

/* ---------------- tiles ---------------- */
.tile{
  position:relative; aspect-ratio:1; border-radius:22%; perspective:340px;
  cursor:pointer; -webkit-tap-highlight-color:transparent; border:0; padding:0; background:none;
}
.tile:focus-visible{outline:2px solid var(--sm-cy); outline-offset:2px; border-radius:22%}
.tile .in{
  position:absolute; inset:0; border-radius:22%;
  transform-style:preserve-3d; transition:transform .38s cubic-bezier(.45,0,.25,1);
}
.tile.flipped .in{transform:rotateY(180deg)}
.tile .face{
  position:absolute; inset:0; border-radius:22%;
  backface-visibility:hidden; -webkit-backface-visibility:hidden;
  display:grid; place-items:center;
}
.tile .front{
  background:linear-gradient(150deg, var(--sm-tile-2), var(--sm-tile));
  border:1px solid var(--sm-line);
  box-shadow:inset 0 1px 0 rgba(215,230,255,.06);
}
.tile .back{
  transform:rotateY(180deg);
  background:var(--sm-spent);
  border:1px solid rgba(24,34,60,.55);
  box-shadow:inset 0 2px 9px rgba(0,0,0,.6);
}
.tile .back::after{
  content:""; position:absolute; inset:22%; border-radius:50%;
  border:1px solid rgba(124,147,184,.09);
}
.tile svg{width:62%; height:62%; display:block; overflow:visible}

/* object glow, per type */
.tile.t1 svg{color:var(--sm-rock);  filter:drop-shadow(0 0 4px rgba(159,182,198,.45))}
.tile.t2 svg{color:var(--sm-rock2); filter:drop-shadow(0 0 5px rgba(211,227,238,.5))}
.tile.t3 svg{color:var(--sm-crys);  filter:drop-shadow(0 0 7px rgba(126,240,208,.65))}
.tile.t4 svg{color:var(--sm-fuel);  filter:drop-shadow(0 0 7px rgba(99,179,255,.6))}
.tile.t5 svg{color:var(--sm-bad);   filter:drop-shadow(0 0 7px rgba(255,95,110,.65))}
.tile.t6 svg{color:var(--sm-flux);  filter:drop-shadow(0 0 9px rgba(201,155,255,.8))}
.tile.t7 svg{color:var(--sm-flux);  filter:drop-shadow(0 0 7px rgba(201,155,255,.6))}
.tile.t8 svg{color:var(--sm-slip);  filter:drop-shadow(0 0 6px rgba(126,240,160,.5))}
.tile.t9 svg{color:var(--sm-field); filter:drop-shadow(0 0 6px rgba(255,122,69,.5))}

/* Occupied tiles take a whisper of their object's colour in the face itself,
   so the board reads as regions at a glance, not only glyph by glyph. Empty
   tiles keep the plain face — the tint marks PRESENCE. Mixed from the same
   tokens as the glyphs, so any palette change carries through by itself.
   These sit before the entry-phase rules on purpose: during the landing
   choice the ring's green face wins the source-order tie and rim objects
   still read as invitations first. */
.tile.t1 .front{background:linear-gradient(150deg, color-mix(in oklab, var(--sm-rock) 9%, var(--sm-tile-2)), color-mix(in oklab, var(--sm-rock) 5%, var(--sm-tile)))}
.tile.t2 .front{background:linear-gradient(150deg, color-mix(in oklab, var(--sm-rock2) 9%, var(--sm-tile-2)), color-mix(in oklab, var(--sm-rock2) 5%, var(--sm-tile)))}
.tile.t3 .front{background:linear-gradient(150deg, color-mix(in oklab, var(--sm-crys) 11%, var(--sm-tile-2)), color-mix(in oklab, var(--sm-crys) 6%, var(--sm-tile)))}
.tile.t4 .front{background:linear-gradient(150deg, color-mix(in oklab, var(--sm-fuel) 11%, var(--sm-tile-2)), color-mix(in oklab, var(--sm-fuel) 6%, var(--sm-tile)))}
.tile.t5 .front{background:linear-gradient(150deg, color-mix(in oklab, var(--sm-bad) 12%, var(--sm-tile-2)), color-mix(in oklab, var(--sm-bad) 7%, var(--sm-tile)));
  /* the hairline goes red too: danger owns its whole tile, border included */
  border-color:color-mix(in oklab, var(--sm-bad) 55%, var(--sm-line))}
.tile.t6 .front{background:linear-gradient(150deg, color-mix(in oklab, var(--sm-flux) 13%, var(--sm-tile-2)), color-mix(in oklab, var(--sm-flux) 7%, var(--sm-tile)))}
.tile.t7 .front{background:linear-gradient(150deg, color-mix(in oklab, var(--sm-flux) 11%, var(--sm-tile-2)), color-mix(in oklab, var(--sm-flux) 6%, var(--sm-tile)))}
.tile.t8 .front{background:linear-gradient(150deg, color-mix(in oklab, var(--sm-slip) 9%, var(--sm-tile-2)), color-mix(in oklab, var(--sm-slip) 5%, var(--sm-tile)))}
.tile.t9 .front{background:linear-gradient(150deg, color-mix(in oklab, var(--sm-field) 11%, var(--sm-tile-2)), color-mix(in oklab, var(--sm-field) 6%, var(--sm-tile)))}

@media (prefers-reduced-motion:no-preference){
  .tile.t6 svg{animation:portalSpin 9s linear infinite}
  .tile.t7 svg{animation:portalSpin 14s linear infinite reverse}
  @keyframes portalSpin{to{transform:rotate(360deg)}}
}

/* ---------------- entry phase ----------------
   The landing ring has to advertise itself. A first-time player who has read
   nothing should still see where a run begins, so every inviting tile takes a
   green cast -- border, gradient and inner glow -- and pulses gently, the
   pulse staggered across the ring so it ripples rather than flashing in
   unison. Green carries no other meaning out here: slipstreams are the only
   other green thing on the board and they are interior-only, so a tile can
   never be both. Legality is wider than the invitation -- see markEntries()
   -- which is why this hangs off .entry-invite and the plain .entryable
   border below stays neutral for the rim bombs. */
.tile.entryable .front{border-color:var(--sm-line-2)}
.tile.entry-invite .front{
  border-color:color-mix(in oklab, var(--sm-entry) 58%, var(--sm-line));
  background:
    linear-gradient(150deg,
      color-mix(in oklab, var(--sm-entry) 14%, var(--sm-tile-2)),
      color-mix(in oklab, var(--sm-entry) 7%, var(--sm-tile)));
  box-shadow:inset 0 0 0 1px rgba(79,224,138,.16), inset 0 1px 0 rgba(215,230,255,.06);
}
@media (prefers-reduced-motion:no-preference){
  .tile.entry-invite .front{animation:entryPulse 2.4s ease-in-out infinite; animation-delay:var(--entry-delay,0s)}
  @keyframes entryPulse{50%{box-shadow:inset 0 0 0 1.7px rgba(79,224,138,.45), inset 0 1px 0 rgba(215,230,255,.06)}}
}
.tile.pv .front{
  border-color:var(--sm-cy);
  box-shadow:inset 0 0 0 1.5px rgba(102,224,255,.5), inset 0 0 14px rgba(102,224,255,.12);
}
.tile.pv-end .front{
  border-color:var(--sm-cy);
  box-shadow:inset 0 0 0 2px var(--sm-cy), inset 0 0 18px rgba(102,224,255,.22);
}
.tile.pv-bad .front{
  border-color:var(--sm-bad) !important;
  box-shadow:inset 0 0 0 2px var(--sm-bad), inset 0 0 18px rgba(255,95,110,.25) !important;
}
.tile.shipHere .front{border-color:var(--sm-cy)}

/* the floating cost chip that follows the preview */
.costchip{
  position:absolute; z-index:4; pointer-events:none; transform:translate(-50%,-130%);
  font-family:var(--mono); font-size:.66rem; font-weight:600; white-space:nowrap;
  background:rgba(10,14,28,.92); color:var(--sm-ink);
  border:1px solid var(--sm-line-2); border-radius:8px; padding:.3rem .55rem;
  box-shadow:0 4px 14px rgba(0,0,0,.45);
}
.costchip .cost{color:var(--sm-fuel)} .costchip .gain{color:var(--sm-crys)}
.costchip .warnx{color:var(--sm-bad)}
.costchip.hidden{display:none}

/* ---------------- action row ---------------- */
.actions{display:flex; gap:.55rem; margin-top:.95rem; flex-wrap:wrap}
/* Deliberately NOT `button.btn`. Anchors wear this class too, and a
   type-qualified selector would (a) skip them entirely, leaving raw link text,
   and (b) outrank .btn-ghost at 0-1-1 vs 0-1-0, so the shorthand border below
   would keep its transparent colour and every ghost button would lose its
   outline. Both of those shipped once. Keep this selector class-only. */
.btn{
  font-family:var(--display); font-weight:700; font-size:.72rem; letter-spacing:.16em;
  text-transform:uppercase; border-radius:8px; padding:.78rem 1.2rem; cursor:pointer;
  display:inline-block; text-decoration:none; text-align:center;
  border:1.5px solid transparent;
  transition:transform .14s ease, filter .18s ease, border-color .18s ease, color .18s ease, box-shadow .3s ease;
}
.btn:active{transform:translateY(1px)}
.btn:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.btn-primary{background:var(--accent); color:var(--accent-ink); border-color:var(--accent); box-shadow:0 3px 12px var(--glow)}
.btn-primary:hover{filter:brightness(1.1)}
.btn-primary:disabled{opacity:.35; cursor:default; box-shadow:none}
.btn-primary.armed{
  background:linear-gradient(120deg, var(--accent), var(--accent-2));
  box-shadow:0 0 0 2px var(--accent-soft), 0 4px 22px var(--glow);
}
@media (prefers-reduced-motion:no-preference){
  .btn-primary.armed{animation:armedGlow 1.6s ease-in-out infinite}
  @keyframes armedGlow{50%{box-shadow:0 0 0 4px var(--accent-soft), 0 4px 30px var(--glow)}}
}
.btn-ghost{background:transparent; color:var(--ink-faint); border-color:var(--line)}
.btn-ghost:disabled{opacity:.35; cursor:default}
.btn-ghost:disabled:hover{color:var(--ink-faint); border-color:var(--line)}
.btn-ghost:hover{color:var(--ink); border-color:var(--ink-soft)}

/* Sits between the HUD and the fuel gauge, where the eye already is; it was
   invisible tucked under the board. min-height keeps the layout from hopping
   when the text changes. */
.runmsg{
  margin:-.15rem 0 .55rem; font-family:var(--mono); font-size:.72rem; letter-spacing:.03em;
  color:var(--ink-soft); min-height:1.3em;
}
.runmsg .hi{color:var(--accent); font-weight:600}
/* The starting-tile prompt is green so the words match the ring they point
   at. It takes the theme-aware --good rather than the board's --sm-entry:
   this line sits on the page, not the board, and the board green is tuned
   for a near-black ground where it would wash out on the light theme. */
.runmsg .go{color:var(--good); font-weight:600}

/* ---------------- side panel: legend / checklist ---------------- */
.side{display:flex; flex-direction:column; gap:1rem}
.panelcard{
  background:var(--surface); border:1px solid var(--line); border-radius:12px;
  padding:1.05rem 1.15rem; box-shadow:var(--shadow-sm);
}
.panelcard h3{
  font-family:var(--mono); font-size:.62rem; letter-spacing:.18em; text-transform:uppercase;
  color:var(--ink-faint); margin:0 0 .8rem; font-weight:500;
}
.legend{display:flex; flex-direction:column; gap:.55rem; margin:0; padding:0; list-style:none}
.legend li{display:grid; grid-template-columns:2.1rem 1fr; gap:.65rem; align-items:center; margin:0}
.legend .sw{
  width:2.1rem; height:2.1rem; border-radius:22%;
  background:linear-gradient(150deg, var(--sm-tile-2), var(--sm-tile));
  border:1px solid var(--sm-line); display:grid; place-items:center;
}
.legend .sw svg{width:62%; height:62%; overflow:visible}
.legend b{display:block; font-size:.84rem; font-weight:600; line-height:1.25}
.legend span.d{display:block; font-size:.74rem; color:var(--ink-soft); line-height:1.35}

/* tutorial checklist */
.check{display:flex; flex-direction:column; gap:.6rem; margin:0; padding:0; list-style:none}
.check li{
  display:grid; grid-template-columns:1.45rem 1fr; gap:.5rem; margin:0;
  font-size:.8rem; line-height:1.4; color:var(--ink-soft);
  opacity:.75; transition:opacity .4s ease;
}
.check li b{display:block; color:var(--ink); font-weight:600; font-size:.82rem}
.check li .mk{
  width:1.15rem; height:1.15rem; border-radius:50%; border:1.5px solid var(--line);
  display:grid; place-items:center; font-size:.62rem; color:transparent; margin-top:.12rem;
  transition:all .35s ease; font-family:var(--mono);
}
.check li.done{opacity:1}
.check li.done .mk{background:var(--good-bg); border-color:var(--good); color:var(--good)}
.check li.note .mk{border-radius:5px}
.check li.note.done .mk{background:var(--warn-bg); border-color:var(--warn); color:var(--warn)}
@media (prefers-reduced-motion:no-preference){
  .check li.justlit .mk{animation:markPop .5s cubic-bezier(.3,1.6,.5,1)}
  @keyframes markPop{0%{transform:scale(.4)}100%{transform:scale(1)}}
}

/* ---------------- game over dialog ---------------- */
.overlay{
  position:fixed; inset:0; z-index:40; display:grid; place-items:center;
  background:rgba(10,8,18,.55); backdrop-filter:blur(3px);
  opacity:0; pointer-events:none; transition:opacity .3s ease;
}
.overlay.show{opacity:1; pointer-events:auto}
.dialog{
  background:var(--surface); border:1px solid var(--line); border-radius:14px;
  box-shadow:var(--shadow-lg); padding:1.7rem 1.9rem; max-width:22rem; width:calc(100vw - 3rem);
  text-align:center; transform:translateY(10px) scale(.97); transition:transform .3s cubic-bezier(.3,1.3,.5,1);
}
.overlay.show .dialog{transform:none}
.dialog h2{font-family:var(--display); font-weight:700; font-size:1.45rem; margin:0 0 .3rem}
.dialog h2.bad{color:var(--bad)}
.dialog p{margin:0 0 1.2rem; color:var(--ink-soft); font-size:.95rem}
.dialog .btnrow{display:flex; gap:.55rem; justify-content:center; flex-wrap:wrap}

/* ---------------- results ---------------- */
.results{
  background:var(--surface); border:1px solid var(--line); border-radius:12px;
  box-shadow:var(--shadow); padding:1.5rem 1.6rem; margin-top:1.4rem;
}
.results .scoreline{display:flex; align-items:baseline; gap:.8rem; flex-wrap:wrap}
.results .big{
  font-family:var(--display); font-weight:700; font-size:2.6rem; line-height:1;
  color:var(--ink); font-variant-numeric:tabular-nums;
}
.results .of{font-family:var(--mono); font-size:1rem; color:var(--ink-faint)}
.band{
  display:inline-block; font-family:var(--display); font-weight:700; font-size:.72rem;
  letter-spacing:.18em; text-transform:uppercase; border-radius:999px; padding:.4rem .95rem;
  border:1.5px solid var(--gold); color:var(--gold); background:var(--gold-soft);
}
.band.master{border-color:var(--accent); color:var(--accent); background:var(--accent-soft)}
.results .haul{
  display:flex; gap:1.3rem; margin:1.1rem 0 0; font-family:var(--mono); font-size:.74rem;
  color:var(--ink-soft); flex-wrap:wrap;
}
.results .haul b{color:var(--ink)}
.results .ractions{display:flex; gap:.55rem; margin-top:1.3rem; flex-wrap:wrap}
.sharefeedback{font-family:var(--mono); font-size:.68rem; color:var(--good); margin-left:.4rem}

/* ---------------- archive ---------------- */
.archgrid{display:grid; grid-template-columns:repeat(auto-fill,minmax(8.4rem,1fr)); gap:.6rem; margin-top:1.4rem}
.archcell{
  display:flex; flex-direction:column; gap:.2rem; text-decoration:none;
  background:var(--surface); border:1px solid var(--line); border-radius:10px;
  padding:.75rem .85rem; box-shadow:var(--shadow-sm);
  transition:border-color .18s ease, transform .16s ease;
}
.archcell:hover{border-color:var(--accent); transform:translateY(-2px)}
.archcell .an{font-family:var(--display); font-weight:700; font-size:1rem}
.archcell .ad{font-family:var(--mono); font-size:.6rem; letter-spacing:.1em; color:var(--ink-faint); text-transform:uppercase}
.archcell .as{font-family:var(--mono); font-size:.72rem; margin-top:.15rem}
.archcell .as.done{color:var(--good)}
.archcell .as.open{color:var(--accent)}
.archcell.worm .ad::after{content:" ◎"; color:var(--accent-2)}
.archcell.locked{opacity:.45; pointer-events:none}

/* intro card (pre-entry hint / tutorial banner) */
.introcard{
  border:1px solid var(--line); border-left:3px solid var(--accent); border-radius:10px;
  background:var(--surface); box-shadow:var(--shadow-sm);
  padding:.8rem 1.05rem; margin:0 0 1rem; font-size:.9rem; color:var(--ink-soft);
}
.introcard b{color:var(--ink)}
.introcard.wed{border-left-color:var(--accent-2)}

@media (max-width:46rem){
  #app{padding:1.1rem .8rem 3.5rem}
  .scorebox{gap:1rem}
  .scorebox .val{font-size:1.25rem}
  .scorebox .bank{font-size:.8rem}
}
