/* =========================================================================
   SORTALIS — page styles for /support and /press.
   =========================================================================

   THIS IS NOT THE GAME'S STYLESHEET AND MUST NOT BECOME IT.

   `src/ui/style.css` is built around `--s`, a scale unit JS sets so the whole
   interface resizes as one object without reflowing. That is exactly wrong for
   a document: these pages are read at whatever width the reader brought, they
   scroll, and their type has to reflow. So the tokens below are COPIED from
   the design system — same ramps, same names, same hex — while the layout is
   ordinary responsive CSS.

   The copy is deliberate. These files ship out of `public/`, which Vite passes
   through verbatim; importing the game's CSS would drag in `--s`, the fixed
   full-viewport body, and 4,500 lines of screen layout for two static pages.

   If the ramps move in `src/ui/style.css`, move them here too. Nothing
   enforces that but this comment.
   ========================================================================= */

/* --------------------------------------------------------------- type */
/**
 * THE GAME'S FACES DO NOT COME TO THESE PAGES.
 *
 * Jersey 15 and Silkscreen are what SORTALIS is set in, and they are right for
 * a HUD: a dozen words at a time, every one of them a label the player already
 * knows the shape of. These two pages are the opposite job. Support is a wall
 * of prose someone reads while something is already broken, and the press page
 * has to survive being skimmed by a journalist on deadline. Neither is a place
 * to spend legibility on brand.
 *
 * Silkscreen in particular could not do it: **its lowercase glyphs are drawn
 * as small capitals**, so `~/.config/sortalis/` renders as
 * `~/.CONFIG/SORTALIS/` — a path that does not exist on macOS or Linux. The
 * support page is largely made of such strings.
 *
 * So the type is the reader's own system UI face and nothing is downloaded for
 * it. The chrome around it — the bevels, the rivets, the palette, the scanline
 * veil, the pixel-art wordmark — is untouched, and carries the brand on its
 * own. No web font here, and no @font-face: adding one back is a decision, not
 * a tidy-up.
 */
:root {
  --font-sans:
    system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
    'Helvetica Neue', Arial, sans-serif;
  --font-mono:
    ui-monospace, SFMono-Regular, Menlo, Consolas, 'DejaVu Sans Mono', monospace;
}

:root {
  /* violets — the vault itself */
  --v0: #0a0d14; --v1: #151b27; --v2: #222b3c; --v3: #313d54;
  --v4: #44536f; --v5: #5f7196; --v6: #8598bf; --v7: #b3c3de;
  /* felts */
  --g0: #0b1d15; --g1: #123326; --g2: #1a4d38; --g3: #206844;
  --g4: #2e8a60; --g5: #48b07f; --g6: #72d6a2;
  /* crimsons */
  --r1: #521824; --r3: #b0324c; --r4: #e84964; --r5: #ff7a90;
  /* golds — money, hot dice, the brand */
  --y0: #3d2a0a; --y1: #6b4a10; --y2: #9c6e1a; --y3: #cf9526;
  --y4: #ffd03a; --y5: #fff0a0;
  /* blues — chips, the brand's other half */
  --b0: #06285c; --b1: #0d4e96; --b2: #1c6fbf; --b3: #2b90de;
  --b4: #3db0f5; --b5: #a8e4ff;
  /* neutrals */
  --n0: #1a1a1a; --n4: #999999; --n5: #bbbbbb; --n6: #dddddd; --n7: #f0f0f0;
  --n-ash: #8c8a94;
  /* leathers — the rail */
  --l0: #1b1418; --l1: #31232a; --l2: #4d3833; --l3: #6e5040;

  /* channel forms, for translucent surfaces that must move when a rung moves */
  --v0-rgb: 10 13 20;   --v1-rgb: 21 27 39;   --v2-rgb: 34 43 60;
  --v3-rgb: 49 61 84;   --v5-rgb: 95 113 150;
  --g0-rgb: 11 29 21;   --g2-rgb: 26 77 56;   --g4-rgb: 46 138 96;
  --y2-rgb: 156 110 26; --y4-rgb: 255 208 58;
  --b2-rgb: 28 111 191; --b3-rgb: 43 144 222;
  --l1-rgb: 49 35 42;

  --page: #06080e;
  --ink: var(--n7);
  --ink-dim: var(--n5);
  --ink-faint: var(--n-ash);
  --brand-gold: var(--y4);
  --brand-blue: var(--b4);

  /* The game's chrome is authored in whole pixels against `--s`. Here it is
     authored in whole pixels full stop — a bevel that lands on a half pixel
     goes soft, and soft is the one thing this look cannot survive. */
  --px: 1px;
  --bevel: 4px;
  --shadow-hard: 3px 3px 0 rgba(0, 0, 0, .55);
  --shadow-soft: 0 4px 14px rgba(0, 0, 0, .5);

  /* The game's `--ls-*` ramp is deliberately absent. It is authored in whole
     pixels for a pixel face at fixed sizes; tracking here is in `em` so it
     scales with the type it is tracking. Do not copy the ramp back in. */

  --measure: 68ch;   /* the reading column */
  --frame: 1080px;   /* the page's outer column */

  color-scheme: dark;
}

