/* ============================================================
   CHESS REACTIONS - Triviagon chrome around a demolition site at night
   ============================================================

   Same contract as Objectivity and Star Miner: the page chrome speaks
   Triviagon (amethyst, antique gold, Cinzel/Spectral/Plex Mono, both
   themes, tokens identical to ob.css), and the BOARD keeps its own
   palette in both themes.

   Objectivity's board is an examination room with the lights off. Star
   Miner's is a window into space. This one is a demolition survey drawn
   at night: everything on the ground is cold - slate, steel, surveyor's
   cyan - and the only warm colour on the board is the blast itself.
   Nothing is orange until the player makes it orange.

   Gold is reserved, as everywhere else on the site, for the thing the
   player has CHOSEN: the armed charges and nothing else.
   ============================================================ */

: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;
  --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 site - one palette, both themes */
  --cs-void:#080C12;         /* board ground */
  --cs-grit:#0C121A;         /* board ground, second layer */
  --cs-tile:#131C27;         /* an empty plot */
  --cs-tile-2:#1A2634;       /* a plot with something on it */
  --cs-line:#22303E;         /* hairline */
  --cs-line-2:#3A5468;       /* hairline, lit */
  --cs-ink:#D8E6F2;          /* board text */
  --cs-dim:#748AA0;          /* board text, secondary */
  --cs-charge:#79D7EF;       /* a charge - surveyor's cyan, cold */
  --cs-charge-2:#0E2A38;     /* a charge, tile ground */
  --cs-crate:#A6BCD0;        /* the payload */
  --cs-crate-2:#18242F;      /* the payload, tile ground */
  --cs-stone:#2C3846;        /* stone - the only thing that blocks */
  --cs-stone-2:#3D4C5C;
  --cs-armed:#F0CE72;        /* ARMED. the one thing the player chose */
  /* Score tiles: one colour per tier, chosen to stay clear of everything
     else already speaking on this board - piece cyan, blast orange, armed
     gold and the violet trace highlight. The blue is pushed bluer than the
     piece cyan and the purple more magenta than the trace violet, because
     at 39px a near-miss between two hues reads as the same colour. */
  --cs-p0:#5FE39B;           /* lowest tier  - green  */
  --cs-p1:#5B94FF;           /* middle tier  - blue   */
  --cs-p2:#C77DFF;           /* highest tier - purple */
  --cs-crys:#5B94FF;         /* legacy alias, still used by the tile glow */
  --cs-fire:#FF8A3C;         /* the blast */
  --cs-fire-2:#FFD86E;       /* the blast, core */
  --cs-scorch:#05080C;       /* what is left afterwards */
  --cs-trace:#A98CFF;        /* the assist, and the only violet on the board */
}
@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;
    --good:#5DC694; --good-bg:#14301F; --bad:#E7768A; --bad-bg:#2E1720;
    --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;
  --good:#5DC694; --good-bg:#14301F; --bad:#E7768A; --bad-bg:#2E1720;
  --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:64rem; margin:0 auto; padding:1.5rem 1.15rem 4.5rem; position:relative}
a{color:inherit}

/* ---------------- masthead ---------------- */
.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:.68rem;
  letter-spacing:.12em; text-transform:uppercase; color:var(--ink); text-decoration:none;
  background:var(--surface); border:1px solid var(--line); border-radius:999px;
  padding:.45rem .85rem; line-height:1; display:inline-block; box-shadow:var(--shadow-sm);
}
.homebtn:hover{color:var(--gold); border-color:var(--gold)}
.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}
/* .patbtn is injected by /assets/bgpat.js and carries no styling of its own -
   every page dresses it alongside its own controls. Left out, it falls back to
   a raw browser button beside two themed ovals. */
.sndbtn,.themebtn,.patbtn{
  font-family:var(--mono); font-size:.68rem; letter-spacing:.12em; text-transform:uppercase;
  color:var(--ink); background:var(--surface); border:1px solid var(--line);
  border-radius:999px; padding:.45rem .85rem; cursor:pointer; line-height:1;
  box-shadow:var(--shadow-sm);
}
.sndbtn:hover,.themebtn:hover,.patbtn:hover{color:var(--gold); border-color:var(--gold)}
.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:2rem; text-align:center; font-size:.78rem; padding:.4rem .6rem}

