:root {
  /* Game design tokens, taken from frontend/src/styles/app.css @theme.
     Those are warm torchlit stone as of 2026-09-02; this page had been
     carrying the cold gothic violet set app.css retired that day, which is
     why the game's own warm renders sat on cold chrome. */
  --bg:            #14100b;  /* unlit stone */
  --surface:       #3b3025;  /* stone with the torch on it */
  --surface-2:     #2a2118;  /* stone in shadow */
  --border:        #4a3c2d;
  --text:          #ede0cd;  /* candlelit cream */
  --text-dim:      #ac9b83;
  --gold:          #e0b25f;  /* brass. the only bright thing */
  --gold-bright:   #f3d089;
  --gold-deep:     #9d7f2e;
  --crimson:       #8a2f22;
  --purple:        #9b86bf;  /* Ember stays cool on purpose */
  --purple-light:  #c3aee0;
  --error:         #d4553c;
  --success:       #7fae5a;

  /* Channel forms of the same tokens. Scrims, glows and hairlines derive from
     these rather than repeating a hex that then has to be hunted down again
     the next time the palette moves. */
  --bg-rgb:          20, 16, 11;
  --surface-rgb:     59, 48, 37;
  --border-rgb:      74, 60, 45;
  --text-rgb:        237, 224, 205;
  --gold-rgb:        224, 178, 95;
  --gold-bright-rgb: 243, 208, 137;
  --crimson-rgb:     138, 47, 34;
  --purple-rgb:      155, 134, 191;
  --error-rgb:       212, 85, 60;

  /* Reading tints, warm-shifted off --text rather than picked as greys. */
  --text-read:     #d8cbb4;
  --text-body:     #c6b9a4;
  --ink:           #1a1206;

  --font-heading: "Grenze Gotisch", "Cinzel", Georgia, serif;
  --font-body:    "Spectral", Georgia, serif;
  --font-ui:      "Barlow Condensed", "Oswald", system-ui, sans-serif;

  --shadow-lift: 0 4px 20px rgba(0,0,0,.4);

  --measure: 64ch;
  --gutter: clamp(1.25rem, 5vw, 5rem);
  --section-y: clamp(1.9rem, 3.4vw, 3.1rem);
}

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

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: clamp(1.0625rem, 0.98rem + 0.4vw, 1.1875rem);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  padding-left:  env(safe-area-inset-left);
  padding-right: env(safe-area-inset-right);
}

img { max-width: 100%; display: block; }

h1, h2, h3, h4 {
  font-family: var(--font-heading);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: .01em;
  margin: 0;
}

a { color: var(--gold); }

::selection { background: rgba(var(--gold-rgb), .28); color: var(--text); }

/* Browser surfaces are part of the design, and a default scrollbar on a
   torchlit page is the one element that still says "web document". The thin
   themed bar on the wide tables is also their only affordance: it is what tells
   a phone reader the table scrolls sideways. */
* { scrollbar-color: var(--border) transparent; scrollbar-width: thin; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: rgba(var(--bg-rgb), .6); }
::-webkit-scrollbar-thumb { background: var(--border); border: 2px solid transparent; background-clip: content-box; }
::-webkit-scrollbar-thumb:hover { background: var(--gold-deep); background-clip: content-box; }

/* Focus is themed once, here, rather than left to the browser's blue ring on a
   page that has no blue in it. */
:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* ─── Layout helpers ─────────────────────────────────────────────── */
.wrap {
  width: 100%;
  max-width: 76rem;
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.section { padding-block: var(--section-y); }

/* Heading for a grid that has no other label. It is the heading, not a kicker
   above one, so it takes heading type rather than tracked-out small caps. */
.grid-label {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: clamp(1.15rem, 1.02rem + .5vw, 1.5rem);
  letter-spacing: .01em;
  line-height: 1.15;
  color: var(--text);
  margin: 0 0 1.1rem;
}

.lede {
  font-size: clamp(1.15rem, 1.02rem + .6vw, 1.5rem);
  color: var(--text-read);
  max-width: var(--measure);
  margin: 0;
}


/* Hairline rule with a centred diamond — echoes the game's panel dividers. */
.rule {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-block: clamp(1.1rem, 2.2vw, 1.7rem);
}
.rule::before, .rule::after {
  content: "";
  height: 1px;
  flex: 1;
  background: linear-gradient(90deg, transparent, var(--border), transparent);
}
.rule i {
  width: 7px; height: 7px;
  rotate: 45deg;
  background: var(--gold);
  opacity: .55;
}

/* ─── Notched pewter panel (app.css `frame-pewter`) ──────────────── */
/* The clip-path is this page's signature notched corner. It clips every
   descendant, so anything meant to sit proud of the panel edge — the corner
   filigree — mounts on the wrapper instead of inside the frame. */
.frame-mount { position: relative; display: block; }
.frame {
  --notch: 11px;
  position: relative;
  background: linear-gradient(158deg, var(--surface) 0%, var(--surface-2) 100%);
  clip-path: polygon(
    var(--notch) 0, calc(100% - var(--notch)) 0, 100% var(--notch),
    100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%,
    var(--notch) 100%, 0 calc(100% - var(--notch)), 0 var(--notch));
}
.frame::before {
  content: "";
  position: absolute; inset: 0;
  padding: 1px;
  background: linear-gradient(150deg, #7d6b51, #33291d 45%, #7d6b51 100%);
  clip-path: inherit;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  pointer-events: none;
  z-index: 3;
}

/* Corner filigree (app.css `orn`) — the game's own generated ornament. */
.orn {
  position: absolute;
  aspect-ratio: 1;
  width: clamp(40px, 5.5vw, 76px);
  background: url("assets/frame-corner.png") no-repeat center / contain;
  pointer-events: none;
  z-index: 4;
  opacity: .9;
}
.orn.tl { top: -2px; left: -2px; }
.orn.tr { top: -2px; right: -2px; scale: -1 1; }
.orn.bl { bottom: -2px; left: -2px; scale: 1 -1; }
.orn.br { bottom: -2px; right: -2px; scale: -1 -1; }

/* ─── Buttons ────────────────────────────────────────────────────── */
.btn {
  --notch: 9px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;                 /* >= 44px tap target */
  padding: .85rem 2rem;
  font-family: var(--font-ui);
  font-size: clamp(.82rem, .78rem + .22vw, .95rem);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  border: 0;
  clip-path: polygon(
    var(--notch) 0, calc(100% - var(--notch)) 0, 100% var(--notch),
    100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%,
    var(--notch) 100%, 0 calc(100% - var(--notch)), 0 var(--notch));
  transition: transform 140ms ease, filter 140ms ease, background-color 140ms ease;
}
.btn-primary {
  background: linear-gradient(178deg, var(--gold-bright), var(--gold) 62%, var(--gold-deep));
  color: var(--ink);
  /* Elevation, not a halo. A zero-offset coloured glow (`0 0 26px gold`) is
     light coming from nowhere: it says "important" without saying where the
     surface sits. This lifts the button off the page with a real offset and a
     soft blur, and keeps one warm hairline along the top edge where a struck
     brass face would actually catch the torchlight. */
  box-shadow:
    0 1px 0 rgba(255, 232, 180, .45) inset,
    0 6px 18px rgba(0, 0, 0, .45),
    0 2px 4px rgba(0, 0, 0, .3);
}
.btn-primary:hover { filter: brightness(1.09); transform: translateY(-1px); }
.btn-ghost {
  background: rgba(var(--surface-rgb), .72);
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--border);
}
.btn-ghost:hover { background: rgba(var(--border-rgb), .72); transform: translateY(-1px); }
@media (prefers-reduced-motion: reduce) {
  .btn:hover { transform: none; }
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: .9rem;
}
@media (max-width: 30rem) {
  .cta-row { flex-direction: column; align-items: stretch; }
  .cta-row .btn { width: 100%; }
}

/* ─── Section rail ───────────────────────────────────────────────────
 *
 * Sticky, and deliberately below the hero rather than over it: a bar floating
 * on the wordmark would cover the one image the page is built around. It
 * carries three jobs — where you are, where else you can go, and the one
 * action — so the page stops being a scroll with no map.
 */
.rail {
  position: sticky;
  top: 0;
  z-index: 40;
  background: linear-gradient(180deg, rgba(var(--bg-rgb), .97), rgba(var(--bg-rgb), .92));
  backdrop-filter: blur(6px);
  box-shadow: 0 1px 0 var(--border), 0 6px 18px rgba(0, 0, 0, .34);
}
.rail-inner {
  display: flex;
  align-items: center;
  gap: clamp(.6rem, 1.6vw, 1.2rem);
  padding-inline: clamp(.75rem, 2.5vw, 1.4rem);
}
.rail-mark { display: none; flex: 0 0 auto; line-height: 0; }
.rail-mark img { width: 6.5rem; height: auto; }
@media (min-width: 64rem) { .rail-mark { display: block; } }

/* The link strip scrolls sideways on a phone rather than collapsing into a
   menu button: twelve destinations behind a tap is worse than twelve you can
   flick through and see. */
.rail-links {
  flex: 1 1 auto;
  display: flex;
  gap: .1rem;
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.rail-links::-webkit-scrollbar { display: none; }
.rail-links {
  mask-image: linear-gradient(90deg, #000 calc(100% - 1.5rem), transparent);
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 1.5rem), transparent);
}
.rail-links a {
  display: flex;
  align-items: center;
  white-space: nowrap;
  min-height: 2.9rem;
  padding: 0 clamp(.6rem, 1.4vw, .95rem);
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: clamp(.78rem, .74rem + .16vw, .88rem);
  letter-spacing: .12em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--text-dim);
  transition: color 160ms ease, background 160ms ease;
}
.rail-links a:hover { color: var(--text); }
/* The current section is marked by a lit face, not an underline: the read
   position sits on a 2px strip immediately below, and two brass rules a few
   pixels apart read as one confused indicator. */
