/* DANKGAME — the game's screen machinery: home, lobby, draft, battle HUD, result.
   The identity (fonts, colour tokens in both themes, the blue|brass|red "front line")
   lives in /assets/site.css, which every page links FIRST; this sheet only uses
   those tokens. Both are linked with a ?v= stamp because /assets/ is served
   immutable-cached for a year: the stamp is what lets a returning visitor see a
   change at all. Bump it in index.html (tools/make-404.cjs copies the link) when
   either sheet changes. */
:root {
  /* #app's own side padding, named because the pinned draft heading has to bleed
     back out to the edge of the screen by exactly this much. */
  --pad: clamp(.9rem, 3vw, 2rem);
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

/* WIDE-SCREEN ROOT LADDER — byte-identical on /, /lanes/ and /chain/.
   No stylesheet is shared by all three pages (only / links dankgame.css;
   /lanes/ and /chain/ carry inline <style>), so this block is duplicated
   verbatim rather than divergently re-authored. Nothing moves at or below
   1679px: the first rung starts at 1680px, so a laptop and a phone render
   byte-identically to what shipped before. */
html{font-size:16px}
@media(min-width:1680px){html{font-size:17px}}
@media(min-width:2100px){html{font-size:18.5px}}
@media(min-width:2800px){html{font-size:20.5px}}
@media(min-width:3600px){html{font-size:22.5px}}

body {
  /* A single low light from the top of the page, cool on the left and warm on the
     right — the two armies' sides, felt rather than drawn. */
  background:
    radial-gradient(60rem 26rem at 18% -6rem, color-mix(in srgb, var(--blue) 13%, transparent), transparent 70%),
    radial-gradient(60rem 26rem at 82% -6rem, color-mix(in srgb, var(--red) 11%, transparent), transparent 70%),
    var(--bg);
  background-repeat: no-repeat;
  color: var(--ink);
  /* 1rem, not 16px: an absolute px here would anchor every element that
     inherits its size (the <li>s in .rules) and make the ladder a no-op for
     them. At the 16px root that ships below 1680px this is the same 16px. */
  font: 1rem/1.55 var(--font-body);
  font-variant-numeric: lining-nums;
  -webkit-text-size-adjust: 100%;
  text-rendering: optimizeLegibility;
}
h1, h2 { font-family: var(--font-display); font-weight: 700; }
h1 { font-size: clamp(1.7rem, 4.2vw, 2.6rem); line-height: 1.05; margin: 0 0 .6rem; letter-spacing: -.005em; }
h2 {
  font-size: 1.35rem; line-height: 1.15; margin: 1.6rem 0 .5rem; color: var(--ink);
  letter-spacing: .01em;
}
a { color: var(--gold); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { text-decoration-thickness: 2px; }
b, strong { font-weight: 700; }
code { font-family: var(--font-mono); font-size: .88em; }

/* ───────────────────────────────────────────────────────────────── the banner */
.top {
  position: relative;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .7rem clamp(.9rem, 3vw, 2rem);
  background: color-mix(in srgb, var(--panel) 82%, transparent);
  border-bottom: 1px solid var(--edge);
}
/* THE FRONT LINE under the header: blue side, the brass centre line, red side.
   Absolutely placed over the header's own bottom border, so it costs the page no
   height — the battle board is sized against a fixed CHROME constant in
   dankgame.js, and a header that grew by 3px would take a row of pixels from it. */
.top::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 3px;
  background: var(--line-band); pointer-events: none;
}
.brand { text-decoration: none; color: var(--ink); display: flex; align-items: center; gap: .55rem; }
/* The shield is the favicon's own geometry (tools/make-favicon.cjs): a heater shield,
   brass-rimmed, party per pale in the two armies' colours. */
.brand::before {
  content: ""; flex: none; width: 1.35rem; height: 1.6rem;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='5 4.5 22 24.5'%3E%3Cpath d='M5.5 5H26.5V15.5A10.5 13 0 0 1 16 28.5A10.5 13 0 0 1 5.5 15.5Z' fill='%23e3ad47'/%3E%3CclipPath id='s'%3E%3Cpath d='M7.6 7.1H24.4V15.5A8.4 10.9 0 0 1 16 26.4A8.4 10.9 0 0 1 7.6 15.5Z'/%3E%3C/clipPath%3E%3Cg clip-path='url(%23s)'%3E%3Crect width='16' height='32' fill='%235b8fc9'/%3E%3Crect x='16' width='16' height='32' fill='%23c0524a'/%3E%3C/g%3E%3C/svg%3E")
    center / contain no-repeat;
}
/* THE NAME IS TWICE AS LONG AS IT USED TO BE. Renaming VALE to DANKGAME on
   2026-09-08 took the wordmark from four characters to eight, and the header once
   overflowed a 390px phone by 5px — caught by wide-ladder, which pins horizontal
   overflow at every width. The tracking tightens first on a narrow screen, and the
   "tactics" subtitle stands down on the narrowest rather than squeezing the name. */
.brand b {
  font-family: var(--font-display); font-weight: 800; font-size: 1.55rem; line-height: 1.2;
  letter-spacing: .06em; color: var(--ink); white-space: nowrap;
}
.brand span {
  font-size: .72rem; font-weight: 700; letter-spacing: .24em; text-transform: uppercase;
  color: var(--gold); white-space: nowrap; padding-left: .55rem; border-left: 1px solid var(--edge);
}
@media (max-width: 460px) {
  .brand b { font-size: 1.35rem; letter-spacing: .04em; }
  .brand span { letter-spacing: .16em; }
}
@media (max-width: 380px) {
  .brand span { display: none; }
}
/* The connection readout, as a small lamp: amber while connecting, green when the
   match server answers, red when it does not. The words stay; the lamp only
   repeats them. */
.status {
  display: inline-flex; align-items: center; gap: .45rem; white-space: nowrap;
  font-size: .8rem; letter-spacing: .04em; color: var(--dim);
  border: 1px solid var(--edge); border-radius: 999px; padding: .2rem .65rem .2rem .55rem;
  background: var(--bg);
}
.status::before {
  content: ""; width: .5rem; height: .5rem; border-radius: 50%; background: var(--gold); flex: none;
}
.status.live { color: var(--ok); }
.status.live::before { background: var(--ok); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 25%, transparent); }
.status.down { color: var(--red-ink); }
.status.down::before { background: var(--red); }