/* ---------------------------------------------------------- foundation */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  min-height: 100%;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: clamp(16px, .4vw + 14.6px, 18px);
  /* Long-form measure, not HUD measure. The game sets 1.5 on lines that are
     three words long; these are 68 characters. */
  line-height: 1.6;
  /* The inverse of the game's rule. Pixel faces must not be anti-aliased; a
     hinted system face must be, or it fights the dark ground and goes chalky. */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/**
 * THE GROUND.
 *
 * Adapted from `--ground-vault` in the game's design system: a cold blue key
 * light at the top, the violets closing back in at the floor, and — because a
 * marketing page is allowed one more object than a ledger room — a pool of
 * felt low and centre, the way `--ground-bout` stages the table.
 *
 * Fixed, so scrolling moves the content through the room rather than dragging
 * the room along with it.
 */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(62% 38% at 50% 0%, rgb(var(--b3-rgb) / .13) 0%, transparent 74%),
    radial-gradient(70% 42% at 50% 42%, rgb(var(--g4-rgb) / .10) 0%, transparent 78%),
    radial-gradient(96% 58% at 50% 100%, rgb(var(--v3-rgb) / .24) 0%, transparent 80%),
    linear-gradient(to bottom, var(--v0) 0%, var(--v1) 38%, var(--v1) 74%, var(--v0) 100%);
}

/* The scanline veil. The game ships CRT on by default; the page wears a much
   quieter version of it so the two read as the same surface. Two-pixel period,
   so it survives a fractional device pixel ratio as texture rather than moire. */
body::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .5;
  background: repeating-linear-gradient(
    to bottom, rgba(0, 0, 0, .16) 0 1px, transparent 1px 2px);
}

@media (prefers-reduced-motion: reduce) {
  body::after { display: none; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    transition-duration: .001ms !important;
  }
}

/* ------------------------------------------------------------- skeleton */
.wrap {
  width: 100%;
  max-width: var(--frame);
  margin: 0 auto;
  padding: 0 clamp(16px, 4vw, 40px);
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 20;
  padding: 10px 16px;
  background: var(--y4);
  color: var(--v0);
  font-weight: 700;
  font-size: 13px;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-decoration: none;
}
.skip:focus { left: 8px; top: 8px; }

/* --------------------------------------------------------------- masthead */
.masthead {
  position: sticky;
  top: 0;
  z-index: 10;
  background: rgb(var(--v0-rgb) / .94);
  box-shadow: inset 0 calc(var(--px) * -1) 0 var(--v2);
  backdrop-filter: blur(6px);
}
.masthead__in {
  display: flex;
  align-items: center;
  gap: clamp(12px, 3vw, 28px);
  min-height: 56px;
  padding-top: 8px;
  padding-bottom: 8px;
}
.masthead__mark {
  display: block;
  flex: 0 0 auto;
  line-height: 0;
}
/* THE WORDMARK IS NOT PIXEL ART, AND THIS USED TO SAY `pixelated`.
   `game-title.png` was a chunky blocky mark that wanted its edges kept; the
   shipped wordmark (`sortalis-wordmark.webp`, cut from the same source the
   title screen bakes — see `tools/art/logobake.mjs`) is soft metal with a bevel and
   an outline, and nearest-neighbour on a smooth gradient is visible crunch on
   every letter. Left to the browser's own filter, deliberately. */
.masthead__mark img {
  display: block;
  width: clamp(108px, 16vw, 150px);
  height: auto;
}
.masthead__nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(10px, 2.4vw, 22px);
  margin-left: auto;
  /* 11px was Silkscreen, whose em is drawn much smaller than the box it sits
     in. Every micro-label on the page moves up ~1.5px for the same optical
     size in a system face. */
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.masthead__nav a {
  color: var(--ink-faint);
  text-decoration: none;
  padding: 6px 0;
  box-shadow: inset 0 -2px 0 transparent;
}
.masthead__nav a:hover,
.masthead__nav a:focus-visible { color: var(--n7); box-shadow: inset 0 -2px 0 var(--y3); }
.masthead__nav a[aria-current='page'] { color: var(--y4); box-shadow: inset 0 -2px 0 var(--y3); }

/* ------------------------------------------------------------- typography */
/**
 * Sentence case, not the game's all-caps.
 *
 * Uppercase is a display-face trick: Jersey 15 has no lowercase worth setting
 * and every heading was one or two words. These headings are sentences —
 * "A run ends. The game around it doesn't." — and a sentence in caps reads as
 * shouting and loses the word-shapes that make it skimmable. Caps survive
 * below, but only on the micro-labels, where they are a convention rather than
 * a voice.
 *
 * Big system sans wants negative tracking; the game's `--ls-*` ramp is for
 * small caps and does not apply here.
 */