.rail-links a[aria-current="true"] {
  color: var(--gold);
  background: linear-gradient(180deg, rgba(var(--gold-rgb), .14), rgba(var(--gold-rgb), .04));
  box-shadow: inset 0 1px 0 rgba(var(--gold-rgb), .4);
}
.rail-cta {
  flex: 0 0 auto;
  min-height: 2.4rem;
  padding: .5rem 1.1rem;
  --notch: 7px;
}
@media (max-width: 40rem) { .rail-cta { display: none; } }

/* Read position. Not decoration: on a page this tall the scrollbar is the only
   other thing that answers "how much is left", and on a phone there isn't one. */
.rail-progress { height: 2px; background: rgba(var(--border-rgb), .7); }
.rail-progress i {
  display: block;
  height: 100%;
  width: 0;
  background: linear-gradient(90deg, var(--gold-deep), var(--gold));
  transform-origin: left;
}

/* Anchor jumps have to clear the sticky bar, or the heading lands underneath
   it. --rail-h is written by script from the bar's real height. */
:root { --rail-h: 3.2rem; }
[id] { scroll-margin-top: calc(var(--rail-h) + .75rem); }

/* ─── Hero ───────────────────────────────────────────────────────── */
.hero {
  position: relative;
  min-height: min(100svh, 52rem);
  display: grid;
  align-items: start;
  overflow: hidden;
  isolation: isolate;
}
/* The art fills the hero at every width. It was a 2560x698 panorama, which is
   why the hero used to be a letterbox strip under a black band: covering a
   desktop viewport with a 3.67:1 image either leaves half the page empty or
   crops the two flanking delvers off the sides. The asset is now 2048x1296 —
   the same render with its vaulted ceiling outpainted in — so cover trims a
   little ceiling instead of trimming the cast.

   Bottom-anchored: the floor, the lantern and the three delvers are the
   composition, and they are all in the lower half. */
.hero-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 100%;
  z-index: -2;
}
/* Two scrims: one to seat text on, one to blend into the page below.
   Lighter at the top than it used to be: there was nothing up there but flat
   background, and now there is a vaulted ceiling worth seeing. */
.hero::after {
  content: "";
  position: absolute; inset: 0;
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(var(--bg-rgb), .62) 0%, rgba(var(--bg-rgb), .34) 30%, rgba(var(--bg-rgb), .12) 56%, rgba(var(--bg-rgb), .30) 84%, var(--bg) 100%),
    linear-gradient(96deg, rgba(var(--bg-rgb), .66) 0%, rgba(var(--bg-rgb), .22) 44%, transparent 72%),
    radial-gradient(66% 42% at 50% 88%, rgba(var(--gold-bright-rgb), .13), transparent 76%);
}
.hero-inner {
  padding-top: clamp(2.5rem, 6vw, 4.5rem);
  padding-bottom: clamp(2rem, 6vw, 4rem);
}

.wordmark {
  margin: 0 0 .35em;
  line-height: 0;
}
.wordmark img {
  display: block;
  width: clamp(15rem, 52vw, 46rem);
  height: auto;
  /* The mark is generated art keyed to real alpha; the drop shadow stands in
     for the candle glow the flat cutout loses against the hero art. */
  filter: drop-shadow(0 6px 34px rgba(var(--gold-rgb), .22));
}

.hero-pitch {
  margin-top: 1.6rem;
  font-size: clamp(1.1rem, .98rem + .7vw, 1.6rem);
  line-height: 1.5;
  max-width: 46ch;
  color: var(--text-read);
  margin: 0 0 1.7rem;
  text-shadow: 0 2px 18px rgba(var(--bg-rgb), .85);
}
.hero-pitch b { color: var(--gold); font-weight: 600; }

.hero-meta {
  margin-top: 1.25rem;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1.5rem;
  font-size: .82rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  font-family: var(--font-ui);
  color: var(--text-dim);
  text-shadow: 0 2px 14px rgba(var(--bg-rgb), .95), 0 0 26px rgba(var(--bg-rgb), .8);
}

/* Candle flicker on the hero glow (app.css `tallow-flicker`). */
@keyframes tallow-flicker {
  0%, 100% { opacity: 1; }
  38%      { opacity: .93; }
  62%      { opacity: 1.03; }
}
.flicker { animation: tallow-flicker 5.5s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .flicker { animation: none; } }

/* ─── Pitch band ─────────────────────────────────────────────────── */
.band {
  background:
    radial-gradient(60% 55% at 26% 42%, rgba(var(--gold-bright-rgb), .06), transparent 70%),
    radial-gradient(80% 60% at 50% 108%, rgba(var(--crimson-rgb), .16), transparent 70%),
    linear-gradient(180deg, #1d1811 0%, var(--bg) 55%, #0c0906 100%);
  border-block: 1px solid var(--border);
}
.pull {
  font-family: var(--font-heading);
  font-size: clamp(1.35rem, 1rem + 2.1vw, 2.6rem);
  line-height: 1.32;
  max-width: 30ch;
  margin: 0;
  color: var(--text);
}
.pull b { color: var(--gold); font-weight: 600; }

/* ─── Pillars ────────────────────────────────────────────────────── */
.pillars {
  display: grid;
  gap: clamp(1.75rem, 3vw, 2.5rem);
  grid-template-columns: 1fr;
}
@media (min-width: 56rem) {
  .pillars { grid-template-columns: repeat(3, 1fr); }
}
.pillar { position: relative; padding: 0 0 1.6rem; }
.pillar-art {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  margin-bottom: 1.4rem;
  --notch: 11px;
}
.pillar-art img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 600ms cubic-bezier(.2,.7,.3,1);
}
.pillar:hover .pillar-art img { transform: scale(1.045); }
@media (prefers-reduced-motion: reduce) {
  .pillar:hover .pillar-art img { transform: none; }
}
.pillar-art::after {
  content: "";
  position: absolute; inset: 0;
  z-index: 2;
  background: linear-gradient(180deg,
    rgba(var(--bg-rgb), .10) 0%, rgba(var(--bg-rgb), .28) 42%, rgba(var(--bg-rgb), .90) 100%);
}
.pillar-no {
  position: absolute;
  bottom: .55rem; left: .95rem;
  z-index: 5;
  font-family: var(--font-heading);
  font-size: clamp(2.6rem, 2rem + 2vw, 3.6rem);
  font-weight: 700;
  line-height: 1;
  color: rgba(var(--text-rgb), .14);
}
.pillar h3 {
  font-family: var(--font-ui);
  font-size: clamp(1.3rem, 1.15rem + .5vw, 1.6rem);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: .5rem;
}
/* The epigraph under a heading. One rule, wherever it appears. */
.claim {
  font-style: italic;
  color: var(--text);
  margin: 0 0 .7rem;
  font-size: 1.02em;
}
.pillar p { margin: 0; color: var(--text-body); }

/* ─── Split feature (art + copy) ─────────────────────────────────── */
.split {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
  grid-template-columns: 1fr;
}
@media (min-width: 60rem) {
  .split { grid-template-columns: 1.1fr .9fr; align-items: start; }
  .split.flip > .split-art { order: 2; }
}
.split-art { position: relative; }
.split-art img { width: 100%; height: auto; aspect-ratio: 1400 / 788; }
.split h2 {
  font-size: clamp(1.8rem, 1.4rem + 1.7vw, 3rem);
  margin-bottom: 1.1rem;
}
.split h2 em { color: var(--gold); font-style: normal; }

/* Denial list — the "no minimap / no nameplates" beats. */
.denies {
  list-style: none;
  margin: 1.6rem 0 0;
  padding: 0;
  display: grid;
  gap: .55rem;
}
.denies li {
  display: flex;
  gap: .8rem;
  align-items: baseline;
  font-family: var(--font-ui);
  font-size: clamp(.9rem, .86rem + .2vw, 1.02rem);
  letter-spacing: .06em;
  color: var(--text-dim);
}
.denies li::before {
  content: "\00d7";
  color: var(--crimson);
  font-size: 1.25em;
  line-height: 1;
  filter: brightness(1.9);
  flex: none;
}

/* Tell list — the information channels that replace the HUD. */
.tells { margin: 1.5rem 0 0; padding: 0; list-style: none; display: grid; gap: 1.1rem; }
.tells li { padding-left: 1.1rem; border-left: 1px solid var(--border); }
.tells b {
  display: block;
  font-family: var(--font-ui);
  font-size: .8rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: .18rem;
}
.tells span { color: var(--text-body); }

/* ─── Screenshot lightbox ────────────────────────────────────────────
 *
 * "No bullshots" is a claim about the captures, so they should be inspectable
 * at full size rather than at gallery-thumbnail resolution.
 */