#app { padding: clamp(1rem, 4vw, 2.5rem) var(--pad) 3rem; }
.screen { max-width: 46rem; margin: 0 auto; }
.screen.wide { max-width: 74rem; }
.lede { font-size: 1.08rem; color: var(--ink-2); max-width: 36rem; }
.sub { color: var(--dim); font-size: .95rem; }
.sub.dim { color: var(--faint); }
.note { color: var(--dim); font-size: .95rem; border-left: 3px solid var(--gold-dim); padding-left: .8rem; }

/* ───────────────────────────────────────────────────────────────── controls */
button {
  font: inherit; font-size: .98rem; font-weight: 700; cursor: pointer;
  background: var(--panel2); color: var(--ink);
  border: 1px solid var(--edge); border-radius: 4px;
  padding: .55rem 1rem; transition: border-color .12s, background-color .12s, color .12s;
  /* Touch targets. The estate has already shipped a game that could not be played
     on a phone at all; nothing here is smaller than a thumb. */
  min-height: 44px;
}
button:hover:not(:disabled) { border-color: var(--gold-dim); background: var(--panel); }
button:disabled { opacity: .4; cursor: not-allowed; }
/* THE SLAB. A brass plate with two corners struck off — the one shape on this site
   that means "press me to fight". The plate is painted on a pseudo-element and the
   CLIP is on that layer only, so the button's own focus outline is never clipped. */