h1, h2, h3 {
  font-family: var(--font-sans);
  font-weight: 700;
  margin: 0;
}
h1 {
  font-size: clamp(34px, 5vw, 54px);
  line-height: 1.08;
  letter-spacing: -.02em;
}
h2 {
  font-size: clamp(25px, 3vw, 34px);
  line-height: 1.15;
  letter-spacing: -.015em;
}
h3 {
  font-size: clamp(16px, 1.1vw + 13px, 19px);
  line-height: 1.35;
  letter-spacing: -.005em;
  color: var(--n7);
}

p { margin: 0 0 1em; max-width: var(--measure); }
p:last-child { margin-bottom: 0; }

a { color: var(--b4); text-underline-offset: 3px; text-decoration-thickness: 1px; }
a:hover { color: var(--b5); }

strong { color: var(--n7); font-weight: 700; }
/**
 * TWO KINDS OF LITERAL, ONE FACE, TWO TREATMENTS.
 *
 * `.mono` quotes something the reader will find ON SCREEN IN THE GAME — a
 * button, a tab, a settings row. The HTML types those in caps because the game
 * shows them in caps; the style does not upper-case them, so a quote that is
 * mixed-case in the game stays mixed-case here.
 *
 * `.path` quotes something the reader will TYPE OR LOOK FOR — a domain, a
 * filename, a directory. Its case is load-bearing (`~/.config/sortalis/` is
 * not `~/.CONFIG/SORTALIS/`), so it never gets a transform either, and it
 * takes a boxed treatment because it is the thing on the page most likely to
 * be copied by hand.
 *
 * `.68em` and `.78em` were corrections for Silkscreen's tiny em; a real
 * monospace next to a real sans needs the opposite nudge, slightly down from
 * 1em to match x-heights.
 */
code, kbd, .mono {
  font-family: var(--font-mono);
  font-size: .88em;
  color: var(--n7);
}

.path {
  font-family: var(--font-mono);
  font-size: .86em;
  color: var(--b5);
  background: rgb(var(--v0-rgb) / .7);
  padding: 1px 5px;
  box-shadow: inset 0 0 0 var(--px) var(--v3);
  /* Paths are the longest unbreakable runs on either page, and
     `%APPDATA%\sortalis\` on a 390px phone is wider than the column. Let them
     break anywhere rather than let one string push the whole document
     sideways — the page body must never scroll horizontally. */
  overflow-wrap: anywhere;
}
kbd {
  display: inline-block;
  padding: 2px 6px;
  background: var(--v2);
  color: var(--n7);
  box-shadow: inset 0 0 0 var(--px) var(--v4);
  white-space: nowrap;
}

/**
 * THE LOT — the one mark the game repeats, carried onto the page unchanged.
 *
 * A single gold square set before a label, the shape of the pip cut into every
 * die face. It is gold, and gold otherwise means money; that is allowed here
 * only because it is 4px. Do not grow it, and do not spend gold elsewhere in
 * the page chrome.
 */
.eyebrow {
  display: block;
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 14px;
}
.eyebrow::before {
  content: '';
  display: inline-block;
  width: 4px;
  height: 4px;
  margin-right: 8px;
  vertical-align: 2px;
  background: var(--y2);
}

.lede {
  font-size: clamp(18px, .7vw + 15px, 22px);
  color: var(--n6);
  line-height: 1.5;
}

.dim { color: var(--ink-faint); }
.gold { color: var(--y4); }
.chip { color: var(--b5); }

/* ---------------------------------------------------------- pixel chrome */
/**
 * A hard-edged bevelled panel, lifted from the game's `.panel`. No
 * border-radius anywhere on this page, for the same reason there is none in
 * the game: a rounded corner cannot be drawn on a pixel grid without lying
 * about where it is.
 *
 * `clip-path` cuts the corners, which also clips the drop shadow — the game
 * accepts that trade and so does this.
 */
.panel {
  position: relative;
  background: var(--v1);
  padding: clamp(20px, 3vw, 32px);
  box-shadow:
    inset 0 0 0 var(--px) var(--v3),
    inset 2px 2px 0 -1px var(--v2),
    0 0 0 2px var(--v0);
  clip-path: polygon(
    var(--bevel) 0, calc(100% - var(--bevel)) 0,
    100% var(--bevel), 100% calc(100% - var(--bevel)),
    calc(100% - var(--bevel)) 100%, var(--bevel) 100%,
    0 calc(100% - var(--bevel)), 0 var(--bevel)
  );
}
.panel--sunken {
  background: var(--v0);
  box-shadow:
    inset 0 0 0 var(--px) var(--v2),
    inset 0 2px 6px rgba(0, 0, 0, .7),
    0 0 0 2px var(--v0);
}
.panel--felt { background: var(--g1); box-shadow:
  inset 0 0 0 var(--px) var(--g3), inset 2px 2px 0 -1px var(--g2), 0 0 0 2px var(--v0); }
