/*
 * FAN TRIBUTES — page-scoped styles for /site/fun/, layered on site.css.
 *
 * Everything here is prefixed .fun-*. The diversions sit on the same gold-on
 * dark chrome as the rest of the site and reuse .btn / .card / .callout rather
 * than restating them, so a change to the site theme carries into this corner
 * for free. What is defined below is only the shapes site.css has no opinion
 * about: an option list, a bracket ladder, a heraldry picker, a share bar.
 */

/* THE HIDDEN ATTRIBUTE HAS TO WIN. tools.css line 14 carries this same line and
 * the same reasoning; this corner never got it, and Oathsworn is what that cost.
 * The browser's own `[hidden] { display: none }` lives in the UA stylesheet,
 * which ANY author declaration outranks regardless of specificity — so
 * `.os-council { display: flex }` below left Alfred's war table, an 82%-opaque
 * full-stage overlay, on screen from the first frame while still reporting
 * itself hidden. The game was unplayable on every device for its entire shipped
 * life: the overlay covered the stage, dimmed the HUD and swallowed every tap
 * meant for the Strike/Shield/Roll buttons underneath it. !important because the
 * point is to beat every layout rule in this file, the ones written after this
 * line included — a conditional overlay is the normal shape of an interactive
 * page here, so the next one must not have to remember. */
[hidden] { display: none !important; }

.fun-wrap { max-width: 820px; }

.fun-head { text-align: center; margin-bottom: 30px; }
.fun-head h1 { font-family: var(--fancy); color: var(--gold); font-size: clamp(28px, 5vw, 44px); margin: 8px 0 14px; line-height: 1.15; }
.fun-sub { color: var(--muted); font-size: 16px; max-width: 640px; margin: 0 auto; }

/* The interactive root. A min-height keeps the page from jumping by several
   hundred pixels the moment the script swaps the placeholder for a question —
   layout shift after load is the single most irritating thing a page can do to
   somebody who has already started reading. */
.fun-app { min-height: 320px; margin: 0 0 40px; }
.fun-app-placeholder { color: var(--muted); text-align: center; padding: 40px 0; }

.fun-card {
  background: var(--glass, rgba(255,255,255,0.03)); border: 1px solid var(--line);
  border-radius: 16px; padding: 26px;
}
.fun-prompt { font-family: var(--fancy); font-size: clamp(19px, 3.2vw, 25px); color: #fff; margin: 0 0 20px; line-height: 1.3; }

/* Progress */
.fun-progress-track { height: 6px; border-radius: 999px; background: rgba(255,255,255,.08); overflow: hidden; margin: 0 0 10px; }
.fun-progress-bar { height: 100%; background: linear-gradient(90deg, var(--gold-dim), var(--gold)); transition: width .25s ease; }
.fun-progress-label { text-align: center; color: var(--muted); font-size: 13px; margin: 0 0 22px; letter-spacing: .5px; }

/* Option lists */
.fun-options { display: flex; flex-direction: column; gap: 10px; }
.fun-option {
  display: block; width: 100%; text-align: left; font: inherit; cursor: pointer;
  background: rgba(255,255,255,.03); border: 1px solid var(--line); border-radius: 12px;
  color: var(--text); padding: 14px 18px; transition: border-color .15s, background .15s, transform .1s;
}
.fun-option:hover { border-color: var(--gold); background: rgba(227,193,104,.06); transform: translateY(-1px); }
.fun-option:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.fun-option.picked { border-color: var(--gold); background: rgba(227,193,104,.12); }
.fun-option.right { border-color: #57a05a; background: rgba(87,160,90,.14); }
.fun-option.wrong { border-color: #b4553f; background: rgba(180,85,63,.14); }
.fun-option[disabled] { cursor: default; transform: none; }
.fun-option-mark { float: right; margin-left: 12px; color: var(--muted); font-size: 13px; }

.fun-nav { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-top: 20px; }
.fun-nav .muted { font-size: 13px; }

/* Results */
.fun-result { text-align: center; }
.fun-band { width: 100%; max-width: 220px; height: 8px; border-radius: 999px; margin: 0 auto 20px; }
.fun-result h2 { font-family: var(--fancy); font-size: clamp(28px, 6vw, 44px); margin: 0 0 6px; color: var(--gold); }
.fun-result-words { font-style: italic; color: var(--text); font-size: 18px; margin: 0 0 6px; }
.fun-result-meta { color: var(--muted); font-size: 14px; margin: 0 0 20px; }
.fun-reading {
  text-align: left; background: rgba(255,255,255,.03); border-left: 3px solid var(--gold);
  border-radius: 4px; padding: 16px 20px; margin: 0 0 18px; font-size: 16px; line-height: 1.6;
}
.fun-traits { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 0 0 20px; list-style: none; padding: 0; }
.fun-traits li {
  font-size: 12.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--gold-bright);
  border: 1px solid var(--line); border-radius: 999px; padding: 4px 12px;
}
.fun-runner { color: var(--muted); font-size: 14px; margin: 0 0 22px; }
.fun-actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin-top: 6px; }

/* Share bar — the point of the whole directory, so it is not a footnote. */
.fun-share { margin: 22px 0 4px; padding: 18px; border: 1px dashed var(--line); border-radius: 14px; background: rgba(227,193,104,.04); }
.fun-share-lead { margin: 0 0 10px; color: var(--muted); font-size: 14px; }
.fun-share-row { display: flex; gap: 10px; flex-wrap: wrap; }
.fun-share-url {
  flex: 1 1 260px; min-width: 0; font: inherit; font-size: 14px; color: var(--text);
  background: rgba(0,0,0,.32); border: 1px solid var(--line); border-radius: 10px; padding: 11px 13px;
}
.fun-share-url:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }

/* Shared-result banner: what somebody sees when they open a friend's link. */
.fun-visiting { margin: 0 0 18px; font-size: 14px; }

/* Hub section headings.
   The hub used to be one undifferentiated grid of six tiles, which was right
   when everything on it was the same kind of thing. It is now three groups —
   naming tools, design tools, and the themed diversions the corner began as —
   and a reader scanning for "the Discord one" needs the groups to be visible
   before they read a single tile. The heading is deliberately quieter than the
   page h1 and louder than a tile's own h3, so the hierarchy reads at a glance
   rather than by inference. */
.fun-section-h {
  font-family: var(--fancy); color: var(--gold); font-size: clamp(21px, 3.2vw, 27px);
  margin: 34px 0 4px;
}
.fun-note { color: var(--muted); font-size: 14.5px; max-width: 720px; margin: 6px 0 0; }

/* Hub index cards */
.fun-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 16px; margin: 24px 0 8px; }
.fun-tile {
  display: block; border: 1px solid var(--line); border-radius: 16px; padding: 22px;
  background: linear-gradient(180deg, var(--panel), var(--panel-2)); color: inherit; text-decoration: none;
  transition: border-color .2s, transform .2s;
}
.fun-tile:hover { border-color: var(--gold); transform: translateY(-2px); text-decoration: none; }
.fun-tile h3 { font-family: var(--fancy); color: var(--gold-bright); margin: 0 0 6px; font-size: 19px; }
.fun-tile p { color: var(--muted); font-size: 14px; margin: 0 0 10px; }
.fun-tile .fun-shape { font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--gold-dim); }

/* Trivia */
.fun-score { font-family: var(--fancy); font-size: clamp(34px, 8vw, 56px); color: var(--gold); margin: 0 0 4px; }
.fun-score-of { color: var(--muted); font-size: 15px; margin: 0 0 18px; }
.fun-review { text-align: left; list-style: none; padding: 0; margin: 0 0 20px; }
.fun-review li { border-top: 1px solid var(--line); padding: 12px 0; }
.fun-review li:first-child { border-top: 0; }
.fun-review .q { color: var(--text); margin: 0 0 4px; font-size: 15px; }
.fun-review .a { color: var(--muted); font-size: 13.5px; margin: 0; }
.fun-review .a b { color: var(--gold-bright); font-weight: 600; }

/* Bracket */
.fun-match { display: grid; grid-template-columns: 1fr auto 1fr; gap: 12px; align-items: stretch; margin: 0 0 6px; }
.fun-match .vs { align-self: center; color: var(--gold-dim); font-family: var(--fancy); font-size: 15px; }
.fun-pick {
  font: inherit; cursor: pointer; text-align: left; color: var(--text);
  background: rgba(255,255,255,.03); border: 1px solid var(--line); border-radius: 14px; padding: 16px;
  transition: border-color .15s, background .15s, transform .1s;
}
.fun-pick:hover { border-color: var(--gold); background: rgba(227,193,104,.06); transform: translateY(-1px); }
.fun-pick:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.fun-pick b { display: block; font-family: var(--fancy); color: var(--gold-bright); font-size: 17px; font-weight: 400; margin-bottom: 4px; }
.fun-pick span { color: var(--muted); font-size: 13px; }
.fun-path { text-align: left; list-style: none; padding: 0; margin: 0 0 18px; color: var(--muted); font-size: 14px; }
.fun-path li { padding: 5px 0; border-top: 1px solid var(--line); }
.fun-path b { color: var(--gold-bright); font-weight: 600; }