button.big {
  position: relative; isolation: isolate;
  background: none; border: 0; border-radius: 0;
  color: var(--on-gold); font-family: var(--font-display); font-weight: 700;
  font-size: 1.2rem; letter-spacing: .02em; line-height: 1.2;
  padding: .75rem 1.7rem;
}
button.big::before, button.big::after {
  content: ""; position: absolute; z-index: -1; pointer-events: none;
  clip-path: polygon(var(--cut) 0, 100% 0, 100% calc(100% - var(--cut)), calc(100% - var(--cut)) 100%, 0 100%, 0 var(--cut));
}
button.big::before { inset: 0; background: var(--gold-fill-2); }
button.big::after {
  inset: 1px; background: linear-gradient(180deg, #f0c566, var(--gold-fill) 45%, var(--gold-fill-2));
  box-shadow: inset 0 1px 0 rgba(255,255,255,.35);
}
button.big:hover:not(:disabled) { background: none; }
button.big:hover:not(:disabled)::after { background: linear-gradient(180deg, #f7d27c, #eab655 45%, #cf9433); }
button.big:active:not(:disabled)::after { background: var(--gold-fill-2); }
button.big:focus-visible { outline-offset: 3px; }

input {
  font: inherit; background: var(--bg); color: var(--ink);
  border: 1px solid var(--edge); border-radius: 4px;
  padding: .6rem .8rem; min-height: 44px; width: 100%;
}
input::placeholder { color: var(--faint); }
input:focus-visible, button:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

.cta { margin: 1.6rem 0; }
.cta .sub { margin: .5rem 0 0; max-width: 36rem; }
/* THE TWO DOORS, AND WHICH ONE WEARS THE BRASS.
   There is one slab (button.big, above) and one outline treatment, and exactly one
   of the two doors gets each: a second brass slab beside the first would be two
   shouts and no hierarchy. Same size, same font, same 44px target either way — the
   quieter door is a peer, never a footnote.

   Which door is which is NOT decided here. dankgame.js sets .door-first on the block
   the server's `caps` list says a lone visitor can actually open, and .door-second on
   the other one (see applyCaps/orderDoors); with no capability negotiated, neither
   class is set and these selectors fall back to exactly what shipped before
   2026-09-09 — solo outlined, under the rule, beneath "Start a match".
   So the outline treatment is written ONCE and lands on whichever block is second:
   the solo block by default, the invite block once the machine door leads. */
.cta.solo:not(.door-first),
.cta.door-second { border-top: 1px solid var(--rule); padding-top: 1.4rem; }
.cta.solo:not(.door-first) button.big,
.cta.door-second button.big { color: var(--gold); }
.cta.solo:not(.door-first) button.big::before,
.cta.door-second button.big::before { background: var(--gold-dim); }
.cta.solo:not(.door-first) button.big::after,
.cta.door-second button.big::after { background: var(--panel); box-shadow: none; }
.cta.solo:not(.door-first) button.big:hover:not(:disabled)::before,
.cta.door-second button.big:hover:not(:disabled)::before { background: var(--gold); }
.cta.solo:not(.door-first) button.big:hover:not(:disabled)::after,
.cta.door-second button.big:hover:not(:disabled)::after { background: var(--panel2); }
/* The leading door carries the page's only slab and needs no rule above it: it is
   the first thing under the lede, not a section break. */
.cta.door-first { border-top: 0; padding-top: 0; }
/* Names the opponent, above the roster and above the board, for as long as the
   match lasts. Bordered rather than tinted so it reads on either backdrop. */
.modeline {
  margin: 0 0 .9rem; font-size: .95rem; color: var(--dim);
  border-left: 3px solid var(--red); padding: .2rem 0 .2rem .7rem;
}
.modeline b { color: var(--ink); font-weight: 700; }
.joinrow { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; margin-top: 2rem; }
.joinrow label { color: var(--dim); font-size: .95rem; font-weight: 700; }
.joinrow input { max-width: 15rem; text-transform: uppercase; letter-spacing: .12em; font-family: var(--font-mono); font-size: .95rem; }
/* THE TWO SIDE DOORS (2026-09-09). /chain/ and /lanes/ used to reach this page only
   through the footer, which meant the daily board and its streak — the only reason
   to return tomorrow this property owns — were found by nobody. This block gives
   both a named entry in the page proper.
   IT IS QUIETER THAN EVERYTHING ABOVE IT ON PURPOSE: no brass slab, no button, body
   type, one dim label, separated by the same hairline rule the practice door and the
   rules section already use. "Start a match" keeps the only filled button on the
   page. test/front-doors.test.cjs fails if a door link ever grows past btn-create's
   font-size or moves above the three controls. */
.doors { border-top: 1px solid var(--rule); margin-top: 2rem; padding-top: 1rem; }
.doors-h { margin: 0; color: var(--dim); font-size: .78rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; }
.door { margin: .35rem 0 .2rem; }
/* inline-flex + min-height, so the target is a thumb rather than a text baseline:
   44px is the floor every <button> and <input> on this page already has. The suite
   measures the rendered rect at 390 and fails under 44x44. */
.doors a {
  display: inline-flex; align-items: center; min-height: 44px; min-width: 44px;
  color: var(--gold); font-weight: 700; font-size: 1.05rem; text-decoration: underline;
  text-decoration-color: var(--gold-dim); text-underline-offset: 4px;
}
.doors a:hover { text-decoration-color: var(--gold); }
.doors .sub { display: block; margin: 0; max-width: 44rem; line-height: 1.5; }
.rules { border-top: 1px solid var(--rule); margin-top: 2.5rem; padding-top: .5rem; }
.rules ol { padding-left: 0; list-style: none; counter-reset: step; display: grid; gap: .2rem; }
.rules li { margin: .5rem 0; padding-left: 2.6rem; position: relative; counter-increment: step; }
.rules li::before {
  content: counter(step); position: absolute; left: 0; top: -.1rem;
  width: 1.8rem; height: 1.8rem; display: grid; place-items: center;
  font: 700 1.1rem/1 var(--font-display); color: var(--on-gold); background: var(--gold-fill);
  clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
}
.rules li b { font-family: var(--font-display); font-size: 1.12em; color: var(--ink); }

.linkbox { display: flex; gap: .5rem; margin: 1rem 0; }
.linkbox input { font-family: var(--font-mono); font-size: .88rem; flex: 1 1 auto; min-width: 0; }
/* The Copy button used to take half the row: both children inherit width:100% from
   the base control rule, so flex split them evenly and the link had nowhere to be
   read. The button asks for its own text and no more. */
.linkbox button { flex: 0 0 auto; width: auto; padding-left: 1.1rem; padding-right: 1.1rem; }

/* ─────────────────────────────────────────────────────────── the lobby
   The invite is the one thing on this screen, so it sits in a card with the front
   line along its top edge — the same band as the header, because what you are
   sending is a seat on the other side of that line. */
#s-lobby {
  position: relative; background: var(--panel); border: 1px solid var(--edge);
  border-radius: 6px; padding: 1.3rem clamp(1rem, 3vw, 1.6rem) 1rem; overflow: hidden;
}
#s-lobby::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 3px;
  background: var(--line-band); pointer-events: none;
}
#s-lobby h1 { margin-top: .2rem; }
#s-lobby .linkbox input { background: var(--bg); border-color: var(--gold-dim); color: var(--ink); }
#lobby-note { color: var(--ink-2); }
/* ------------------------------------------------- THE WAIT IS ALSO THE DRAFT
   A host with an empty room used to get the invite block and ~500px of black at
   1440x900. The draft panel now sits under the invite instead, so the person doing
   the recruiting can spend their thousand gold while they recruit. Two rules, and
   both are about ALIGNMENT only — no game state is decided in a stylesheet:

   The lobby widens to the draft's own 74rem so the invite is flush with the left
   edge of the roster grid rather than floating in a narrower 46rem column above it,
   and the link box keeps its readable width inside that, because a 74rem monospace
   input is a stripe with a URL in one corner. */
#s-lobby.with-draft { max-width: 74rem; padding-bottom: .9rem; margin-bottom: 1.2rem; }
#s-lobby.with-draft .linkbox { max-width: 34rem; }

/* THE OFFER ON THE PRACTICE RESULT. Deliberately quieter than "Play again": a rule,
   one sentence, and the same link box the lobby uses. A second brass slab here would
   be a nag; a line under the result is an offer somebody can ignore for free. */
.cta.pass { border-top: 1px solid var(--rule); padding-top: 1.3rem; margin-top: 1.8rem; }
.cta.pass .sub { margin: 0; max-width: 44rem; }
.cta.pass .linkbox { margin: .8rem 0 0; }

/* THE AFTER-ACTION REVEAL — both armies as they were bought, side by side. It is a
   quiet ledger, not a scoreboard: no colour that reads as a verdict, no winner
   highlight, no medal. The two columns carry the armies' own side colours as a thin
   rule — blue for yours, red for theirs, as on the board — and nothing else. It sits
   UNDER "Play again" on purpose, so at 390 the button that starts the next battle
   keeps the position it already had. Two columns are kept at every width. */
#over-title { font-size: clamp(2rem, 6vw, 3.2rem); }
.aftermath { border-top: 1px solid var(--rule); margin-top: 1.7rem; padding-top: 1.2rem; }
.aftercols { display: grid; grid-template-columns: 1fr 1fr; gap: .35rem 1.4rem; align-items: start; }
.afterh {
  margin: 0; font-family: var(--font-body); font-size: .76rem; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--dim); align-self: end;
  padding-bottom: .3rem; border-bottom: 2px solid var(--blue);
}
.afterh + .afterh { border-bottom-color: var(--red); }
.afterlist { list-style: none; margin: 0; padding: 0; }
.afterlist li {
  display: flex; justify-content: space-between; align-items: baseline; gap: .5rem;
  padding: .25rem 0; border-bottom: 1px solid var(--rule); font-size: .95rem;
}
.afterlist li:last-child { border-bottom: 0; }
.aftercost { flex: 0 0 auto; font-variant-numeric: tabular-nums; font-size: .82rem; color: var(--dim); }
.aftergold { margin: .45rem 0 0; font-variant-numeric: tabular-nums; font-size: .85rem; font-weight: 700; color: var(--gold); }
.afterline { margin: 1rem 0 0; }
@media (max-width: 30rem) {
  .aftercols { gap: .4rem .8rem; }
  .afterlist li { font-size: .88rem; padding: .16rem 0; }
  .aftercost { font-size: .76rem; }
}

