/* footmenwars.com (2026-10-31, the design-system pass). The toy box: the landing opens on the sunny table (the lid),
   then the figures sit on navy felt and the rules on ivory paper. Every value is a token from DESIGN.md's front matter
   (scripts/tokens.ts writes tokens.css, which every page links first); this file only names them. Direction contract:
   docs/briefs/site.md. Rules for what goes where: DESIGN.md. */
@font-face { font-family: 'Alfa Slab One'; src: url('/fonts/alfa-slab-one-latin.woff2') format('woff2'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Zilla Slab'; src: url('/fonts/zilla-slab-500-latin.woff2') format('woff2'); font-weight: 500; font-display: swap; }
@font-face { font-family: 'Zilla Slab'; src: url('/fonts/zilla-slab-700-latin.woff2') format('woff2'); font-weight: 700; font-display: swap; }

:root { color-scheme: light; }
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; background: var(--felt-deep); scrollbar-color: var(--navy-hi) var(--felt-deep); scroll-padding-top: calc(var(--bar-h) + var(--sp-4)); }
body { margin: 0; background: var(--paper); color: var(--navy); font: 500 var(--fs-body)/1.6 var(--text); min-height: 100dvh; display: flex; flex-direction: column;
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; overflow-x: clip; }
main { flex: 1; }
img, video { max-width: 100%; height: auto; display: block; }
strong, b { font-weight: 700; }
::selection { background: var(--gold); color: var(--navy); }
a { color: inherit; text-decoration-thickness: 1.5px; text-underline-offset: .2em; }
a:hover { text-decoration-thickness: 2.5px; }
:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; border-radius: var(--r-chip); }
.paper :focus-visible, .article :focus-visible { outline-color: var(--navy); } /* gold is 1.5:1 on the paper */
input, textarea { caret-color: var(--gold-deep); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.skip { position: absolute; left: var(--sp-3); top: -80px; z-index: var(--z-skip); padding: var(--sp-3) var(--sp-4); border-radius: var(--r-btn); background: var(--gold); color: var(--navy); font-weight: 700; text-decoration: none; }
.skip:focus { top: var(--sp-3); }
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gl) var(--gr); }
h1, h2, h3 { font-family: var(--display); font-weight: 400; line-height: 1.02; letter-spacing: -.01em; text-wrap: balance; margin: 0; }
p { text-wrap: pretty; }

/* ---------- the felt and the paper: the two grounds below the lid ---------- */
/* the sun falls into the box from the top: a soft light on the felt at the top of each felt band */
.felt { background: radial-gradient(120% 70% at 50% 0%, var(--felt-lit), var(--felt) 70%); color: var(--ivory); }
.felt a:not(.btn) { color: var(--gold); }
.paper { background: var(--paper); color: var(--navy); }

/* ---------- buttons: an enamel key, gold, pressed like a toy ---------- */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2); min-height: 48px; padding: var(--sp-3) 22px; border-radius: var(--r-btn);
  font: 700 18px/1 var(--text); text-decoration: none; cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  transition: transform var(--dur-press) var(--ease-out), box-shadow var(--dur-quick) ease, background-color var(--dur-quick) ease; }
.btn svg { width: 22px; height: 22px; flex: none; fill: currentColor; }
/* gold is 1.5:1 on the paper, so the navy edge (the logo's outline, like the game's plaques) carries the 3:1 */
.btn-gold { color: var(--navy); background: var(--gold); border: 2px solid var(--navy); box-shadow: inset 0 -3px 0 var(--gold-deep), var(--shadow-btn); }
.btn-gold:hover { background: var(--gold-hi); color: var(--navy); }
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) { .btn-gold:hover { transform: translateY(-1px); box-shadow: inset 0 -3px 0 var(--gold-deep), var(--shadow-btn-hover); } }
.btn-gold:active { transform: translateY(1px) scale(.98); box-shadow: inset 0 -1px 0 var(--gold-deep), var(--shadow-btn); }
.btn-sm { min-height: 44px; padding: var(--sp-2) var(--sp-4); font-size: 16px; }
.btn-sm svg { width: 20px; height: 20px; }

/* ---------- header: wide screens; phones get the tab bar ---------- */
.bar { position: sticky; top: 0; z-index: var(--z-bar); height: var(--bar-h); display: flex; align-items: center; gap: var(--sp-6);
  padding: 0 var(--gr) 0 var(--gl); background: var(--felt); color: var(--ivory); box-shadow: var(--shadow-bar); }
@media (min-width: 1276px) { .bar { padding-inline: calc((100% - var(--wrap)) / 2 + var(--sp-7)); } }
.brand { display: inline-flex; align-items: center; gap: var(--sp-3); min-height: 44px; text-decoration: none; color: var(--ivory); font: 400 21px/1 var(--display); white-space: nowrap; }
.brand img { width: 36px; height: 36px; border-radius: var(--r-chip); }
.nav { display: flex; gap: var(--sp-1); margin-left: auto; }
.nav a { position: relative; display: inline-flex; align-items: center; min-height: 44px; padding: 0 var(--sp-3); color: var(--mist); text-decoration: none; font-size: 17px; white-space: nowrap; transition: color var(--dur-quick) ease; }
.nav a:hover { color: var(--ivory); }
.nav a[aria-current], .nav a[data-current] { color: var(--ivory); font-weight: 700; }
.nav a[aria-current]::after, .nav a[data-current]::after { content: ''; position: absolute; left: var(--sp-3); right: var(--sp-3); bottom: 6px; border-top: 3px solid var(--gold); border-radius: var(--r-tick); }
.bar-cta { flex: none; transition: opacity var(--dur-medium) var(--ease-out), visibility var(--dur-medium); }
html.tabs-wait .bar-cta { opacity: 0; visibility: hidden; }
@media (max-width: 760px) { .bar { display: none; } html { scroll-padding-top: var(--sp-4); } }

/* ---------- phone tab bar (Sheep Tag's, in the toy box's felt): five slots, the action a raised gold disc; four while there is no action ---------- */
.tabs { display: none; }
@media (max-width: 760px) {
  body:has(> .tabs) .foot { padding-bottom: calc(var(--sp-6) + var(--tabs-h)); }
  .tabs { position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-tabs); display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); align-items: end;
    padding: var(--sp-1) max(var(--sp-1), env(safe-area-inset-right, 0px)) calc(var(--sp-1) + env(safe-area-inset-bottom, 0px)) max(var(--sp-1), env(safe-area-inset-left, 0px));
    background: var(--felt-deep); border-top: 1px solid rgba(var(--ivory-rgb), .08); transition: transform var(--dur-medium) var(--ease-out); }
  /* the landing: out of sight while the hero's own button is on screen (one gold action per view); back for keyboard focus */
  html.tabs-wait .tabs:not(:focus-within) { transform: translateY(calc(100% + 36px)); }
  /* reading down, it tucks away; scrolling up brings it back (render.ts TUCK) */
  html.tabs-tuck .tabs:not(:focus-within) { transform: translateY(calc(100% + 36px)); }
  .tab { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 5px; min-height: 56px; padding-bottom: 6px;
    color: var(--mist); font: 500 13px/1 var(--text); text-decoration: none; white-space: nowrap; -webkit-tap-highlight-color: transparent; user-select: none; -webkit-user-select: none;
    transition: color var(--dur-quick) ease, transform var(--dur-press) var(--ease-out); }
  .tab svg { width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
  .tab[aria-current], .tab[data-current] { color: var(--ivory); font-weight: 700; }
  .tab[aria-current]::before, .tab[data-current]::before { content: ''; position: absolute; top: calc(-1 * var(--sp-1)); left: 50%; width: 22px; margin-left: -11px; border-top: 3px solid var(--gold); border-radius: 0 0 var(--r-tick) var(--r-tick); }
  .tab:active { transform: scale(.94); }
  .tab:focus-visible { outline-offset: -3px; }
  .tab-go:focus-visible { outline: none; }
  .tab-go:focus-visible .tab-disc { outline: 3px solid var(--ivory); outline-offset: 3px; }
  /* the action: an enamel disc, the toys' own base, raised out of the bar */
  .tab-go { color: var(--ivory); }
  .tab-disc { display: grid; place-items: center; width: 58px; height: 58px; margin: -30px 0 -2px; border-radius: 50%; color: var(--navy); background: var(--gold);
    box-shadow: 0 0 0 5px var(--felt-deep), inset 0 -4px 0 var(--gold-deep), var(--shadow-tab-disc); transition: background-color var(--dur-quick) ease; }
  .tab-disc svg { width: 28px; height: 28px; fill: currentColor; stroke: none; }
  .tab-go:hover .tab-disc { background: var(--gold-hi); }
}