.shot-open {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  position: relative;
}
.shot-open img { width: 100%; height: auto; }
.shot-zoom {
  position: absolute;
  right: .6rem; bottom: .6rem;
  display: grid;
  place-items: center;
  width: 2.2rem; height: 2.2rem;
  color: var(--text);
  background: rgba(var(--bg-rgb), .72);
  box-shadow: inset 0 0 0 1px rgba(var(--text-rgb), .22);
  opacity: 0;
  transition: opacity 180ms ease;
}
.shot-open:hover .shot-zoom,
.shot-open:focus-visible .shot-zoom { opacity: 1; }
/* Touch has no hover, and the affordance is the whole point of the control. */
@media (hover: none) { .shot-zoom { opacity: 1; } }
.shot-sr {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.lightbox {
  width: min(94vw, 78rem);
  max-height: 92dvh;
  padding: clamp(.6rem, 2vw, 1.1rem);
  border: 0;
  color: var(--text);
  background: linear-gradient(158deg, var(--surface-2), rgba(var(--bg-rgb), .96));
  box-shadow: inset 0 0 0 1px var(--border), 0 24px 60px rgba(0, 0, 0, .6);
}
.lightbox::backdrop { background: rgba(6, 4, 2, .82); }
.lightbox img { width: 100%; height: auto; max-height: 78dvh; object-fit: contain; }
.lightbox p {
  margin: .7rem 0 0;
  font-family: var(--font-ui);
  font-size: .8rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.lightbox-close {
  position: absolute;
  top: .5rem; right: .5rem;
  z-index: 2;
  display: grid;
  place-items: center;
  width: 2.75rem; height: 2.75rem;
  border: 0;
  cursor: pointer;
  color: var(--text);
  background: rgba(var(--bg-rgb), .7);
  box-shadow: inset 0 0 0 1px var(--border);
}
.lightbox-close:hover { color: var(--gold); }

/* ─── The ledger ─────────────────────────────────────────────────────
 *
 * "Loot is money" was asserted and then not shown. These are the real seven
 * items and the real prices, and the point of the table is the last column:
 * a Warden's Key is worth 325 Wax a kilogram and a Reliquary 43.
 */
.ledger { grid-column: 1 / -1; margin-top: clamp(1.8rem, 4vw, 3rem); }
.ledger-grid { display: grid; gap: clamp(1.2rem, 3vw, 2.2rem); align-items: start; }
@media (min-width: 62rem) { .ledger-grid { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); } }
.ltable-wrap { overflow-x: auto; overscroll-behavior-x: contain; padding-bottom: .35rem; }
.ltable { min-width: 32rem; }
.ltable td:nth-child(4), .ltable td:nth-child(5) { color: var(--text); }
.ltable tr[data-rarity="rare"] th { color: var(--gold); }
.ledger-note { margin: 0; color: var(--text-body); font-size: 1rem; }
.ledger-note b { color: var(--text); font-weight: 600; }

.prices { display: grid; gap: 1px; margin: 0; }
@media (min-width: 42rem) { .prices { grid-template-columns: 1fr 1fr; } }
@media (min-width: 72rem) { .prices { grid-template-columns: repeat(3, 1fr); } }
.price {
  padding: .8rem .95rem;
  background: rgba(var(--surface-rgb), .42);
  box-shadow:
    inset -1px 0 0 var(--border),
    inset 0 1px 0 var(--border),
    inset 0 -1px 0 var(--border);
}
.price dt {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .4rem;
  font-family: var(--font-ui);
  font-size: .74rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.price dt b {
  font-family: var(--font-heading);
  font-size: 1.1rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}
.price dd { margin: .3rem 0 0; color: var(--text-body); font-size: .94rem; line-height: 1.45; }

/* ─── Bestiary ───────────────────────────────────────────────────────
 *
 * Three equal cards said a swarm of 36-health skeletons and a 500-health boss
 * were the same kind of thing. They are not. The two you meet constantly get
 * a compact stat block each; the one that gates every exit gets the room.
 */
.mobs {
  display: grid;
  gap: clamp(1.2rem, 3vw, 2.2rem);
  margin-top: clamp(1.2rem, 2.6vw, 2rem);
}
@media (min-width: 48rem) { .mobs { grid-template-columns: 1fr 1fr; } }

.mob { display: grid; gap: 1rem; }
@media (min-width: 30rem) { .mob { grid-template-columns: minmax(0, 11rem) minmax(0, 1fr); } }
.mob-art { margin: 0; --notch: 9px; align-self: start; }
.mob-art img { width: 100%; height: auto; }
.mob-body h3 { font-size: clamp(1.25rem, 1.15rem + .45vw, 1.55rem); color: var(--text); }
.mob-body > p:last-child { margin: .8rem 0 0; color: var(--text-body); font-size: .97rem; }

.mstats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr));
  gap: 1px;
  margin: .8rem 0 0;
}
.mstat {
  padding: .45rem .6rem;
  background: rgba(var(--surface-rgb), .5);
  box-shadow:
    inset -1px 0 0 var(--border),
    inset 0 1px 0 var(--border),
    inset 0 -1px 0 var(--border);
}
.mstat dt {
  font-family: var(--font-ui);
  /* 11px functional floor. These label real numbers a reader scans, and wide
     tracking makes small caps read smaller still than their number suggests. */
  font-size: .6875rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.mstat dd {
  margin: .1rem 0 0;
  font-family: var(--font-heading);
  font-size: 1.02rem;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}
.mstats--wide { grid-template-columns: repeat(3, 1fr); }
@media (min-width: 46rem) { .mstats--wide { grid-template-columns: repeat(6, 1fr); } }

.boss {
  display: grid;
  gap: clamp(1.2rem, 3vw, 2.4rem);
  margin-top: clamp(1.6rem, 3.4vw, 2.6rem);
  padding-top: clamp(1.4rem, 3vw, 2.2rem);
  border-top: 1px solid var(--border);
}
@media (min-width: 56rem) { .boss { grid-template-columns: minmax(0, 26rem) minmax(0, 1fr); } }
.boss-art { margin: 0; --notch: 11px; align-self: start; }
.boss-art img { width: 100%; height: auto; }
.boss-body h3 { font-size: clamp(1.7rem, 1.4rem + 1.4vw, 2.6rem); color: var(--text); }
.boss-body > p { margin: .9rem 0 0; color: var(--text-body); }

/* The phases are a sequence with thresholds, so they are numbered and the
   numbers mean something — unlike an 01/02/03 pinned to three parallel ideas. */
.phases { list-style: none; counter-reset: p; margin: 1.4rem 0 0; padding: 0; display: grid; gap: .8rem; }
.phases li {
  counter-increment: p;
  display: grid;
  grid-template-columns: 1.9rem 1fr;
  gap: .8rem;
  padding-top: .7rem;
  border-top: 1px solid rgba(var(--border-rgb), .8);
}
.phases li::before {
  content: counter(p);
  grid-row: 1 / span 2;
  font-family: var(--font-heading);
  font-size: 1.3rem;
  line-height: 1;
  color: var(--gold-deep);
  font-variant-numeric: tabular-nums;
}
.phases b {
  grid-column: 2;
  font-family: var(--font-heading);
  font-size: 1.1rem;
  color: var(--gold);
}
.phases b i {
  font-style: normal;
  font-family: var(--font-ui);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding-left: .5em;
}
.phases span { grid-column: 2; color: var(--text-body); font-size: .97rem; }

/* ─── Noise: the radii, drawn to scale ───────────────────────────────
 *
 * The pitch of this game is that sound is the interface, and until now the
 * page asserted that in prose. These are the server's own constants drawn at
 * one scale, so eighteen metres and four metres are a picture rather than two
 * numbers a paragraph apart. Selecting a row lifts its ring.
 */
.noise { grid-column: 1 / -1; margin-top: clamp(1.8rem, 4vw, 3rem); }
.noise-grid {
  display: grid;
  gap: clamp(1.2rem, 3vw, 2.4rem);
  align-items: center;
}
@media (min-width: 54rem) { .noise-grid { grid-template-columns: minmax(0, 24rem) minmax(0, 1fr); } }

.noise-map { width: 100%; height: auto; overflow: visible; }
.ring {
  fill: none;
  stroke: var(--border);
  stroke-width: 1;
  stroke-dasharray: 3 5;
  transition: stroke 220ms ease, stroke-width 220ms ease, fill 220ms ease;
}
.ring-m {
  font-family: var(--font-ui);
  font-size: 11px;
  letter-spacing: .1em;
  text-anchor: middle;
  fill: var(--text-dim);
  transition: fill 220ms ease;
}
.noise-you { fill: var(--gold-bright); }
.noise-you-t {
  font-family: var(--font-ui);
  font-size: 11px;
  letter-spacing: .18em;
  text-transform: uppercase;
  text-anchor: middle;
  fill: var(--text-dim);
}
/* The selected radius is the only lit ring; everything else stays a survey
   line so the comparison is still readable behind it. */
.noise[data-ring="crank"] .ring[data-ring="crank"],
.noise[data-ring="hit"]   .ring[data-ring="hit"],
.noise[data-ring="lit"]   .ring[data-ring="lit"],
.noise[data-ring="near"]  .ring[data-ring="near"],
.noise[data-ring="dark"]  .ring[data-ring="dark"] {
  stroke: var(--gold);
  stroke-width: 2;
  stroke-dasharray: none;
  fill: rgba(var(--gold-rgb), .07);
}
.noise[data-ring="crank"] .ring-m[data-ring="crank"],
.noise[data-ring="hit"]   .ring-m[data-ring="hit"],
.noise[data-ring="lit"]   .ring-m[data-ring="lit"],
.noise[data-ring="near"]  .ring-m[data-ring="near"],
.noise[data-ring="dark"]  .ring-m[data-ring="dark"] { fill: var(--gold); }

.nrows { list-style: none; margin: 0; padding: 0; display: grid; }
.nrow {
  font: inherit;
  display: grid;
  grid-template-columns: 3.6rem 1fr;
  gap: .9rem;
  width: 100%;
  min-height: 2.9rem;
  padding: .7rem .6rem;
  border: 0;
  border-top: 1px solid var(--border);
  background: transparent;
  text-align: left;
  cursor: pointer;
  transition: background 180ms ease;
}
.nrows li:last-child .nrow { border-bottom: 1px solid var(--border); }
.nrow b {
  font-family: var(--font-heading);
  font-size: clamp(1.4rem, 1.2rem + .7vw, 1.9rem);
  line-height: 1;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  transition: color 180ms ease;
}
.nrow b i {
  font-style: normal;
  font-family: var(--font-ui);
  font-size: .6em;
  letter-spacing: .1em;
  padding-left: .1em;
}
.nlabel {
  display: block;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: .8rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text);
  margin-bottom: .2rem;
}
.nrow > span { color: var(--text-body); font-size: .96rem; line-height: 1.5; }
.nrow em { color: var(--text); font-style: italic; }
.nrow:hover { background: rgba(var(--border-rgb), .3); }
.nrow[aria-pressed="true"] { background: rgba(var(--gold-rgb), .07); }
.nrow[aria-pressed="true"] b { color: var(--gold); }