/* ─────────────────────────────────────────────────────────── the draft */
.drafthead { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; flex-wrap: wrap; }
.purse {
  font-family: var(--font-display); font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--gold); font-size: 1.2rem; letter-spacing: .01em;
}
.purse.over { color: var(--red-ink); }
.roster { display: grid; gap: .8rem; margin: 1.2rem 0; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); }
.card {
  background: var(--panel); border: 1px solid var(--edge); border-radius: 6px; overflow: hidden;
  display: flex; flex-direction: column; position: relative;
  transition: border-color .12s, box-shadow .12s;
}
.card:hover { border-color: color-mix(in srgb, var(--gold) 45%, var(--edge)); }
.card.picked { border-color: var(--gold); box-shadow: 0 0 0 1px var(--gold) inset, 0 6px 18px -10px var(--gold); }
/* THE PAINTING IS WRAPPED IN A BUTTON, and above 32rem that button is disabled: the
   square is already at full size there, so a control would do nothing. It must not
   LOOK like a control at any width either — every one of these declarations is
   undoing something the base <button> rule does (padding, border, radius, panel
   background, 44px floor, hover tint, the .4 disabled fade). */
.card .artbtn {
  display: block; width: 100%; margin: 0; padding: 0; border: 0; border-radius: 0;
  background: var(--board); min-height: 0; position: relative; overflow: hidden;
  cursor: default; transition: none;
}
.card .artbtn:hover:not(:disabled) { background: var(--board); border: 0; }
.card .artbtn:disabled { opacity: 1; cursor: default; }
.card .art { aspect-ratio: 1/1; width: 100%; object-fit: cover; display: block; background: var(--board); }
.card .body { padding: .7rem .8rem .8rem; display: flex; flex-direction: column; gap: .4rem; flex: 1; }
.card .name { font-family: var(--font-display); font-weight: 700; font-size: 1.2rem; line-height: 1.15; display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; }
.card .cost { color: var(--gold); font-family: var(--font-body); font-weight: 700; font-variant-numeric: tabular-nums; font-size: .9rem; white-space: nowrap; }
.card .stats { font-variant-numeric: tabular-nums; font-size: .8rem; color: var(--dim); display: grid; grid-template-columns: 1fr 1fr; gap: .1rem .6rem; }
.card .blurb { font-size: .9rem; line-height: 1.4; color: var(--ink-2); flex: 1; }
.card .buy { display: flex; align-items: center; gap: .4rem; }
/* 44, not the 40 this row shipped with: every other control on the page already has
   a 44px floor and these three are the ones a thumb uses most. */