.panel--gold { background: var(--y1); box-shadow:
  inset 0 0 0 var(--px) var(--y3), inset 2px 2px 0 -1px var(--y2), 0 0 0 2px var(--v0); }

/* Corner rivets — the detail that sells the "physical object" read. */
.panel--riveted::before,
.panel--riveted::after {
  content: '';
  position: absolute;
  top: 7px;
  width: 3px;
  height: 3px;
  background: var(--v4);
}
.panel--riveted::before { left: 7px; }
.panel--riveted::after { right: 7px; }

/* ---------------------------------------------------------------- buttons */
.btn {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 12px 22px;
  font-weight: 700;
  font-size: clamp(13px, 1vw, 15px);
  letter-spacing: .06em;
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  color: var(--n7);
  background: var(--v3);
  border: 0;
  cursor: pointer;
  transition: transform .07s cubic-bezier(.2, .9, .1, 1), filter .12s linear;
  box-shadow:
    inset 0 0 0 var(--px) var(--v5),
    inset 0 -3px 0 rgba(0, 0, 0, .35),
    0 3px 0 var(--v0),
    var(--shadow-hard);
}
.btn:hover, .btn:focus-visible { filter: brightness(1.22); }
.btn:active { transform: translateY(2px); box-shadow:
  inset 0 0 0 var(--px) var(--v5), inset 0 -1px 0 rgba(0, 0, 0, .35), 0 1px 0 var(--v0); }

.btn__sub {
  font-weight: 400;
  font-size: 11px;
  letter-spacing: .04em;
  color: var(--ink-faint);
}
.btn--gold { background: var(--y3); color: var(--v0); box-shadow:
  inset 0 0 0 var(--px) var(--y5), inset 0 -3px 0 rgba(0, 0, 0, .3),
  0 3px 0 var(--y0), var(--shadow-hard); }
.btn--gold .btn__sub { color: var(--y0); }
.btn--blue { background: var(--b2); box-shadow:
  inset 0 0 0 var(--px) var(--b4), inset 0 -3px 0 rgba(0, 0, 0, .3),
  0 3px 0 var(--b0), var(--shadow-hard); }
.btn--blue .btn__sub { color: var(--b5); }

.btnrow {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: stretch;
}

/* ------------------------------------------------------------- structure */
.section { padding: clamp(48px, 7vw, 88px) 0; }
.section + .section { box-shadow: inset 0 var(--px) 0 rgb(var(--v3-rgb) / .55); }
.section__head { margin-bottom: clamp(24px, 3.4vw, 40px); }
.section__head p { margin-top: .6em; }

.grid { display: grid; gap: clamp(14px, 2vw, 20px); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
/* 280px, not 230px: at the frame's 1000px of usable width, 230 fits four
   across and leaves the six feature panels as a 4+2 row with two holes in it.
   280 lands on three, which divides six evenly. */
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

/* --------------------------------------------------------------- footer */
.foot {
  padding: clamp(36px, 5vw, 56px) 0 clamp(48px, 6vw, 72px);
  box-shadow: inset 0 var(--px) 0 var(--v2);
  background: linear-gradient(to bottom, transparent, rgb(var(--l1-rgb) / .35));
}
.foot__grid {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(20px, 4vw, 48px);
  align-items: flex-start;
  justify-content: space-between;
}
.foot__links {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .08em;
  text-transform: uppercase;
  list-style: none;
  margin: 0;
  padding: 0;
}
.foot__links a { color: var(--ink-faint); text-decoration: none; }
.foot__links a:hover, .foot__links a:focus-visible { color: var(--n7); }
.foot__fine {
  margin-top: 22px;
  font-size: .82em;
  color: var(--ink-faint);
  max-width: var(--measure);
}

/* --------------------------------------------------------- focus states */
:focus-visible {
  outline: 2px solid var(--y4);
  outline-offset: 2px;
}

/* =========================================================================
   COMPONENTS — the parts only these two pages have.
   Everything above is the design system carried over from the game; below is
   document furniture the game has no equivalent of.
   ========================================================================= */

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ------------------------------------------------------------------ hero */
/**
 * The press hero stages the same three horizontal zones the key art reads as
 * — dark stands up top, the felt pooling low and centre under the lamp — but
 * it is a page header, not a room, so the felt only ever gets to be a glow.
 */
.hero {
  position: relative;
  padding: clamp(44px, 7vw, 96px) 0 clamp(44px, 6vw, 80px);
  overflow: hidden;
}
.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    radial-gradient(64% 44% at 50% 0%, rgb(var(--y4-rgb) / .14) 0%, rgb(var(--y2-rgb) / .05) 46%, transparent 76%),
    radial-gradient(80% 56% at 50% 96%, rgb(var(--g4-rgb) / .18) 0%, rgb(var(--g2-rgb) / .10) 46%, transparent 80%);
}
/* The rail: the hard wooden band the table ends in, as the hero's bottom edge. */
.hero::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 6px;
  background: linear-gradient(to bottom, var(--l3) 0 2px, var(--l2) 2px 4px, var(--l0) 4px);
}