.noise-foot {
  margin: clamp(1.2rem, 2.6vw, 1.8rem) 0 0;
  max-width: 72ch;
  color: var(--text-body);
  font-size: 1rem;
}

/* ─── Melee: the weapon bands ────────────────────────────────────────
 *
 * The core mechanic of the game had no section at all. It is three bands and
 * four armour tiers, and the interesting part is the cross-reference between
 * them — so picking a band re-reads the armour table against that band's
 * impact rather than restating it in prose.
 */
.weapons { margin-top: clamp(1.2rem, 2.6vw, 2rem); }

.wtabs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: .5rem;
}
.wtab {
  --notch: 8px;
  min-height: 3.4rem;
  padding: .6rem .9rem;
  border: 0;
  cursor: pointer;
  text-align: left;
  background: linear-gradient(158deg, var(--surface-2), rgba(var(--bg-rgb), .9));
  box-shadow: inset 0 0 0 1px var(--border);
  clip-path: polygon(
    var(--notch) 0, calc(100% - var(--notch)) 0, 100% var(--notch),
    100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%,
    var(--notch) 100%, 0 calc(100% - var(--notch)), 0 var(--notch));
  transition: background 200ms ease, box-shadow 200ms ease;
}
.wtab b {
  display: block;
  font-family: var(--font-heading);
  font-size: clamp(1.05rem, .98rem + .3vw, 1.25rem);
  color: var(--text);
}
.wtab span {
  font-family: var(--font-ui);
  font-size: .74rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}
.wtab:hover { background: linear-gradient(158deg, var(--surface), var(--surface-2)); }
.wtab[aria-selected="true"] {
  background: linear-gradient(158deg, var(--surface), var(--surface-2));
  box-shadow: inset 0 0 0 1px rgba(var(--gold-rgb), .55), 0 6px 16px rgba(0, 0, 0, .38);
}
.wtab[aria-selected="true"] span { color: var(--gold); }

.wpanel { margin-top: clamp(1rem, 2.4vw, 1.6rem); }
.wpanel[hidden] { display: none; }
.wpanel-line {
  margin: 0 0 1.2rem;
  max-width: 62ch;
  font-size: clamp(1.05rem, 1rem + .35vw, 1.24rem);
  font-style: italic;
  color: var(--text);
}
.wpanel-ex {
  display: block;
  font-style: normal;
  font-family: var(--font-ui);
  font-size: .86rem;
  letter-spacing: .04em;
  color: var(--text-dim);
  margin-top: .3rem;
}

.wgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7rem, 1fr));
  gap: 1px;
  margin: 0 0 clamp(1.2rem, 2.6vw, 1.8rem);
}
.wcell {
  padding: .7rem .85rem;
  background: linear-gradient(178deg, var(--surface-2), rgba(var(--bg-rgb), .85));
  box-shadow:
    inset -1px 0 0 var(--border),
    inset 0 1px 0 var(--border),
    inset 0 -1px 0 var(--border);
}
.wcell dt {
  font-family: var(--font-ui);
  /* 11px functional floor. These label real numbers a reader scans, and wide
     tracking makes small caps read smaller still than their number suggests. */
  font-size: .6875rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.wcell dd {
  margin: .1rem 0 0;
  font-family: var(--font-heading);
  font-size: clamp(1.15rem, 1.05rem + .4vw, 1.45rem);
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}

/* A wide table on a narrow screen scrolls inside its own frame. The page
   itself never scrolls sideways. */
.wtable-wrap { overflow-x: auto; overscroll-behavior-x: contain; padding-bottom: .35rem; }
.wtable {
  width: 100%;
  min-width: 40rem;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
/* Sentence case, not caps: these captions are seventy-odd characters, and we
   read words by their ascenders and descenders, which uppercase removes. */
.wtable caption {
  caption-side: top;
  text-align: left;
  font-family: var(--font-ui);
  font-size: .86rem;
  letter-spacing: .04em;
  color: var(--text-dim);
  padding-bottom: .6rem;
}
.wtable th, .wtable td {
  text-align: left;
  padding: .6rem .8rem;
  border-top: 1px solid var(--border);
  font-size: .95rem;
}
.wtable thead th {
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: .7rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-dim);
  border-top: 0;
}
.wtable tbody th { font-family: var(--font-heading); font-weight: 700; color: var(--text); font-size: 1.02rem; }
.wtable td { color: var(--text-body); }
.wstag { font-family: var(--font-ui); font-size: .72rem; letter-spacing: .16em; text-transform: uppercase; }
.wtable tr[data-stagger="true"]  { background: rgba(var(--error-rgb), .09); }
.wtable tr[data-stagger="true"] .wstag  { color: var(--error); }
.wtable tr[data-stagger="false"] .wstag { color: var(--text-dim); }

/* ─── Strata: a depth selector ───────────────────────────────────────
 *
 * Three cards side by side said the floors were alternatives. They are not —
 * they are stacked, and the whole design pitch is that danger is expressed as
 * how far down you walked. So the selector runs downward, and the numbers each
 * floor actually differs by (swarm size, bonewright frequency, rare-chest odds,
 * entry price) are on the page instead of adjectives about them.
 */
.depth {
  display: grid;
  gap: clamp(1rem, 2.6vw, 1.8rem);
  margin-top: clamp(1.2rem, 2.6vw, 2rem);
}
@media (min-width: 52rem) { .depth { grid-template-columns: minmax(0, 13rem) minmax(0, 1fr); } }

.dtabs { display: grid; gap: .4rem; align-content: start; }
.dtab {
  --notch: 8px;
  display: grid;
  grid-template-columns: 2.2rem 1fr;
  align-items: center;
  gap: .6rem;
  min-height: 3rem;
  padding: .55rem .9rem;
  border: 0;
  cursor: pointer;
  text-align: left;
  background: linear-gradient(158deg, var(--surface-2), rgba(var(--bg-rgb), .9));
  box-shadow: inset 0 0 0 1px var(--border);
  clip-path: polygon(
    var(--notch) 0, calc(100% - var(--notch)) 0, 100% var(--notch),
    100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%,
    var(--notch) 100%, 0 calc(100% - var(--notch)), 0 var(--notch));
  transition: background 200ms ease, box-shadow 200ms ease;
}
/* The depth numeral is the one place a Roman numeral earns itself: it is the
   floor's name in the game, not a decorative index. */
.dtab-no {
  font-family: var(--font-heading);
  font-style: normal;
  font-size: 1.25rem;
  line-height: 1;
  text-align: center;
  color: var(--text-dim);
  transition: color 200ms ease;
}
.dtab b {
  font-family: var(--font-heading);
  font-size: clamp(1rem, .95rem + .25vw, 1.15rem);
  font-weight: 700;
  color: var(--text);
}
.dtab:hover { background: linear-gradient(158deg, var(--surface), var(--surface-2)); }
.dtab[aria-selected="true"] {
  background: linear-gradient(158deg, var(--surface), var(--surface-2));
  box-shadow: inset 0 0 0 1px rgba(var(--gold-rgb), .55), 0 6px 16px rgba(0, 0, 0, .38);
}
.dtab[aria-selected="true"] .dtab-no { color: var(--gold); }

.dpanel { display: grid; gap: clamp(1rem, 2.6vw, 1.8rem); align-content: start; }
.dpanel[hidden] { display: none; }
@media (min-width: 68rem) { .dpanel { grid-template-columns: minmax(0, 22rem) minmax(0, 1fr); } }

.dpanel-art { margin: 0; --notch: 10px; align-self: start; }
.dpanel-art img { width: 100%; height: auto; }

.dpanel-line {
  margin: 0 0 1rem;
  font-size: clamp(1.05rem, 1rem + .35vw, 1.24rem);
  font-style: italic;
  color: var(--text);
}
.dpanel-note {
  margin: 1.1rem 0 0;
  color: var(--text-body);
  font-size: 1rem;
}
.depth-foot {
  margin: clamp(1.4rem, 3vw, 2.2rem) 0 0;
  max-width: 70ch;
  color: var(--text-body);
  font-size: 1rem;
}
.depth-foot b { color: var(--text); font-weight: 600; }

/* ─── Classes: a switcher, not four cards ────────────────────────────
 *
 * Four identical cards said the same thing four times and carried a role
 * badge each. The same space now holds one class at a time with everything
 * the game actually knows about it — resource, weapon band, armour numbers,
 * every ability with its real cost and cooldown, and the two capstones you
 * have to choose between. Tabs, so it is one tap on a phone and arrow keys
 * on a keyboard.
 */
.picker { margin-top: clamp(1.2rem, 2.6vw, 2rem); }

.ptabs {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: .5rem;
}
@media (min-width: 46rem) { .ptabs { grid-template-columns: repeat(4, 1fr); } }

.ptab {
  --notch: 8px;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "art name" "art role";
  align-items: center;
  gap: 0 .75rem;
  min-height: 3.6rem;
  padding: .55rem .8rem .55rem .55rem;
  border: 0;
  cursor: pointer;
  text-align: left;
  background: linear-gradient(158deg, var(--surface-2), rgba(var(--bg-rgb), .9));
  box-shadow: inset 0 0 0 1px var(--border);
  clip-path: polygon(
    var(--notch) 0, calc(100% - var(--notch)) 0, 100% var(--notch),
    100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%,
    var(--notch) 100%, 0 calc(100% - var(--notch)), 0 var(--notch));
  transition: background 200ms ease, box-shadow 200ms ease;
}
.ptab img {
  grid-area: art;
  width: 2.9rem; height: 2.9rem;
  object-fit: cover;
  object-position: 50% 18%;
  filter: saturate(.6) brightness(.8);
  transition: filter 220ms ease;
}
.ptab b {
  grid-area: name;
  font-family: var(--font-heading);
  font-size: clamp(1rem, .94rem + .3vw, 1.2rem);
  font-weight: 700;
  color: var(--text);
}
/* Role badge. Violet is Ember, the premium currency, so it is not available
   to mean "tank" — the three roles read as ember, stone and moss instead. */
.role {
  display: inline-block;
  font-family: var(--font-ui);
  font-weight: 700;
  /* 11px floor for functional text: a reader scans these, and wide tracking
     makes small caps read smaller still than their number suggests. */
  font-size: .6875rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  padding: .2rem .55rem;
  color: var(--bg);
  background: var(--error);
}
.role[data-role="TANK"]   { background: var(--text-dim); }
.role[data-role="HEALER"] { background: var(--success); }
.ptab .role { grid-area: role; justify-self: start; margin: .15rem 0 0; }
.ptab:hover { background: linear-gradient(158deg, var(--surface), var(--surface-2)); }
.ptab[aria-selected="true"] {
  background: linear-gradient(158deg, var(--surface), var(--surface-2));
  box-shadow: inset 0 0 0 1px rgba(var(--gold-rgb), .55), 0 6px 16px rgba(0, 0, 0, .38);
}
.ptab[aria-selected="true"] img { filter: none; }

.ppanel {
  display: grid;
  gap: clamp(1.1rem, 3vw, 2.2rem);
  margin-top: clamp(1rem, 2.4vw, 1.6rem);
}
.ppanel[hidden] { display: none; }
@media (min-width: 56rem) { .ppanel { grid-template-columns: minmax(0, 19rem) minmax(0, 1fr); } }

.ppanel-art { margin: 0; --notch: 10px; align-self: start; }
.ppanel-art img { width: 100%; height: auto; }

.ppanel-line {
  margin: 0 0 1.1rem;
  font-size: clamp(1.06rem, 1rem + .35vw, 1.28rem);
  font-style: italic;
  color: var(--text);
}
/* A real h3 between the section's h2 and its body, and sized like one: at
   12px tracked caps it was smaller than the paragraphs it introduced. */
.ppanel-h {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: clamp(1.08rem, 1.02rem + .25vw, 1.25rem);
  line-height: 1.2;
  letter-spacing: .01em;
  color: var(--gold);
  margin: 1.6rem 0 .7rem;
}

/* Specs read as a table because they are one. */
.spec { margin: 0; display: grid; gap: 0; }
.spec-row {
  display: grid;
  gap: .15rem .9rem;
  padding: .55rem 0;
  border-top: 1px solid rgba(var(--border-rgb), .8);
}
@media (min-width: 34rem) { .spec-row { grid-template-columns: 6.5rem 1fr; } }
.spec dt {
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: .72rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding-top: .2em;
}
.spec dd { margin: 0; color: var(--text-body); font-size: .99rem; }
.spec dd b { color: var(--text); font-weight: 600; }

.abils { list-style: none; margin: 0; padding: 0; display: grid; gap: .8rem; }
.abil {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .9rem;
  align-items: start;
}
.abil img {
  width: 3rem; height: 3rem;
  --notch: 6px;
  clip-path: polygon(
    var(--notch) 0, calc(100% - var(--notch)) 0, 100% var(--notch),
    100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%,
    var(--notch) 100%, 0 calc(100% - var(--notch)), 0 var(--notch));
  box-shadow: 0 2px 8px rgba(0, 0, 0, .45);
}
.abil b {
  display: block;
  font-family: var(--font-heading);
  font-size: 1.06rem;
  color: var(--text);
}
.abil p { margin: .1rem 0 .3rem; color: var(--text-body); font-size: .96rem; line-height: 1.5; }
.abil-cost { display: flex; flex-wrap: wrap; gap: .35rem; }
.abil-cost i {
  font-family: var(--font-ui);
  font-style: normal;
  font-size: .7rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-dim);
  padding: .15rem .5rem;
  background: rgba(var(--border-rgb), .55);
}