/* ---------- crumbs ---------- */
.crumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: var(--sp-1); padding: 0; margin: 0 0 var(--sp-5); font-size: var(--fs-small); color: var(--mist); }
.crumbs li + li::before { content: '/'; margin-right: 6px; opacity: .6; }
.felt .crumbs a { color: var(--mist); }
.felt .crumbs a:hover { color: var(--ivory); }

/* ---------- the landing: the lid ---------- */
.lid { position: relative; z-index: 1; isolation: isolate; overflow: clip; display: grid; min-height: 100svh; background: var(--sky); box-shadow: var(--shadow-lid); }
@media (min-width: 761px) { .lid { min-height: min(calc(100svh - var(--bar-h)), 920px); } }
/* the backdrop steps back behind the logo and the words (2026-11-03, the hero taste pass, Devin: "a little all over the
   place ... better contrast"): one filter on the whole art, so the painting, the replay and the live match are one
   quieter table, softer and a little darker but still sunny (a greyer .6 read as overcast to the image review), and
   the full-colour logo owns the front. Tuned on the worst replay frame (scripts/hero-check.ts) */
.lid-art { position: absolute; inset: 0; z-index: -1; filter: saturate(.8) brightness(.84) contrast(.84); }
.lid-art img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 62%; }
/* one centred column: the logo, the one-line promise, the two buttons, the small lines, at every width; the words come
   up into the bottom of the logo's clear canvas (below its bases and their dust), so the logo and the words read as one
   group, not two (h1 margin below) */
.lid-in { display: grid; align-content: center; justify-items: center; gap: var(--sp-5); padding-top: clamp(16px, 4svh, 48px); padding-bottom: clamp(28px, 5svh, 56px); }
/* the lid's logo is one canvas, the still with clear room round it (src/site/logoloop.ts LID: 1440 x 1112, the 1200 x 886
   still in its middle), and the h1 is that canvas's box, so no blade, footman or puff of dust is ever cut (round 3,
   Devin: "a bunch that gets cropped ... and masked"). The still as wide as round 2 made it (694 px, 62.5svh) is the box
   at 1.2 times that; on a phone the box may use the gutters, up to 4 px from the screen's edge. A whole number of pixels
   wide: a moment's clip is its own compositor layer, and at 562.5 px (1440 x 900) the still was resampled to the half
   pixel and the clip wasn't (0.40% of pixels jumped at the swap, 0.03% whole; logo-check --moments); landing-page.ts
   snaps where it sits. Wider than the column on a phone, it is centred by its margins (a grid area's width). 380px +
   30vw (the 2026-11-03 taste pass) keeps a portrait tablet's logo in scale between the phone's and the laptop's: 768
   wide was 760 px against 576 at 1024 x 768. */
.lid h1 { --lw: round(down, min(832px, 100vw - 8px, 75svh, 380px + 30vw), 1px); position: relative; width: var(--lw);
  margin-inline: calc((100% - var(--lw)) / 2); margin-bottom: calc(var(--lw) * -48 / 1440); aspect-ratio: 1440 / 1112;
  /* a soft felt pool under the logo, so its fighters and dust lift off the paths and units behind them */
  background: radial-gradient(ellipse 44% 42% at 50% 54%, rgba(var(--felt-rgb), .42), rgba(var(--felt-rgb), 0)); }
/* every layer fills the box: the dust (landing-page.ts), the still, the crest that opens it, a fight's clip. A clip takes
   over from the still on its first frame, which is the still, and gives it back on its last (logoloop.ts) */
.lid h1 > * { position: absolute; inset: 0; width: 100%; height: 100%; }
.lid h1 :is(.logo-still, .logo-crest, .logo-moment) { display: block; filter: drop-shadow(var(--shadow-logo)); }
.lid h1 :is(.logo-crest, .logo-moment) { opacity: 0; pointer-events: none; }
.lid h1 .logo-moment { object-fit: fill; }
.lid h1[data-moment-on] .logo-moment { opacity: 1; }
.lid h1[data-moment-on] .logo-still { opacity: 0; }
.lid-foot { position: relative; width: 100%; display: grid; justify-items: center; gap: var(--sp-5); text-align: center; color: var(--ivory); }
/* the felt rises to meet the words: a full-bleed fade from 120 px above the promise down past the lid's foot (clipped
   there), dark enough under every line on the brightest replay frame */
.lid-foot::before { content: ''; position: absolute; z-index: -1; top: -120px; bottom: -50svh; left: calc(50% - 50vw); right: calc(50% - 50vw); pointer-events: none;
  background: linear-gradient(to bottom, rgba(var(--felt-rgb), 0), rgba(var(--felt-rgb), .8) 120px, rgba(var(--felt-rgb), .92) 50%); }
.lid .lede { margin: 0; max-width: 34rem; font-size: var(--fs-lede); line-height: 1.35; text-wrap: balance; text-shadow: var(--shadow-text-art); }
.lid-act { display: grid; gap: var(--sp-3); justify-items: center; }
.lid-act .btn { min-height: 56px; padding-inline: 26px; font-size: 19px; }
.lid .note { margin: 0; font-size: var(--fs-small); color: var(--mist); text-wrap: balance; text-shadow: var(--shadow-text-art); }
@media (max-width: 599px) { .lid-act, .lid-act .btn { width: 100%; justify-items: stretch; } }
/* before there is an action the phone tab bar shows from the start, over the lid's foot: it hid 18 to 33 px of the
   note at 360 to 430 wide (2026-11-01, measured by scripts/first-open.ts), so the foot clears it */
@media (max-width: 760px) { .lid:not(:has(.lid-act .btn)) .lid-in { padding-bottom: calc(var(--tabs-h) + var(--sp-4)); } }
/* the one authored moment: the crest drops onto the table the way a soldier drops onto his disc at spawn (STYLE.md),
   and opens into the logo */