/* ---------------- top nav ---------------- */
.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}

/* ---------------- HUD ---------------- */
.hud{display:flex; align-items:flex-end; justify-content:space-between; gap:1rem; margin:1.1rem 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}
.hud .day .past{
  display:inline-block; margin-left:.5rem; padding:.1rem .5rem; border-radius:999px;
  border:1px solid var(--line); color:var(--ink-faint); font-size:.58rem;
}
.hud .day .tier{
  display:inline-block; margin-left:.4rem; padding:.1rem .5rem; border-radius:999px;
  font-size:.58rem; letter-spacing:.1em;
}
.tier-easy{border:1px solid var(--good); color:var(--good)}
.tier-medium{border:1px solid var(--gold); color:var(--gold)}
.tier-hard{border:1px solid var(--bad); color:var(--bad)}

.scorebox{display:flex; gap:1.15rem; align-items:flex-end; flex-wrap:wrap; justify-content:flex-end}
.scorebox .cell{text-align:right}
.scorebox .lbl{font-family:var(--mono); font-size:.58rem; letter-spacing:.09em; text-transform:uppercase; color:var(--ink-faint); display:block; white-space:nowrap}
.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 .val.dim{font-size:1.15rem; color:var(--ink-soft)}
/* five stars rather than three, so they are set a little smaller and
   tighter to keep the HUD row on one line at narrow widths */
.stars{display:inline-flex; gap:.12rem; font-size:.95rem; line-height:1; padding-bottom:.25rem}
@media (max-width:24rem){ .stars{font-size:.82rem; gap:.08rem} }
.stars i{font-style:normal; color:var(--gold)}
.stars i.out{color:var(--line); }
.stars.assisted i{color:var(--accent)}

/* ---------------- layout ---------------- */
.playwrap{display:grid; grid-template-columns:minmax(0,1fr) 15.5rem; gap:1.3rem; align-items:start}
@media (max-width:52rem){ .playwrap{grid-template-columns:1fr} }

/* ---------------- the board ---------------- */
.boardshell{
  position:relative; border-radius:12px; padding:clamp(.7rem,2.2vw,1.1rem);
  background:
    radial-gradient(120% 80% at 50% -10%, rgba(121,215,239,.07) 0%, transparent 60%),
    linear-gradient(180deg, var(--cs-grit) 0%, var(--cs-void) 100%);
  border:1px solid #1B2735; box-shadow:inset 0 1px 0 rgba(255,255,255,.04), var(--shadow-lg);
  overflow:hidden;
}
/* surveyor's paper: a faint measured grid under everything */
.boardshell::before{
  content:""; position:absolute; inset:0; pointer-events:none; opacity:.5;
  background-image:linear-gradient(rgba(121,215,239,.045) 1px, transparent 1px),
                   linear-gradient(90deg, rgba(121,215,239,.045) 1px, transparent 1px);
  background-size:22px 22px;
}
.boardshell > *{position:relative; z-index:1}
.boardshell.shake{animation:shake .34s ease}
@keyframes shake{
  0%,100%{transform:translate(0,0)}
  20%{transform:translate(-2px,1px)} 40%{transform:translate(3px,-1px)}
  60%{transform:translate(-2px,-1px)} 80%{transform:translate(2px,1px)}
}

.grid{display:grid; grid-template-columns:repeat(var(--cols,7),1fr); gap:clamp(4px,.85vw,7px)}
.plot{
  position:relative; aspect-ratio:1/1; border-radius:5px; padding:0; margin:0;
  display:flex; align-items:center; justify-content:center;
  background:var(--cs-tile); border:1px solid var(--cs-line);
  color:var(--cs-dim); font-family:var(--mono); cursor:default;
  transition:transform .12s ease, border-color .14s ease, box-shadow .14s ease, background .18s ease;
  -webkit-tap-highlight-color:transparent;
}
.plot svg{width:58%; height:58%; display:block; overflow:visible}
/* Every square names itself, chessboard style, in the top-left corner. Kept
   deliberately faint: it is a reference for reading a line back, not part of
   the picture, and 64 labels shouting at once would bury the pieces. */