.caps { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
@media (min-width: 40rem) { .caps { grid-template-columns: 1fr 1fr; } }
.caps li { padding-left: .85rem; border-left: 1px solid var(--border); }
.caps b {
  display: block;
  font-family: var(--font-heading);
  font-size: 1.02rem;
  color: var(--gold);
}
.caps span { color: var(--text-body); font-size: .95rem; }

.picker-foot {
  margin: clamp(1.4rem, 3vw, 2.2rem) 0 0;
  max-width: 68ch;
  color: var(--text-body);
  font-size: 1rem;
}
.picker-foot b { color: var(--text); font-weight: 600; }

/* ─── The clock ──────────────────────────────────────────────────── */
/* ─── The run clock: a dial you can drag ─────────────────────────────
 *
 * This section used to describe a sealing schedule — stairwells closing at
 * minute twelve, the Ossuary following at sixteen. None of it exists; the GDD
 * rejects it outright (run-lifecycle.md #8) and the code has one flat
 * fifteen-minute deadline per floor. What *is* real is healing dampening, and
 * it is a better mechanic to show anyway, because it is a curve — so the
 * reader gets to move along it rather than read a number off a card.
 */
.dial {
  display: grid;
  gap: clamp(1.4rem, 4vw, 3rem);
  align-items: center;
  margin-top: clamp(1.2rem, 2.6vw, 2rem);
  padding: clamp(1.2rem, 3vw, 2rem);
  background: linear-gradient(158deg, var(--surface-2), rgba(var(--bg-rgb), .82));
  box-shadow: inset 0 0 0 1px var(--border);
  --notch: 12px;
  clip-path: polygon(
    var(--notch) 0, calc(100% - var(--notch)) 0, 100% var(--notch),
    100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%,
    var(--notch) 100%, 0 calc(100% - var(--notch)), 0 var(--notch));
}
@media (min-width: 56rem) { .dial { grid-template-columns: minmax(0, 17rem) minmax(0, 1fr); } }

.dial-time {
  display: flex;
  align-items: baseline;
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: clamp(2.8rem, 2rem + 4vw, 4.4rem);
  line-height: 1;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}
.dial-time span { color: var(--text-dim); padding: 0 .06em; }
.dial-phase {
  margin: .5rem 0 1.2rem;
  min-height: 3em;
  color: var(--text);
  font-style: italic;
  font-size: 1.05rem;
}
.dial-meter-label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-family: var(--font-ui);
  font-size: .74rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: .35rem;
}
.dial-meter-label b { color: var(--text); font-size: .95rem; font-variant-numeric: tabular-nums; }
.dial-bar { height: 8px; background: rgba(var(--bg-rgb), .7); box-shadow: inset 0 0 0 1px var(--border); }
/* A meter fill is one of the few honest uses of transitioning `width`: the bar
   IS the value, so animating the value animates the bar. */