@media (prefers-reduced-motion: no-preference) {
  /* the opening, once a load (round 3, Devin: "just the shield icon load at first with the castle and the swords
     crossing, then it morphs into the full logo"): the crest, the Discord icon's shield laid on the logo's own shield
     (logo-crest-*.webp), drops onto the table; at .55 s the logo opens out of it from the heart of the shield, its
     lettering arriving as the crest's castle and swords fade, then the four footmen. CSS only, so Safari and iOS get it
     too; Save-Data (html[data-lite], launch.ts) and reduced motion get the still at once */
  :root:not([data-lite]) .lid h1 .logo-crest { animation: drop var(--dur-focal) var(--ease-out-expo) both, crest-out 1.2s linear both; }
  :root:not([data-lite]) .lid h1 .logo-still { transform-origin: 50% 60.9%; animation: logo-out 1.5s var(--ease-sweep) backwards;
    mask-image: radial-gradient(ellipse 50% 50% at 50% 60.9%, black calc(var(--reveal) - 24%), transparent var(--reveal)); }
  @keyframes drop { from { translate: 0 -22px; scale: .97; filter: drop-shadow(var(--shadow-logo-drop)); } }
  @keyframes crest-out { 0%, 42% { opacity: 1; } 72%, 100% { opacity: 0; } }  /* gone before the lettering is strong: a longer overlap read as two shields (Astra F1) */
  @keyframes logo-out { 0%, 36% { opacity: 0; --reveal: 30%; scale: .96; } 50% { opacity: 1; } 100% { --reveal: 190%; scale: 1; } }
  /* scrolling: the table drifts a little slower than the page as the lid leaves (scroll timeline, compositor only) */
  @supports (animation-timeline: view()) {
    .lid-art img { animation: drift linear both; animation-timeline: view(); animation-range: exit 0% exit 100%; }
    @keyframes drift { to { transform: translateY(14%); } }
  }
}
/* the first open (2026-11-01, Sheep Tag's cold open in the toy box's navy; html[data-open] and the circle's centre come
   from src/site/launch.ts): the logo comes into focus alone on the launch navy, the app's own splash ground; at 0.95 s a
   circle with the coin's gold rim opens from the heart of the logo's shield onto the table, the logo's shadow lands as
   the table arrives, and the words rise. Only transform, opacity, filter and one painted layer move: nothing shifts. */
@property --iris { syntax: '<length-percentage>'; inherits: false; initial-value: 150%; }
@property --reveal { syntax: '<percentage>'; inherits: false; initial-value: 190%; }
@media (prefers-reduced-motion: no-preference) {
  :root[data-open] .lid::before { content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
    background: radial-gradient(circle at var(--iris-x, 50%) var(--iris-y, 45%), transparent var(--iris), var(--gold-deep) calc(var(--iris) + 1px),
      var(--gold) calc(var(--iris) + 3px), var(--gold-hi) calc(var(--iris) + 5px), var(--gold) calc(var(--iris) + 7px), var(--gold-deep) calc(var(--iris) + 9px), var(--felt) calc(var(--iris) + 10px));
    animation: open-iris 1.1s var(--ease-iris) .95s both; }
  :root[data-open] .lid-in { position: relative; z-index: 1; }
  /* the crest comes into focus where the logo used to; the logo's shadow still lands as the table arrives */
  :root[data-open]:not([data-lite]) .lid h1 .logo-crest { animation: open-title 2s var(--ease-out-expo) .05s both, crest-out 1.2s linear both; }
  :root[data-open]:not([data-lite]) .lid h1 .logo-still { animation: open-title 2s var(--ease-out-expo) .05s both, logo-out 1.5s var(--ease-sweep) backwards; }
  :root[data-open] .lid-foot { animation: open-rise .6s var(--ease-out-expo) 1.45s both; }
  /* the header's words and the phone tab bar come with the table, not over the navy (the bar's own felt stays) */
  :root[data-open] .bar > *, :root[data-open] .tabs { animation: open-fade .5s var(--ease-out-expo) 1.4s both; }
  /* once the open has played, or at the first focus, the head script marks it done (src/site/launch.ts, FIRST_OPEN_HEAD):
     the same animations from far in the past, so a running one jumps to its end and one made later (the header a phone
     shows when turned past 760 px) starts there. The names never change, so nothing replays */
  :root[data-open="done"] .lid::before, :root[data-open="done"] :is(.lid-foot, .bar > *, .tabs) { animation-delay: -9s; }
  :root[data-open="done"]:not([data-lite]) .lid h1 :is(.logo-crest, .logo-still) { animation-delay: -9s; }  /* as strong as the open's own rules above */
  @keyframes open-iris { from { --iris: 0%; } to { --iris: 105%; } }
  @keyframes open-title {
    0% { transform: scale(1.04); filter: blur(14px) drop-shadow(var(--shadow-logo-clear)); }
    40% { transform: none; filter: blur(0) drop-shadow(var(--shadow-logo-clear)); }
    72% { filter: blur(0) drop-shadow(var(--shadow-logo-clear)); }
    100% { transform: none; filter: blur(0) drop-shadow(var(--shadow-logo)); }
  }
  @keyframes open-rise { from { opacity: 0; transform: translateY(8px); } }
  @keyframes open-fade { from { opacity: 0; } }
}

/* ---------- bands ---------- */
.band { padding: var(--sp-band) 0; }
.band h2 { font-size: var(--fs-band); margin: 0 0 var(--sp-4); }
.band .intro { max-width: 40rem; margin: 0 0 var(--sp-7); font-size: var(--fs-lede); line-height: 1.5; }
.felt .intro { color: var(--mist); }
.paper .intro { color: var(--ink-2); }
.more { margin: var(--sp-6) 0 0; color: var(--mist); }
.band.felt + .band.felt { padding-top: 0; background: var(--felt); } /* two felt bands read as one box: no second gap */

/* ---------- the pick: the game's army and hero pick, as a radio group (no script) ---------- */
.pick { position: relative; display: grid; gap: var(--sp-2); } /* phones: 8 px, so 'Cuauhtemoc' fits a tile at 360 */
@media (min-width: 600px) { .pick { gap: var(--sp-3); } }
.tile { position: relative; display: grid; border-radius: var(--r); overflow: hidden; cursor: pointer; background: var(--felt-deep); box-shadow: var(--shadow-poster);
  -webkit-tap-highlight-color: transparent; transition: filter var(--dur-fast) ease, transform var(--dur-press) var(--ease-out), box-shadow var(--dur-quick) ease; }
.tile input { position: absolute; inset: 0; opacity: 0; margin: 0; pointer-events: none; }
.tile img { grid-area: 1 / 1; width: 100%; aspect-ratio: 2 / 3; object-fit: cover; }
.tile-name { grid-area: 1 / 1; align-self: end; z-index: 1; padding: 30% 3px var(--sp-2); font: 700 clamp(13px, 1.25vw, 16px)/1.15 var(--text); letter-spacing: -.01em; color: var(--ivory); text-align: center;
  background: linear-gradient(rgba(var(--felt-deep-rgb), 0), rgba(var(--felt-deep-rgb), .9) 70%); text-shadow: var(--shadow-text-art); }
.tile:active { transform: scale(.97); }
.card { position: relative; display: grid; border-radius: var(--r); overflow: hidden; background: var(--felt-deep); box-shadow: var(--shadow-poster); }
.card img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 30%; background: var(--felt-deep) center 30% / cover no-repeat; }
.card-words { align-self: end; z-index: 1; padding: 34% var(--sp-5) var(--sp-5); color: var(--ivory);
  background: linear-gradient(rgba(var(--felt-deep-rgb), 0), rgba(var(--felt-deep-rgb), .72) 38%, rgba(var(--felt-deep-rgb), .9)); }