.hero__in { text-align: center; }

/* Not `pixelated` — see the masthead mark above for why. */
.hero__mark {
  display: block;
  width: min(660px, 100%);
  height: auto;
  margin: 0 auto;
  /* The wordmark is the one place gold and blue get to be loud, so it gets the
     game's hard shadow rather than a soft page-header glow. */
  filter: drop-shadow(4px 4px 0 rgba(0, 0, 0, .55));
}

.hero__tag {
  margin: clamp(14px, 2.4vw, 24px) auto 0;
  font-weight: 700;
  font-size: clamp(13px, 1.3vw, 16px);
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.hero__lede { margin: clamp(20px, 3vw, 30px) auto 0; }
/* The one line the press page is actually pitching with. It was Jersey 15 in
   caps; as a sentence in a system face it stays the loudest thing on the page
   through weight and gold alone. */
.hero__pitch {
  margin: 1em auto 0;
  font-weight: 700;
  font-size: clamp(22px, 2.5vw, 30px);
  line-height: 1.25;
  letter-spacing: -.015em;
  color: var(--y4);
}
.hero__in p { max-width: 60ch; }

.hero__cta { justify-content: center; margin-top: clamp(26px, 3.6vw, 38px); }
.hero__plat {
  margin-top: clamp(22px, 3vw, 30px);
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* ----------------------------------------------------------- screenshots */
.shots { display: grid; gap: clamp(28px, 4vw, 44px); }

.shot { margin: 0; }
.shot img {
  display: block;
  width: 100%;
  height: auto;
  background: var(--v0);
  /* Bevelled like everything else. `clip-path` eats the outer ring, so the
     frame is drawn as an inset shadow on the image itself. */
  box-shadow: inset 0 0 0 var(--px) var(--v3);
  clip-path: polygon(
    var(--bevel) 0, calc(100% - var(--bevel)) 0,
    100% var(--bevel), 100% calc(100% - var(--bevel)),
    calc(100% - var(--bevel)) 100%, var(--bevel) 100%,
    0 calc(100% - var(--bevel)), 0 var(--bevel)
  );
}
.shot figcaption {
  margin-top: 14px;
  max-width: var(--measure);
  font-size: .92em;
  color: var(--ink-faint);
}
.shot figcaption strong { color: var(--n6); }

/* Two-up once there is room for both to stay legible. Below that they stack —
   a screenshot of a 1440-wide interface at 300px is decoration, not evidence. */
@media (min-width: 900px) {
  .shots { grid-template-columns: 1fr 1fr; }
  /* One shot in the set is a phone frame — 2.16:1 against everyone else's 4:3
     — because the shop is dense at that aspect and half-empty at the tablet's.
     A short picture in a tall cell is a hole in the grid, so it takes the whole
     row instead and the mismatch reads as a band rather than as a mistake. */
  .shot--wide { grid-column: 1 / -1; }
}

/* ------------------------------------------------------------- features */
.feat h3 { margin-bottom: 10px; color: var(--b5); }
.feat p { font-size: .94em; color: var(--ink-dim); }
.feat--house h3 { color: var(--r5); }

/* ---------------------------------------------------------------- stats */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--v3);   /* shows through the 2px gaps as hairlines */
  box-shadow: 0 0 0 2px var(--v0);
}
.stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: clamp(18px, 2.6vw, 28px) 10px;
  text-align: center;
  background: var(--v1);
}
.stat__n {
  font-weight: 800;
  font-size: clamp(34px, 4.4vw, 50px);
  /* .85 was Jersey 15's, whose glyphs sit high in a tall box. A system face
     fills its box, and .85 clips the digits' own ascenders. */
  line-height: 1;
  letter-spacing: -.03em;
  font-variant-numeric: tabular-nums;
  color: var(--y4);
}
.stat__k {
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.stats__note { margin-top: 20px; font-size: .9em; }

/* ----------------------------------------------------------- fact sheet */
.fact__h { font-size: clamp(24px, 2.8vw, 32px); margin-bottom: 18px; }
.fact {
  display: grid;
  grid-template-columns: minmax(90px, auto) 1fr;
  gap: 8px 20px;
  margin: 0;
  font-size: .94em;
}
.fact dt {
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding-top: .35em;
}
.fact dd { margin: 0; color: var(--n6); overflow-wrap: anywhere; }

.panel--gold h3 { color: var(--y5); }
.panel--gold p { color: var(--y5); }
.panel--gold .eyebrow { color: var(--y3); }
.panel--gold .eyebrow::before { background: var(--y4); }
.panel--gold a { color: #fff; }
/* An email address, not a headline. Jersey 15 could carry one at 28px; a
   system face at that size just looks like a mistake, and the address has to
   stay copyable-by-eye more than it has to be big. */
.fact__contact {
  font-weight: 700;
  font-size: clamp(17px, 1.6vw, 22px);
  line-height: 1.3;
  word-break: break-word;
}
.fact__contact a { text-decoration-thickness: 2px; }
.fact__go { margin-top: 22px; }

/* -------------------------------------------------------------- contact */
.contact__card { display: flex; flex-direction: column; }
.contact__addr {
  font-weight: 700;
  font-size: clamp(18px, 2vw, 26px);
  line-height: 1.3;
  margin: 8px 0 18px;
  word-break: break-word;
}

.checklist, .plainlist {
  margin: 0;
  padding-left: 1.15em;
  display: grid;
  gap: 10px;
  max-width: var(--measure);
}
.checklist li, .plainlist li { color: var(--ink-dim); }
.plainlist { list-style: none; padding-left: 0; }
.plainlist li { position: relative; padding-left: 18px; }
/* The Lot again, at list-item scale — the same square pip, doing duty as a bullet. */
.plainlist li::before {
  content: '';
  position: absolute;
  left: 0;
  top: .62em;
  width: 4px; height: 4px;
  background: var(--y2);
}
.checklist { counter-reset: step; list-style: none; padding-left: 0; }
.checklist li { position: relative; padding-left: 34px; }
.checklist li::before {
  counter-increment: step;
  content: counter(step);
  position: absolute;
  left: 0; top: .1em;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  font-weight: 700;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--v0);
  background: var(--y3);
}

/* ------------------------------------------------------------------ faq */
.faq { display: grid; gap: 2px; background: var(--v3); box-shadow: 0 0 0 2px var(--v0); }

.faq__item { background: var(--v1); }
.faq__item > summary {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: clamp(16px, 2vw, 20px) clamp(16px, 2.4vw, 26px);
  cursor: pointer;
  list-style: none;
  /* Questions, in the words a reader would use: "There's no sound on my iPhone
     or iPad." Caps made that a sign; sentence case makes it a question, which
     is what the reader is scanning for. */
  font-weight: 700;
  font-size: clamp(15px, .5vw + 13.5px, 17px);
  line-height: 1.45;
  color: var(--n6);
}
.faq__item > summary::-webkit-details-marker { display: none; }
.faq__item > summary:hover { background: var(--v2); color: var(--n7); }
.faq__item[open] > summary { color: var(--y4); background: var(--v2); }

/* The disclosure marker is the Lot rotated — a square that becomes a bar. No
   chevron: the game has no curves and this page does not get to introduce one. */
.faq__item > summary::before {
  content: '';
  flex: 0 0 auto;
  width: 8px; height: 8px;
  margin-top: .35em;
  background: var(--y2);
  transition: transform .12s cubic-bezier(.2, .9, .1, 1), background .12s linear;
}
.faq__item[open] > summary::before { background: var(--y4); transform: scaleY(.28); }

.faq__body {
  padding: 0 clamp(16px, 2.4vw, 26px) clamp(20px, 2.6vw, 26px);
  border-top: var(--px) solid rgb(var(--v3-rgb) / .8);
  padding-top: clamp(16px, 2vw, 22px);
}
.faq__body p, .faq__body ul { color: var(--ink-dim); }
.faq__body ul { margin-bottom: 1em; }
.faq__body ul:last-child, .faq__body p:last-child { margin-bottom: 0; }

/* --------------------------------------------------------------- tables */
/* A wide table must scroll in its own box. The page body never scrolls sideways. */
.tablewrap { overflow-x: auto; box-shadow: 0 0 0 2px var(--v0); }
.spec {
  width: 100%;
  min-width: 560px;
  border-collapse: collapse;
  background: var(--v1);
  font-size: .92em;
}
.spec th, .spec td {
  text-align: left;
  padding: 14px clamp(12px, 1.6vw, 18px);
  border-bottom: var(--px) solid var(--v3);
  vertical-align: top;
}
.spec thead th {
  font-weight: 700;
  font-size: 11.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  background: var(--v0);
}
.spec tbody th { color: var(--n7); font-weight: 400; white-space: nowrap; }
.spec td { color: var(--ink-dim); }
.spec tbody tr:last-child th, .spec tbody tr:last-child td { border-bottom: 0; }
.spec__note { margin-top: 18px; font-size: .9em; }

/* =========================================================================
   HOME PAGE — the front door's own furniture.
   Added for the marketing refresh; nothing above was removed or renamed, and
   /how-to-play, /support and /privacy-policy keep every selector they use.
   ========================================================================= */

/* The hero's screenshot: the LCP, and the only image above the fold. It sits
   under the CTA rather than beside it so the phone gets the copy first and the
   desktop still gets a cinematic 2.16:1 band. */
.hero__shot {
  margin: clamp(30px, 4.5vw, 52px) auto 0;
  max-width: 920px;
}
.hero__shot figcaption { margin-inline: auto; text-align: center; max-width: 56ch; }

/* Room between the three bullets and the counters under them. */
.stats--below { margin-top: clamp(24px, 3vw, 36px); }

/* --------------------------------------------------------------- beats */
/**
 * One beat of the loop: a screenshot and the paragraph that earns it. Stacked
 * on a phone — image first, because the picture is the argument — and two-up
 * from 900px, where `--flip` puts the shot on the right.
 */
.beats { display: grid; gap: clamp(44px, 6vw, 80px); }

.beat { display: grid; gap: clamp(18px, 3vw, 40px); align-items: center; }
.beat__media { margin: 0; }
.beat__copy .eyebrow { margin-bottom: 12px; }
.beat__copy h2,
.beat__copy h3 {
  font-size: clamp(21px, 1.4vw + 16px, 28px);
  line-height: 1.2;
  letter-spacing: -.015em;
  color: var(--n7);
  margin-bottom: .55em;
}
.beat__copy p { color: var(--ink-dim); }
.beat__copy p + p { margin-top: -.2em; }

@media (min-width: 900px) {
  /* The screenshot always takes the wider column, whichever side it is on. */
  .beat { grid-template-columns: 1.14fr .86fr; }
  .beat--flip { grid-template-columns: .86fr 1.14fr; }
  .beat--flip .beat__media { order: 2; }
  /* The wrap-up beat is copy over a pair of shots, not a side-by-side. */
  .beat--stack { grid-template-columns: 1fr; align-items: start; }
}

.beat--stack .beat__copy { max-width: var(--measure); }

/* Two shots that read as one row. Below 760px they stack; a 2.16:1 frame in a
   half column on a phone is decoration, not evidence. */
.shots--pair { gap: clamp(16px, 2.4vw, 24px); }
@media (min-width: 760px) {
  .shots--pair { grid-template-columns: 1fr 1fr; }
}

/* ------------------------------------------------------------ press kit */
.kit { margin-top: clamp(14px, 2vw, 20px); }
.kit h3 { margin-bottom: 8px; }
.kit__list { margin-top: 18px; max-width: none; }
.kit__list li { color: var(--ink-dim); font-size: .94em; }

/* ------------------------------------------------------- touch targets */
/* Phones: the mark and four links do not share one 375px row, so the nav
   drops to its own full-width row and stays on ONE line — a wrapped menu
   reads as a bug. Tighter tracking buys the width; the labels stay caps. */
@media (max-width: 599px) {
  .masthead__in { flex-wrap: wrap; row-gap: 0; padding-bottom: 0; }
  .masthead__mark img { width: 104px; }
  .masthead__nav {
    flex: 1 0 100%;
    flex-wrap: nowrap;
    justify-content: space-between;
    gap: 8px;
    margin-left: 0;
    font-size: 11px;
    letter-spacing: .04em;
    white-space: nowrap;
  }
  .masthead__nav a { padding: 8px 0 10px; }
}

/* The nav and footer rows are 12.5px labels; on a touch device they need a
   real 44px box around them without changing how they look on a pointer. */
@media (pointer: coarse) {
  /* Not the press-kit filenames: those are inline links inside sentences, and
     forcing them into a 44px inline-flex box would stop them wrapping. */
  .masthead__nav a,
  .foot__links a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* =========================================================================
   HOME PAGE — concise pass.
   Appended block; nothing above is removed or renamed.
   ========================================================================= */

/* One supporting line under each approved bullet — a stat, not a paragraph. */
.feat p { margin-top: 6px; }

/* The craft note: one caption line under the title shot, then the closing CTA. */
.craft__shot { max-width: 920px; margin-inline: auto; }
.craft__shot figcaption { margin-inline: auto; text-align: center; max-width: 56ch; }
.craft__cta { justify-content: center; margin-top: clamp(22px, 3vw, 32px); }

/* Beat four is copy under a pair of shots; on a phone the image still leads. */
.beat--stack .beat__media { order: -1; }

@media (max-width: 599px) {
  /* Five counters must read as a strip, not as five full-width boxes. A six
     column track gives 3 across, then 2 half-width — 3+2, never a stack. */
  .stats { grid-template-columns: repeat(6, 1fr); }
  .stat { grid-column: span 2; padding: 14px 6px; gap: 4px; }
  .stat:nth-child(4), .stat:nth-child(5) { grid-column: span 3; }
  .stat__n { font-size: 30px; }
  .stat__k { font-size: 9.5px; letter-spacing: .08em; }
}

/* The hero's one secondary link is a lone 11.5px label — give it a real box. */
@media (pointer: coarse) {
  .hero__plat a { display: inline-flex; align-items: center; min-height: 44px; }
}

/* =========================================================================
   THE FRONT DOOR
   =========================================================================
   `/` is a storefront, not a pitch deck. Two buttons decide the page —
   wishlist, or play — and everything under them is evidence: the trailer,
   then four shots. Nothing here may grow a paragraph.
   ========================================================================= */

/* No pitch line and no hero shot, so the hero is only as tall as the mark,
   one line of tag and the buttons. Half the press hero's padding. */
.hero--lean { padding: clamp(28px, 4.5vw, 56px) 0 clamp(26px, 4vw, 44px); }
.hero--lean .hero__mark { width: min(560px, 90%); }
.hero--lean .hero__cta { margin-top: clamp(20px, 3vw, 30px); }

/* Steam's own blue, not the chip blue — this button is a link to their store
   and reads as one against the gold demo button beside it. */
.btn--steam {
  background: #2a475e;
  color: var(--n7);
  box-shadow:
    inset 0 0 0 var(--px) #66c0f4, inset 0 -3px 0 rgba(0, 0, 0, .35),
    0 3px 0 #16202d, var(--shadow-hard);
}
.btn--steam .btn__sub { color: #a8c7dd; }

/* The store plaques. Not Apple's or Google's artwork — those are licensed
   badges and neither store will serve us one until the app is live — so they
   are drawn in the site's own chrome and say plainly that they do not work
   yet. Swap each for the official badge at launch and make it a link. */
.badges {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 12px;
  margin: clamp(18px, 2.6vw, 26px) 0 0;
  padding: 0;
  list-style: none;
}
.badge {
  display: grid;
  gap: 1px;
  min-width: 168px;
  padding: 9px 18px;
  text-align: left;
  background: rgb(var(--v1-rgb) / .8);
  box-shadow: inset 0 0 0 var(--px) var(--v3), var(--shadow-hard);
  opacity: .72;
}
.badge__k {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.badge__n { font-size: 19px; font-weight: 700; line-height: 1.1; color: var(--n6); }
.badge__s {
  margin-top: 2px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--y3);
}

/* The evidence sections sit closer together than the press page's chapters. */
.section--tight { padding: clamp(28px, 4vw, 48px) 0; }

/* ------------------------------------------------------------- trailer */
/* A facade: our own poster and a play glyph, replaced by the iframe on click.
   YouTube is not contacted until someone asks for the video. */
.vid {
  max-width: 900px;
  margin-inline: auto;
  aspect-ratio: 16 / 9;
  background: var(--v0);
  box-shadow: inset 0 0 0 var(--px) var(--v3), var(--shadow-soft);
}
.vid__play,
.vid__frame {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}
.vid__play {
  position: relative;
  padding: 0;
  background: none;
  cursor: pointer;
}
.vid__play img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: brightness(.66) saturate(.9);
  transition: filter .15s linear;
}
.vid__play:hover img, .vid__play:focus-visible img { filter: brightness(.86); }

/* The glyph is a CSS triangle in a gold disc: no asset, and it stays crisp. */
.vid__glyph {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -54%);
  width: 76px;
  height: 76px;
  border-radius: 50%;
  background: var(--y4);
  box-shadow: var(--shadow-hard);
}
.vid__glyph::before {
  content: '';
  position: absolute;
  top: 50%; left: 54%;
  transform: translate(-50%, -50%);
  border: 20px solid transparent;
  border-left: 30px solid var(--v0);
  border-right: 0;
}
.vid__play:active .vid__glyph { transform: translate(-50%, -52%) scale(.94); }
.vid__label {
  position: absolute;
  left: 0; right: 0;
  bottom: clamp(14px, 3vw, 26px);
  font-weight: 700;
  font-size: clamp(12px, 1.1vw, 14px);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--n7);
  text-shadow: 2px 2px 0 rgba(0, 0, 0, .7);
}