.dial-bar i {
  display: block;
  height: 100%;
  background: linear-gradient(90deg, var(--gold-deep), var(--gold));
  transition: width 90ms linear, background 300ms ease;
}
.dial-bar i[data-low="true"] { background: linear-gradient(90deg, #7a2c1d, var(--error)); }

.dial-label {
  display: block;
  font-family: var(--font-ui);
  font-size: .74rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: .6rem;
}

/* Native range input: touch, pointer and keyboard for free, themed rather
   than rebuilt out of divs. */
.dial-range {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 2.75rem;              /* the tap target, not the track */
  margin: 0;
  background: transparent;
  cursor: pointer;
}
.dial-range::-webkit-slider-runnable-track {
  height: 6px;
  background: linear-gradient(90deg, var(--gold) 0 var(--at, 0%), rgba(var(--border-rgb), .9) var(--at, 0%) 100%);
}
.dial-range::-moz-range-track {
  height: 6px;
  background: rgba(var(--border-rgb), .9);
}
.dial-range::-moz-range-progress { height: 6px; background: var(--gold); }
.dial-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 20px; height: 20px;
  margin-top: -7px;
  rotate: 45deg;
  background: var(--gold-bright);
  box-shadow: 0 2px 6px rgba(0, 0, 0, .5);
  border: 0;
}
.dial-range::-moz-range-thumb {
  width: 20px; height: 20px;
  rotate: 45deg;
  background: var(--gold-bright);
  box-shadow: 0 2px 6px rgba(0, 0, 0, .5);
  border: 0;
}
.dial-range:focus-visible { outline: 2px solid var(--gold); outline-offset: 6px; }

.dial-ticks {
  position: relative;
  list-style: none;
  margin: .4rem 0 0;
  padding: 0;
  height: 3.4rem;
}
.dial-ticks li {
  position: absolute;
  top: 0;
  left: var(--at);
  width: max-content;
  max-width: 9rem;
  padding-left: .5rem;
  border-left: 1px solid var(--border);
}
.dial-ticks li:last-child { left: auto; right: 0; padding: 0 .5rem 0 0; border-left: 0; border-right: 1px solid var(--border); text-align: right; }
.dial-ticks b {
  display: block;
  font-family: var(--font-ui);
  font-size: .78rem;
  letter-spacing: .12em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.dial-ticks span { font-size: .8rem; color: var(--text-dim); line-height: 1.3; display: block; }

/* Four short facts, deliberately not four cards: one hairline each, no box. */
.facts {
  display: grid;
  gap: clamp(1rem, 2.4vw, 1.8rem);
  margin-top: clamp(1.4rem, 3vw, 2.4rem);
}
@media (min-width: 46rem) { .facts { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 74rem) { .facts { grid-template-columns: repeat(4, 1fr); } }
.fact { padding-top: .8rem; border-top: 1px solid var(--border); }
.fact b {
  display: block;
  font-family: var(--font-heading);
  font-size: 1.08rem;
  color: var(--gold);
  margin-bottom: .35rem;
}
.fact p { margin: 0; color: var(--text-body); font-size: .97rem; line-height: 1.55; }
.fact em { color: var(--text); font-style: italic; }

/* ─── Screenshot figure ──────────────────────────────────────────── */
.shot { position: relative; }
.shot img { width: 100%; }
.shot figcaption {
  margin-top: .9rem;
  font-size: .88rem;
  color: var(--text-dim);
  font-style: italic;
}

/* ─── Promise strip ──────────────────────────────────────────────── */
.promise {
  display: grid;
  gap: clamp(1.2rem, 3vw, 2.5rem);
  /* auto-fit rather than a fixed 3-up: this strip also lives inside the
     narrower column of a .split, where three tracks would crush the labels. */
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
}
.promise div { padding-top: 1.1rem; border-top: 1px solid var(--border); }
.promise b {
  display: block;
  font-family: var(--font-ui);
  font-size: .78rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: .45rem;
}
.promise p { margin: 0; color: var(--text-body); font-size: 1rem; }

/* ─── Closing CTA ────────────────────────────────────────────────── */
.close {
  position: relative;
  text-align: center;
  overflow: hidden;
  background:
    radial-gradient(58% 70% at 50% 100%, rgba(var(--gold-bright-rgb), .13), transparent 72%),
    linear-gradient(180deg, var(--bg), #0c0906);
  border-top: 1px solid var(--border);
}
.close h2 {
  font-size: clamp(2rem, 1.4rem + 3.4vw, 4.2rem);
  margin-bottom: 1rem;
}
.close .lede { margin-inline: auto; text-align: center; }
.close .cta-row { justify-content: center; margin-top: 2.4rem; }

/* ─── Footer ─────────────────────────────────────────────────────── */
footer {
  border-top: 1px solid var(--border);
  padding-block: 2.5rem;
  padding-bottom: max(2.5rem, env(safe-area-inset-bottom));
  font-size: .88rem;
  color: var(--text-dim);
}
.foot-mark {
  font-family: var(--font-ui);
  font-size: 1.1rem;
  letter-spacing: .3em;
  color: var(--gold);
}
footer nav { display: flex; flex-wrap: wrap; gap: .75rem 1rem; margin-inline: -.5rem; }
footer nav a {
  color: var(--text-dim);
  text-decoration: none;
  /* 44x44 minimum tap target — short labels like "Play" need the min-width too. */
  min-height: 2.75rem;
  min-width: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
footer nav a:hover { color: var(--gold); }

/* ─── Reveal on scroll ───────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  .reveal { opacity: 0; transform: translateY(18px); }
  .reveal.in {
    opacity: 1; transform: none;
    transition: opacity 700ms ease, transform 700ms cubic-bezier(.2,.7,.3,1);
  }
}

/* ═══════════════════════════════════════════════════════════════════════
   Density pass — sections built from art the game already ships.
   ═══════════════════════════════════════════════════════════════════════ */

/* ─── Stats band ─────────────────────────────────────────────────────── */
.stats {
  display: grid;
  /* Explicit counts rather than auto-fit: six cells over five columns leaves
     one alone on a second row, which reads as a mistake. Two, three or six. */
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 34rem) { .stats { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 62rem) { .stats { grid-template-columns: repeat(6, 1fr); } }
.stat {
  background: linear-gradient(178deg, #1d1811, var(--bg));
  /* Each cell rules its own edges from the inside, so the band reads as one
     ruled row without the wrapper needing a background the cells would then sit
     flush against. Inset, not outset: with no grid gap, the next cell's own
     background paints straight over an outset hairline. */
  box-shadow:
    inset -1px 0 0 var(--border),
    inset 0 1px 0 var(--border),
    inset 0 -1px 0 var(--border);
  padding: clamp(1.1rem, 2.4vw, 1.7rem) clamp(.9rem, 2vw, 1.4rem);
  text-align: center;
}
.stat b {
  display: block;
  font-family: var(--font-heading);
  font-weight: 800;
  font-size: clamp(1.7rem, 1.3rem + 1.6vw, 2.6rem);
  line-height: 1;
  color: var(--gold);
  letter-spacing: .01em;
}
.stat span {
  display: block;
  margin-top: .4rem;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: clamp(.72rem, .68rem + .18vw, .82rem);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* ─── Services grid (the game's own painterly lobby tiles) ───────────── */
.services {
  display: grid;
  gap: clamp(.7rem, 1.6vw, 1.1rem);
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 46rem) { .services { grid-template-columns: repeat(4, 1fr); } }

.service {
  position: relative;
  display: block;
  margin: 0;
  overflow: hidden;
  aspect-ratio: 4 / 3;
  --notch: 9px;
}
.service img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 600ms cubic-bezier(.2,.7,.3,1);
}
.service:hover img { transform: scale(1.06); }
@media (prefers-reduced-motion: reduce) { .service:hover img { transform: none; } }
/* Reweighted for the in-game tiles (2026-09-08). These were painted icons —
   dark objects on a dark vignette — where a .42 midpoint was plenty. They are
   the hub's own renders now: lit rooms, bright at the bottom of the frame
   exactly where the caption sits. The gradient reaches its full weight before
   the text rather than at the very last pixel, and the caption carries its own
   shadow, so a label stays readable over a candle instead of only over stone. */
.service::after {
  content: "";
  position: absolute; inset: 0; z-index: 2;
  background: linear-gradient(180deg,
    rgba(var(--bg-rgb), .10) 0%, rgba(var(--bg-rgb), .38) 44%,
    rgba(var(--bg-rgb), .82) 76%, rgba(var(--bg-rgb), .96) 100%);
}
.service figcaption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 5;
  padding: .7rem .85rem .8rem;
  text-align: center;
}
.service figcaption b {
  display: block;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(.9rem, .84rem + .3vw, 1.08rem);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text);
  text-shadow: 0 1px 3px rgba(8, 5, 3, .9);
}
.service figcaption span {
  display: block;
  font-size: .82rem;
  color: var(--text-dim);
  line-height: 1.3;
  margin-top: .1rem;
  text-shadow: 0 1px 3px rgba(8, 5, 3, .9);
}

/* ─── Ability plates ─────────────────────────────────────────────────── */
/* The plates were a hover-only grid: the ability names appeared on hover and
   nowhere else, so on a phone seventeen unlabelled thumbnails taught nothing.
   They are now a real selector — name always visible, and picking one opens
   what it actually does. */
.plates-wrap { display: grid; gap: clamp(1rem, 2.4vw, 1.6rem); }
@media (min-width: 62rem) { .plates-wrap { grid-template-columns: minmax(0, 1fr) minmax(0, 21rem); } }

.plates {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(4.6rem, 1fr));
  gap: clamp(.5rem, 1.2vw, .8rem);
  align-content: start;
}
.plate {
  font: inherit;
  display: grid;
  gap: .35rem;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: center;
}
.plate img {
  width: 100%;
  /* The height attribute on the tag is a presentational hint and beats
     aspect-ratio unless height is declared. */
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  border: 1px solid var(--border);
  background: var(--surface-2);
  /* 52px of a dark painting goes muddy — the game's action bar lifts these
     the same way (see the a342fe3 notes). */
  filter: saturate(1.12) contrast(1.06) brightness(1.08);
  transition: border-color 160ms ease, transform 160ms ease, filter 160ms ease;
}
.plate i {
  font-style: normal;
  font-family: var(--font-ui);
  /* 11px functional floor — these are the names the plates exist to teach. */
  font-size: .6875rem;
  line-height: 1.25;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--text-dim);
  transition: color 160ms ease;
}
.plate:hover img { border-color: rgba(var(--gold-rgb), .6); transform: translateY(-2px); }
.plate:hover i { color: var(--text); }
.plate[aria-selected="true"] img {
  border-color: var(--gold);
  filter: saturate(1.2) contrast(1.08) brightness(1.14);
}
.plate[aria-selected="true"] i { color: var(--gold); }
@media (prefers-reduced-motion: reduce) { .plate:hover img { transform: none; } }

.plate-panel {
  align-self: start;
  padding: clamp(1rem, 2.4vw, 1.4rem);
  background: linear-gradient(158deg, var(--surface-2), rgba(var(--bg-rgb), .85));
  box-shadow: inset 0 0 0 1px var(--border);
  --notch: 10px;
  clip-path: polygon(
    var(--notch) 0, calc(100% - var(--notch)) 0, 100% var(--notch),
    100% calc(100% - var(--notch)), calc(100% - var(--notch)) 100%,
    var(--notch) 100%, 0 calc(100% - var(--notch)), 0 var(--notch));
}
.plate-panel[hidden] { display: none; }
.plate-panel h4 {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: clamp(1.25rem, 1.15rem + .4vw, 1.5rem);
  line-height: 1.15;
  color: var(--text);
  margin: 0;
}
.plate-panel h4 span {
  display: block;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: .72rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gold);
  margin-top: .3rem;
}
.plate-panel p { margin: .8rem 0 0; color: var(--text-body); font-size: .99rem; }
.plate-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px; margin: 1.1rem 0 0; }
.plate-stats > div {
  padding: .5rem .6rem;
  background: rgba(var(--surface-rgb), .5);
  box-shadow:
    inset -1px 0 0 var(--border),
    inset 0 1px 0 var(--border),
    inset 0 -1px 0 var(--border);
}
.plate-stats dt {
  font-family: var(--font-ui);
  /* 11px functional floor. These label real numbers a reader scans, and wide
     tracking makes small caps read smaller still than their number suggests. */
  font-size: .6875rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-dim);
}
.plate-stats dd {
  margin: .12rem 0 0;
  font-family: var(--font-heading);
  font-size: .98rem;
  color: var(--gold);
  font-variant-numeric: tabular-nums;
}

/* ─── Talent lattice ─────────────────────────────────────────────────── */
.lattice {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(2.9rem, 1fr));
  gap: clamp(.35rem, .9vw, .55rem);
}
.node {
  aspect-ratio: 1;
  border: 1px solid var(--border);
  background: var(--surface-2);
  box-shadow: inset 0 2px 7px rgba(0,0,0,.72);
  overflow: hidden;
}
.node img { width: 100%; height: 100%; object-fit: cover; opacity: .82; }
.node:hover { border-color: rgba(var(--gold-rgb), .65); }
.node:hover img { opacity: 1; }