/* Heraldry picker + banner */
.fun-swatches { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 22px; }
.fun-swatch {
  cursor: pointer; font: inherit; font-size: 13.5px; color: var(--text);
  border: 1px solid var(--line); border-radius: 12px; padding: 10px 14px;
  background: rgba(255,255,255,.03); display: inline-flex; align-items: center; gap: 9px;
  transition: border-color .15s, background .15s;
}
.fun-swatch:hover { border-color: var(--gold); }
.fun-swatch:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.fun-swatch.picked { border-color: var(--gold); background: rgba(227,193,104,.12); }
/* The swatch chip. Its border is LIGHT, not dark: sable is very nearly the
   page background, and a dark outline round a dark chip on a dark panel makes
   the first colour in the row look like an empty box rather than a choice. */
.fun-dot { width: 16px; height: 16px; border-radius: 4px; border: 1px solid rgba(255,255,255,.32); display: inline-block; }
.fun-fieldset { margin: 0 0 6px; }
.fun-fieldset h3 { margin: 0 0 10px; font-size: 15px; letter-spacing: .1em; text-transform: uppercase; color: var(--gold-dim); font-family: var(--display); }
.fun-banner-svg { display: block; margin: 0 auto 18px; max-width: 260px; width: 100%; height: auto; filter: drop-shadow(0 10px 24px rgba(0,0,0,.5)); }

/* The name field on the words generator */
.fun-field { display: flex; gap: 10px; flex-wrap: wrap; margin: 0 0 8px; }
.fun-input {
  flex: 1 1 220px; min-width: 0; font: inherit; font-size: 16px; color: var(--text);
  background: rgba(0,0,0,.32); border: 1px solid var(--line); border-radius: 12px; padding: 13px 15px;
}
.fun-input:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }
.fun-hint { color: var(--muted); font-size: 13px; margin: 0 0 20px; }

/* Static, always-rendered prose. This is what a crawler and a JS-off visitor
   read, so it is styled to be genuinely readable rather than hidden away. */
.fun-static { border-top: 1px solid var(--line); padding-top: 26px; margin-top: 10px; }
.fun-static h2 { font-size: 22px; margin-top: 28px; }
.fun-static h2:first-child { margin-top: 0; }
.fun-static ul { padding-left: 20px; }
.fun-static li { margin: 6px 0; }

/* ── TOUCH TARGETS ───────────────────────────────────────────────────────────
 *
 * Apple's minimum tappable area is 44x44pt, and the number is not arbitrary —
 * it is about the contact patch of an adult fingertip. Below it, the tap that
 * lands next to the button is not the user's mistake.
 *
 * KEYED TO THE INPUT, NOT THE VIEWPORT, exactly as the game's own stylesheet
 * does it (see the TOUCH TARGETS block at the end of src/styles.css). A
 * `max-width` query asks the wrong question in both directions: a 1024px tablet
 * is a finger, and a narrow desktop window is a mouse. `pointer: coarse` asks
 * the real one.
 *
 * Which is why this is NOT applied unconditionally. A mouse is precise, and the
 * heraldry picker on the sigil page shows eighteen swatches at once — grown to
 * 44px each on a desktop they wrap into a wall and the visitor loses the sense
 * of the palette as one set of choices. Small on desktop is a better control
 * there; big on a phone is a better control everywhere. Both are true, and this
 * query is how both are honoured.
 */