.card .buy button { padding: .35rem .7rem; min-height: 44px; min-width: 44px; }
.card .buy .n { flex: 1; text-align: center; font-family: var(--font-display); font-weight: 700; font-variant-numeric: tabular-nums; font-size: 1.25rem; }
.draftbar {
  position: sticky; bottom: 0;
  background: linear-gradient(180deg, color-mix(in srgb, var(--bg) 40%, transparent), var(--bg) 40%);
  padding: .9rem 0 .3rem; display: flex; gap: 1rem; align-items: center; justify-content: space-between; flex-wrap: wrap;
}
.army { color: var(--ink-2); font-size: .95rem; }

/* ---------------------------------------------------------------- THE PHONE DRAFT
   MEASURED 2026-09-09 at 390x844, after a real tap on "Play the machine": eight
   cards of ~590px, document.scrollHeight 5900 against a 844px viewport — SEVEN
   SCREENS to buy one army — with the "−  0  +  max" row of the FIRST unit sitting
   underneath the sticky "Confirm army" bar, and the purse readout gone at the first
   flick of a thumb. Below 32rem the card becomes a ROW: a painted thumbnail down
   the left, name, price, stat line, blurb and buy row beside it.

   THE PAINTINGS ARE NOT SACRIFICED — they are the best thing on this property. The
   thumbnail is a button: one tap puts the full square back at the width of the card,
   a second folds it away, and the ⤢ corner glyph says so.

   test/draft-phone.test.cjs holds all of it — height as a multiple of the viewport,
   the first buy row clear of the measured bar height, elementFromPoint at the centre
   of every control in every card, and the purse still hit-testable at the bottom. */
@media (max-width: 32rem) {
  /* WHAT YOU CAN STILL AFFORD IS THE WHOLE DECISION, so the heading row pins itself
     to the top for the length of the draft. The negative inline margin is exactly
     #app's own side padding, so the pinned strip reaches both edges of the phone. */
  .drafthead {
    position: sticky; top: 0; z-index: 4;
    margin: 0 calc(-1 * var(--pad)); padding: .45rem var(--pad) .4rem;
    background: var(--bg); border-bottom: 1px solid var(--edge);
    align-items: center; flex-wrap: nowrap; gap: .6rem;
  }
  .drafthead h1 { font-size: 1.3rem; margin: 0; }
  .purse { font-size: .95rem; white-space: nowrap; }

  .roster { grid-template-columns: 1fr; gap: .45rem; margin: .6rem 0 .9rem; }
  .card { display: grid; grid-template-columns: 5.5rem 1fr; align-items: stretch; }
  .card .artbtn { height: 100%; cursor: pointer; border-right: 1px solid var(--edge); }
  .card .art { height: 100%; aspect-ratio: auto; object-position: 50% 22%; }
  .card .artbtn::after {
    content: "⤢"; position: absolute; right: .18rem; bottom: .14rem;
    font-size: .7rem; line-height: 1; color: #f1eadc;
    background: rgba(12, 14, 17, .74); border-radius: 3px; padding: .1rem .22rem;
  }
  .card .body { padding: .4rem .55rem .45rem; gap: .22rem; }
  .card .name { font-size: 1.08rem; line-height: 1.2; }
  .card .stats { display: flex; flex-wrap: wrap; gap: 0 .5rem; font-size: .76rem; line-height: 1.3; }
  .card .blurb { font-size: .82rem; line-height: 1.3; flex: 0 1 auto; }
  .card .buy { margin-top: .05rem; }

  /* TAPPED OPEN: the row gives way to the painting it was a thumbnail of. */
  .card.showart { grid-template-columns: 1fr; }
  .card.showart .artbtn { border-right: 0; border-bottom: 1px solid var(--edge); }
  .card.showart .art { aspect-ratio: 1/1; height: auto; object-position: 50% 50%; }
  .card.showart .artbtn::after { content: "×"; font-size: .8rem; padding: .05rem .3rem; }
}