/* ─── Gallery ────────────────────────────────────────────────────────── */
.gallery {
  display: grid;
  gap: clamp(.7rem, 1.6vw, 1.1rem);
  grid-template-columns: 1fr;
}
@media (min-width: 46rem) { .gallery { grid-template-columns: repeat(2, 1fr); } }

.frame-shot {
  position: relative;
  overflow: hidden;
  --notch: 10px;
  margin: 0;
}
.frame-shot img { width: 100%; height: auto; display: block; aspect-ratio: 16 / 9; object-fit: cover; }
.frame-shot figcaption {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 5;
  padding: 1.6rem .95rem .7rem;
  font-family: var(--font-ui);
  font-size: .8rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text);
  background: linear-gradient(180deg, transparent, rgba(var(--bg-rgb), .9));
}

/* ─── Two-column body for denser prose sections ──────────────────────── */
.cols2 {
  display: grid;
  gap: clamp(1.2rem, 3vw, 2.2rem);
  grid-template-columns: 1fr;
}
@media (min-width: 52rem) { .cols2 { grid-template-columns: repeat(2, 1fr); } }

/* The denial list sits under the capture as the left column's second beat,
   so that column stops running short against the taller text beside it. */
.denies--big {
  margin-top: clamp(1.4rem, 3vw, 2.2rem);
  gap: .75rem;
}
.denies--big li {
  font-size: clamp(1rem, .94rem + .34vw, 1.25rem);
  letter-spacing: .1em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--text);
  padding-bottom: .75rem;
  border-bottom: 1px solid var(--border);
}
.denies--big li::before { font-size: 1.15em; }

/* ═══════════════════════════════════════════════════════════════════════
   Phase 2 — strata, bestiary, arena, economy.
   ═══════════════════════════════════════════════════════════════════════ */

/* ─── Wide feature (arena) ───────────────────────────────────────────── */
.feature {
  position: relative;
  overflow: hidden;
  --notch: 12px;
}
.feature img { width: 100%; height: auto; display: block; aspect-ratio: 16 / 9; object-fit: cover; }
.feature-body {
  position: absolute;
  inset: auto 0 0 0;
  z-index: 5;
  padding: clamp(3rem, 12vw, 7rem) clamp(1.1rem, 4vw, 3rem) clamp(1.2rem, 3vw, 2.2rem);
  background: linear-gradient(180deg, transparent, rgba(var(--bg-rgb), .55) 38%, rgba(var(--bg-rgb), .95));
}
.feature-body h3 {
  font-size: clamp(1.4rem, 1.1rem + 1.5vw, 2.4rem);
  margin-bottom: .5rem;
  color: var(--text);
}
.feature-body p { margin: 0; max-width: 52ch; color: var(--text-read); }
/* Below ~46rem the overlay would swallow the art, so it sits underneath. */
@media (max-width: 46rem) {
  .feature-body {
    position: static;
    padding: 1.1rem 0 0;
    background: none;
  }
}

/* ─── Economy split ──────────────────────────────────────────────────── */
.coin-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: clamp(.9rem, 2vw, 1.5rem);
  margin-top: 1.6rem;
}
.coin {
  padding: 1rem 0 0;
  border-top: 1px solid var(--border);
}
.coin b {
  display: block;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: .82rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  margin-bottom: .35rem;
}
.coin[data-cur="wax"]   b { color: var(--gold); }
/* Ember is the violet gem in game, and stays violet here so the two
   currencies are never mistaken for each other at a glance. */
.coin[data-cur="ember"] b { color: var(--purple-light); }
.coin p { margin: 0; font-size: .97rem; color: var(--text-body); }

/* ═══════════════════════════════════════════════════════════════════════
   Phase 3 — FAQ and a real footer.
   ═══════════════════════════════════════════════════════════════════════ */

/* ─── FAQ ────────────────────────────────────────────────────────────── */
.faq {
  display: grid;
  gap: clamp(1.5rem, 3vw, 2.4rem) clamp(2rem, 5vw, 4rem);
  grid-template-columns: 1fr;
}
@media (min-width: 52rem) { .faq { grid-template-columns: repeat(2, 1fr); } }

.faq > div { padding-top: 1.1rem; border-top: 1px solid var(--border); }
.faq h3 {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(1rem, .95rem + .35vw, 1.18rem);
  letter-spacing: .04em;
  color: var(--gold);
  margin-bottom: .5rem;
}
.faq p { margin: 0; color: var(--text-body); font-size: 1rem; }
.faq p + p { margin-top: .55rem; }

/* ─── Footer ─────────────────────────────────────────────────────────── */
.foot-grid {
  display: grid;
  gap: clamp(1.8rem, 4vw, 3rem);
  grid-template-columns: 1fr;
  /* Kept as clamp deliberately: this resolves to 35.2-48px of real inset above
     the rule. The design detector reports it as zero because its CSS parser
     does not evaluate clamp(); measured in the browser at 375/768/1440. */
  padding-bottom: clamp(2.2rem, 4.5vw, 3rem);
  border-bottom: 1px solid var(--border);
}
@media (min-width: 46rem) { .foot-grid { grid-template-columns: 1.4fr repeat(3, 1fr); } }

.foot-brand .foot-mark {
  display: block;
  width: clamp(9rem, 16vw, 12rem);
  height: auto;
  margin-bottom: .9rem;
}
.foot-brand p {
  margin: 0;
  max-width: 34ch;
  color: var(--text-dim);
  font-size: .95rem;
  font-style: italic;
}
.foot-col h3 {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: .8125rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--text);
  margin: 0 0 .7rem;
}
.foot-col ul { list-style: none; margin: 0; padding: 0; }
.foot-col a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  min-width: 2.75rem;
  color: var(--text-dim);
  text-decoration: none;
  font-size: .95rem;
}
.foot-col a:hover { color: var(--gold); }

.foot-base {
  display: flex;
  flex-wrap: wrap;
  gap: .6rem 1.5rem;
  align-items: center;
  justify-content: space-between;
  padding-top: 1.4rem;
  font-size: .87rem;
  color: var(--text-dim);
}

/* ═══════════════════════════════════════════════════════════════════════
   Atmosphere — the flat var(--bg) read as raw, so the page now sits under a
   grain layer with per-section ambient light instead of one dead colour.
   All procedural: one inline SVG and some gradients, no new image weight.
   ═══════════════════════════════════════════════════════════════════════ */

/* Film grain. Fixed, so it reads as a property of the screen rather than
   scrolling wallpaper. Sits above the art but below nothing interactive. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 60;
  opacity: .05;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='180' height='180' filter='url(%23n)'/></svg>");
  background-size: 180px 180px;
}
@media (prefers-reduced-motion: reduce) { body::after { opacity: .035; } }

/* Page-edge vignette — pulls the eye to the centre column and stops the
   dark from reading as a flat wall. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 55;
  background: radial-gradient(130% 90% at 50% 40%, transparent 52%, rgba(0,0,0,.55) 100%);
}

/* Every section gets its own faint light source, alternating warm candle and
   cold stone, so consecutive bands stop looking like one flat sheet. */
.section, .band { position: relative; isolation: isolate; }
.section > *, .band > * { position: relative; z-index: 1; }

.section::before, .band::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.section:nth-of-type(odd)::before {
  background:
    radial-gradient(58% 42% at 12% 0%, rgba(var(--gold-bright-rgb), .055), transparent 68%),
    radial-gradient(46% 38% at 92% 100%, rgba(var(--crimson-rgb), .07), transparent 70%);
}
.section:nth-of-type(even)::before {
  background:
    radial-gradient(52% 40% at 88% 4%, rgba(var(--gold-bright-rgb), .045), transparent 70%),
    radial-gradient(50% 44% at 6% 96%, rgba(var(--crimson-rgb), .07), transparent 72%);
}

/* The banded sections take their depth from light, not from a grid. The two
   repeating-linear-gradients that used to sit here drew a masonry rhythm at
   .014 and .012 alpha — below the threshold where anything reads, which is the
   tell: a pattern present in the stylesheet and absent from the page. The
   radial pools below already do the work of keeping a long dark stretch from
   going featureless. */
.band {
  background-image:
    radial-gradient(60% 55% at 26% 42%, rgba(var(--gold-bright-rgb), .06), transparent 70%),
    radial-gradient(80% 60% at 50% 108%, rgba(var(--crimson-rgb), .16), transparent 70%),
    linear-gradient(180deg, #1d1811 0%, var(--bg) 55%, #0c0906 100%);
}

/* A hairline of candlelight on every section seam, so the boundary is a
   deliberate rule rather than a gap where the content stopped. */
.band, .section { border-top: 1px solid transparent; }
.band::after, .section::after {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(var(--gold-rgb), .22) 30%, rgba(var(--gold-rgb), .22) 70%, transparent);
}

/* ═══════════════════════════════════════════════════════════════════════
   Hover states.
   Everything animates transform / opacity / filter only, so none of it
   triggers layout. `.frame` elements are clipped by clip-path, which also
   clips box-shadow — so their glow uses drop-shadow, which applies to the
   clipped result instead of being cut off by it.
   ═══════════════════════════════════════════════════════════════════════ */