@media (pointer: coarse) {
  .fun-option,
  .fun-pick,
  .fun-swatch,
  .fun-tap,
  .fun-share-url,
  .fun-input,
  .fun-app .btn { min-height: 44px; }

  /* The quiz wing's recap toggle. A <summary> is a real control and it sits
     directly under the share bar, which is the densest part of a result card on
     a phone — exactly where a small target costs a mis-tap on the control beside
     it rather than on itself. Given its own rule rather than added to the list
     above because it needs the flex centring too, and putting `display` on that
     shared line would quietly restyle every button in the panel. */
  .fun-recap summary { min-height: 44px; display: flex; align-items: center; }

  /* The swatch row is the one place the visual box genuinely wants to stay
     small: a colour chip reads as a chip. So the BOX keeps its own height and
     the TARGET grows underneath it — a transparent, centred pseudo-element that
     extends the hit area to the full 44px without moving one pixel of layout.
     Same technique, same reason, as the tier chips in the game's stylesheet. */
  .fun-swatches .fun-swatch { position: relative; }
  .fun-swatches .fun-swatch::after {
    content: "";
    position: absolute; top: 50%; left: 0; right: 0;
    height: 44px; transform: translateY(-50%);
    /* Purely a target: it must never paint, and never eat a tap meant for
       something stacked above it. */
    background: transparent;
  }

  /* Buttons that sit side by side get a little vertical room too, so a
     two-line wrap does not put two 44px targets flush against each other. */
  .fun-actions .btn, .fun-share-row .btn { margin-bottom: 2px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PALETTE PASS — the fan corner onto the site's tokens
   ───────────────────────────────────────────────────────────────────────────
   Same two corrections as the tools stylesheet, for the same two reasons:
   `rgba(255,255,255,.03)` is not a colour (it is "a bit of whatever is behind
   me", and on a pale ground it is nothing at all), and gold had quietly become
   the hover, the focus ring, the selected state, the heading and the emphasis
   all at once. Surfaces now come from the ramp; interaction is frost; the
   selected state is the section tone, which for this corner is HEATHER.

   The right/wrong answer states keep a colour of their own and are moved onto
   the semantic tokens — a quiz that marks a wrong answer in a slightly
   different gold from the right one is not marking it.
   ═══════════════════════════════════════════════════════════════════════════ */

.fun-card, .fun-option, .fun-pick, .fun-swatch, .fun-reading {
  background: linear-gradient(180deg, var(--surface-2), var(--surface-1));
  border: 1px solid var(--hair);
  box-shadow: var(--lift), var(--e1);
}
.fun-head h1, .fun-result h2, .fun-score { color: var(--gold-500); }
.fun-prompt { color: var(--text-strong); }
.fun-progress-track { background: var(--surface-3); }
.fun-progress-bar { background: linear-gradient(90deg, var(--tone-edge), var(--tone)); }
.fun-reading { border-left: 3px solid var(--tone); }

.fun-option:hover, .fun-pick:hover, .fun-swatch:hover {
  border-color: var(--frost-600); background: var(--surface-3);
}
.fun-option.picked, .fun-swatch.picked { border-color: var(--tone); background: var(--tone-wash); }
.fun-option.right { border-color: var(--ok); background: var(--ok-wash); }
.fun-option.wrong { border-color: var(--danger); background: var(--danger-wash); }
.fun-option:focus-visible, .fun-pick:focus-visible, .fun-swatch:focus-visible,
.fun-share-url:focus-visible, .fun-input:focus-visible {
  outline: 2px solid var(--frost-300); outline-offset: 2px;
}

.fun-tile { border-color: var(--hair); }
.fun-tile:hover { border-color: var(--tone-edge); }
.fun-tile h3, .fun-pick b, .fun-review .a b, .fun-path b { color: var(--text-strong); }
.fun-tile .fun-shape, .fun-fieldset h3, .fun-match .vs { color: var(--tone); }
.fun-share { background: var(--tone-wash); border: 1px dashed var(--tone-edge); }
.fun-dot { border: 1px solid var(--hair-strong); }
.fun-input { background: var(--ink-900); border: 1px solid var(--edge); color: var(--text); }
/* Section headings move off gold for the same reason they did site-wide: when
   every heading is the accent, none of them can be the important one. */
.fun-section-h { font-family: var(--display); color: var(--text-strong); }

/* ── The quiz wing's answer recap ──────────────────────────────────────────
 *
 * Shown under a result, and only when the page can prove it reconstructed the
 * same run the share code describes (see scripts/quiz-kit.mjs). A <details>
 * rather than a permanently-open list because the result card is the thing
 * people came for and the recap is the thing they look at second — and because
 * a collapsed block cannot push the share bar below the fold on a phone, which
 * is where these links are opened.
 */
.fun-recap { text-align: left; margin: 18px 0 0; border-top: 1px solid var(--line); padding-top: 14px; }
.fun-recap summary {
  cursor: pointer; color: var(--gold-dim); font-size: 13.5px;
  letter-spacing: .06em; text-transform: uppercase; list-style: none;
}
.fun-recap summary::-webkit-details-marker { display: none; }
.fun-recap summary::before { content: "▸ "; }
.fun-recap[open] summary::before { content: "▾ "; }
.fun-recap summary:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; border-radius: 4px; }
.fun-recap .fun-review { margin-top: 12px; }

/* A FANDOM THAT IS ANNOUNCED BUT NOT BUILT YET.
   A div rather than an <a>, deliberately: a tile that looks clickable and is
   not is worse than one that plainly says it is coming. Dimmed rather than
   hidden, because the whole point of announcing it is that somebody sees it. */
.fun-tile-soon { opacity: .62; cursor: default; }
.fun-tile-soon:hover { transform: none; }
.fun-tile-soon .fun-shape { font-style: italic; }

/* THE REWATCH CARD'S GRID — the only control fun-tool-kit.mjs adds beyond the
   quiz kit's vocabulary. Five columns on every screen, deliberately: a bingo
   card that reflows to one column on a phone is a list, and the whole point of
   the shape is that a line is visible at a glance. The cells shrink and the text
   shrinks with them, which is safe because a square is short by construction —
   the pool sanitiser caps it at 110 characters. `.fun-cell` carries `.fun-tap`
   in the markup rather than relying on a new selector, so the coarse-pointer
   44px block above already covers it and no stylesheet edit is needed there. */
.fun-grid { display: grid; gap: 4px; margin: 14px 0 6px; }
.fun-cell {
  display: flex; align-items: center; justify-content: center; text-align: center;
  min-height: 92px; padding: 6px; font: inherit; font-size: 12px; line-height: 1.25;
  color: var(--text); background: rgba(255,255,255,.03);
  border: 1px solid var(--line); border-radius: 8px; cursor: pointer;
  transition: border-color .15s, background .15s;
}
.fun-cell:hover { border-color: var(--gold); background: rgba(227,193,104,.06); }
.fun-cell:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.fun-cell.dabbed { border-color: var(--gold); background: rgba(227,193,104,.16); color: #fff; }
.fun-cell.free { cursor: default; font-style: italic; color: var(--muted); }
.fun-cell-t { display: block; }

/* THE STRICKLAND SHIFT — the propane counter game.
   ------------------------------------------------------------------------
   A gauge, a band and a needle, built from three divs rather than a canvas.
   The corner forbids remote assets and forbids building a node from an HTML
   string, and a canvas would want a sprite sheet to look like anything; three
   boxes scale to any screen for free, stay legible to a screen reader as
   numbers, and cost nothing to draw.

   THE HEIGHT IS CAPPED IN VIEWPORT UNITS, not pixels. The whole game has to be
   visible at once on a phone in landscape — a gauge you have to scroll to see
   the top of is a gauge you cannot aim at, and this is a game about aiming.
   The second `height` declaration below asks for dvh, the viewport unit that
   tracks the ADDRESS BAR rather than assuming it is gone; a browser that does
   not understand dvh discards that whole declaration and keeps the vh one
   above it, so this is free on every engine and correct on the ones where
   the toolbar can appear mid-shift, which on a phone is most of them. */
.pg-board { display: flex; flex-direction: column; align-items: center; gap: 10px; padding-bottom: env(safe-area-inset-bottom, 0px); }
.pg-order { display: flex; flex-direction: column; align-items: center; gap: 2px; margin: 0; }
.pg-order-name {
  margin: 0; min-height: 1.2em; font-size: 12px; font-weight: 700;
  letter-spacing: .05em; text-transform: uppercase; color: var(--gold-dim);
}
.pg-order-text {
  margin: 0; min-height: 1.4em; max-width: 34ch; text-align: center;
  font-family: var(--display, inherit); font-size: 17px; line-height: 1.3;
  color: var(--text-strong);
}
.pg-aside { margin: 0; min-height: 1.2em; max-width: 38ch; text-align: center; font-size: 12px; font-style: italic; color: var(--muted); }
.pg-gaugewrap { display: flex; justify-content: center; width: 100%; }
.pg-tank {
  position: relative; width: 108px; height: min(46vh, 300px);
  height: min(46dvh, 300px);
  background: rgba(255,255,255,.04);
  border: 1px solid var(--line); border-radius: 12px; overflow: hidden;
  transition: border-color .2s, box-shadow .2s;
}
/* THE BOSS INSPECTION. A gold ring on the gauge, nothing on the pump — the
   band actually tightening is the real signal, this is just so a glance at
   the tank explains why the fill suddenly feels tighter. */
.pg-tank.is-boss {
  border-color: var(--gold-bright, #e3c168);
  box-shadow: 0 0 0 1px var(--gold-bright, #e3c168), 0 0 16px rgba(227,193,104,.35);
}
/* The fill is drawn from the bottom so the needle and the liquid agree; a
   top-anchored fill reads as draining, which is the wrong verb entirely. */
.pg-fill {
  position: absolute; left: 0; right: 0; bottom: 0; height: 0;
  background: linear-gradient(180deg, rgba(227,193,104,.55), rgba(227,193,104,.22));
}
.pg-band {
  position: absolute; left: 0; right: 0;
  background: rgba(122,168,94,.20);
  border-top: 1px solid var(--ok, #7ba85e); border-bottom: 1px solid var(--ok, #7ba85e);
}
.pg-needle {
  position: absolute; left: -3px; right: -3px; height: 3px; margin-bottom: -1px;
  background: var(--text-strong, #fff); box-shadow: 0 0 6px rgba(0,0,0,.6);
}
.pg-verdict { margin: 0; min-height: 1.4em; font-size: 15px; font-weight: 600; }
.pg-verdict.is-perfect { color: var(--gold-bright, #e3c168); }
.pg-verdict.is-good { color: var(--ok, #7ba85e); }
.pg-verdict.is-bad { color: var(--danger, #b4553f); }
/* A boss-inspection verdict keeps its win/lose colour above; the gold weight
   is additive, not a third colour, so a red boss-miss still reads as a miss. */
.pg-verdict.is-boss { text-shadow: 0 0 10px rgba(227,193,104,.4); }
.pg-stats { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 18px; }
.pg-stat { display: flex; flex-direction: column; align-items: center; min-width: 62px; }
.pg-stat-k { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.pg-stat-v { font-size: 18px; font-weight: 700; color: var(--text-strong); font-variant-numeric: tabular-nums; }
/* Wide and tall on purpose: this is the only control, it is held rather than
   tapped, and a thumb resting on it for three seconds wants somewhere to rest.
   `touch-action: none` stops a held press turning into a page scroll — but on
   an iPhone that alone is not the whole fight: -webkit-touch-callout is the
   long-press "copy / look up" bubble Safari raises independently of scrolling,
   and without -webkit-tap-highlight-color:transparent every hold flashes the
   grey highlight rect for the duration, which on a gauge you are staring at
   reads as the button stuttering rather than as decoration. All three exist to
   remove something Safari would otherwise insert between a held finger and
   this handler; touch-action and user-select alone are the Chrome/Android
   half of that fight, not the whole one. */
.pg-pump {
  width: min(100%, 320px); min-height: 60px; font-size: 17px;
  touch-action: none; user-select: none; -webkit-user-select: none;
  -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent;
}
.pg-hint { margin: 0; max-width: 40ch; text-align: center; font-size: 13px; color: var(--muted); }
.pg-open, .pg-over { display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; }
.pg-shared { margin: 0; max-width: 44ch; color: var(--muted); }
.pg-start { width: min(100%, 320px); min-height: 56px; font-size: 17px; }
.pg-over-h { margin: 0; font-family: var(--fancy, inherit); color: var(--gold); }
.pg-over-score { margin: 0; font-size: 46px; font-weight: 800; line-height: 1; color: var(--text-strong); font-variant-numeric: tabular-nums; }
.pg-over-sub { margin: 0; color: var(--muted); }
.pg-over-review { margin: 6px 0 0; max-width: 40ch; font-size: 16px; color: var(--text-strong); }
.pg-over-by { margin: 2px 0 0; font-size: 12px; color: var(--gold-dim); }
.pg-over-best { margin: 0; min-height: 1.3em; font-size: 13px; color: var(--muted); }
.pg-again { width: min(100%, 320px); min-height: 52px; }

/* A player who has asked for less motion still needs the needle to move — it
   IS the game — so only the decorative easing goes. */
@media (prefers-reduced-motion: reduce) {
  .pg-fill, .pg-needle { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THE MEDIUM RARE LINE — king-of-the-hill/grill/
   ───────────────────────────────────────────────────────────────────────────
   Four slots that have to be readable AT A GLANCE, because the whole game is
   deciding which one to look at. That constraint drives every choice here:
   the temperature is the biggest thing in the tile, the state of a steak is
   carried by the tile's own colour rather than by text somebody would have to
   stop and read, and the pull button carries the number the steak would LAND
   at rather than the number it is now — so the decision never requires mental
   arithmetic under time pressure.

   THE GRID IS 2x2 AND STAYS 2x2. One column would put slot four below the
   fold, and a slot you have to scroll to is a slot you will lose a steak in.
   Four across on a narrow screen leaves each tile too thin for a 44px button.
   Two by two is the only arrangement where every slot is on screen and every
   control is still thumb-sized.
   ═══════════════════════════════════════════════════════════════════════ */
.gr-board { display: flex; flex-direction: column; align-items: stretch; gap: 12px; padding-bottom: env(safe-area-inset-bottom, 0px); }
.gr-stats { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 18px; }
.gr-stat { display: flex; flex-direction: column; align-items: center; min-width: 62px; }
.gr-stat-k { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.gr-stat-v { font-size: 18px; font-weight: 700; color: var(--text-strong); font-variant-numeric: tabular-nums; }

.gr-tank { display: flex; align-items: center; gap: 10px; }
.gr-tank-k { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); white-space: nowrap; }
.gr-tank-bar { position: relative; flex: 1; height: 10px; border: 1px solid var(--line); border-radius: 6px; overflow: hidden; background: rgba(0,0,0,.18); }
.gr-tank-fill { height: 100%; width: 100%; background: linear-gradient(90deg, var(--gold-dim, #8a7434), var(--gold, #e3c168)); transition: width .12s linear; }
/* A tank about to starve the burner has to register in peripheral vision —
   the player is looking at a steak, not at the gauge. */
.gr-tank-bar.is-low .gr-tank-fill { background: var(--danger, #b4553f); }
.gr-tank-btn { min-height: 36px; padding: 4px 12px; font-size: 13px; white-space: nowrap; }

.gr-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.gr-slot {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px; border: 1px solid var(--line); border-radius: 12px;
  background: rgba(227,193,104,.03);
  transition: border-color .12s linear, background .12s linear;
}
.gr-slot.is-empty { opacity: .5; }
.gr-slot.is-sel { border-color: var(--gold, #e3c168); }
/* THE THREE STATES THAT MATTER, AS COLOUR. In the window is the only good
   one; past the line is unrecoverable and should look it; a flare-up is the
   one that needs a hand right now. Nothing else gets a colour, because a
   board where everything is coloured is a board where nothing stands out. */
.gr-slot.is-window { border-color: var(--ok, #7ba85e); background: rgba(123,168,94,.10); }
.gr-slot.is-past { border-color: var(--danger, #b4553f); background: rgba(180,85,63,.12); }
.gr-slot.is-flare { border-color: #d98a3a; background: rgba(217,138,58,.14); }

.gr-slot-n { margin: 0; font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.gr-patron { margin: 0; min-height: 1.1em; font-size: 12px; font-weight: 700; color: var(--gold, #e3c168); }
.gr-order { margin: 0; min-height: 2.4em; font-size: 12px; line-height: 1.25; color: var(--muted); }
.gr-bar { position: relative; height: 14px; border: 1px solid var(--line); border-radius: 7px; overflow: hidden; background: rgba(0,0,0,.2); }
.gr-fill { height: 100%; background: linear-gradient(90deg, #7a4b2a, #c4622e, #b4553f); transition: width .1s linear; }
/* The band drawn here is the PULL window, which sits BELOW the doneness band
   by exactly the carryover. Outlined rather than filled so the temperature
   bar reads through it — the player needs both at once. */
.gr-band { position: absolute; top: 0; bottom: 0; border-left: 2px solid var(--ok, #7ba85e); border-right: 2px solid var(--ok, #7ba85e); background: rgba(123,168,94,.22); }
.gr-readout { display: flex; align-items: baseline; gap: 2px; margin: 0; flex-wrap: wrap; }
.gr-temp { font-size: 20px; font-weight: 800; color: var(--text-strong); font-variant-numeric: tabular-nums; }
.gr-tag { font-size: 10px; color: var(--muted); }
.gr-acts { display: flex; gap: 6px; }
.gr-act { flex: 1; min-height: 38px; padding: 2px 6px; font-size: 12px; }
.gr-pull { min-height: 44px; font-size: 13px; }

.gr-rest { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 14px; min-height: 1.4em; }
.gr-rest-item { display: inline-flex; align-items: baseline; gap: 5px; font-size: 12px; }
.gr-rest-k { color: var(--muted); }
.gr-rest-v { font-weight: 700; color: var(--gold, #e3c168); font-variant-numeric: tabular-nums; }

.gr-note { margin: 0; min-height: 1.4em; text-align: center; font-size: 14px; font-weight: 600; }
.gr-note.is-good { color: var(--ok, #7ba85e); }
.gr-note.is-warn { color: var(--gold, #e3c168); }
.gr-note.is-bad { color: var(--danger, #b4553f); }
.gr-hint { margin: 0 auto; max-width: 52ch; text-align: center; font-size: 12px; color: var(--muted); }

.gr-open, .gr-over { display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; }
.gr-shared { margin: 0; max-width: 46ch; color: var(--muted); }
.gr-start { width: min(100%, 320px); min-height: 56px; font-size: 17px; }
.gr-over-h { margin: 0; font-family: var(--fancy, inherit); color: var(--gold); }
.gr-over-score { margin: 0; font-size: 46px; font-weight: 800; line-height: 1; color: var(--text-strong); font-variant-numeric: tabular-nums; }
.gr-over-sub { margin: 0; color: var(--muted); }
.gr-over-review { margin: 6px 0 0; max-width: 40ch; font-size: 16px; color: var(--text-strong); }
.gr-over-by { margin: 2px 0 0; font-size: 12px; color: var(--gold-dim); }
.gr-over-best { margin: 0; min-height: 1.3em; font-size: 13px; color: var(--muted); }
.gr-again { width: min(100%, 320px); min-height: 52px; }

/* The bar IS the information. Only the easing goes. */
@media (prefers-reduced-motion: reduce) {
  .gr-fill, .gr-tank-fill { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   LAST CALL AT THE ROADHOUSE — supernatural/roadhouse/
   ───────────────────────────────────────────────────────────────────────────
   A two-tap palette: arm a tool in the tray, then tap a stool. Which makes the
   ARMED STATE the most important thing on screen — a player who has forgotten
   what they are holding will pour whiskey at a shapeshifter. So the armed
   button is the only gold thing in the tray, and every stool button relabels
   itself to say what the tap will actually do.

   The grid is 2x2 for the reason the grill's is, and the argument is the same:
   one column puts the fourth one below the fold, and a stool you have to
   scroll to is a stool you will lose somebody in. The tray is two rows of four
   rather than one row of eight, because eight across on a phone is thinner
   than a thumb.
   ═══════════════════════════════════════════════════════════════════════ */
.rh-board { display: flex; flex-direction: column; gap: 12px; padding-bottom: env(safe-area-inset-bottom, 0px); }
.rh-stats { display: flex; flex-wrap: wrap; justify-content: center; gap: 4px 18px; }
.rh-stat { display: flex; flex-direction: column; align-items: center; min-width: 68px; }
.rh-stat-k { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.rh-stat-v { font-size: 18px; font-weight: 700; color: var(--text-strong); font-variant-numeric: tabular-nums; }

.rh-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.rh-seat {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px; border: 1px solid var(--line); border-radius: 12px;
  background: rgba(227,193,104,.03);
  transition: border-color .12s linear, background .12s linear;
}
.rh-seat.is-empty { opacity: .45; }
/* Two states earn a colour and nothing else does: about to walk, and busy
   with a test. A board where everything is coloured is a board where nothing
   stands out. */
.rh-seat.is-urgent { border-color: var(--danger, #b4553f); background: rgba(180,85,63,.12); }
.rh-seat.is-busy { border-color: var(--gold-dim, #8a7434); }
.rh-who { margin: 0; font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.rh-line { margin: 0; min-height: 3.2em; font-size: 12px; line-height: 1.3; color: var(--text-strong); }
.rh-want { margin: 0; font-size: 12px; font-weight: 700; color: var(--gold, #e3c168); }
.rh-pat { height: 8px; border: 1px solid var(--line); border-radius: 5px; overflow: hidden; background: rgba(0,0,0,.2); }
.rh-pat-fill { height: 100%; width: 100%; background: linear-gradient(90deg, var(--danger, #b4553f), var(--gold, #e3c168)); transition: width .1s linear; }
.rh-read { margin: 0; min-height: 1.2em; font-size: 10px; color: var(--muted); }
.rh-stool { min-height: 44px; font-size: 13px; touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent; }

.rh-tray { display: flex; flex-direction: column; gap: 6px; }
.rh-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.rh-tool {
  min-height: 44px; padding: 2px 4px; font-size: 12px;
  touch-action: none; user-select: none; -webkit-user-select: none;
  -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent;
}
/* THE ONLY GOLD THING IN THE TRAY. See the note above: forgetting what you
   are holding is the mistake this game punishes hardest. */
.rh-tool.is-armed { border-color: var(--gold, #e3c168); background: rgba(227,193,104,.16); color: var(--text-strong); font-weight: 700; }

.rh-note { margin: 0; min-height: 1.4em; text-align: center; font-size: 14px; font-weight: 600; }
.rh-note.is-good { color: var(--ok, #7ba85e); }
.rh-note.is-warn { color: var(--gold, #e3c168); }
.rh-note.is-bad { color: var(--danger, #b4553f); }
.rh-aside { margin: 0; min-height: 1.2em; text-align: center; font-size: 12px; font-style: italic; color: var(--muted); }
.rh-hint { margin: 0 auto; max-width: 52ch; text-align: center; font-size: 12px; color: var(--muted); }

.rh-open, .rh-over { display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; }
.rh-shared { margin: 0; max-width: 46ch; color: var(--muted); }
.rh-start { width: min(100%, 320px); min-height: 56px; font-size: 17px; }
.rh-over-h { margin: 0; font-family: var(--fancy, inherit); color: var(--gold); }
.rh-over-score { margin: 0; font-size: 46px; font-weight: 800; line-height: 1; color: var(--text-strong); font-variant-numeric: tabular-nums; }
.rh-over-sub { margin: 0; color: var(--muted); }
.rh-over-why { margin: 4px 0 0; max-width: 42ch; font-size: 14px; color: var(--danger, #b4553f); }
.rh-over-review { margin: 6px 0 0; max-width: 40ch; font-size: 16px; color: var(--text-strong); }
.rh-over-best { margin: 0; min-height: 1.3em; font-size: 13px; color: var(--muted); }
.rh-again { width: min(100%, 320px); min-height: 52px; }

/* The patience bar IS the information. Only the easing goes. */
@media (prefers-reduced-motion: reduce) {
  .rh-pat-fill { transition: none; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   BABY'S MIDNIGHT RUN — supernatural/drive/
   ───────────────────────────────────────────────────────────────────────────
   drive.js builds its whole cockpit inline, and deliberately: a dashboard is
   one page's furniture and does not belong in a shared stylesheet. These few
   things do, because an inline style physically cannot express them:

     · env(safe-area-inset-*) — a notched iPhone puts glass over the corners of
       the viewport and a home indicator across the bottom of it. Only the
       stylesheet can ask the browser how much.
     · a landscape media query — the game is far better held sideways, and a
       phone in landscape has around 390px of height to fit a cockpit AND its
       switches into. Something has to give, and which things give is a
       question about the viewport, not about the run.
     · a portrait grid for the switch row — an inline `display:flex` would win
       over any media query trying to make it a two-column block, so the
       display property has to start out here.
     · the coarse-pointer 44px rule further up this file already covers these
       buttons through `.fun-app .btn`; what it cannot do is stop an inline
       font-size and padding from pinning them wide in landscape.

   Everything is `drv-` prefixed and nothing outside that page uses it.
   ═══════════════════════════════════════════════════════════════════════════ */

.drv-frame {
  position: relative; width: 100%;
  height: var(--drv-h, min(74vh, 720px));
  min-height: var(--drv-min, 400px);
  background: #04060c; overflow: hidden; cursor: crosshair;
  /* touch-action stops the steering drag becoming a page scroll or a
     rubber-band. On iOS that is only the first third of the fight:
     -webkit-touch-callout is the long-press "copy / look up" bubble Safari
     raises on its own schedule — and a steering drag IS a long press by every
     definition Safari uses — and without the tap-highlight override every
     touch flashes a grey rect over the windscreen for as long as it is held.
     Same three-part fix, same reason, as .pg-pump above. */
  touch-action: none; user-select: none; -webkit-user-select: none;
  -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent;
  overscroll-behavior: contain;
}
.drv-frame.is-big { --drv-h: min(86vh, 900px); }

.drv-panel {
  display: flex; flex-wrap: wrap; gap: 8px;
  padding: 11px calc(12px + env(safe-area-inset-right, 0px))
           13px calc(12px + env(safe-area-inset-left, 0px));
  background: linear-gradient(180deg, #0a0c11, #121620);
  border-top: 1px solid rgba(255, 255, 255, .08);
}
.drv-sw {
  flex: 1 1 128px; min-width: 110px; display: flex; align-items: center;
  justify-content: center; gap: 7px; padding: 9px 8px; font-size: 12.5px;
  letter-spacing: .02em; background: linear-gradient(180deg, #1a1e25, #12151b);
  border: 1px solid rgba(255, 255, 255, .10); color: #dbe1ea;
  -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent;
}
/* The view toggle sits in the switch row but is not a switch, so it does not
   claim a switch's share of the line — which on a reading-column-width card is
   the difference between one row of six and five plus an orphan. */
.drv-panel .btn.ghost { flex: 0 1 auto; min-width: 104px; }
.drv-hint {
  margin: 0; font-size: 12.5px; text-align: center; background: #121620;
  padding: 0 12px calc(12px + env(safe-area-inset-bottom, 0px));
}

/* PORTRAIT PHONE: two thumb-wide columns rather than one line of six narrow
   switches. Six buttons at 44px in a 2x3 block sit as a slab directly under
   the glass — which on a phone held one-handed is where the thumb already is —
   instead of a row you have to aim along. */
@media (pointer: coarse) and (orientation: portrait) {
  .drv-panel { display: grid; grid-template-columns: 1fr 1fr; }
  .drv-sw { min-width: 0; }
}

/* PHONE IN LANDSCAPE — the orientation this game actually wants, and the one
   with no room. A 844x390 iPhone has to hold a cockpit and its controls at
   once, so the page furniture above the game goes: the crumbs, the eyebrow and
   the standfirst are all re-readable by rotating back. What is left is sized so
   the frame plus the switch row comes to well under 340px, which fits inside
   390 with the heading still on screen — and drive.js scrolls the card into
   view when a run starts, so the site nav leaves the top the way it does in any
   full-bleed view. `max-height` only, never `max-width`: the coarse-pointer
   rule further up is keyed to the input and must stay that way. */
@media (orientation: landscape) and (max-height: 560px) {
  .drv-page .crumbs, .drv-page .fun-head .eyebrow, .drv-page .fun-sub { display: none; }
  .drv-page .fun-head { margin-bottom: 8px; }
  .drv-page .fun-head h1 { font-size: 19px; margin: 2px 0 4px; }
  .drv-page .fun-app {
    min-height: 0; margin-bottom: 20px;
    padding-left: env(safe-area-inset-left, 0px);
    padding-right: env(safe-area-inset-right, 0px);
  }
  /* dvh tracks the address bar instead of assuming it is gone; an engine that
     does not know it discards the second declaration and keeps the vh one. */
  .drv-frame, .drv-frame.is-big {
    --drv-h: min(calc(100vh - 120px), 430px);
    --drv-h: min(calc(100dvh - 120px), 430px);
    --drv-min: 170px;
  }
  .drv-panel {
    gap: 5px;
    padding: 6px calc(6px + env(safe-area-inset-right, 0px))
             calc(6px + env(safe-area-inset-bottom, 0px))
             calc(6px + env(safe-area-inset-left, 0px));
  }
  .drv-sw { flex: 1 1 0; min-width: 0; font-size: 11px; padding: 6px 3px; gap: 4px; }
  .drv-hint { display: none; }
}

/* The near-miss and crash cues are the loudest motion on the page, and they are
   feedback rather than decoration — so a reader who asked for less motion gets
   them stilled here, and drive.js damps the camera shake this file cannot
   reach on the same query. */
@media (prefers-reduced-motion: reduce) {
  .drv-glow, .drv-flash { transition: none; }
}

/* ── The per-page FAQ ───────────────────────────────────────────────────────
   Visible prose, not just structured data. The FAQPage node in the head is
   only honoured while a reader can see the same answers on the page, so this
   block is the half that makes the markup legitimate rather than decorative —
   and it is also the half an assistant quotes. A plain <dl> because that is
   what the content is; nothing here needs a widget. */
.fun-faq { margin: 14px 0 0; }
.fun-faq dt {
  font-weight: 650; color: var(--ink-strong, #e9e4d8); margin: 18px 0 6px;
  line-height: 1.4;
}
.fun-faq dt:first-child { margin-top: 0; }
.fun-faq dd { margin: 0 0 4px; padding-left: 14px; border-left: 2px solid var(--line); }

/* Free text entry.
 *
 * THE CORNER HAD NO TEXTAREA STYLE AT ALL until The King's Shadow needed one,
 * and its first version wore a page-specific class with nothing behind it — so
 * the box rendered at the browser default width and sat crammed beside its
 * button. That is the same fault, in the same corner, as the choice buttons
 * that shipped in #609 wearing a bespoke class with no CSS: label and note ran
 * together because nothing styled them. Named `fun-` rather than `ks-` so the
 * next page that needs a text box inherits a styled one instead of repeating
 * the mistake a third time. */
.fun-textarea {
  display: block; width: 100%; box-sizing: border-box; margin: 0 0 14px;
  font: inherit; font-size: 15px; line-height: 1.5; color: var(--text);
  background: rgba(255,255,255,.03); border: 1px solid var(--line);
  border-radius: 14px; padding: 14px; resize: vertical; min-height: 96px;
  transition: border-color .15s, background .15s;
}
.fun-textarea::placeholder { color: var(--muted); opacity: .75; }
.fun-textarea:hover { border-color: rgba(227,193,104,.5); }
.fun-textarea:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; border-color: var(--gold); }

/* The King's Shadow.
 *
 * THE CHRONICLE'S TWO LINE KINDS HAVE TO LOOK DIFFERENT, or the game does not
 * make its point. Both kinds first shipped wearing classes with no rules behind
 * them, so eight identical grey paragraphs scrolled past and the thing the
 * player is supposed to NOTICE — that the king is named for half of their life
 * — was invisible. The gilded left rule is his; the plain indent is yours, and
 * there are always at least as many of his. */
.ks-meters { margin: 4px 0 18px; }
.ks-meter { margin: 0 0 6px; color: var(--muted); font-size: 14.5px; }
.ks-meter b { color: var(--gold-bright); font-weight: 600; }
.ks-when { margin-bottom: 6px; }
.ks-q { font-size: 17px; line-height: 1.55; margin: 0 0 16px; }
.ks-verdict { font-size: 17px; line-height: 1.6; color: var(--ink-strong, #e9e4d8); }
.ks-line {
  margin: 0 0 7px; padding: 7px 0 7px 14px; font-size: 14.5px; line-height: 1.5;
  border-left: 2px solid var(--line); color: var(--muted);
}
.ks-his { border-left-color: var(--gold); color: var(--ink-strong, #e9e4d8); }
.ks-yours { border-left-style: dotted; }
.ks-closing { margin: 14px 0 6px; font-size: 15px; line-height: 1.6; }
.ks-epithet {
  font-family: var(--fancy); font-size: 21px; line-height: 1.35; font-weight: 400;
  color: var(--gold-bright); margin: 10px 0 18px;
}

/* Storm the Coast. The status block is the whole contract of this game: every
 * option prints its own price, and the row-home odds are always on screen. */
.sc-status { margin: 4px 0 14px; }
.sc-line { margin: 0 0 5px; color: var(--muted); font-size: 14.5px; }
.sc-line b { color: var(--gold-bright); font-weight: 600; }
.sc-prompt { font-size: 17px; line-height: 1.55; margin: 0 0 14px; }
.sc-log { margin: 12px 0 0; font-style: italic; }
.sc-verdict { font-size: 17px; line-height: 1.6; color: var(--ink-strong, #e9e4d8); }
.sc-take b { color: var(--gold-bright); }
.sc-run b { color: #e9a2a2; }
.sc-skip b { color: #a9bcd4; }

/* The Burh Holds. A fallen district is still listed — you have to see the gap
 * where it was, and the reeve's list at the end has to match it exactly. */
.bh-head { margin-bottom: 4px; }
.bh-sign { margin: 0 0 14px; color: var(--muted); font-size: 14.5px; }
.bh-ward b { font-size: 16px; }
.bh-safe { border-color: rgba(120,190,140,.45); }
.bh-gone { opacity: .5; cursor: default; }
.bh-gone b { color: var(--muted); text-decoration: line-through; }
.bh-reeve { margin: 12px 0 6px; font-style: italic; color: var(--gold-bright); font-size: 15px; }
.bh-act { margin: 8px 0 0; }
.bh-verdict { font-size: 17px; line-height: 1.6; color: var(--ink-strong, #e9e4d8); }
.bh-eulogy { margin: 0 0 8px; padding-left: 14px; border-left: 2px solid var(--line); color: var(--muted); font-size: 14.5px; }
.bh-swatch { display: inline-block; width: 11px; height: 11px; border-radius: 3px; margin-right: 8px; vertical-align: baseline; }

/* Night at the Fortress Gate. */
.fg-head { margin-bottom: 10px; }
.fg-lane b { font-size: 16px; }
.fg-gone { opacity: .5; cursor: default; }
.fg-gone b { color: var(--muted); text-decoration: line-through; }
.fg-comp { margin-top: 10px; }
.fg-master { margin: 12px 0 6px; font-style: italic; color: var(--gold-bright); font-size: 15px; min-height: 1.4em; }

/* Uhtred: Ashore. The wing's first real-time game — a HUD (health/stamina
 * bars, live enemy count) sits under the canvas rather than over it, so
 * nothing on-screen occludes the fight itself. */
.uh-wrap { display: flex; flex-direction: column; gap: 12px; }
.uh-stage { border-radius: 10px; overflow: hidden; min-height: 260px; background: #0a0e10; }
.uh-hud { display: flex; flex-direction: column; gap: 6px; }
.uh-bar { height: 12px; border-radius: 6px; background: rgba(255,255,255,.08); border: 1px solid var(--line); overflow: hidden; }
.uh-fill { height: 100%; width: 100%; transition: width .12s linear; }
.uh-hp { background: #b2412f; }
.uh-stam { background: #c9a227; }
.uh-enemies { margin: 0; color: var(--muted); font-size: 14px; }
.uh-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.uh-controls p { margin: 0; color: var(--muted); font-size: 13.5px; flex-basis: 100%; }
.uh-pad { width: 64px; height: 64px; border-radius: 50%; border: 1px solid var(--line); background: rgba(255,255,255,.06); touch-action: none; }
.uh-btn-attack, .uh-btn-block, .uh-btn-dodge { padding: 8px 16px; border-radius: 8px; border: 1px solid var(--line); background: rgba(255,255,255,.06); color: var(--ink-strong, #e9e4d8); }
.uh-end h2 { margin: 0 0 6px; }
.uh-end p { color: var(--muted); }
.fg-verdict { font-size: 17px; line-height: 1.6; color: var(--ink-strong, #e9e4d8); }

/* Oathsworn. Same HUD shape as Ashore's .uh-* block (bars under the canvas,
 * never over it) plus two things Ashore never needed: a stand/supplies/renown
 * status row, because this game tracks state ACROSS fights, and a war-table
 * overlay that has to fully occlude the stage while it is open — the council
 * is a hard stop between stands, not a HUD element layered over live combat. */
.os-wrap { display: flex; flex-direction: column; gap: 12px; position: relative; }
.os-stage { border-radius: 10px; overflow: hidden; min-height: 260px; background: #0a0e10; }
.os-hud { display: flex; flex-direction: column; gap: 6px; }
.os-bar { height: 12px; border-radius: 6px; background: rgba(255,255,255,.08); border: 1px solid var(--line); overflow: hidden; }
.os-fill { height: 100%; width: 100%; transition: width .12s linear; }
.os-hp { background: #b2412f; }
.os-stam { background: #c9a227; }
.os-stats { display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 0; color: var(--muted); }
.os-stats .os-stand { color: var(--ink-strong, #e9e4d8); font-weight: 600; }
.os-enemies { margin: 0; color: var(--muted); font-size: 14px; }
.os-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.os-controls p { margin: 0; color: var(--muted); font-size: 13.5px; flex-basis: 100%; }
.os-pad { width: 64px; height: 64px; border-radius: 50%; border: 1px solid var(--line); background: rgba(255,255,255,.06); touch-action: none; }
.os-btn-attack, .os-btn-block, .os-btn-dodge { padding: 8px 16px; border-radius: 8px; border: 1px solid var(--line); background: rgba(255,255,255,.06); color: var(--ink-strong, #e9e4d8); }

.os-council {
  position: absolute; inset: 0; z-index: 5; display: flex; align-items: center;
  justify-content: center; padding: 16px; background: rgba(6,8,10,.82);
  border-radius: 10px;
}
.os-council-card {
  width: 100%; max-width: 420px; background: var(--glass, rgba(255,255,255,.03));
  border: 1px solid var(--line); border-radius: 16px; padding: 22px;
}
.os-council-card .eyebrow { margin: 0 0 6px; }
.os-council-stage { border-radius: 10px; overflow: hidden; min-height: 120px; background: #0a0e10; margin: 0 0 12px; }
.os-council-quote { margin: 0 0 12px; font-style: italic; }
.os-council-choices .fun-option b { display: block; color: var(--gold-bright); }
.os-council-choices .fun-option small { display: block; color: var(--muted); margin-top: 2px; }
.os-council-msg { min-height: 1.4em; margin: 10px 0 0; }
/* Scoped rather than a bare .warn: the corner has no such utility class (only
 * .callout.warn exists, on a different element shape), and this exact gap —
 * a class wired up in the markup with nothing behind it — is how the choice
 * buttons in #609 and the free-text box before them both shipped invisible. */
.os-council-msg.warn { color: var(--warn); }
.os-end h2 { margin: 0 0 6px; }
.os-end p { color: var(--muted); }

/* Hidage — four men to a pole. The HUD sits UNDER the map, the same rule
   Ashore and Oathsworn are built to: the shape of the claim is the entire
   information in this game, so nothing may be drawn on top of it. */
.hg-wrap { display: flex; flex-direction: column; gap: 12px; }
.hg-stage { border-radius: 10px; overflow: hidden; background: #0a0e10; border: 1px solid var(--line); }
/* touch-action none because the input IS a drag across the map; without it the
   first steer on a phone scrolls the page instead and the rider never turns. */
.hg-canvas { display: block; width: 100%; height: auto; aspect-ratio: 1 / 1; touch-action: none; cursor: crosshair; }
.hg-hud { display: flex; flex-direction: column; gap: 6px; }
.hg-stats { display: flex; flex-wrap: wrap; gap: 4px 18px; margin: 0; color: var(--muted); }
.hg-n { color: var(--ink-strong, #e9e4d8); font-variant-numeric: tabular-nums; }
/* The one number that decides the run, so it is the one number with a colour.
   Everything else on the strip is context for it. */
.hg-net.hg-good { color: #7fc98a; }
.hg-net.hg-bad { color: #d2694f; }
.hg-bar { display: block; height: 8px; border-radius: 4px; background: rgba(255,255,255,.08);
  border: 1px solid var(--line); overflow: hidden; }
.hg-fill { display: block; height: 100%; width: 0; background: var(--gold-dim, #8a7237); }
.hg-say { margin: 0; min-height: 1.4em; color: var(--gold-bright); font-size: 14.5px; }
.hg-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: 12px; }
.hg-controls p { margin: 0; color: var(--muted); font-size: 13.5px; flex-basis: 100%; }
.hg-end { margin-top: 16px; }
.hg-end h2 { margin: 0 0 6px; }
.hg-end p { color: var(--muted); }
.hg-tally { font-variant-numeric: tabular-nums; }

/* The Roommate Agreement Generator. A document, so it is set as one: the
   articles are the only place in this corner where a numbered list carries
   meaning rather than sequence, and the preamble and signature line are the
   frame that tells a reader which register they are in. */
.ra-preamble { font-style: italic; color: var(--muted); margin: 0 0 16px; }
.ra-doc { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 14px; }
.ra-clause b { display: block; color: var(--gold-bright); letter-spacing: .3px; }
.ra-clause p { margin: 4px 0 0; }
.ra-sign { margin: 18px 0 0; font-style: italic; color: var(--muted); }

/* The Takeout Night Optimiser. The TABLE is the feature — a reader has to be
   able to see the biggest total losing to a better minimum — so it gets real
   table styling rather than being squeezed into the corner's card idiom. */
.tk-who { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 14px; }
.tk-diner { text-align: left; opacity: .42; }
.tk-diner b { display: block; }
.tk-diner small { display: block; color: var(--muted); font-size: 12.5px; margin-top: 2px; }
.tk-diner.tk-in { opacity: 1; border-color: var(--gold-dim, #8a7237); }
/* OPACITY ALONE IS NOT A STATE. A dimmed button reads as disabled, not as
   "not at the table tonight", and the difference matters here because the
   whole tool is about who is in — a visitor who cannot tell at a glance is
   reading the wrong answer to the wrong question. aria-pressed already says
   it for a screen reader; this says it for everyone else. */
.tk-diner:not(.tk-in) b::after { content: " — not eating"; color: var(--muted); font-weight: 400; }
.tk-none { color: var(--muted); }
.tk-verdict { font-size: 17px; line-height: 1.6; }
.tk-table { width: 100%; border-collapse: collapse; margin: 12px 0; font-variant-numeric: tabular-nums; }
.tk-table th, .tk-table td { text-align: left; padding: 7px 10px; border-bottom: 1px solid var(--line); }
.tk-table thead th { color: var(--muted); font-weight: 600; font-size: 13px; text-transform: uppercase; letter-spacing: 1px; }
.tk-table td small { color: var(--muted); }
/* The winning row has to be findable in a six-row table at a glance, and an
   8% wash over this ground was invisible on every screen it was checked on. */
.tk-win { background: rgba(227,193,104,.15); }
.tk-win th { box-shadow: inset 3px 0 0 0 var(--gold-dim, #8a7237); }
.tk-win th, .tk-win td { color: var(--ink-strong, #e9e4d8); font-weight: 600; }
.tk-rule { color: var(--muted); font-size: 13.5px; }

/* Actual Science Trivia. The REVIEW is the product — the questions are the
   excuse — so a wrong answer is marked and then immediately explained, rather
   than being scored and left. */
.sci-day { color: var(--muted); font-size: 13px; margin: 12px 0 0; }
.sci-review { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 14px; }
.sci-item { padding-left: 10px; border-left: 3px solid var(--line); }
.sci-item.sci-ok { border-left-color: #7fc98a; }
.sci-item.sci-no { border-left-color: #d2694f; }
.sci-answer { margin: 4px 0 0; color: var(--gold-bright); }
.sci-why { margin: 4px 0 0; color: var(--muted); font-size: 14px; line-height: 1.55; }
.sci-note { color: var(--muted); font-size: 13.5px; margin-top: 14px; }

/* The First Winter. Three meters, always on screen, because the whole game is
   watching one of them fall to hold another up — a HUD that only appeared at
   the end would turn twelve trades into twelve guesses. */
.jw-hud { display: flex; flex-direction: column; gap: 6px; margin: 0 0 14px; }
.jw-meter { display: grid; grid-template-columns: minmax(78px, auto) 1fr auto; align-items: center; gap: 10px; }
.jw-meter-name { color: var(--muted); font-size: 13px; text-transform: uppercase; letter-spacing: 1px; }
.jw-meter-val { color: var(--ink-strong, #e9e4d8); font-variant-numeric: tabular-nums; min-width: 2ch; text-align: right; }
.jw-bar { display: block; height: 10px; border-radius: 5px; background: rgba(255,255,255,.08);
  border: 1px solid var(--line); overflow: hidden; }
.jw-fill { display: block; height: 100%; transition: width .2s linear; }
/* One hue each, and they are not interchangeable: grain, lamplight, and the
   one that is about you. */
.jw-stores { background: #c9a227; }
.jw-standing { background: #6f9ec4; }
.jw-self { background: #a97fb8; }
.jw-act { margin: 0 0 6px; color: var(--muted); font-size: 13px; text-transform: uppercase; letter-spacing: 1px; }
.jw-echo { margin: 12px 0 0; padding-left: 12px; border-left: 2px solid var(--line);
  color: var(--muted); font-style: italic; font-size: 14.5px; }
.jw-side { color: var(--gold-bright); }
.jw-recap { margin: 14px 0; }
.jw-recap-sum { cursor: pointer; }
.jw-recap-list { margin: 8px 0 0; padding-left: 20px; display: flex; flex-direction: column; gap: 8px;
  color: var(--muted); font-size: 14.5px; line-height: 1.55; }

/* ── COLLATERAL (The Boys wing) ─────────────────────────────────────────────
   A flight game's HUD has one hard requirement the rest of this corner does
   not: it has to be readable while the thing behind it is moving at four
   hundred metres a second. So every figure is tabular, every label is fixed
   width, and nothing in the strip reflows when a number gains a digit — a HUD
   that jumps as the speed crosses 100 is a HUD you stop reading. */
.cl-wrap { display: grid; gap: 10px; }
.cl-stage { border-radius: 10px; overflow: hidden; min-height: 300px; background: #0a1014; touch-action: none; }
.cl-hud { display: grid; grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); gap: 8px; }
.cl-stat { border: 1px solid var(--line); border-radius: 8px; padding: 7px 10px; background: rgba(0,0,0,.18); }
.cl-stat-k { display: block; font-size: 11px; letter-spacing: 1.4px; text-transform: uppercase; color: var(--muted); }
.cl-stat-v { display: block; font-family: var(--display); font-size: 19px; font-variant-numeric: tabular-nums; }
/* The one colour the HUD uses, and it means exactly one thing: you are over
   the line that costs the city something. */
.cl-hot { color: #ff6a5a; }
.cl-warn { margin: 0; padding: 7px 10px; border-radius: 8px; border-left: 3px solid #ff6a5a;
  background: rgba(255,106,90,.09); font-size: 14px; }
.cl-help { margin: 0; color: var(--muted); font-size: 13.5px; }
.cl-nogl { margin: 0; padding: 16px; border: 1px solid var(--line); border-radius: 10px; color: var(--muted); }
/* THE LEDGER IS THE TEACHING SURFACE, so it is three fixed columns rather
   than a sentence: the eye has to find the cost without reading the line. */
.cl-ledger { list-style: none; margin: 0; padding: 0; display: grid; gap: 3px; }
.cl-line { display: grid; grid-template-columns: 52px 1fr auto; gap: 8px; align-items: baseline;
  font-size: 13px; padding: 3px 0; border-bottom: 1px solid var(--line); }
.prose .cl-line { max-width: none; }
.cl-line-t { color: var(--muted); font-variant-numeric: tabular-nums; }
.cl-line-c { color: #ff6a5a; font-variant-numeric: tabular-nums; }
.cl-answer .cl-line-x { color: #6ff0c8; }
.cl-result { border: 1px solid var(--line); border-radius: 10px; padding: 14px; }
.cl-result h3 { margin: 0 0 6px; font-family: var(--display); font-size: 26px; }
.cl-result p { margin: 0 0 8px; }
.cl-grade-note { color: var(--muted); font-size: 13.5px; }
.cl-btn { min-height: 44px; padding: 0 16px; border: 1px solid var(--line); border-radius: 8px;
  background: transparent; color: inherit; font: inherit; cursor: pointer; }
.cl-btn:hover { border-color: var(--gold); }
@media (max-width: 560px) { .cl-stat-v { font-size: 17px; } }
/* The mark to beat, when somebody arrived on a shared link. Set apart from the
   HUD because it describes a DIFFERENT run — a reader who confused the two
   would think they had already flown. */
.cl-shared { border: 1px solid var(--line); border-left: 3px solid var(--gold);
  border-radius: 8px; padding: 9px 12px; font-size: 14px; }
.cl-shared strong { display: block; font-family: var(--display); }

/* ── THE SMILE (The Boys wing) ──────────────────────────────────────────────
   A press conference read from behind the face. The stage is a canvas and
   carries the dial; everything a player has to READ — the question, what he
   says, what he thinks — is page text below it, full size, because on a
   phone the stage is two hundred pixels tall and a teleprompter line drawn
   into it would be decoration nobody could read. Two lines, two treatments:
   SAYS is the teleprompter (cool glass, upright), THINKS is the inner voice
   (warm, italic, dashed), so the gap between them is visible before either
   is read. Prefix sm-. */
.sm-wrap { display: grid; gap: 10px; }
.sm-shared { border: 1px solid var(--line); border-left: 3px solid var(--gold); border-radius: 8px;
  padding: 9px 12px; font-size: 14px; }
.sm-shared strong { display: block; font-family: var(--display); }
.sm-brief { border: 1px solid var(--line); border-radius: 10px; padding: 12px 14px; display: grid; gap: 8px; }
.sm-brief p { margin: 0; }
.sm-conf { color: var(--muted); font-size: 14px; }
.sm-actions { justify-content: flex-start; margin: 0; }
.sm-best { color: var(--muted); font-size: 13.5px; }
/* pan-y, not none: a sideways drag is the analogue push, an upward one must
   still scroll the page on a phone. The script sets the same thing inline. */
.sm-stage { position: relative; border-radius: 10px; overflow: hidden; background: #0c1022; min-height: 220px;
  touch-action: pan-y; user-select: none; -webkit-user-select: none; }
.sm-stage:focus { outline: none; }
.sm-stage:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.sm-canvas { display: block; width: 100%; }
.sm-nocanvas { margin: 0; padding: 16px; color: var(--muted); }
/* Four fixed cells that never reflow as a number gains a digit. */
.sm-hud { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.sm-stat { border: 1px solid var(--line); border-radius: 8px; padding: 6px 9px; background: rgba(0,0,0,.18); min-width: 0; }
.sm-stat-k { display: block; font-size: 11px; letter-spacing: 1.2px; text-transform: uppercase; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sm-stat-v { display: block; font-family: var(--display); font-size: 18px; font-variant-numeric: tabular-nums; }
/* The question, as a lower third. A fixed minimum height so the lines under
   it do not jump every time a short question replaces a long one. */
.sm-q { border-left: 3px solid var(--gold); padding: 4px 12px; min-height: 5.2em; }
.sm-who { margin: 0; font-size: 12px; letter-spacing: 1.2px; text-transform: uppercase; color: var(--muted); }
.sm-ask { margin: 3px 0 0; font-size: 16px; line-height: 1.45; }
.sm-lines { display: grid; gap: 6px; }
.sm-says, .sm-thinks { margin: 0; display: grid; grid-template-columns: 64px 1fr; gap: 10px; align-items: baseline;
  padding: 9px 12px; border-radius: 8px; min-height: 3.2em; line-height: 1.45; }
.sm-says { background: #0a0e17; border: 1px solid rgba(160,200,255,.22); color: #eaf2ff; }
.sm-thinks { background: rgba(255,120,95,.06); border: 1px dashed rgba(255,160,140,.34); font-style: italic; }
.sm-tag { font-size: 11px; font-style: normal; letter-spacing: 1.4px; text-transform: uppercase; color: var(--muted); }
.sm-dim { color: var(--muted); }
.sm-pad { display: grid; grid-template-columns: 1fr minmax(0, 1.25fr) 1fr; gap: 8px; align-items: center; }
/* Hold-buttons: no text selection, no long-press callout, and no browser
   gesture stealing the touch mid-hold. */
.sm-push { min-height: 52px; font-size: 16px; touch-action: none; user-select: none; -webkit-user-select: none;
  -webkit-touch-callout: none; }
.sm-push.sm-on { border-color: var(--gold); background: rgba(255,174,155,.14); transform: none; }
.sm-push[disabled] { opacity: .45; cursor: default; }
.sm-state { margin: 0; text-align: center; font-size: 14px; color: var(--muted); }
.sm-state.sm-in { color: var(--ok); }
.sm-state.sm-snarl { color: #ff9a8a; }
.sm-state.sm-smirk { color: #ffd27a; }
.sm-state.sm-crack { color: #fff; font-weight: 600; }
.sm-help { margin: 0; color: var(--muted); font-size: 13.5px; }
/* The ledger is the same teaching surface as Collateral's: three columns,
   so the eye finds the cost without reading the line. */
.sm-ledger { list-style: none; margin: 0; padding: 0; display: grid; gap: 3px; }
.sm-line-row { display: grid; grid-template-columns: 52px 1fr auto; gap: 8px; align-items: baseline;
  font-size: 13px; padding: 3px 0; border-bottom: 1px solid var(--line); }
.sm-line-t { color: var(--muted); font-variant-numeric: tabular-nums; }
.sm-line-c { color: #ff6a5a; font-variant-numeric: tabular-nums; }
.sm-clean .sm-line-x { color: #6ff0c8; }
.sm-result .fun-score-of { margin-bottom: 10px; }
.sm-final { font-style: italic; margin: 0 0 8px; }
.sm-honest { color: var(--muted); font-size: 14px; max-width: 60ch; margin: 0 auto 4px; }
.sm-transcript { margin: 10px 0 0; padding-left: 22px; display: grid; gap: 14px; }
.sm-transcript p { margin: 0 0 3px; }
.sm-t-who { color: var(--muted); font-size: 12px; letter-spacing: 1.1px; text-transform: uppercase; }
.sm-t-thinks { font-style: italic; }
.sm-t-held { color: var(--muted); font-size: 13.5px; }
/* On a phone the dial, the buttons, the question and both lines have to share
   one screen (the script orders them that way and scrolls the stage to the
   top on start), so every row here is spent carefully. The HUD stays ONE row
   below them. The Says/Thinks tag runs in ahead of its line instead of
   taking a row of its own: with the tag on its own row the longest question
   and answer in the bank ran 28 px past a 360x640 screen; run in, the
   tallest card ends inside it. The buttons pair up with the spoken state
   line beneath them. */
@media (max-width: 560px) {
  .sm-hud { gap: 4px; }
  .sm-stat { padding: 5px 7px; }
  .sm-stat-k { font-size: 10px; letter-spacing: .6px; }
  .sm-stat-v { font-size: 15px; }
  .sm-says, .sm-thinks { display: block; }
  .sm-says .sm-tag, .sm-thinks .sm-tag { margin-right: 8px; }
  .sm-pad { grid-template-columns: 1fr 1fr; }
  .sm-state { grid-column: 1 / -1; grid-row: 2; }
}
@media (prefers-reduced-motion: reduce) {
  .sm-push { transition: none; }
}

/* ── THE BANNER FORGE (westeros/sigil) ───────────────────────────────────────
 *
 * The page grew from a three-choice picker into a forge: templates, six option
 * rows and four exports. Six rows of chips are a long page, and the thing a
 * visitor is doing is looking at the banner while they choose. So the preview
 * is STICKY. On a wide screen it is a left column that stays put while the
 * controls scroll beside it. On a phone it becomes a thin bar under the site
 * nav (the banner small, its name beside it) so a tap on a charge four screens
 * down still shows what it did. --fun-nav-h is set by sigil.js from the real
 * nav height, because the nav wraps onto a second row on some phones and a
 * hard-coded offset would tuck the bar under it.
 */
.fun-wrap-wide { max-width: 1080px; }
.fun-forge { display: grid; gap: 14px; }
.fun-forge-controls { min-width: 0; }
.fun-forge-view {
  position: sticky; top: calc(var(--fun-nav-h, 0px) + 6px); z-index: 6;
  display: grid; grid-template-columns: 64px 1fr; column-gap: 14px; align-items: center; text-align: left;
  padding: 8px 10px; border-radius: 12px;
  background: linear-gradient(180deg, var(--surface-2), var(--surface-1)); border: 1px solid var(--hair);
}
.fun-forge-view .fun-banner-svg { grid-row: 1 / span 2; width: 64px; margin: 0; filter: none; }
.fun-forge-view .fun-result-words { margin: 0 0 2px; font-size: 16px; align-self: end; }
.fun-forge-view .fun-result-meta { margin: 0; font-size: 13px; align-self: start; }
@media (min-width: 860px) {
  .fun-forge { grid-template-columns: minmax(250px, 330px) minmax(0, 1fr); gap: 34px; align-items: start; }
  .fun-forge-view {
    display: block; text-align: center; padding: 20px 16px 16px; top: calc(var(--fun-nav-h, 0px) + 16px);
  }
  .fun-forge-view .fun-banner-svg { width: 100%; max-width: 260px; margin: 0 auto 14px; filter: drop-shadow(0 10px 24px rgba(0,0,0,.5)); }
  .fun-forge-view .fun-result-words { font-size: 19px; margin: 0 0 6px; }
  .fun-forge-view .fun-result-meta { font-size: 14px; }
}

/* A little drawing of the choice, ahead of its name. Sized by height so the
   banner-shaped division icons keep their aspect; currentColor lets a charge
   take the chip's text colour and so the theme's. */
.fun-glyph { height: 24px; width: auto; max-width: 30px; flex: none; color: var(--text-strong); }

/* The starting templates: a live thumbnail over a name. */
.fun-tpl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 10px; margin: 0 0 12px; }
.fun-tpl {
  font: inherit; cursor: pointer; color: var(--text); font-size: 12.5px; line-height: 1.25; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 7px; padding: 10px 6px 9px; border-radius: 12px;
  background: linear-gradient(180deg, var(--surface-2), var(--surface-1)); border: 1px solid var(--hair);
  transition: border-color .15s, background .15s;
}
.fun-tpl .fun-glyph { height: 72px; max-width: 60px; }
.fun-tpl:hover { border-color: var(--frost-600); background: var(--surface-3); }
.fun-tpl.picked { border-color: var(--tone); background: var(--tone-wash); }
.fun-tpl:focus-visible { outline: 2px solid var(--frost-300); outline-offset: 2px; }
.fun-tpl-more { margin: 0 0 22px; }

/* An ink that would vanish on the current field. It stays focusable and says
   why (the click reads the reason aloud) rather than being `disabled`, which
   would hide the reason from a keyboard or a screen reader. */
.fun-swatch.unfit { opacity: .5; cursor: not-allowed; border-style: dashed; }
.fun-swatch.unfit:hover { border-color: var(--hair); background: inherit; }

.fun-export-row { display: flex; flex-wrap: wrap; gap: 10px; margin: 0 0 10px; }
.fun-export .fun-hint { margin: 0 0 8px; }
.fun-said { min-height: 1.5em; margin: 0 0 18px; font-size: 14px; color: var(--text-strong); }