.card h3 { font-size: var(--fs-card-name); margin: 0 0 var(--sp-2); text-shadow: var(--shadow-text-art); }
.card p { margin: 0; font-size: 17px; line-height: 1.45; max-width: 34ch; }
/* where :has() works, the pick is live: one card shows, the picked tile wears the gold ring and the check, the rest dim */
@supports selector(:has(*)) {
  .pk { display: contents; }
  .pk:not(:has(input:checked)) .card { display: none; }
  .tile:not(:has(input:checked)) { filter: brightness(.7) saturate(.8); }
  .tile:has(input:checked) { box-shadow: 0 0 0 3px var(--gold), var(--shadow-poster); }
  .tile:has(input:checked)::after { content: ''; position: absolute; top: 8px; right: 8px; width: 24px; height: 24px; border-radius: 50%; z-index: 2;
    background: var(--gold) url('data:image/svg+xml,%3Csvg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 24 24%22%3E%3Cpath d=%22M6 12.5l4 4 8-9%22 fill=%22none%22 stroke=%22%231f2a4a%22 stroke-width=%223%22 stroke-linecap=%22round%22 stroke-linejoin=%22round%22/%3E%3C/svg%3E') center / 16px no-repeat;
    box-shadow: 0 0 0 2px var(--navy); }
  .tile:has(input:focus-visible) { outline: 3px solid var(--ivory); outline-offset: 4px; }
  @media (hover: hover) and (pointer: fine) { .tile:not(:has(input:checked)):hover { filter: brightness(.9) saturate(.92); } }
  .card img { transition: opacity var(--dur-fast) ease; }
  @starting-style { .card img { opacity: .3; } }
  /* phones: the card full width, the poster cut to 4:5, the tiles four across under it */
  .pick { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .card { grid-column: 1 / -1; grid-row: 1; aspect-ratio: 4 / 5; margin-bottom: var(--sp-2); }
  /* 600 to 899: the card is one row, its poster beside its words */
  @media (min-width: 600px) and (max-width: 899px) {
    .card { aspect-ratio: auto; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr); background: transparent; box-shadow: none; overflow: visible; }
    .card img { position: static; height: auto; aspect-ratio: 2 / 3; border-radius: var(--r); box-shadow: var(--shadow-poster); }
    .card-words { align-self: center; padding: 0 0 0 var(--sp-6); background: none; }
  }
  /* 900 and up: six columns, the card two wide and two tall, the eight tiles beside it (armies left, heroes right) */
  @media (min-width: 900px) {
    .pick { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: var(--sp-4); }
    .card { grid-column: 1 / 3; grid-row: 1 / 3; aspect-ratio: auto; margin: 0; }
    .pick-right .card { grid-column: 5 / 7; }
  }
}
/* without :has(): every army as a plain poster with its words, two then four across */
@supports not selector(:has(*)) {
  .pick { grid-template-columns: repeat(2, 1fr); }
  .pk { display: grid; }
  .tile { display: none; }
  .card { aspect-ratio: 2 / 3; }
  @media (min-width: 900px) { .pick { grid-template-columns: repeat(4, 1fr); } }
}

/* ---------- the rule sheet: a match on the clock ---------- */
.table-shot { margin: 0 0 var(--sp-7); }
.table-shot img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--r-plate); box-shadow: var(--shadow-plate); }
.table-shot figcaption { margin-top: var(--sp-3); font-size: var(--fs-small); color: var(--ink-2); }
.clock { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; max-width: 44rem; }
.clock li { display: grid; grid-template-columns: 96px 1fr; gap: var(--sp-4) var(--sp-5); position: relative; padding-bottom: var(--sp-6); }
.clock li::before { content: ''; position: absolute; left: 48px; top: 64px; bottom: 6px; margin-left: -1.5px; border-left: 3px dashed var(--paper-line); }
.clock li:last-child::before { display: none; }
/* an enamel disc in the team colour, the toys' base, the time on it */
.clock time { display: grid; place-items: center; width: 96px; height: 56px; border-radius: 50%; font: 400 24px/1 var(--display); color: var(--ivory); font-variant-numeric: tabular-nums;
  background: var(--c, var(--navy)); box-shadow: inset 0 -6px 0 rgba(var(--navy-rgb), .28), var(--shadow-btn); }
.clock h3 { font-size: var(--fs-h3); margin: var(--sp-2) 0 var(--sp-2); }
.clock p { margin: 0; color: var(--ink-2); max-width: 36rem; }
@media (min-width: 960px) {
  .clock { max-width: none; grid-template-columns: repeat(4, 1fr); gap: var(--sp-6); }
  .clock li { grid-template-columns: 1fr; align-content: start; gap: var(--sp-3); padding-bottom: 0; }
  .clock li::before { left: 112px; right: -16px; top: 28px; bottom: auto; margin: -1.5px 0 0; border-left: 0; border-top: 3px dashed var(--paper-line); }
}
.clock .red { --c: var(--red); } .clock .blue { --c: var(--blue); } .clock .gold { --c: var(--bronze-deep); } .clock .teal { --c: var(--teal-deep); }