/* ─────────────────────────────────────────────────────────── the battle */
.fieldwrap { width: 100%; overflow-x: auto; }
#field {
  display: block; margin: 0 auto;
  /* The board's own frame carries the two sides: your edge blue, theirs red. */
  border: 1px solid var(--edge); border-left: 3px solid var(--blue); border-right: 3px solid var(--red);
  border-radius: 4px; background: var(--board);
  box-shadow: 0 18px 40px -24px rgba(0,0,0,.7);
  touch-action: manipulation;
  /* A press-and-hold on the board asks what a creature is (dankgame.js, THE STACK
     INSPECTOR). Without these, the same gesture raises iOS's selection callout and
     the desktop text-selection drag over a canvas that has no text to select. */
  -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
}
/* ─────────────────────────── the stack inspector ───────────────────────────
   The card a press-and-hold (or a tap on your own stack) opens during a battle. It
   is laid out like the draft card's compact row — portrait, then name/stats/voice —
   because it is the same card. It lives UNDER the battlefield in normal flow rather
   than floating over it: an overlay would hide the board the question is about. */
.inspect {
  display: grid; grid-template-columns: 4.25rem minmax(0, 1fr) auto; gap: .1rem .65rem;
  align-items: start; margin-top: .7rem;
  background: var(--panel); border: 1px solid var(--gold-dim); border-radius: 6px;
  padding: .5rem .55rem;
}
.inspect[hidden] { display: none; }
.inspect .art {
  grid-area: 1 / 1;
  width: 4.25rem; height: 4.25rem; object-fit: cover; object-position: 50% 22%;
  border-radius: 4px; background: var(--board); display: block;
}
.inspect .body { grid-area: 1 / 2; min-width: 0; display: flex; flex-direction: column; gap: .22rem; }
.inspect .name { font-family: var(--font-display); font-weight: 700; font-size: 1.1rem; line-height: 1.2; display: flex; gap: .45rem; align-items: baseline; flex-wrap: wrap; }
.inspect .who { font-family: var(--font-body); font-weight: 700; font-size: .72rem; color: var(--dim); letter-spacing: .1em; text-transform: uppercase; }
.inspect .live { font-family: var(--font-body); font-weight: 700; font-variant-numeric: tabular-nums; font-size: .85rem; color: var(--gold); }
.inspect .stats {
  font-variant-numeric: tabular-nums; font-size: .8rem;
  color: var(--dim); display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .05rem .6rem;
}
.inspect .blurb { grid-area: 2 / 1 / 3 / -1; font-size: .88rem; color: var(--ink-2); margin-top: .3rem; }
/* A close button that is a real 44px target, without a 44px slab of chrome. */
.inspect .x {
  grid-area: 1 / 3;
  background: none; border: 0; color: var(--dim); font-size: 1.2rem; line-height: 1;
  padding: 0; min-width: 44px; min-height: 44px; align-self: start;
}
.inspect .x:hover { color: var(--ink); background: none; border: 0; }
.inspect-hint { margin: .5rem 0 0; font-size: .85rem; color: var(--dim); }
@media (min-width: 40rem) {
  .inspect { max-width: 44rem; margin-left: auto; margin-right: auto; }
  .inspect .stats { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .inspect-hint { text-align: center; }
}

.hud { margin-top: .9rem; display: grid; gap: .7rem; grid-template-columns: 1fr; }
/* WHOSE MOVE IT IS, in the side's own colour: your stacks are ringed blue on the
   board and so is your turn here; the other side's turn is ruled red. */
.turnline { font-size: 1.05rem; border-left: 3px solid var(--blue); padding-left: .65rem; }
.turnline b { color: var(--gold); }
.turnline.theirs { color: var(--dim); border-left-color: var(--red); }
/* align-items keeps the buttons their own height when the row they sit in grows —
   which it does when the creature card takes the log's cell beside them. */
.actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: flex-start; align-content: flex-start; }
.actions > button { min-width: 5.5rem; }
/* THE LINE THAT SAYS WHAT BRACE AND WAIT DO. A FLEX ITEM OF THE BUTTON ROW, not a
   row of its own — `flex: 1 0 100%` drops it onto its own line under the buttons on
   a phone, and the rule below sits it BESIDE them the moment there is width. See the
   comment in index.html for the one pixel of headroom that forced that choice.
   Never positioned, never over the board. */