@media (hover: hover) {

  /* ─── Sconce service tiles ─────────────────────────────────────────── */
  .service { transition: transform 260ms cubic-bezier(.2,.7,.3,1), filter 260ms ease; }
  .service:hover {
    transform: translateY(-4px);
    filter: drop-shadow(0 10px 20px rgba(0,0,0,.5));
  }
  .service figcaption b { transition: color 200ms ease; }
  .service:hover figcaption b { color: var(--gold); }

  /* ─── Ability plates ───────────────────────────────────────────────── */
  .plate img {
    transition: transform 180ms cubic-bezier(.2,.7,.3,1),
                border-color 180ms ease, box-shadow 180ms ease, filter 180ms ease;
  }
  .plate:hover img {
    transform: translateY(-3px) scale(1.06);
    border-color: var(--gold);
    box-shadow: 0 8px 16px rgba(0,0,0,.5), 0 0 0 1px rgba(var(--gold-rgb), .4);
    position: relative;
    z-index: 2;
  }
  .plate:hover img { filter: saturate(1.3) contrast(1.1) brightness(1.28); }

  /* ─── Talent lattice ───────────────────────────────────────────────── */
  .node {
    transition: transform 160ms cubic-bezier(.2,.7,.3,1),
                border-color 160ms ease, box-shadow 160ms ease;
  }
  .node:hover {
    transform: scale(1.16);
    border-color: var(--gold);
    /* Lifted, not haloed — the same correction the primary button got. */
    box-shadow: 0 6px 16px rgba(0, 0, 0, .5), 0 0 0 1px rgba(var(--gold-rgb), .35);
    z-index: 2;
  }
  .node img { transition: opacity 160ms ease; }
  .node:hover img { opacity: 1; }

  /* ─── Class cards ──────────────────────────────────────────────────── */
  .ptab img, .dtab, .wtab { transition: filter 240ms ease, transform 240ms ease; }
  .ptab:hover img { transform: translateY(-2px); }

  /* ─── Gallery frames ───────────────────────────────────────────────── */
  .frame-shot { transition: filter 260ms ease; }
  .frame-shot img { transition: transform 620ms cubic-bezier(.2,.7,.3,1); }
  .frame-shot:hover img { transform: scale(1.05); }
  .frame-shot:hover { filter: drop-shadow(0 10px 20px rgba(0,0,0,.5)); }
  .frame-shot figcaption { transition: color 220ms ease, letter-spacing 320ms ease; }
  .frame-shot:hover figcaption { color: var(--gold); letter-spacing: .2em; }

  /* ─── Stat band ────────────────────────────────────────────────────── */
  .stat { transition: background 240ms ease; }
  .stat:hover { background: linear-gradient(178deg, #241d14, #15100a); }
  .stat b { transition: transform 240ms cubic-bezier(.2,.7,.3,1), color 240ms ease; }
  .stat:hover b { transform: translateY(-2px); color: var(--gold-bright); }

  /* ─── FAQ entries ──────────────────────────────────────────────────── */
  .faq > div { transition: border-color 220ms ease; }
  .faq > div:hover { border-color: rgba(var(--gold-rgb), .55); }
  .faq h3 { transition: transform 220ms cubic-bezier(.2,.7,.3,1), color 220ms ease; }
  .faq > div:hover h3 { transform: translateX(4px); color: var(--gold-bright); }

  /* ─── Pillars ──────────────────────────────────────────────────────── */
  .pillar h3 { transition: color 200ms ease, letter-spacing 320ms ease; }
  .pillar:hover h3 { color: var(--gold-bright); letter-spacing: .16em; }
  .pillar .pillar-no { transition: color 260ms ease, transform 260ms ease; }
  .pillar:hover .pillar-no { color: rgba(var(--gold-rgb), .3); transform: translateY(-3px); }

  /* ─── Economy coins ────────────────────────────────────────────────── */
  .coin { transition: border-color 220ms ease, transform 220ms ease; }
  .coin:hover { border-color: rgba(var(--gold-rgb), .6); transform: translateY(-2px); }

  /* ─── Denial list ──────────────────────────────────────────────────── */
  .denies--big li { transition: color 200ms ease, border-color 200ms ease, transform 220ms ease; }
  .denies--big li:hover { color: var(--gold); border-color: rgba(var(--gold-rgb), .45); transform: translateX(4px); }

  /* ─── Footer links ─────────────────────────────────────────────────── */
  .foot-col a { transition: color 180ms ease, transform 180ms cubic-bezier(.2,.7,.3,1); }
  .foot-col a:hover { transform: translateX(4px); }

  /* ─── Primary button: a light sweeps across the gold ───────────────── */
  .btn-primary { position: relative; overflow: hidden; }
  .btn-primary::after {
    content: "";
    position: absolute;
    inset: 0 auto 0 -60%;
    width: 45%;
    pointer-events: none;
    background: linear-gradient(100deg, transparent, rgba(255,255,255,.5), transparent);
    transform: skewX(-18deg);
    opacity: 0;
  }
  .btn-primary:hover::after {
    animation: sheen 780ms cubic-bezier(.25,.6,.35,1);
  }
  @keyframes sheen {
    0%   { left: -60%; opacity: 0; }
    12%  { opacity: .85; }
    100% { left: 118%; opacity: 0; }
  }
  .btn-ghost { transition: transform 160ms ease, background-color 200ms ease, box-shadow 200ms ease; }
  .btn-ghost:hover { box-shadow: inset 0 0 0 1px rgba(var(--gold-rgb), .5); }

  /* ─── The hero wordmark answers the cursor, faintly ────────────────── */
  .wordmark img { transition: filter 420ms ease; }
  .wordmark:hover img { filter: drop-shadow(0 6px 40px rgba(var(--gold-rgb), .42)); }
}

/* Nothing above should move for a viewer who asked for stillness. */
@media (prefers-reduced-motion: reduce) {
  .service:hover, .plate:hover img, .node:hover,
  .stat:hover b, .faq > div:hover h3, .coin:hover, .denies--big li:hover,
  .foot-col a:hover, .btn-ghost:hover,
  .frame-shot:hover img, .pillar:hover .pillar-no {
    transform: none;
  }
  .btn-primary:hover::after { animation: none; }
  .frame-shot:hover figcaption, .pillar:hover h3 { letter-spacing: inherit; }
}

/* ═══════════════════════════════════════════════════════════════════════
   Fill pass — the measured emptiness was horizontal, not vertical: headings
   and ledes stacked down the left while the right third of the content
   column stayed blank. These pair them instead.
   ═══════════════════════════════════════════════════════════════════════ */

.sec-head {
  display: grid;
  gap: clamp(.6rem, 2vw, 2.6rem);
  grid-template-columns: 1fr;
  align-items: end;
  margin-bottom: clamp(.4rem, 1.4vw, 1rem);
}
@media (min-width: 60rem) {
  .sec-head { grid-template-columns: 1.05fr .95fr; }
}
.sec-head h2 {
  font-size: clamp(1.9rem, 1.4rem + 2vw, 3.2rem);
  margin-bottom: 0;
}
.sec-head .lede { max-width: 46ch; }
/* Optical alignment: the lede's first line should sit on the heading's
   baseline, not float above it. */
@media (min-width: 60rem) {
  .sec-head .lede { padding-bottom: .35rem; }
}

/* ─── Pitch band ─────────────────────────────────────────────────────── */
.pull-row {
  display: grid;
  gap: clamp(1.6rem, 4vw, 3.5rem);
  grid-template-columns: 1fr;
  align-items: center;
}
@media (min-width: 58rem) { .pull-row { grid-template-columns: 1fr 1fr; } }

.creed { list-style: none; margin: 0; padding: 0; display: grid; gap: .9rem; }
.creed li {
  padding-left: 1.1rem;
  border-left: 1px solid var(--border);
  transition: border-color 220ms ease;
}
.creed li b {
  display: block;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: .82rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: .15rem;
}
.creed li span { color: var(--text-body); font-size: .98rem; }
@media (hover: hover) {
  .creed li:hover { border-color: rgba(var(--gold-rgb), .6); }
}

/* ─── Closing CTA ────────────────────────────────────────────────────── */
.close { position: relative; overflow: hidden; }
.close-crowd {
  position: absolute;
  inset: auto 0 -6% 0;
  z-index: 0;
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: clamp(1rem, 6vw, 5rem);
  pointer-events: none;
  /* They are wallpaper behind the ask, not content — faded out hard so the
     headline keeps every bit of its contrast. */
  opacity: .17;
  filter: grayscale(.35);
  mask-image: linear-gradient(180deg, transparent, #000 55%);
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 55%);
}
.close-crowd img {
  width: clamp(6rem, 15vw, 13rem);
  height: auto;
}
@media (max-width: 46rem) {
  .close-crowd img:nth-child(4) { display: none; }
}

/* ─── Footer brand column ────────────────────────────────────────────── */
.foot-cta {
  margin-top: 1.2rem;
  min-height: 2.75rem;
  padding: .6rem 1.4rem;
  font-size: .78rem;
}


/* The build section's prose sits in the header's right column, stacked. */

/* Four nav columns rather than three, so they reach the depth the brand
   block does instead of leaving the right half of the footer bare. */
@media (min-width: 46rem) {
  .foot-grid { grid-template-columns: 1.5fr repeat(4, minmax(0, 1fr)); }
}


/* ---------------------------------------------------------------------------
   Music toggle
   Fixed, bottom-left so it never lands on the hero CTA or the footer links.
   44px minimum box on every axis: it is icon-only, which is exactly the case
   where a comfortable-looking control is still too small to hit on a phone.
--------------------------------------------------------------------------- */
.music-toggle {
  position: fixed;
  left: max(0.9rem, env(safe-area-inset-left));
  bottom: max(0.9rem, env(safe-area-inset-bottom));
  z-index: 60;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0;
  color: var(--text-dim);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  border: 1px solid var(--border);
  border-radius: 999px;
  cursor: pointer;
  backdrop-filter: blur(6px);
  transition: color .18s ease, border-color .18s ease, background-color .18s ease;
}
.music-toggle:hover,
.music-toggle:focus-visible {
  color: var(--gold);
  border-color: var(--gold);
  background: color-mix(in srgb, var(--surface) 96%, transparent);
}
.music-toggle[aria-pressed="true"] { color: var(--gold); border-color: color-mix(in srgb, var(--gold) 60%, var(--border)); }
.music-toggle svg { display: block; }