/* ---------- where it comes from ---------- */
.split { display: grid; gap: var(--sp-6); align-items: center; }
@media (min-width: 860px) { .split { grid-template-columns: 1.1fr .9fr; gap: var(--sp-8); } }
.split p { max-width: 36rem; }
.heritage { margin-top: var(--sp-band); }
/* the landing's questions (2026-11-01): every answer shown, no accordion (Google reads FAQ markup only when it is visible) */
.faq-block { margin-top: var(--sp-band); }
.faq-block h2 { margin-bottom: var(--sp-7); }   /* no intro under it, so it takes the gap .band .intro leaves */
.faq { display: grid; gap: var(--sp-6) var(--sp-7); }
@media (min-width: 900px) { .faq { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.faq h3 { font-size: var(--fs-h3); margin: 0 0 var(--sp-2); }
.faq p { margin: 0; color: var(--ink-2); max-width: 36rem; }
.faq a { color: var(--navy); }
/* the logo loop has a white ground: multiply lays it straight onto the paper, no frame */
.loop-fig { margin: 0; }
.loop-fig video { width: 100%; max-width: 460px; aspect-ratio: 1; margin-inline: auto; mix-blend-mode: multiply; }
.loop-fig figcaption { text-align: center; font-size: var(--fs-small); color: var(--ink-2); }

/* ---------- the close ---------- */
.ending { padding: 0 0 var(--sp-band); }
.ending > .wrap { max-width: calc(var(--read-width) + var(--sp-8)); }
.home .ending { padding-top: var(--sp-4); }
.home .ending > .wrap { max-width: var(--wrap); }
.trophy { margin: 0 auto var(--sp-6); max-width: 760px; }
.trophy img { width: 100%; border-radius: var(--r-plate); box-shadow: var(--shadow-poster); }

/* the close's 3D scene (2026-11-01, site parity 2; Sheep Tag's closing fort; src/site/diorama3d.ts): the middle of the
   table in daylight, full bleed, its edges dissolving into the navy. The stage keeps one height whatever shows in it,
   so nothing moves when the scene fades in over the trophy or the trophy comes back. The trophy is the still: for
   Save-Data, no WebGL2, a slow device, and until the scene is ready */
.close-scene { position: relative; height: clamp(360px, 44vw, 640px); margin: 0 0 var(--sp-5); display: grid; place-items: center; padding-inline: var(--gutter); }
.close-scene .trophy { width: 100%; margin: 0 auto; transition: opacity 1.2s var(--ease-out), visibility 0s; }
.close-3d { position: absolute; inset: 0; opacity: 0; pointer-events: none; touch-action: pan-y; cursor: grab; transition: opacity 1.4s var(--ease-out);
  --fade: radial-gradient(ellipse 64% 80% at 50% 56%, black 55%, transparent 100%), linear-gradient(transparent, black 24%, black 86%, transparent);
  -webkit-mask-image: var(--fade); mask-image: var(--fade); -webkit-mask-composite: source-in; mask-composite: intersect; }
.close-3d canvas { display: block; width: 100%; height: 100%; }
.close-3d.grabbing { cursor: grabbing; }
.close-scene.scene-on .close-3d { opacity: 1; pointer-events: auto; }
.close-scene.scene-on .trophy { opacity: 0; visibility: hidden; transition: opacity 1.2s var(--ease-out), visibility 0s 1.2s; }
.scene-hint { position: absolute; left: 50%; bottom: var(--sp-3); translate: -50% 0; z-index: 1; margin: 0; padding: 6px 13px; border-radius: var(--r-chip); background: rgba(var(--navy-rgb), .7);
  color: var(--ivory); font: 700 var(--fs-tiny)/1.2 var(--text); white-space: nowrap; pointer-events: none; opacity: 0; transition: opacity .5s ease 1.2s; }
.close-scene.scene-on .scene-hint { opacity: 1; }
.close-scene.scene-touched .scene-hint { opacity: 0; transition-delay: 0s; }
@media (max-width: 600px) { .close-scene { height: clamp(340px, 96vw, 460px); padding-inline: var(--sp-4); } }

/* matches played (2026-11-01, Sheep Tag's games played; landing-page.ts playedLine): invisible in its reserved line until
   a real number arrives, then it fades in; the number goes gold for a moment when it rolls on */
.played { margin: var(--sp-4) 0 0; min-height: 1.5em; text-align: center; font-size: var(--fs-small); line-height: 1.5; color: var(--mist); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  visibility: hidden; opacity: 0; transform: translateY(4px); transition: opacity .7s var(--ease-out), transform .7s var(--ease-out), visibility 0s .7s; }
.played.on { visibility: visible; opacity: 1; transform: none; transition: opacity .7s var(--ease-out), transform .7s var(--ease-out), visibility 0s; }
.played b { font-weight: 700; color: var(--ivory); transition: color 1.2s ease; }
.played.bump b { color: var(--gold); transition: color .15s ease; }
.played .live { margin-left: .6em; }
.played .live[hidden] { display: none; }
.live-dot { display: inline-block; width: 8px; height: 8px; margin-right: 7px; border-radius: 50%; background: var(--teal); vertical-align: 1px; animation: online-dot 2.4s ease-in-out infinite; }
@keyframes online-dot { 50% { opacity: .35; } }
/* a phone keeps the number and "online now", so the line never wraps: "1,204 matches played  3 online now" */
@media (max-width: 640px) { .played .sofar, .played .long { display: none; } }
@media (prefers-reduced-motion: reduce) { .played { transform: none; } .live-dot { animation: none; } .close-3d, .close-scene .trophy { transition: none; } }
.cta { margin: var(--sp-7) 0 0; padding: clamp(28px, 5vw, 48px); border-radius: var(--r-sheet); text-align: center;
  background: radial-gradient(120% 90% at 50% 0%, var(--felt-lit), var(--felt) 70%); color: var(--ivory); }
.home .cta { margin: 0; padding: 0; background: none; border-radius: 0; }
.home .cta .btn { min-height: 56px; padding-inline: 26px; font-size: 19px; }
.cta h2 { font-size: clamp(30px, 4.6vw, 56px); margin: 0 0 var(--sp-3); }
.cta p { margin: 0 auto var(--sp-5); max-width: 32rem; color: var(--mist); font-size: var(--fs-lede); line-height: 1.5; }
/* Play free in gold, the Discord outlined beside it (render.ts cta); stacked full width on a phone */
.cta-btns { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-3); }
@media (max-width: 599px) { .cta-btns { display: grid; } }

/* ---------- the Discord under the landing's closing buttons (2026-11-01; render.ts community, community-page.ts) ---------- */
/* each piece is hidden until our own /api/* gives a real answer; with none the close is just the button */
.community { display: grid; justify-items: center; text-align: center; }
/* hidden means gone: .dc-count's own display would otherwise beat the attribute and leave an empty line (community-check) */
.community [hidden] { display: none; }
.dc-count { display: inline-flex; align-items: center; gap: var(--sp-2); margin: var(--sp-4) 0 0; color: var(--mist); font-size: var(--fs-small); font-variant-numeric: tabular-nums; }
.dc-count svg { width: 18px; height: 18px; fill: currentColor; flex: none; }
.lobby { margin: var(--sp-6) 0 0; width: 100%; max-width: 44rem; }
.lobby h3 { margin: 0 0 var(--sp-3); font: 700 var(--fs-small)/1.3 var(--text); letter-spacing: .02em; color: var(--mist); }
/* a grid of fixed-width cells, centered, so the rows line up at every width (2026-11-01: the wrapped row was ragged at
   390, one name alone on a line); two to a row on a phone, four on a desktop; "and N more" takes a row of its own */
.lb-list { list-style: none; margin: 0 auto; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, 10rem); justify-content: center; gap: var(--sp-3) var(--sp-4); }
.lb-p { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; text-align: left; }
.lb-face { position: relative; flex: none; width: 40px; height: 40px; }
.lb-face img, .lb-init { width: 40px; height: 40px; border-radius: 50%; background: var(--felt-deep); box-shadow: 0 0 0 2px rgba(var(--ivory-rgb), .16); }
.lb-init { display: grid; place-items: center; font: 400 18px/1 var(--display); color: var(--ivory); background: var(--navy-hi); }
/* the status dot (and the played line's live dot): Discord's meaning in the game's colours (never green): teal on, bronze away, red busy */
.lb-dot { position: absolute; right: -1px; bottom: -1px; width: 13px; height: 13px; border-radius: 50%; background: var(--teal); box-shadow: 0 0 0 3px var(--felt); }
.lb-idle .lb-dot { background: var(--bronze); }
.lb-dnd .lb-dot { background: var(--red); }
.lb-txt { display: grid; min-width: 0; line-height: 1.25; }
/* its status for screen readers (absolute) sits at the start of the name, not past the end of a long one, where it
   widened the page on a phone (2026-11-01, garrison-check longname: the landing went 510 px wide at 390) */