.action-help { flex: 1 0 100%; margin: .15rem 0 0; font-size: .82rem; line-height: 1.4; color: var(--dim); }
.action-help span { display: block; }
.action-help b { color: var(--ink-2); font-weight: 700; }
@media (min-width: 48rem) {
  .action-help { flex: 1 1 22rem; margin: 0; align-self: center; }
}
.log {
  background: var(--panel); border: 1px solid var(--edge); border-radius: 6px;
  padding: .6rem .8rem; max-height: 11rem; overflow-y: auto;
  font-size: .9rem; color: var(--dim); font-variant-numeric: tabular-nums;
}
.log div { padding: .12rem 0; border-bottom: 1px solid var(--rule); }
.log div:last-child { border-bottom: 0; color: var(--ink); }
@media (min-width: 60rem) {
  .hud { grid-template-columns: 1fr 22rem; grid-template-areas: "turn log" "act log"; }
  .turnline { grid-area: turn; }
  .actions { grid-area: act; }
  .log { grid-area: log; max-height: 9rem; }
  /* THE CARD TAKES THE LOG'S COLUMN, AND THE LOG STANDS DOWN WHILE IT IS OPEN.
     On a wide screen the board is sized to fill whatever height the HUD leaves it, so
     a card stacked above the HUD pushed Brace and Wait off the bottom of a 1280x900
     window. In the log's cell the card costs the board nothing. */
  .inspect {
    grid-area: log; max-width: none; margin: 0; align-self: start;
    padding: .45rem .5rem;
    max-height: 10rem; overflow-y: auto;
  }
  .hud.carded .log { display: none; }
  .inspect .body { gap: .15rem; }
  /* A wrapped FLEX line rather than a block of inline text: the chips are built with
     no whitespace between them, so flex items wrap between chips, never inside one. */
  .inspect .stats { display: flex; flex-wrap: wrap; column-gap: .85rem; row-gap: 0; line-height: 1.5; }
  .inspect .stats span { white-space: nowrap; }
  .inspect .blurb { margin-top: .15rem; }
}

/* ─────────────────────────────────────────────────────────── the footer */
.foot {
  position: relative; border-top: 1px solid var(--edge);
  padding: 1.2rem clamp(.9rem, 3vw, 2rem) 1.6rem; color: var(--dim); font-size: .9rem;
  background: var(--bg-lift);
}
.foot a { color: var(--ink-2); }
.foot a:hover { color: var(--gold); }

/* ───────────────────────────────────────────────────── the home screen
   Moved here from an inline <style> in index.html, where it lived because this
   sheet used to be linked without a version stamp and a rule added here would not
   reach a returning visitor. The ?v= stamp on the link ends that. */

/* "More from this maker" band. */
.foot .maker { max-width: 44rem; margin: 1.1rem 0 .15rem; }
.foot .maker h3 { margin: 0 0 .5rem; font-size: .78rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--dim); }
.foot .maker ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .45rem; }
.foot .maker li { line-height: 1.5; color: var(--dim); }
.foot .maker li a { color: var(--ink); font-weight: 700; }

/* THE ARMY STRIP. IT IS CALLED .buys AND NOT .roster ON PURPOSE: .roster above is
   the DRAFT screen's auto-fill card grid, and the first draft of this block inherited
   it. Every class below is unique to this block for that reason. The number that
   matters — how many a full purse buys — is set in the display face, large, because
   "1000 gold" should be a concrete thing before anybody presses anything. */
.buys { border-top: 1px solid var(--rule); margin-top: 2.5rem; padding-top: .5rem; }
.buys h2 { margin: .7rem 0 .35rem; }
.buys-note { margin: 0 0 1.1rem; max-width: 44rem; color: var(--dim); font-size: .95rem; }
.buys-strip { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: .7rem; }
.buys-strip li {
  background: var(--panel); border: 1px solid var(--edge); border-radius: 6px; overflow: hidden;
  display: flex; flex-direction: column; position: relative;
}
/* width/height are on every <img> and the ratio is restated here so the row reserves
   its box before a single byte of painting arrives. */