.plot .cd{
  position:absolute; top:1px; left:3px; pointer-events:none; line-height:1;
  font-family:var(--mono); font-size:clamp(.44rem,1.15vw,.5rem); font-weight:600;
  letter-spacing:.02em; color:var(--cs-dim); opacity:.5;
}
.plot.charge .cd{color:var(--cs-charge); opacity:.4}
/* the piece names itself in the opposite corner, in the same hand as the
   coordinate so the two read as one layer of annotation rather than two */
.plot .pn{
  position:absolute; bottom:1px; right:3px; pointer-events:none; line-height:1;
  font-family:var(--mono); font-size:clamp(.44rem,1.15vw,.5rem); font-weight:600;
  letter-spacing:.02em; color:var(--cs-charge); opacity:.4;
}
.plot.armed .pn{color:var(--cs-armed); opacity:.75}

.plot.stone .cd{opacity:.32}
.plot.gone .cd{opacity:.5; color:var(--cs-dim)}
.plot.armed .cd{color:var(--cs-armed); opacity:.75}
.plot .num{font-size:clamp(.62rem,1.7vw,.86rem); font-weight:600; letter-spacing:.01em}

.plot.empty{background:linear-gradient(180deg,#0E151E,#0B1119); border-color:#182430}
.plot.stone{
  background:
    repeating-linear-gradient(135deg, var(--cs-stone) 0 5px, var(--cs-stone-2) 5px 10px);
  border-color:#46586A; box-shadow:inset 0 1px 0 rgba(255,255,255,.07);
}
.plot.crate{background:linear-gradient(180deg,var(--cs-crate-2),#121C25); border-color:#26343F; color:var(--cs-crate)}
/* The number IS the tile: bold, centred, in its tier colour. This replaced
   faceted crystal artwork with a small numeral in the corner - at 39px on a
   phone the art and the value were competing for one square, and the only
   thing a player needs off a score tile is the number. */
.plot.crate .pv{
  font-family:var(--display); font-weight:700; line-height:1; font-style:normal;
  font-size:clamp(.9rem,3.4vw,1.4rem); letter-spacing:-.01em;
  font-variant-numeric:tabular-nums;
}
.plot.crate[data-tier="0"] .pv{color:var(--cs-p0)}
.plot.crate[data-tier="1"] .pv{color:var(--cs-p1)}
.plot.crate[data-tier="2"] .pv{color:var(--cs-p2)}
/* a hint of the tier colour in the border, so the tile reads as scoring
   ground even before the eye lands on the numeral */
.plot.crate[data-tier="0"]:not(.lit):not(.traced):not(.armed){border-color:#265741}
.plot.crate[data-tier="1"]:not(.lit):not(.traced):not(.armed){border-color:#25406E}
.plot.crate[data-tier="2"]:not(.lit):not(.traced):not(.armed){border-color:#4A2E6B}
.plot.charge{
  background:linear-gradient(180deg,var(--cs-charge-2),#0A1D27);
  border-color:#255A6E; color:var(--cs-charge); cursor:pointer;
  box-shadow:inset 0 1px 0 rgba(121,215,239,.14);
}
.plot.charge:hover{border-color:var(--cs-charge); transform:translateY(-1px)}
.plot.charge:focus-visible{outline:2px solid var(--cs-charge); outline-offset:2px}
.board.locked .plot.charge{cursor:default}
.board.locked .plot.charge:hover{transform:none; border-color:#255A6E}

/* the footprint of whatever is under the cursor - DECLARED, always on */
.plot.lit{
  border-color:var(--cs-armed);
  box-shadow:0 0 0 1px var(--cs-armed), 0 0 14px rgba(240,206,114,.28);
}
.plot.lit.empty,.plot.lit.gone{background:linear-gradient(180deg,#1A1B16,#121309)}
/* the assist: the whole chain, not just the first blast */
.plot.traced{
  border-color:var(--cs-trace);
  box-shadow:0 0 0 1px rgba(169,140,255,.65), 0 0 12px rgba(169,140,255,.25);
}

.plot.armed{
  border-color:var(--cs-armed); color:var(--cs-armed);
  background:linear-gradient(180deg,#2A2313,#1A1509);
  box-shadow:0 0 0 2px var(--cs-armed), 0 0 20px rgba(240,206,114,.4);
}
@media (prefers-reduced-motion:no-preference){
  .plot.armed{animation:armpulse 1.5s ease-in-out infinite}
  @keyframes armpulse{
    0%,100%{box-shadow:0 0 0 2px var(--cs-armed), 0 0 14px rgba(240,206,114,.32)}
    50%{box-shadow:0 0 0 2px var(--cs-armed), 0 0 26px rgba(240,206,114,.62)}
  }
}
/* the sequential move record: plain white, centred, no edge treatment */
.plot .movetag{
  position:absolute; inset:0; z-index:2; pointer-events:none;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  text-align:center; gap:.05em;
  font-family:var(--mono); font-weight:700; letter-spacing:.01em; line-height:1.05;
  color:#fff; padding:0 1px;
  text-shadow:0 1px 3px rgba(0,0,0,.9), 0 0 2px rgba(0,0,0,.7);
}
/* "Move" over the number, both centred. The number carries the information,
   so it takes the larger size of the two. */
.plot .movetag .mv-w{font-size:clamp(.5rem,1.7vw,.68rem); opacity:.9}
.plot .movetag .mv-n{font-size:clamp(.66rem,2.4vw,.95rem)}
.plot.armed .pin{
  position:absolute; top:-5px; right:-5px; width:14px; height:14px; border-radius:50%;
  background:var(--cs-armed); color:#1A1509; font-size:9px; font-weight:700;
  display:flex; align-items:center; justify-content:center; line-height:1;
  box-shadow:0 0 8px rgba(240,206,114,.7);
}

/* the blast */
.plot.boom{ z-index:3; }
.plot.boom::after{
  content:""; position:absolute; inset:-3px; border-radius:7px; pointer-events:none;
  background:radial-gradient(circle at 50% 50%, var(--cs-fire-2) 0%, var(--cs-fire) 45%, rgba(255,138,60,0) 72%);
  animation:flash .46s ease-out forwards;
}
@keyframes flash{
  0%{opacity:0; transform:scale(.35)}
  22%{opacity:1; transform:scale(1.18)}
  100%{opacity:0; transform:scale(1.5)}
}
@media (prefers-reduced-motion:no-preference){
  .plot.boom{animation:pop .4s ease-out}
  @keyframes pop{ 0%{transform:scale(1)} 34%{transform:scale(1.2)} 100%{transform:scale(1)} }
}
.plot.source::before{
  content:""; position:absolute; inset:0; border-radius:5px; pointer-events:none;
  border:2px solid var(--cs-fire-2); animation:ring .6s ease-out forwards;
}
@keyframes ring{
  0%{opacity:.95; transform:scale(.6)}
  100%{opacity:0; transform:scale(2.5)}
}
/* A destroyed square becomes ORDINARY EMPTY GROUND, not a scorch mark: the
   same face, border and coordinate an empty square has had all along, as
   though nothing was ever standing there. The contents fade out rather than
   vanishing, so the blast still reads as something being removed.

   Values are deliberately duplicated from .plot.empty rather than shared via
   a class, because the two states are reached from opposite directions -
   .empty is markup, .gone is added at runtime - and a gone tile must win on
   the cascade against .charge and .crate, which sit between them. */
.plot.gone,
.plot.gone.crate[data-tier="0"],
.plot.gone.crate[data-tier="1"],
.plot.gone.crate[data-tier="2"]{
  background:linear-gradient(180deg,#0E151E,#0B1119);
  filter:none; color:var(--cs-dim); cursor:default;
}
/* The border and the flattened shadow are held back while the tile carries a
   highlight. Without this guard the rule above silently ate the hover
   preview on every destroyed square and every broken wall: .lit was applied
   correctly and the gold was simply never painted, so a bishop looked like
   it had a hole in its diagonal and a king looked like it had lost two
   neighbours. The tile still LOOKS cleared - background, contents and cursor
   all still come from the rule above; only the outline is yielded. */
.plot.gone:not(.lit):not(.traced):not(.armed),
.plot.gone.crate[data-tier="0"]:not(.lit):not(.traced):not(.armed),
.plot.gone.crate[data-tier="1"]:not(.lit):not(.traced):not(.armed),
.plot.gone.crate[data-tier="2"]:not(.lit):not(.traced):not(.armed){
  border-color:#182430; box-shadow:none;
}
.plot svg,.plot .pv,.plot .pn{transition:opacity .25s ease}
.plot.gone svg,.plot.gone .num,.plot.gone .pv,.plot.gone .pn{opacity:0}
/* the armed badge carries a digit in simultaneous mode; without .armed it
   has no styling of its own, so on a cleared tile it would render as a
   stray number sitting on empty ground */
.plot.gone .pin{display:none}
.plot.gone.charge,.plot.gone.crate{cursor:default}

/* An 8x8 needs the width back on a phone. At 375px the default page and
   board padding left 36px tiles with 8px numerals on the coins - legible
   in a screenshot, not in a hand. Tightening the chrome buys ~4px a tile,
   which is the difference between a coin you can read and one you cannot. */
@media (max-width:480px){
  #app{padding:1.1rem .55rem 3rem}
  .boardshell{padding:.45rem; border-radius:9px}
  .hud{margin-top:.8rem}
}

/* ---------------- side panel ---------------- */
.panel{display:flex; flex-direction:column; gap:.9rem}
.card{
  background:var(--surface); border:1px solid var(--line); border-radius:10px;
  padding:.85rem .9rem; box-shadow:var(--shadow-sm);
}
.card h3{
  font-family:var(--mono); font-size:.6rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-faint); margin:0 0 .6rem; font-weight:600;
}
.armrow{display:flex; gap:.4rem; align-items:center; margin-bottom:.7rem}
.armslot{
  flex:1; height:2.1rem; border-radius:6px; border:1px dashed var(--line);
  display:flex; align-items:center; justify-content:center;
  font-family:var(--mono); font-size:.62rem; letter-spacing:.1em; color:var(--ink-faint);
}
.armslot.set{border:1px solid var(--gold); color:var(--gold); background:var(--gold-soft); font-weight:600}

.bigbtn{
  width:100%; font-family:var(--display); font-weight:700; font-size:.9rem;
  letter-spacing:.14em; text-transform:uppercase; padding:.75rem .8rem;
  border-radius:8px; cursor:pointer; line-height:1;
  color:var(--cs-fire); background:#2A1608; border:2px solid var(--cs-fire);
  transition:background .16s ease, color .16s ease, transform .1s ease;
}
.bigbtn:hover:not(:disabled){background:var(--cs-fire); color:#1A0E04}
.bigbtn:active:not(:disabled){transform:translateY(1px)}
.bigbtn:disabled{opacity:.4; cursor:not-allowed; color:var(--ink-faint); border-color:var(--line); background:transparent}
.bigbtn:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
/* sequential has no plunger - the click is the detonation - so the big
   button becomes a status line reading how far through the go you are */
.seqstate{
  width:100%; text-align:center; font-family:var(--display); font-weight:700;
  font-size:.82rem; letter-spacing:.13em; text-transform:uppercase;
  padding:.7rem .8rem; border-radius:8px; line-height:1;
  color:var(--cs-fire); background:#2A1608; border:2px solid var(--cs-fire);
}
.minibtn{
  font-family:var(--mono); font-size:.63rem; letter-spacing:.1em; text-transform:uppercase;
  color:var(--ink-soft); background:transparent; border:1px solid var(--line);
  border-radius:999px; padding:.4rem .75rem; cursor:pointer; line-height:1; margin-top:.5rem;
}
.minibtn:hover{color:var(--ink); border-color:var(--ink-soft)}
#retry, #retrybtn{color:var(--accent); border-color:var(--accent)}
#retry:hover, #retrybtn:hover{color:var(--accent-ink); background:var(--accent); border-color:var(--accent)}
.minibtn:focus-visible{outline:2px solid var(--accent); outline-offset:2px}

.toggle{display:flex; align-items:flex-start; gap:.55rem; cursor:pointer; margin:0}
.toggle input{margin:.28rem 0 0; accent-color:var(--accent); flex:none}
.toggle .tt{font-size:.78rem; line-height:1.45}
.toggle .tt b{display:block; font-family:var(--mono); font-size:.63rem; letter-spacing:.1em; text-transform:uppercase; color:var(--ink)}
.toggle .tt span{color:var(--ink-faint); font-size:.74rem}

/* the shape legend - built by calling the engine's own footprint() */
.legend{display:flex; flex-direction:column; gap:.5rem}
.lrow{display:flex; align-items:center; gap:.6rem}
.lrow .mini{
  flex:none; display:grid; grid-template-columns:repeat(5,7px); grid-template-rows:repeat(5,7px);
  gap:1px; padding:2px; background:var(--sunken); border:1px solid var(--line); border-radius:3px;
}
.lrow .mini i{background:var(--line-soft); border-radius:1px}
.lrow .mini i.c{background:var(--accent)}
.lrow .mini i.h{background:var(--gold-2)}
.lrow .txt{min-width:0}
.lrow .txt b{display:block; font-family:var(--mono); font-size:.62rem; letter-spacing:.1em; text-transform:uppercase; color:var(--ink)}
.lrow .txt span{display:block; font-size:.72rem; line-height:1.35; color:var(--ink-faint)}

/* ---------------- brief + result ---------------- */
.brief{text-align:center; margin:0 0 .9rem; padding:0 .4rem}
.brief .lead{margin:0; font-size:.95rem; color:var(--ink-soft)}
.brief .lead b{color:var(--ink); font-weight:600}

.result{margin-top:1rem; border:1px solid var(--line); border-radius:10px; background:var(--surface); padding:1.05rem 1.1rem; box-shadow:var(--shadow-sm)}
.result h2{font-family:var(--display); font-size:1.15rem; margin:0 0 .2rem; color:var(--ink)}
.result .verdict{font-size:.9rem; color:var(--ink-soft); margin:0 0 .85rem}
.bars{display:flex; flex-direction:column; gap:.5rem; margin:.9rem 0}
.bar{display:grid; grid-template-columns:5.4rem 1fr 3rem; gap:.6rem; align-items:center; font-size:.74rem}
.bar .bl{font-family:var(--mono); font-size:.6rem; letter-spacing:.08em; text-transform:uppercase; color:var(--ink-faint)}
.bar .bt{height:9px; border-radius:999px; background:var(--sunken); overflow:hidden; border:1px solid var(--line-soft)}
.bar .bf{height:100%; border-radius:999px; transition:width .7s cubic-bezier(.2,.7,.3,1)}
.bar .bv{text-align:right; font-family:var(--mono); font-variant-numeric:tabular-nums; color:var(--ink); font-size:.72rem}
.bar.you .bf{background:linear-gradient(90deg,var(--cs-fire),var(--cs-fire-2))}
.bar.par .bf{background:var(--gold-2)}
.bar.greedy .bf{background:var(--ink-faint)}
.bar.bang .bf{background:var(--line)}
.resbtns{display:flex; gap:.5rem; flex-wrap:wrap; margin-top:.9rem}
.card .minibtn + .minibtn{margin-left:.4rem}

/* ---------------- the scoreboard under the board ----------------
   Replaced the old comparison bars. Those measured the BOARD (par, the
   obvious line, the biggest blast); this measures the PLAYER, which is what
   somebody actually wants to look at after a go. Par still sits in the HUD. */
.atth{
  font-family:var(--mono); font-size:.62rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--ink-faint); margin:0 0 .7rem; font-weight:600;
}
.attempts{list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:.3rem}
.attempts li{
  display:flex; align-items:baseline; gap:.5rem; font-size:.86rem;
  padding:.28rem .1rem; border-bottom:1px solid var(--line-soft);
}
.attempts li:last-child{border-bottom:0}
.attempts .ln{
  font-family:var(--mono); font-size:.8rem; letter-spacing:.04em; color:var(--ink);
  white-space:nowrap; font-weight:500;
}
.attempts .dots{flex:1; border-bottom:1px dotted var(--line); transform:translateY(-.25em); min-width:1.5rem}
.attempts .sc{
  font-family:var(--display); font-weight:700; font-size:1rem; color:var(--ink);
  font-variant-numeric:tabular-nums; white-space:nowrap;
}
.attempts .asst{
  font-family:var(--mono); font-size:.54rem; letter-spacing:.1em; text-transform:uppercase;
  color:var(--accent); border:1px solid var(--accent); border-radius:999px;
  padding:.1rem .38rem; white-space:nowrap;
}
/* the line that matched par gets the gold, same as everywhere else here */
.attempts li.parline .ln,
.attempts li.parline .sc{color:var(--gold)}
.attempts li.parline .sc::after{content:" ★"; font-size:.8em}
.revealnote{
  margin:0 0 .8rem; padding:.5rem .7rem; border-radius:6px; font-size:.84rem;
  color:var(--ink-soft); background:var(--accent-soft); border:1px solid var(--accent);
}

/* The archive lives in /assets/arc.css now - one definition shared by
   every original puzzle. See that file for why. */

/* ---------------- how to play ---------------- */
/* How to play now rides in the side panel as a .card, so it inherits the
   card surface, border and heading and only needs its list styled. The old
   rules positioned it as a full-width section under the board with its own
   display-face heading - none of that applies any more. */
.card.howto p{margin:0 0 .7rem; font-size:.82rem; color:var(--ink-soft)}
.card.howto p b{color:var(--ink); font-weight:600}
/* three lines now, so they get room to breathe rather than being packed */
.card.howto ol{margin:0; padding-left:1.15rem; font-size:.78rem; line-height:1.45; color:var(--ink-soft)}
.card.howto li{margin-bottom:.5rem}
.card.howto li:last-child{margin-bottom:0}
.card.howto li::marker{color:var(--ink-faint); font-family:var(--mono); font-size:.72rem}
.note{text-align:center; padding:2.5rem 1rem; color:var(--ink-soft); font-size:.95rem}

/* ---------------- tile descriptions ----------------
   Towerpath's shape: a coloured left edge so the KIND registers before the
   words do, the name in that colour, one soft sentence underneath. It sits
   inside .boardshell, which is already position:relative, and never takes
   pointer events - a tooltip that can be hovered fights the board it is
   describing. */
.tiletip{
  position:absolute; z-index:8; pointer-events:none; max-width:15rem;
  background:var(--cs-tile-2); border:1px solid var(--cs-line-2);
  border-left:3px solid var(--cs-charge); border-radius:9px; padding:.5rem .7rem;
  box-shadow:0 10px 28px rgba(0,0,0,.6);
}
.tiletip[hidden]{display:none}
.tiletip .tt-name{
  font-family:var(--mono); font-size:.7rem; font-weight:600; letter-spacing:.08em;
  text-transform:uppercase; margin-bottom:.2rem; line-height:1.2;
}
.tiletip .tt-body{font-size:.76rem; color:var(--cs-dim); line-height:1.45}
.tiletip .tt-body[hidden]{display:none}
/* header-only cards lose the gap the name kept for a body beneath it */
.tiletip .tt-name:last-child{margin-bottom:0}
.tiletip .tt-body b{color:var(--cs-ink); font-weight:600}
/* the live reading - what this piece reaches on the board as it stands */
.tiletip .tt-now{display:block; margin-top:.35rem; color:var(--cs-ink); opacity:.85}
@media (max-width:30rem){
  .tiletip{max-width:12rem; padding:.42rem .55rem}
  .tiletip .tt-body{font-size:.7rem}
}

/* the running chain counter, over the board */
.chain{
  position:absolute; top:.7rem; right:.8rem; z-index:5; pointer-events:none;
  font-family:var(--display); font-weight:700; font-size:1.05rem; color:var(--cs-fire-2);
  text-shadow:0 0 14px rgba(255,138,60,.65); opacity:0; transform:translateY(4px);
  transition:opacity .18s ease, transform .18s ease;
}
.chain.on{opacity:1; transform:none}
.chain small{display:block; font-family:var(--mono); font-size:.52rem; letter-spacing:.14em;
  text-transform:uppercase; color:var(--cs-dim); text-shadow:none; text-align:right}

/* the live tally under the board */
/* Label ABOVE value, matching the scorebox at the top of the page. The row
   was inline - "Pieces 16  Destroyed 15  Chain 4" - which stopped working
   the moment the labels became sentences: "Highest Possible Score" alone is
   wider than a third of a phone. Each cell is now its own column, free to
   wrap its label onto two lines without pushing its neighbours around. */
.tally{
  display:flex; justify-content:space-between; align-items:flex-end; gap:.7rem;
  margin-top:.7rem; padding-top:.65rem; border-top:1px solid var(--cs-line);
  font-family:var(--mono); font-size:.55rem; letter-spacing:.08em; line-height:1.3;
  text-transform:uppercase; color:var(--cs-dim);
}
.tally span{display:flex; flex-direction:column; gap:.25rem; flex:1 1 0; min-width:0}
.tally span:nth-child(2){align-items:center; text-align:center}
.tally span:last-child{align-items:flex-end; text-align:right}
.tally b{font-family:var(--display); font-size:1.25rem; color:var(--cs-ink); font-variant-numeric:tabular-nums; line-height:1}
.tally .hi b{color:var(--cs-fire-2)}
@media (max-width:26rem){
  .tally{font-size:.5rem; letter-spacing:.05em; gap:.5rem}
  .tally b{font-size:1.05rem}
}

/* ---------------- the results popup ----------------
   The result used to render only into #resultslot, under the board. On an
   8x8 that is well past the fold, so finishing a day without hitting par
   looked like nothing had happened. The board still gets its quiet moment -
   the dialog opens on Accept Score, not on its own. */
.modal{
  position:fixed; inset:0; z-index:60;
  display:flex; align-items:center; justify-content:center; padding:1.2rem;
  background:rgba(6,9,14,.72); backdrop-filter:blur(3px);
}
.modal[hidden]{display:none}
body.modalopen{overflow:hidden}
.modalcard{
  position:relative; width:min(28rem,100%); max-height:calc(100vh - 2.4rem); overflow:auto;
  background:var(--surface); border:1px solid var(--line); border-radius:14px;
  padding:1.5rem 1.4rem 1.25rem; text-align:center; box-shadow:var(--shadow-lg);
}
@media (prefers-reduced-motion:no-preference){
  .modalcard{animation:rmIn .18s ease-out}
  @keyframes rmIn{from{opacity:0; transform:translateY(8px) scale(.985)} to{opacity:1; transform:none}}
}
.modalx{
  position:absolute; top:.5rem; right:.6rem; width:1.9rem; height:1.9rem; line-height:1;
  font-size:1.15rem; cursor:pointer; border-radius:6px;
  background:transparent; border:1px solid transparent; color:var(--ink-faint);
}
.modalx:hover{border-color:var(--line); color:var(--ink)}
.modalx:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.modalcard h2{
  font-family:var(--display); font-size:1.35rem; font-weight:600;
  color:var(--ink); margin:0 0 .7rem;
}
.rmstars{display:flex; justify-content:center; gap:.2rem; font-size:1.9rem; line-height:1; margin-bottom:.8rem}
.rmstars i{font-style:normal; color:var(--gold)}
.rmstars i.out{color:var(--line)}
.rmstars.assisted i{opacity:.55}
.rmscore{font-family:var(--body); font-size:1rem; color:var(--ink-soft); margin:0 0 .3rem}
.rmscore b{font-family:var(--display); font-size:1.25rem; color:var(--ink); font-variant-numeric:tabular-nums}
.rmnote{
  font-family:var(--mono); font-size:.62rem; letter-spacing:.08em; text-transform:uppercase;
  color:var(--ink-faint); margin:0 0 1.1rem;
}
/* the popup's own button row wraps and centres; the one under the board
   does not exist any more */
.modalcard .resbtns{display:flex; flex-wrap:wrap; justify-content:center; gap:.4rem}
.modalcard .resbtns .minibtn{text-decoration:none}