/* ------------------------------------------------------------- gallery */
/* Two up from tablet, one up on a phone. Four 4:3 shots and no third column:
   at this frame a third would put the pips below the size they were baked at. */
.gallery {
  display: grid;
  gap: clamp(14px, 2.2vw, 22px);
  margin: 0;
  padding: 0;
  list-style: none;
}
@media (min-width: 760px) {
  .gallery { grid-template-columns: 1fr 1fr; }
}
.gallery figcaption { text-align: center; }
.gallery__cta { justify-content: center; margin-top: clamp(24px, 3.4vw, 36px); }

/* --------------------------------------------------- press kit, folded */
/* The kit is a footer drawer now. It is still the address journalists were
   given, so every file in it stays where it was. */
.kit {
  margin-top: clamp(24px, 3.4vw, 36px);
  background: rgb(var(--v1-rgb) / .6);
  box-shadow: inset 0 0 0 var(--px) var(--v3);
}
.kit > summary {
  padding: 14px 18px;
  font-weight: 700;
  font-size: 12px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-dim);
  cursor: pointer;
  list-style: none;
}
.kit > summary::-webkit-details-marker { display: none; }
.kit > summary:hover { color: var(--n7); }
.kit[open] > summary { color: var(--y4); box-shadow: inset 0 -1px 0 var(--v3); }
.kit__body { padding: 18px; }
.kit__body > :first-child { margin-top: 0; }