.buys-strip img { display: block; width: 100%; height: auto; aspect-ratio: 1/1; object-fit: cover; object-position: 50% 20%; background: var(--board); }
.buys-strip .tx { padding: .5rem .6rem .65rem; border-top: 2px solid var(--gold-dim); }
.buys-strip p { margin: 0; }
.buys-strip .nm { font-family: var(--font-display); font-weight: 700; font-size: 1.12rem; line-height: 1.15; }
.buys-strip .qty { font-size: .8rem; color: var(--dim); margin-top: .15rem; white-space: nowrap; }
.buys-strip .qty b { font-family: var(--font-display); color: var(--gold); font-size: 1.35rem; font-weight: 800; font-variant-numeric: tabular-nums; margin-right: .1rem; }
.buys-strip .ea { font-size: .78rem; color: var(--faint); white-space: nowrap; }
@media (max-width: 34rem) {
  .buys-strip { grid-template-columns: repeat(2, 1fr); gap: .55rem; }
  .buys h2 { font-size: 1.25rem; }
}

/* THE BATTLEFIELD BAND — and the site's one loud gesture. The painting is framed as
   the field is held: blue side on the left edge, red side on the right, the front
   line under it, and a dashed brass centre line down the middle, because the rock
   really is mirrored across it and the caption says so. Every mark is a border or a
   pointer-events:none layer: test/front-picture-fold.test.cjs hit-tests the painting
   and none of this may cover it.
   PHONE (single column, the default): figure, then h1, then the prose, and the band
   is 2/1 — every pixel is spent on keeping BOTH buttons whole inside 844px.
   LAPTOP (>=64rem): two columns laid out with grid AREAS so placement is independent
   of document order: the painting and the side doors sit in a right-hand rail beside
   the headline, which is what keeps /chain/ and /lanes/ on the first screen at
   1280x900 (front-doors.test.cjs). */
.shot { margin: 0 0 1.4rem; position: relative; }
.shot img {
  display: block; width: 100%; height: auto; aspect-ratio: 16/9; object-fit: cover; object-position: 50% 50%;
  border: 0; border-left: 4px solid var(--blue); border-right: 4px solid var(--red);
  border-radius: 4px 4px 0 0; background: var(--board);
}
.shot .axis {
  position: absolute; left: 4px; right: 4px; top: 0; aspect-ratio: 16/9; pointer-events: none;
  background: repeating-linear-gradient(180deg, rgba(232,179,79,.75) 0 9px, transparent 9px 18px) center / 2px 100% no-repeat;
  opacity: .8;
}
.shot figcaption {
  position: relative; margin: 0; padding: .7rem 0 0; max-width: 44rem;
  color: var(--dim); font-size: .9rem; line-height: 1.45;
}
.shot figcaption::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 4px;
  background: var(--line-band); pointer-events: none;
}
.hero h1 { font-size: clamp(2rem, 4.4vw, 3.1rem); line-height: 1; letter-spacing: -.01em; margin-bottom: .7rem; }
.hero h1::after {
  content: ""; display: block; width: 4.5rem; height: 4px; margin-top: .7rem;
  background: var(--line-band);
}
@media (max-width: 34rem) {
  .shot img, .shot .axis { aspect-ratio: 2/1; }
  #s-home .cta { margin: 1.25rem 0; }
  .hero h1::after { margin-top: .5rem; }
}
@media (min-width: 64rem) {
  /* :not([hidden]) IS LOAD-BEARING. Every screen in this app is toggled with the
     `hidden` attribute, and `#s-home{display:grid}` outranks the UA's [hidden] rule on
     specificity, so without this guard the home screen stayed laid out UNDER the
     draft screen. Any future rule that sets `display` on a #screen id needs it. */
  #s-home:not([hidden]) {
    max-width: 74rem; display: grid; align-items: start; column-gap: 2.6rem;
    /* A FIXED 25rem RAIL, NOT A FLUID ONE — measured: a fluid rail wrapped the doors'
       blurbs and pushed /lanes/ lower. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 25rem);
    /* The headline spans two rows so the side doors sit directly under the
       painting's caption instead of waiting for the hero column to end. */
    grid-template-areas: "hero shot" "hero doors" "buys doors" "rules rules";
  }
  #s-home > .shot { grid-area: shot; margin: 0; }
  #s-home > .shot img, #s-home > .shot .axis { aspect-ratio: 3/2; }
  #s-home > .hero { grid-area: hero; padding-top: .4rem; }
  #s-home > .doors { grid-area: doors; margin-top: 1.4rem; }
  #s-home > .buys { grid-area: buys; }
  #s-home > .rules { grid-area: rules; max-width: 46rem; }
  /* Between 1024px and ~1200px the main column is narrow enough that "83 for 1000
     gold" is wider than a tile, so the price lines wrap instead of being clipped. */
  .buys-strip .qty, .buys-strip .ea { white-space: normal; }
}