.lb-name { position: relative; font-weight: 700; color: var(--ivory); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-name > .sr-only { left: 0; top: 0; }
.lb-game { font-size: var(--fs-tiny); color: var(--mist); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lb-more { grid-column: 1 / -1; color: var(--mist); font-size: var(--fs-small); }

/* the Garrison (2026-11-01, src/site/garrison.ts): the people in the strip as toy footmen round the barracks, Sheep Tag's
   Flock in the game's daylight. A window onto the board over the strip, faded in once its first frames are drawn; the
   list under it stays the readable version. Wider than tall on a desktop, nearer square on a phone */
.garrison { position: relative; width: 100%; aspect-ratio: 16 / 9; margin: 0 0 var(--sp-5); border-radius: var(--r-plate); overflow: hidden; background: var(--sky);
  box-shadow: 0 0 0 2px rgba(var(--ivory-rgb), .12), var(--shadow-poster); opacity: 0; transition: opacity .9s var(--ease-out); touch-action: pan-y; }
@media (max-width: 600px) { .garrison { aspect-ratio: 4 / 3; } }
.garrison.on { opacity: 1; }
.garrison canvas { display: block; width: 100%; height: 100%; }
.garrison.gr-over { cursor: pointer; }
.gr-chip { position: absolute; left: 0; top: 0; z-index: 2; display: flex; align-items: center; gap: var(--sp-2); max-width: calc(100% - 16px); padding: 5px 11px 5px 5px; border-radius: var(--r-btn); background: rgba(var(--navy-rgb), .92);
  box-shadow: var(--shadow-bar); white-space: nowrap; pointer-events: none; font-size: var(--fs-small); line-height: 1.2; color: var(--ivory); text-align: left; }
.gr-chip[hidden] { display: none; }
.gr-chip.gr-tail::after { content: ''; position: absolute; top: 100%; left: var(--tail, 50%); border: 7px solid transparent; border-top-color: rgba(var(--navy-rgb), .92); transform: translateX(-50%); }
.gr-chip img { flex: none; width: 26px; height: 26px; border-radius: 50%; object-fit: cover; }
/* a long name or game ends in an ellipsis inside the window, never clipped by its edge (Flash round 5 F7) */
.gr-name, .gr-game { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.gr-name { font-weight: 700; }
.gr-game { flex-shrink: 4; color: var(--mist); font-size: var(--fs-tiny); } /* the game gives way first */
@media (max-width: 600px) { .gr-chip { gap: 6px; padding: 3px 9px 3px 3px; font-size: var(--fs-tiny); } .gr-chip img { width: 20px; height: 20px; } }
@media (prefers-reduced-motion: reduce) { .garrison { transition: none; } }

/* the Ideas form: a quieter second step under the action, its fields on the felt, the send key outlined (not gold).
   Taste pass 2026-11-03 (docs/design-reviews/20261103-0018-footmen-ideas-form.md): the idea first, the chips quieter
   than the send key, Post as one connected bar, the thanks and the errors designed */
.ideas { width: 100%; max-width: 36rem; margin: var(--sp-8) 0 0; padding-top: var(--sp-7); border-top: 2px solid rgba(var(--ivory-rgb), .12); text-align: left; }
.ideas h2 { font-size: var(--fs-read-h2); margin: 0 0 var(--sp-2); text-wrap: balance; }
.ideas-lede { margin: 0 0 var(--sp-6); color: var(--mist); }
.ideas-fields { display: grid; gap: var(--sp-5); }
.ideas fieldset { margin: 0; padding: 0; border: 0; min-width: 0; }
.field { display: block; margin: 0 0 var(--sp-2); padding: 0; font-weight: 700; }
.field .opt { font-weight: 500; color: var(--mist); }
.kinds { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.chip { position: relative; display: inline-flex; }
.chip input, .seg input { position: absolute; inset: 0; opacity: 0; margin: 0; cursor: pointer; }
/* the topics are quieter than the send key: a dim edge, filled only when picked */
.chip span { display: inline-flex; align-items: center; min-height: 44px; padding: 0 var(--sp-4); border-radius: var(--r-chip); border: 2px solid rgba(var(--ivory-rgb), .16); color: var(--ivory); font-size: 16px;
  transition: background-color var(--dur-quick) ease, border-color var(--dur-quick) ease, color var(--dur-quick) ease; }
/* picked: the same lit navy and ivory edge as the Post as pick, so no choice outshines the send key (image re-check) */
.chip input:checked + span { background: var(--navy-hi); border-color: rgba(var(--ivory-rgb), .7); color: var(--ivory); }
.chip input:focus-visible + span, .seg input:focus-visible + span { outline: 3px solid var(--gold); outline-offset: 3px; }
/* Post as: one connected bar of three, so it reads as "pick one" and not as more topics */
.seg { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; padding: 4px; border-radius: var(--r-btn); background: var(--felt-deep); box-shadow: inset 0 0 0 2px rgba(var(--ivory-rgb), .16); }
.seg label { position: relative; display: flex; }
.seg span { display: flex; flex: 1; align-items: center; justify-content: center; min-height: 44px; padding: 0 var(--sp-2); border-radius: var(--r-chip); color: rgba(var(--ivory-rgb), .82); font-size: 16px; text-align: center; line-height: 1.15;
  transition: background-color var(--dur-quick) ease, color var(--dur-quick) ease, box-shadow var(--dur-quick) ease; }
.seg input:checked + span { background: var(--navy-hi); color: var(--ivory); font-weight: 700; box-shadow: inset 0 0 0 2px rgba(var(--ivory-rgb), .7); }
@media (hover: hover) and (pointer: fine) {
  .chip input:not(:checked):hover + span { border-color: rgba(var(--ivory-rgb), .45); }
  .seg input:not(:checked):hover + span { color: var(--ivory); background: rgba(var(--ivory-rgb), .06); }
}
.from-name { margin-top: var(--sp-4); }
.from-hint { margin: var(--sp-3) 0 0; font-size: var(--fs-small); line-height: 1.45; color: var(--mist); }
/* links keep the felt's gold (.felt a); bolder here so they read inside a small grey line */
.ideas a { font-weight: 700; text-underline-offset: 3px; }
.ideas a:focus-visible, .again:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; border-radius: var(--r-tick); }
.ideas textarea, .ideas input:not([type="radio"]) { display: block; width: 100%; margin: 0; padding: var(--sp-3); border-radius: var(--r-chip); border: 2px solid rgba(var(--ivory-rgb), .28);
  background: var(--felt-deep); color: var(--ivory); font: 500 17px/1.5 var(--text); caret-color: var(--gold); transition: border-color var(--dur-quick) ease; }
.ideas textarea { resize: vertical; min-height: 7.5rem; }
.ideas textarea:focus-visible, .ideas input:not([type="radio"]):focus-visible { border-color: var(--gold); outline: none; }
.ideas [aria-invalid="true"] { border-color: var(--gold-hi); }
/* the counter only shows near the cap, so it takes no room until then */
.idea-left { display: block; margin-top: var(--sp-1); font-size: var(--fs-tiny); color: var(--mist); text-align: right; font-variant-numeric: tabular-nums; }
.idea-left:empty { display: none; }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.ideas-go { margin-top: var(--sp-2); }
.btn-line { color: var(--ivory); background: transparent; border: 2px solid var(--ivory); }
/* hover only where there is one: on a phone it stuck on after the tap, the key grey under its own thanks */
@media (hover: hover) and (pointer: fine) { .btn-line:hover { background: rgba(var(--ivory-rgb), .1); } }
.btn-line:active { transform: translateY(1px) scale(.98); }
.btn-line:disabled { opacity: .6; cursor: progress; }
/* the one action in the form: the full ivory edge, the form's whole width, taller than the chips, an arrow */
.btn-send { width: 100%; min-height: 52px; padding-inline: var(--sp-5) 20px; }
.btn-send svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; transition: transform var(--dur-quick) var(--ease-out); }
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) { .btn-send:hover svg { transform: translateX(3px); } }
.idea-status { margin: 0; font-size: var(--fs-small); color: var(--mist); scroll-margin-bottom: calc(var(--tabs-h) + var(--sp-4)); }
.idea-status:empty { display: none; }
.idea-status:not(:empty) { margin-top: var(--sp-3); }
/* an error: a mark and the sentence right under the send key, the field it is about edged in gold */
.idea-status[data-kind="err"] { display: flex; gap: var(--sp-2); align-items: flex-start; color: var(--gold-hi); font-weight: 700;
  --mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.4' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9.5'/%3E%3Cpath d='M12 7.5v5.5M12 16.5v.01'/%3E%3C/svg%3E"); }
.idea-status[data-kind="err"]::before, .idea-status[data-kind="ok"]::before { content: ''; flex: none; width: 20px; height: 20px; margin-top: 1px; background: currentColor;
  -webkit-mask: var(--mark) center / contain no-repeat; mask: var(--mark) center / contain no-repeat; }
/* sent: the fields give way to the thanks, which comes in once (the form's one authored moment) */
.idea-status[data-kind="ok"] { display: flex; gap: var(--sp-3); align-items: center; margin-top: 0; color: var(--ivory); font: 700 var(--fs-lede)/1.3 var(--text); outline: none;
  --mark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='m7.5 12.5 3 3 6-6.5'/%3E%3C/svg%3E"); }
.idea-status[data-kind="ok"]::before { width: 32px; height: 32px; margin: 0; background: var(--gold); }
.ideas-sent { margin-top: var(--sp-3); padding-left: calc(32px + var(--sp-3)); scroll-margin-bottom: calc(var(--tabs-h) + var(--sp-4)); }
.ideas-sent p { margin: 0 0 var(--sp-2); color: var(--mist); }
.again { min-height: 44px; padding: 0; border: 0; background: none; color: var(--ivory); font: 700 16px/1.2 var(--text); cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; text-decoration-color: rgba(var(--ivory-rgb), .45); }
.again:hover { text-decoration-color: var(--ivory); }
@media (prefers-reduced-motion: no-preference) {
  .idea-status[data-kind="ok"], .ideas-sent:not([hidden]) { animation: idea-sent var(--dur-medium) var(--ease-out) both; }
  .ideas-sent:not([hidden]) { animation-delay: 60ms; }
}
@keyframes idea-sent { from { opacity: 0; transform: translateY(6px); } }

/* ---------- read pages: a felt title band, then paper ---------- */
.page-top { padding: clamp(28px, 5vw, 64px) 0 clamp(36px, 5vw, 64px); }
.page-top > .wrap, .article > .wrap { max-width: calc(var(--read-width) + var(--sp-8)); }
.page-top h1 { font-size: var(--fs-read-h1); margin: 0 0 var(--sp-4); }
.page-top .lede { margin: 0; font-size: var(--fs-lede); line-height: 1.5; color: var(--ivory); max-width: 40rem; }
.article { padding: var(--sp-read-gap) 0 var(--sp-2); }
.article h2 { font-size: var(--fs-read-h2); margin: var(--sp-8) 0 var(--sp-4); }
.article > .wrap > h2:first-child { margin-top: 0; }
.article h3 { font: 700 21px/1.3 var(--text); letter-spacing: 0; margin: var(--sp-6) 0 var(--sp-2); }
.article p, .article li { max-width: 68ch; }
.article :where(ul, ol) { padding-left: 1.25rem; }
.article li { margin: 6px 0; }
.article li::marker { color: var(--ink-2); }
.article a { color: var(--navy); }
.article .when { font-size: var(--fs-small); color: var(--ink-2); }
.page-top .when { font-size: var(--fs-small); color: var(--mist); margin: var(--sp-3) 0 0; }
.cite { font-size: .72em; line-height: 0; margin-left: 1px; font-variant-numeric: tabular-nums; }
.cite a { text-decoration: none; padding: 0 .12em; font-weight: 700; }
.cite a:hover { text-decoration: underline; }
.refs { font-size: var(--fs-small); line-height: 1.5; color: var(--ink-2); padding-left: 1.75rem; }
.refs li { margin: var(--sp-2) 0; scroll-margin-top: 5rem; }
.refs li:target { background: var(--cream); border-radius: var(--r-chip); }
.refs .back svg { width: 1em; height: 1em; vertical-align: -.12em; fill: none; stroke: currentColor; stroke-width: 1.8; }
[id^="cite-"] { scroll-margin-top: 6rem; }
/* nothing on the paper is a card: a note is ruled above and below */
.box { margin: var(--sp-7) 0; padding: var(--sp-5) 0; border-block: 2px solid var(--navy); }
.box h2 { margin-top: 0; font-size: var(--fs-read-h2); }
.box p:last-child, .box ul:last-child { margin-bottom: 0; }
.place { margin: 0; padding: var(--sp-5) 0; border-top: 1px solid var(--paper-line); }
.place:last-of-type { border-bottom: 1px solid var(--paper-line); }
.place h3 { margin-top: 0; }
.place .who { font-size: var(--fs-small); color: var(--ink-2); margin-bottom: 0; }
.place .who b { color: var(--navy); }
figure.art { margin: var(--sp-7) 0; }
figure.art img { border-radius: var(--r-plate); box-shadow: var(--shadow-plate); }
figure.art figcaption { font-size: var(--fs-small); color: var(--ink-2); margin-top: var(--sp-3); }
/* match-ups: the two figures on the felt, a team disc beside each name */
.versus { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: var(--sp-3); margin: var(--sp-2) 0 var(--sp-6); max-width: 30rem; }
.versus figure { margin: 0; display: grid; gap: var(--sp-2); }
.versus img { width: 100%; border-radius: var(--r); background: var(--cream); box-shadow: var(--shadow-poster); }
.versus figcaption { display: flex; align-items: center; justify-content: center; gap: var(--sp-2); font: 400 19px/1.2 var(--display); color: var(--ivory); }
.versus figcaption::before { content: ''; width: 18px; height: 12px; border-radius: 50%; background: var(--c); box-shadow: inset 0 -2px 0 rgba(var(--navy-rgb), .3); }
.versus .vs { width: 48px; height: 48px; border-radius: 50%; display: grid; place-items: center; color: var(--navy); background: var(--ivory); font: 400 17px/1 var(--display); box-shadow: var(--shadow-btn); }
.compare { margin: var(--sp-4) 0; display: grid; gap: var(--sp-5); }
@media (min-width: 700px) { .compare { grid-template-columns: 1fr 1fr; gap: var(--sp-6); } }
.compare section { padding-top: var(--sp-3); border-top: 4px solid var(--c); }
.compare h3 { margin-top: 0; }
.compare ul { margin: 0; }
.red { --c: var(--red); } .blue { --c: var(--blue); } .gold { --c: var(--bronze); } .teal { --c: var(--teal); }

/* link lists: Read next and the hubs, ruled rows with an arrow */
.links { list-style: none; padding: 0; margin: 0; border-top: 1px solid var(--paper-line); }
.links li { border-bottom: 1px solid var(--paper-line); }
.links a { display: grid; grid-template-columns: 1fr auto; column-gap: var(--sp-4); align-items: center; padding: var(--sp-4) var(--sp-1); min-height: 44px; text-decoration: none; color: var(--navy);
  border-radius: var(--r-chip); transition: background-color var(--dur-quick) ease; }
.links a:hover { background: rgba(var(--navy-rgb), .05); }
.links .ln { font-weight: 700; font-size: 19px; }
.links .lb { grid-column: 1; color: var(--ink-2); font-size: var(--fs-small); line-height: 1.45; }
.links .go { grid-row: 1 / span 2; grid-column: 2; width: 24px; height: 24px; fill: none; stroke: var(--navy); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: transform var(--dur-quick) var(--ease-out); }
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) { .links a:hover .go { transform: translateX(3px); } }
.links.big .ln { font: 400 24px/1.15 var(--display); }
.read-next { margin: var(--sp-8) 0 0; }
.read-next h2 { font-size: var(--fs-h3); margin: 0 0 var(--sp-3); }

/* ---------- footer ---------- */
.foot { background: var(--felt-deep); color: var(--mist); padding: var(--sp-8) 0 var(--sp-6); font-size: var(--fs-small); }
.foot-links { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--sp-5); margin-bottom: var(--sp-6); }
.foot-col { display: grid; align-content: start; }
.foot-col a { display: inline-flex; align-items: center; min-height: 44px; padding: var(--sp-2) 0; line-height: 1.3; color: var(--ivory); text-decoration: none; }
.foot-col a:hover { text-decoration: underline; }
.foot-col a[aria-current] { font-weight: 700; }
.foot-h { margin: 0 0 var(--sp-1); font: 400 18px/1.2 var(--display); color: var(--ivory); }
.made { margin: 0 0 var(--sp-2); }
.made a { display: inline-flex; align-items: center; gap: 6px; color: var(--ivory); text-decoration: none; min-height: 44px; vertical-align: middle; }
.made a:hover { text-decoration: underline; }
.made img { display: inline; }
.heart { color: var(--heart); }
.legal { margin: 0; font-size: var(--fs-tiny); max-width: 60rem; }

/* ---------- 404 ---------- */
.lost { text-align: center; }
.lost img { margin: 0 auto var(--sp-5); width: 200px; border-radius: var(--r); box-shadow: var(--shadow-poster); }
.lost h1 { margin-inline: auto; max-width: 18ch; }
.lost .lede { margin-inline: auto; }

/* ---------- the landing's hero loop and Sound (2026-11-01, site parity with Sheep Tag; src/site/landing-page.ts) ---------- */
/* a real match from the game (a canvas the script paints from a video) fades in over the painted table once the first open has played; the art's filter
   and the words' scrim (.lid-foot::before) stay over it, so the words read the same on both. Reduced motion and Save-Data never get one (the script's rule). */
.lid-loop { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; transition: opacity 1.4s var(--ease-out); }
.lid.loop-on .lid-loop { opacity: 1; }
/* the video the canvas is drawn from: decoding, out of sight (a hidden or detached video can stop decoding) */
.lid-loop-src { position: absolute; top: 0; left: 0; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: no-preference) { @supports (animation-timeline: view()) {
  .lid-loop, .lid-live { animation: drift linear both; animation-timeline: view(); animation-range: exit 0% exit 100%; }
} }
/* the live hero (2026-11-01, src/site/livehero.ts): the game itself running a bot match, in a frame over the loop, faded in
   once it holds the frame rate; under the same scrim; nobody can click, focus or read into it */
.lid-live { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; opacity: 0; pointer-events: none; transition: opacity 1.4s var(--ease-out); }
.lid.live-on .lid-live { opacity: 1; }
/* Jump in: the lid's gold button, the page's one action (2026-11-02, Play first: render.ts second; its red live dot
   went in the 2026-11-03 taste pass, a third hue in the gold read as noise); the Discord beside it is the outlined
   second button, on a navy wash so its line reads on the moving art */
.lid-btns { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-3); }
.btn-jump { text-decoration: none; }
.lid-act .btn-second { background: rgba(var(--navy-rgb), .38); }
.lid-act .btn-second:hover { background: rgba(var(--navy-rgb), .55); color: var(--ivory); }
.jump-d { margin: 0; font-size: var(--fs-small); color: var(--ivory); text-wrap: balance; text-shadow: var(--shadow-text-art); }
@media (max-width: 599px) { .lid-btns { display: grid; } }
/* Sound: a quiet button beside the header's links on wide screens; on a phone (no header) a round one in the lid's corner */
.sound-btn { display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 44px; padding: 0 var(--sp-3); border: 0; border-radius: var(--r-chip);
  background: transparent; color: var(--mist); font: inherit; font-size: 17px; cursor: pointer; transition: color var(--dur-quick) ease, background-color var(--dur-quick) ease; }
.sound-btn[hidden] { display: none; }
.sound-btn:hover, .sound-btn[aria-pressed="true"] { color: var(--ivory); }
.sound-btn svg { width: 22px; height: 22px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.sound-btn .sw { display: none; }
.sound-btn[aria-pressed="true"] .sw { display: inline; }
.sound-btn[aria-pressed="true"] .sx { display: none; }
.sound-st { min-width: 2.2ch; font-size: var(--fs-small); color: var(--mist); }
.sound-bar { margin-left: calc(-1 * var(--sp-4)); }
.sound-lid { display: none; }
@media (max-width: 760px) {
  .sound-lid:not([hidden]) { display: inline-flex; position: absolute; z-index: 2; top: calc(env(safe-area-inset-top, 0px) + var(--sp-3)); right: var(--sp-3);
    width: 44px; padding: 0; justify-content: center; border-radius: 50%; color: var(--ivory); background: rgba(var(--felt-rgb), .55); }
  .sound-lid .sound-l, .sound-lid .sound-st { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
/* the lid's Sound comes with the table during the first open, as the header and the tab bar do (launch.ts's marks) */
@media (prefers-reduced-motion: no-preference) {
  :root[data-open] .sound-lid { animation: open-fade .5s var(--ease-out-expo) 1.4s both; }
  :root[data-open="done"] .sound-lid { animation-delay: -9s; }
}

/* ---------- the army card's 3D soldier (2026-11-01, site parity: Sheep Tag's field guide specimens) ---------- */
/* the button sits on the poster's top corner; the stage takes the poster's place, a sunny sky behind the felt round */
.card-3d-btn { position: absolute; z-index: 2; top: var(--sp-3); right: var(--sp-3); display: inline-flex; align-items: center; gap: var(--sp-2);
  min-height: 44px; padding: 0 var(--sp-4); border: 2px solid rgba(var(--ivory-rgb), .7); border-radius: var(--r-chip); background: rgba(var(--felt-rgb), .72);
  color: var(--ivory); font: 700 15px/1 var(--text); cursor: pointer; backdrop-filter: blur(4px); transition: background-color var(--dur-quick) ease; }
.card-3d-btn:hover { background: rgba(var(--felt-rgb), .9); }
.card-3d-btn svg { width: 20px; height: 20px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.card-3d-btn[data-state="loading"] { cursor: progress; }
.card-3d { position: absolute; inset: 0; z-index: 0; border-radius: var(--r); overflow: hidden; touch-action: pan-y; cursor: grab;
  background: linear-gradient(to bottom, var(--sky), var(--paper)); }
.card-3d:active { cursor: grabbing; }
.card-3d:focus-visible { outline: 3px solid var(--gold); outline-offset: -3px; }
.card-3d-canvas { display: block; width: 100%; height: 100%; }
.card.is-3d img { visibility: hidden; }
/* out of sight while the soldier loads: the poster shows until he is ready */
.card:not(.is-3d) .card-3d { visibility: hidden; }
/* the words' scrim reaches a third up the card: in 3D a drag or tap there is for the soldier (the words hold no links) */
.card.is-3d .card-words { pointer-events: none; }
/* 600 to 899 the poster is the card's left column, 2:3 (the words beside it): the stage covers that column only */
@media (min-width: 600px) and (max-width: 899px) {
  .card-3d { inset: 0 auto auto 0; width: 40%; height: auto; aspect-ratio: 2 / 3; }
  .card-3d-btn { right: auto; left: calc(40% - var(--sp-3)); transform: translateX(-100%); }
}

/* page to page: the browser cross-fades one page into the next (2026-11-01, Sheep Tag's landing.css; Chrome and Safari 18.2,
   others just load the page). The header and the tab bar are the same on both sides, so only the page under them moves. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  .bar { view-transition-name: bar; }
  .tabs { view-transition-name: tabs; }
}

/* reduced motion: colour and opacity feedback stay; nothing slides, lifts or presses (DESIGN.md Motion) */
@media (prefers-reduced-motion: reduce) {
  .btn, .tab, .tile, .links .go, .tabs, .bar-cta { transition-property: color, background-color, box-shadow, filter, opacity, visibility; }
  .btn:active, .btn-gold:active, .tab:active, .tile:active { transform: none; }
  html.tabs-wait .tabs:not(:focus-within), html.tabs-tuck .tabs:not(:focus-within) { transform: none; opacity: 0; visibility: hidden; }
}
