/*
 * Design tokens — "Тёмный кабинет".
 *
 * Two layers on purpose:
 *   1. Primitives (--ink-*, --parchment-*, --brass-*, …) hold the raw values.
 *   2. Semantic aliases keep every name the rest of the codebase already uses
 *      and re-point it at a primitive.
 * Nothing downstream has to change to be re-skinned, and the palette can be
 * retuned in one place.
 */

:root {
  color-scheme: dark;

  /* --- Ink -------------------------------------------------------------
   * The hue walks 20 → 27 → 32 → 25 → 31 → 36 → 31 → 30 rather than holding
   * one value, and saturation peaks at --ink-600 instead of climbing evenly.
   * Mixed ink is never a single hue at even steps; a flat ramp is the thing
   * that reads as machine-made.
   */
  --ink-1000: #0d0b0a;
  --ink-900: #17120e;
  --ink-850: #1d1712;
  --ink-800: #241b14;
  --ink-750: #2b211a;
  --ink-700: #34291f;
  --ink-600: #423424;
  --ink-500: #55432e;
  --ink-400: #6d5741;
  --ink-350: #7a6249;

  /* Text warms as it quiets, so muted copy sits back without going grey. */
  --parchment-100: #f3ece0;
  --parchment-200: #ece3d4;
  --parchment-400: #c3b7a4;
  /* Lifted once the panels went translucent: over the brightest part of the
     backdrop the old #968875 fell to 3.88:1, under the 4.5 floor. */
  --parchment-600: #a89a86;
  --parchment-700: #746a5e;

  /* --- Accents ---------------------------------------------------------
   * Four inks, each with one job. Brass is rationed: primary action and the
   * active navigation marker, nothing else, so a screen has one gold moment.
   */
  --brass-300: #d8b06a;
  --brass-400: #c2913f;
  --brass-500: #b8873f;
  --brass-600: #94682c;
  --brass-ink: #1a1208;
  --brass-tint: #2c2113;

  --oxide-400: #cc7a6c;
  --oxide-500: #7a3b32;
  --oxide-600: #52251f;
  --oxide-tint: #2a1512;

  --verdigris-400: #7fa892;
  --verdigris-500: #4e6b5f;
  --verdigris-tint: #182420;

  --slate-400: #8aa4b2;
  --slate-500: #4d6472;
  --slate-tint: #16212a;

  --plum-400: #a08ac0;
  --plum-tint: #221c2c;

  /* Paper: the one light surface, reserved for long-form writing. */
  --paper-100: #efe6d5;
  --paper-200: #e7dfd1;
  --paper-300: #ddd3c3;
  --paper-rule: #cdbfa6;
  --paper-ink: #28231f;
  /* Darkened from #6d645b: on paper-200 that sat at 3.9:1, under the 4.5
     floor, once labels and hints started being set in it. */
  --paper-ink-muted: #5c544c;

  /* --- Semantic aliases ------------------------------------------------ */
  --color-bg-primary: var(--ink-900);
  --color-bg-secondary: var(--ink-850);
  --color-surface-primary: var(--ink-800);
  --color-surface-secondary: var(--ink-750);
  --color-surface-elevated: var(--ink-700);
  --color-surface-hover: var(--ink-600);
  --color-text-primary: var(--parchment-200);
  --color-text-secondary: var(--parchment-400);
  --color-text-muted: var(--parchment-600);
  --color-border: var(--ink-600);
  --color-border-subtle: var(--ink-750);
  --color-border-control: var(--ink-350);
  --color-accent: var(--brass-500);
  --color-accent-hover: var(--brass-400);
  --color-accent-contrast: var(--brass-ink);
  --color-success: var(--verdigris-400);
  --color-warning: var(--brass-300);
  --color-warning-border: var(--brass-600);
  --color-danger: var(--oxide-400);
  --color-danger-muted: var(--oxide-tint);
  --color-info: var(--slate-400);
  --color-paper: var(--paper-200);
  --color-paper-text: var(--paper-ink);
  --color-paper-muted: var(--paper-ink-muted);
  /* Heading ink. Neutral here; the navy theme re-points it at gold. */
  --color-heading: var(--color-text-primary);

  /* Tones for the structured story blocks, replacing six loose hex values. */
  --tone-read-aloud: var(--slate-400);
  --tone-read-aloud-bg: var(--slate-tint);
  --tone-master: var(--plum-400);
  --tone-master-bg: var(--plum-tint);
  --tone-secret: var(--oxide-400);
  --tone-secret-bg: var(--oxide-tint);
  --tone-check: var(--brass-300);
  --tone-check-bg: var(--brass-tint);
  --tone-objective: var(--verdigris-400);
  --tone-objective-bg: var(--verdigris-tint);
  --tone-link: var(--slate-400);
  --tone-link-bg: var(--slate-tint);

  /* --- Type ------------------------------------------------------------
   * Alegreya and Alegreya Sans are one superfamily, so display and interface
   * share a skeleton without being the same voice. Fallbacks are metric-
   * matched in fonts.css so the swap does not shift a single line.
   */
  --font-display: 'Display', 'Display Fallback', Georgia, serif;
  --font-serif: 'Alegreya', 'Alegreya Fallback', Georgia, serif;
  --font-ui: 'Inter', 'Inter Fallback', 'Inter Fallback 2', 'Segoe UI', system-ui, sans-serif;
  --font-sc: var(--font-display);
  --font-mono: 'JetBrains Mono', 'Cascadia Code', Consolas, monospace;

  /* Steps 13/14/15/16/18/21/26/34/44/60px, hand-tuned rather than a fixed
   * ratio. 13px is the floor — nothing in the interface may set type below
   * --fs-micro. Inter's tall x-height carries these sizes comfortably. */
  --fs-micro: .8125rem;
  --fs-mini: .875rem;
  --fs-small: .9375rem;
  --fs-base: 1rem;
  --fs-lead: 1.125rem;
  --fs-h4: 1.3125rem;
  --fs-h3: 1.625rem;
  --fs-h2: 2.125rem;
  --fs-h1: 2.75rem;
  --fs-display: 3.75rem;

  --lh-micro: 1.4;
  --lh-mini: 1.45;
  --lh-small: 1.5;
  --lh-base: 1.6;
  --lh-lead: 1.6;
  --lh-h4: 1.3;
  --lh-h3: 1.24;
  --lh-h2: 1.16;
  --lh-h1: 1.08;
  --lh-display: 1.02;

  /* Inscriptional capitals want air, not the negative tracking a lowercase
   * display face takes — Display is caps, so heading tracking is positive. */
  --ls-micro: .012em;
  --ls-mini: .006em;
  --ls-caps: .05em;
  --ls-h4: .015em;
  --ls-h3: .012em;
  --ls-h2: .01em;
  --ls-h1: .008em;
  --ls-display: .006em;

  /* Oldstyle figures in running prose, tabular ones wherever numbers are
   * compared down a column. */
  --fvn-prose: oldstyle-nums proportional-nums;
  --fvn-data: lining-nums tabular-nums;

  /* --- Shape ----------------------------------------------------------- */
  --radius-sm: 2px;
  --radius-md: 3px;
  --radius-lg: 5px;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;

  /* Vertical rhythm, named by what it separates rather than by size. */
  --rhythm-tight: 10px;
  --rhythm-row: 14px;
  --rhythm-block: 22px;
  --rhythm-section: 38px;
  --rhythm-chapter: 62px;

  /* --- Edges and elevation ---------------------------------------------
   * Shadows carry a warm tint and a 1–2px horizontal offset, so the light
   * reads as coming from one place above and to the left.
   */
  --edge-top: inset 0 1px 0 rgb(236 227 212 / 5%);
  --edge-brass: inset 2px 0 0 var(--brass-500);
  --focus-ring: 0 0 0 2px var(--ink-900), 0 0 0 4px var(--brass-300);
  --focus-ring-paper: 0 0 0 2px var(--paper-200), 0 0 0 4px var(--brass-600);
  --shadow-sm: 0 1px 0 rgb(10 7 5 / 55%);
  --shadow-md: 0 6px 16px -8px rgb(10 7 5 / 70%), 0 1px 2px rgb(10 7 5 / 45%);
  --shadow-lg: 1px 14px 34px -14px rgb(10 7 5 / 78%), 0 2px 4px rgb(10 7 5 / 40%);
  --shadow-elevated: 2px 22px 56px -20px rgb(8 5 3 / 82%), 0 2px 6px rgb(8 5 3 / 45%);

  /* --- Motion ---------------------------------------------------------- */
  --duration-fast: 120ms;
  --duration-normal: 200ms;
  --duration-enter: 240ms;
  --ease-state: cubic-bezier(.32, .72, 0, 1);
  --ease-enter: cubic-bezier(.22, 1, .36, 1);
  --ease-exit: cubic-bezier(.4, 0, 1, 1);

  /* --- Texture ---------------------------------------------------------- */
  --grain-opacity: .05;
  --grain-size: 160px;

  /* --- Density -----------------------------------------------------------
   * Screens are not all the same kind of room. Editorial screens breathe,
   * workspaces sit tighter, forms hold a steady middle. The tier is stamped
   * as data-density on the content shell by AuthenticatedLayout. */
  --density-pad: var(--space-6);
  --density-gap: var(--rhythm-block);
  --density-row: 48px;

  /* --- Shell ------------------------------------------------------------ */
  --content-width: 1440px;
  --topbar-height: 68px;
  /* Inside a campaign the area's tabs run under the top bar, and the shell
     adds their height to --topbar-height so sticky panels clear both. */
  --campaign-tabs-height: 46px;
  /* The navigation pill on phones and tablets: its own height, and how far
     the dice crown stands above it. --bottom-bar-height is what everything
     else pads for: zero until the pill is on screen (see mobile.css), then
     pill, crown, the gap beneath and the device's home-indicator inset. */
  --bottom-bar-size: 64px;
  --bottom-bar-crown: 36px;
  --bottom-bar-height: 0px;

  --z-sidebar: 20;
  --z-header: 30;
  --z-topbar: 80;
  --z-dropdown: 120;
  --z-overlay: 200;
  --z-toast: 240;
}

[data-density='workspace'] {
  --density-pad: var(--space-4);
  --density-gap: var(--rhythm-row);
  --density-row: 44px;
}

[data-density='form'] {
  --density-pad: var(--space-6);
  --density-gap: var(--rhythm-tight);
  --density-row: 44px;
}

/*
 * Self-hosted webfaces. All families are SIL Open Font License 1.1;
 * the licence texts ship alongside the files in public/fonts/.
 * Regenerate with `python tools/build-fonts.py --download`.
 *
 * 'Display' is a cross-script pair under one family name: Cinzel carries the
 * Latin range, Forum the Cyrillic one — Cinzel ships no Cyrillic, and Forum is
 * its closest inscriptional companion that does. Both are used at weight 400
 * only (Forum has a single weight), so headings never depend on bold and the
 * two scripts stay optically matched.
 *
 * Cyrillic is declared before Latin in every pair because the interface
 * defaults to Russian, so the Cyrillic subset is the one on the critical path.
 */

/* Display — headings, labels, the brand voice */
@font-face {
  font-family: 'Display';
  src: url('/fonts/forum-400-cyrillic-v1.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Display';
  src: url('/fonts/cinzel-400-latin-v1.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Inter — the interface */
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-400-cyrillic-v1.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-400-latin-v1.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-500-cyrillic-v1.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-500-latin-v1.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-700-cyrillic-v1.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-700-latin-v1.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Alegreya — the paper editor's long-form voice, and the read-aloud italic.
   Cinzel has no lowercase, so it cannot carry running text; Alegreya stays. */
@font-face {
  font-family: 'Alegreya';
  src: url('/fonts/alegreya-400-cyrillic-v1.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Alegreya';
  src: url('/fonts/alegreya-400-latin-v1.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Alegreya';
  src: url('/fonts/alegreya-700-cyrillic-v1.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Alegreya';
  src: url('/fonts/alegreya-700-latin-v1.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Alegreya';
  src: url('/fonts/alegreya-400-italic-cyrillic-v1.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'Alegreya';
  src: url('/fonts/alegreya-400-italic-latin-v1.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* JetBrains Mono — codes, keys, raw values */
@font-face {
  font-family: 'JetBrains Mono';
  src: url('/fonts/jetbrains-mono-400-cyrillic-v1.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('/fonts/jetbrains-mono-400-latin-v1.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2212, U+2215, U+FEFF, U+FFFD;
}

/*
 * Metric-compatible fallbacks. `font-display: swap` means the first paint uses
 * a local face; without these the swap shifts every line. The percentages are
 * measured, not estimated — `python tools/build-fonts.py --metrics` prints them
 * from the real hhea/OS2 tables and must be re-run if a font is upgraded.
 *
 * 'Display Fallback' is tuned to Forum, because Russian is the default UI
 * language and Forum is the face the Cyrillic first paint swaps into.
 */
@font-face {
  font-family: 'Display Fallback';
  src: local('Georgia');
  size-adjust: 92.7%;
  ascent-override: 92.3%;
  descent-override: 26.7%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Inter Fallback';
  src: local('Segoe UI');
  size-adjust: 118.9%;
  ascent-override: 81.5%;
  descent-override: 20.3%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Inter Fallback 2';
  src: local('Arial');
  size-adjust: 145%;
  ascent-override: 66.8%;
  descent-override: 16.6%;
  line-gap-override: 0%;
}

@font-face {
  font-family: 'Alegreya Fallback';
  src: local('Georgia');
  size-adjust: 124.8%;
  ascent-override: 81.4%;
  descent-override: 27.6%;
  line-gap-override: 0%;
}

*, *::before, *::after { box-sizing: border-box; }
html { min-width: 320px; background: var(--color-bg-primary); }
body { margin: 0; min-width: 320px; min-height: 100vh; }
button, input, textarea, select { font: inherit; }
button { border: 0; }
img, svg { display: block; max-width: 100%; }
a { color: inherit; }
h1, h2, h3, p { margin-top: 0; }
fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
/* The landing (features/landing) applies its own reduced-motion policy —
   fades and counting figures stay, movement goes — so it is left out here. */
@media (prefers-reduced-motion: reduce) {
  :not(.landing, .landing *), :not(.landing *)::before, :not(.landing *)::after {
    scroll-behavior: auto !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  color: var(--color-text-primary);
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  font-variant-numeric: var(--fvn-prose);
  line-height: var(--lh-base);
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  color: var(--color-heading);
  font-family: var(--font-display);
  text-wrap: balance;
}

/* Display is an inscriptional-capitals pair (Cinzel for Latin, Forum for
   Cyrillic) that ships a single weight — all three levels sit at 400 and are
   distinguished by size and tracking, never by synthetic bold, so Russian and
   English headings stay optically identical. */
h1 {
  font-size: var(--fs-h1);
  font-weight: 400;
  letter-spacing: var(--ls-h1);
  line-height: var(--lh-h1);
}

h2 {
  font-size: var(--fs-h2);
  font-weight: 400;
  letter-spacing: var(--ls-h2);
  line-height: var(--lh-h2);
}

h3 {
  font-size: var(--fs-h3);
  font-weight: 400;
  letter-spacing: var(--ls-h3);
  line-height: var(--lh-h3);
}

/* Labels are set in the Display capitals at small size. Uppercase is applied
   so Cyrillic (Forum has a true lowercase) matches the caps-only Cinzel, and
   the tracking is the wide inscriptional kind, not grotesque letterspacing. */
.eyebrow {
  margin-bottom: var(--space-2);
  color: var(--color-text-muted);
  font-family: var(--font-sc);
  font-size: var(--fs-micro);
  font-weight: 400;
  letter-spacing: var(--ls-caps);
  text-transform: uppercase;
}

.caption {
  color: var(--color-text-muted);
  font-size: var(--fs-mini);
  line-height: var(--lh-mini);
}

.muted { color: var(--color-text-secondary); }

/* Figures compared down a column must line up; figures inside a sentence
   should sit on the baseline like letters. */
.tnum,
table,
.stat strong,
.ability-card,
.ability-grid,
.sheet-training-grid,
.character-facts dd,
.map-viewer__toolbar,
.invite-code code,
time,
kbd {
  font-variant-numeric: var(--fvn-data);
}

/* Russian runs roughly 15% longer than English at the same content, so the
   measure is set per language rather than once. */
[lang='ru'] .prose { max-width: 68ch; }
[lang='en'] .prose { max-width: 72ch; }

code, kbd, samp, pre { font-family: var(--font-mono); }

:root { --backdrop-gateway: image-set(url('/art/gateway-backdrop.avif') type('image/avif'), url('/art/gateway-backdrop.webp') type('image/webp')); }
@media (min-width: 1600px) { :root { --backdrop-gateway: image-set(url('/art/gateway-backdrop@2x.avif') type('image/avif'), url('/art/gateway-backdrop@2x.webp') type('image/webp')); } }
.language-switcher { display: inline-flex; align-items: center; gap: 2px; padding: 3px; border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-bg-secondary); }
.language-switcher button { min-width: 38px; min-height: 32px; padding: 0 .45rem; color: var(--color-text-muted); cursor: pointer; border-radius: 5px; background: transparent; font-size: var(--fs-micro); font-weight: 800; }
.language-switcher button:hover { color: var(--color-text-primary); }
.language-switcher button.is-active { color: var(--color-accent-contrast); background: var(--color-accent); }
.language-switcher span { display: none; }
.ui-button {
  display: inline-flex; min-height: 44px; align-items: center; justify-content: center; gap: .55rem; padding: .62rem 1rem;
  color: var(--color-text-primary); cursor: pointer; border: 1px solid transparent; border-radius: var(--radius-md);
  background: transparent; font-weight: 700; line-height: 1; text-decoration: none; transition: background var(--duration-fast), border-color var(--duration-fast), color var(--duration-fast), transform var(--duration-fast);
}
.ui-button svg { width: 18px; height: 18px; }
.ui-button:active:not(:disabled) { transform: translateY(1px); }
.ui-button:disabled { cursor: not-allowed; opacity: .48; }
.ui-button--primary { color: var(--color-accent-contrast); background: var(--color-accent); }
.ui-button--primary:hover:not(:disabled) { background: var(--color-accent-hover); }
.ui-button--compact { min-height: 36px; padding: .45rem .7rem; font-size: var(--fs-mini); }
.gateway-backdrop {
  position: absolute;
  z-index: 0;
  inset: -12px;
  background:
    radial-gradient(ellipse 60% 70% at 50% 50%, color-mix(in srgb, var(--ink-1000) 34%, transparent), color-mix(in srgb, var(--ink-1000) 14%, transparent) 60%, color-mix(in srgb, var(--ink-1000) 48%, transparent)),
    var(--backdrop-gateway) center / cover no-repeat var(--ink-1000);
  transition: transform .9s var(--ease-state);
  will-change: transform;
}
/* The ember canvas: bottom half, under everything, ignores the pointer. */
.gateway-embers { position: absolute; z-index: 0; right: 0; bottom: 0; left: 0; width: 100%; height: min(54vh, 560px); pointer-events: none; }
/* Haze under the sparks: a warm glow rising from the bottom edge, and two
   wide soft plumes drifting sideways at different speeds. Transforms only,
   so it is composited on the GPU and costs no layout or paint per frame. */
.gateway-haze { position: absolute; z-index: 0; right: 0; bottom: 0; left: 0; height: min(46vh, 480px); overflow: hidden; pointer-events: none; background: linear-gradient(to top, color-mix(in srgb, var(--brass-600) 22%, transparent), color-mix(in srgb, var(--ink-600) 30%, transparent) 40%, transparent); }
.gateway-haze::before, .gateway-haze::after { content: ''; position: absolute; bottom: -30%; width: 70%; height: 90%; border-radius: 50%; background: radial-gradient(ellipse at center, color-mix(in srgb, var(--brass-500) 16%, transparent), transparent 65%); filter: blur(30px); will-change: transform; }
.gateway-haze::before { left: -10%; animation: gateway-haze-a 38s ease-in-out infinite alternate; }
.gateway-haze::after { right: -15%; height: 75%; background: radial-gradient(ellipse at center, color-mix(in srgb, var(--brass-600) 18%, transparent), transparent 65%); animation: gateway-haze-b 47s ease-in-out infinite alternate; }
@keyframes gateway-haze-a { from { transform: translate(0, 0) scale(1); } to { transform: translate(14%, -6%) scale(1.12); } }
@keyframes gateway-haze-b { from { transform: translate(0, 0) scale(1.05); } to { transform: translate(-12%, -4%) scale(.95); } }
@media (prefers-reduced-motion: reduce) { .gateway-haze::before, .gateway-haze::after { animation: none; } }
.gate-corner { position: absolute; width: 16px; height: 16px; border: 0 solid var(--brass-400); }
.gate-corner--tl { top: -7px; left: -7px; border-width: 2px 0 0 2px; }
.gate-corner--tr { top: -7px; right: -7px; border-width: 2px 2px 0 0; }
.gate-corner--bl { bottom: -7px; left: -7px; border-width: 0 0 2px 2px; }
.gate-corner--br { right: -7px; bottom: -7px; border-width: 0 2px 2px 0; }
/*
 * The landing at '/'.
 *
 * Atmosphere first. Each part of the product is a painted scene in its own
 * light — amber scriptorium, moonlit valley, ember-red road, violet tavern —
 * and the scenes fade into one another through dark seams rather than
 * sitting on a black page. A small window of the real product is set into
 * each scene and carries a glow of that scene's light.
 *
 * Motion (landingMotion.ts): wheel scrolling glides; the hero recedes, scene
 * paintings drift and zoom out, windows tip up into place, all tied to the
 * scroll position; blocks fade up as they arrive, figures count up, windows
 * lean toward the pointer and run their own loops. One easing for
 * arrivals, nothing bounces. Under reduced motion the gentle tier at the
 * end of this file keeps fades and figures and drops all movement.
 */

html:has(.landing) { scroll-behavior: smooth; }

.landing {
  --landing-width: 1200px;
  --landing-gutter: clamp(16px, 4vw, 48px);
  --landing-header: 64px;
  --landing-ease: cubic-bezier(.16, 1, .3, 1);
  position: relative;
  min-height: 100dvh;
  overflow-x: clip;
  color: var(--color-text-primary);
  background: var(--ink-1000);
}
.landing [id] { scroll-margin-top: var(--landing-header); }
.landing-container { width: min(100% - 2 * var(--landing-gutter), var(--landing-width)); margin-inline: auto; }
.landing-sentinel { height: 1px; margin-top: -1px; }

/* --- Reveal ------------------------------------------------------------------ */
.landing--armed [data-reveal] {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 1s var(--landing-ease), transform 1.1s var(--landing-ease);
  transition-delay: calc(var(--i, 0) * 90ms);
}
.landing--armed [data-reveal].is-revealed { opacity: 1; transform: none; }
/* The window's movement belongs to the scroll (useScrollScene); here it only
   fades. */
.landing--armed .landing-scene__window[data-reveal] { transform: none; transition-duration: 1.4s; transition-delay: .1s; }
.landing--armed .landing-chips [data-reveal] { transform: translateY(14px) scale(.96); transition-delay: calc(.25s + var(--i, 0) * 70ms); }

@keyframes landing-fade { from { opacity: 0; } }

/* --- Header ---------------------------------------------------------------- */
.landing-header { position: fixed; z-index: var(--z-topbar); top: 0; right: 0; left: 0; border-bottom: 1px solid transparent; transition: background .4s, border-color .4s, backdrop-filter .4s; }
.landing-header.is-scrolled { border-bottom-color: color-mix(in srgb, var(--parchment-100) 8%, transparent); background: color-mix(in srgb, var(--ink-1000) 78%, transparent); backdrop-filter: blur(14px); }
.landing-header__inner { display: flex; width: min(100% - 2 * var(--landing-gutter), var(--landing-width)); height: var(--landing-header); align-items: center; gap: 28px; margin-inline: auto; }
.landing-brand { display: inline-flex; align-items: center; gap: 10px; color: var(--brass-400); text-decoration: none; }
.landing-brand span { color: var(--parchment-100); font-family: var(--font-display); font-size: var(--fs-lead); letter-spacing: .1em; text-transform: uppercase; }
.landing-nav { display: flex; gap: 24px; }
.landing-nav a { color: var(--parchment-400); font-size: var(--fs-mini); text-decoration: none; transition: color var(--duration-normal); }
.landing-nav a:hover { color: var(--parchment-100); }
.landing-header__actions { display: flex; align-items: center; gap: 16px; margin-left: auto; }
.landing-header .language-switcher { background: color-mix(in srgb, var(--ink-1000) 50%, transparent); }
.landing-signin { color: var(--parchment-100); font-size: var(--fs-mini); text-decoration: none; }
.landing-signin:hover { color: var(--brass-300); }
.landing-header .ui-button { white-space: nowrap; text-decoration: none; }

/* --- Hero ------------------------------------------------------------------ */
.landing-hero {
  position: relative;
  display: grid;
  min-height: min(100svh, 940px);
  align-items: center;
  padding: calc(var(--landing-header) + 40px) var(--landing-gutter) 96px;
  overflow: hidden;
  isolation: isolate;
}
.landing-hero__depth { position: absolute; z-index: 0; inset: 0; will-change: transform; }
.landing-hero .landing-hero__backdrop {
  background:
    linear-gradient(to bottom, transparent 55%, var(--ink-1000)),
    linear-gradient(to right, color-mix(in srgb, var(--ink-1000) 78%, transparent), color-mix(in srgb, var(--ink-1000) 20%, transparent) 62%, transparent),
    var(--backdrop-gateway) 70% center / cover no-repeat var(--ink-1000);
  animation: landing-breathe 30s ease-in-out infinite alternate;
}
@keyframes landing-breathe { from { scale: 1; } to { scale: 1.06; } }
/* Over the embers' haze too, so the hero ends in the same ink the first
   scene begins in instead of a lit edge. */
.landing-hero::after { content: ''; position: absolute; z-index: 0; right: 0; bottom: 0; left: 0; height: 180px; background: linear-gradient(transparent, var(--ink-1000)); pointer-events: none; }
.landing-hero__content { position: relative; z-index: 1; width: min(100%, var(--landing-width)); margin-inline: auto; will-change: transform, opacity; }
.landing-hero__content > * { animation: landing-arrive 1.3s var(--landing-ease) both; animation-delay: .1s; }
.landing-hero__content > :nth-child(2) { animation-delay: .25s; }
.landing-hero__content > :nth-child(3) { animation-delay: .4s; }
@keyframes landing-arrive { from { opacity: 0; transform: translateY(18px); } }
.landing-hero h1 { max-width: 14ch; margin: 0 0 24px; color: var(--parchment-100); font-size: clamp(2.6rem, 6vw, 4.75rem); line-height: 1.04; }
.landing-hero__lead { max-width: 34em; margin: 0 0 34px; color: var(--parchment-200); font-family: var(--font-serif); font-size: clamp(var(--fs-lead), 1.7vw, 1.3125rem); line-height: 1.55; }
.landing-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 14px 28px; }
.landing-cta { min-height: 48px; padding-inline: 24px; font-size: var(--fs-base); text-decoration: none; }
.landing-textlink { color: var(--parchment-100); font-size: var(--fs-base); text-decoration: underline; text-decoration-color: var(--brass-600); text-decoration-thickness: 1px; text-underline-offset: 5px; transition: color var(--duration-normal), text-decoration-color var(--duration-normal); }
.landing-textlink:hover { color: var(--brass-300); text-decoration-color: var(--brass-300); }

/* --- What it is: one line and four figures that count up ------------------ */
.landing-intro { position: relative; padding-block: clamp(72px, 9vw, 120px) clamp(40px, 5vw, 64px); text-align: center; background: radial-gradient(50% 60% at 50% 40%, color-mix(in srgb, var(--brass-600) 12%, transparent), transparent), var(--ink-1000); }
.landing-intro__label { margin: 0 0 16px; color: var(--brass-300); font-family: var(--font-display); font-size: var(--fs-small); letter-spacing: .16em; text-transform: uppercase; }
.landing-intro h2 { max-width: 22ch; margin: 0 auto clamp(48px, 6vw, 72px); color: var(--parchment-100); font-size: clamp(1.9rem, 3.6vw, 3rem); line-height: 1.12; text-wrap: balance; }
.landing-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); margin: 0; }
.landing-stat { padding: 8px 16px; border-left: 1px solid color-mix(in srgb, var(--brass-600) 40%, transparent); }
.landing-stat:first-child { border-left: 0; }
.landing-stat dt { color: var(--brass-300); font-family: var(--font-display); font-size: clamp(2.6rem, 5.2vw, 4.25rem); font-variant-numeric: var(--fvn-data); line-height: 1; text-shadow: 0 0 40px color-mix(in srgb, var(--brass-500) 45%, transparent); }
.landing-stat dd { margin: 10px 0 0; color: var(--parchment-400); font-size: var(--fs-small); }

/* --- Scenes ------------------------------------------------------------------ */
.landing-scene--chapters { --tint: var(--brass-400); --scene: url('/art/landing/scene-chapters.jpg'); --focus: 70% 50%; }
.landing-scene--world { --tint: var(--slate-400); --scene: url('/art/landing/scene-world.jpg'); --focus: 70% 40%; }
.landing-scene--session { --tint: var(--oxide-400); --scene: url('/art/landing/scene-session.jpg'); --focus: 65% 50%; }
.landing-scene--players { --tint: var(--plum-400); --scene: url('/art/landing/scene-players.jpg'); --focus: 60% 50%; }

.landing-scene {
  position: relative;
  padding-block: clamp(120px, 15vw, 210px) clamp(80px, 9vw, 130px);
  overflow: hidden;
  isolation: isolate;
}
/* Oversized so the parallax drift never shows an edge. */
.landing-scene__art { position: absolute; z-index: -2; inset: -12% 0; background: var(--scene) var(--focus) / cover no-repeat var(--ink-1000); transform: scale(1.18); will-change: transform; }
/* Dark seams top and bottom so neighbouring scenes fade through each other,
   the text side held down, and a pool of the scene's light behind the window. */
.landing-scene__shade {
  position: absolute;
  z-index: -1;
  inset: 0;
  background:
    linear-gradient(to bottom, var(--ink-1000) 0%, transparent 24%, transparent 72%, var(--ink-1000) 100%),
    linear-gradient(to right, color-mix(in srgb, var(--ink-1000) 84%, transparent) 0%, color-mix(in srgb, var(--ink-1000) 52%, transparent) 46%, color-mix(in srgb, var(--ink-1000) 30%, transparent) 100%),
    radial-gradient(50% 55% at 72% 52%, color-mix(in srgb, var(--tint) 16%, transparent), transparent 70%);
}
.landing-scene__inner { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); align-items: center; gap: clamp(36px, 5vw, 80px); }
.landing-scene__label { display: flex; align-items: center; gap: 12px; margin: 0 0 16px; color: color-mix(in srgb, var(--tint) 75%, var(--parchment-100)); font-family: var(--font-display); font-size: var(--fs-small); letter-spacing: .14em; text-transform: uppercase; }
.landing-scene__label::before { content: ''; width: 28px; height: 1px; background: currentColor; transition: width 1.2s var(--landing-ease) .2s; }
.landing--armed .landing-scene__label[data-reveal]:not(.is-revealed)::before { width: 0; }
.landing-scene h2 { margin: 0 0 20px; color: var(--parchment-100); font-size: clamp(2rem, 3.8vw, 3.1rem); line-height: 1.08; text-wrap: balance; text-shadow: 0 2px 24px color-mix(in srgb, var(--ink-1000) 70%, transparent); }
.landing-scene__copy { max-width: 30em; margin: 0 0 30px; color: var(--parchment-200); font-family: var(--font-serif); font-size: var(--fs-lead); line-height: 1.6; }
.landing-scene__cta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 46px;
  padding: 0 20px;
  color: var(--parchment-100);
  border: 1px solid color-mix(in srgb, var(--tint) 55%, transparent);
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--tint) 16%, color-mix(in srgb, var(--ink-1000) 70%, transparent));
  font-size: var(--fs-small);
  font-weight: 600;
  text-decoration: none;
  transition: background .4s var(--landing-ease), border-color .4s, box-shadow .6s var(--landing-ease);
}
.landing-scene__cta svg { width: 17px; height: 17px; transition: transform .4s var(--landing-ease); }
.landing-scene__cta:hover { border-color: var(--tint); background: color-mix(in srgb, var(--tint) 28%, var(--ink-1000)); box-shadow: 0 0 32px -6px color-mix(in srgb, var(--tint) 55%, transparent); }
.landing-scene__cta:hover svg { transform: translateX(4px); }

/* Chips: what else lives here, and one line that is not entirely serious. */
.landing-chips { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 12px; margin-top: clamp(48px, 6vw, 80px); margin-bottom: 0; padding: 0; list-style: none; }
.landing-chips li { display: inline-flex; align-items: center; gap: 8px; padding: 8px 15px; color: var(--parchment-200); border: 1px solid color-mix(in srgb, var(--tint) 28%, transparent); border-radius: 999px; background: color-mix(in srgb, var(--ink-1000) 55%, transparent); backdrop-filter: blur(6px); font-size: var(--fs-mini); }
.landing-chips svg { width: 15px; height: 15px; color: var(--tint); }
.landing-chips li { transition: opacity 1s var(--landing-ease), transform .9s var(--landing-ease), border-color .4s, background .4s; }
.landing-chips li:hover { border-color: color-mix(in srgb, var(--tint) 70%, transparent); background: color-mix(in srgb, var(--tint) 14%, var(--ink-1000)); transform: translateY(-3px); }
.landing-chips li.is-joke { color: var(--parchment-100); font-family: var(--font-serif); font-style: italic; }

/* --- Product window ---------------------------------------------------------- */
.landing-window-stage { perspective: 1400px; transform-origin: 50% 100%; will-change: transform; }
.landing-window {
  position: relative;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--tint) 34%, var(--ink-600));
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--ink-900) 94%, transparent);
  box-shadow:
    0 40px 90px -40px var(--ink-1000),
    0 0 70px -24px color-mix(in srgb, var(--tint) 50%, transparent),
    inset 0 1px 0 color-mix(in srgb, var(--parchment-100) 7%, transparent);
  font-size: var(--fs-mini);
  transform: rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg));
  transition: transform .9s var(--landing-ease);
}
/* A spot of the scene's light where the pointer is. */
.landing-window::after { content: ''; position: absolute; inset: 0; background: radial-gradient(380px circle at var(--light-x, 50%) var(--light-y, 0%), color-mix(in srgb, var(--tint) 16%, transparent), transparent 65%); opacity: 0; pointer-events: none; transition: opacity .6s; }
.landing-window.is-lit::after { opacity: 1; }
.landing-window__bar { display: flex; align-items: center; gap: 10px; padding: 10px 16px; overflow: hidden; color: var(--color-text-muted); border-bottom: 1px solid var(--ink-700); background: var(--ink-1000); font-size: var(--fs-micro); letter-spacing: .04em; text-overflow: ellipsis; white-space: nowrap; }
.landing-window__mark { width: 8px; height: 8px; flex: 0 0 auto; background: var(--tint); transform: rotate(45deg); }

/* Chapters: scenes with the plan / ready / played switch. */
.window-chapters__head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; padding: 14px 18px 12px; }
.window-chapters__head strong { color: var(--parchment-100); font-family: var(--font-display); font-size: var(--fs-h4); font-weight: 400; }
.window-modes { display: inline-flex; padding: 3px; border: 1px solid var(--ink-600); border-radius: var(--radius-md); background: var(--ink-1000); }
.window-modes span { display: inline-flex; align-items: center; gap: 5px; padding: 5px 10px; color: var(--color-text-secondary); border-radius: var(--radius-sm); font-size: var(--fs-micro); font-weight: 600; }
.window-modes svg { width: 13px; height: 13px; }
.window-modes .is-active { color: var(--brass-ink); background: var(--brass-500); }
.window-chapters__scenes { display: grid; gap: 10px; padding: 2px 18px 16px; }
.window-scene { padding: 12px 14px; border: 1px solid var(--ink-600); border-left: 3px solid var(--slate-400); border-radius: var(--radius-sm); background: var(--ink-850); }
.window-scene header { display: flex; align-items: center; gap: 10px; }
.window-scene__number { color: var(--brass-400); font-family: var(--font-mono); font-size: var(--fs-micro); }
.window-scene header strong { min-width: 0; overflow: hidden; color: var(--parchment-100); font-family: var(--font-display); font-size: var(--fs-base); font-weight: 400; text-overflow: ellipsis; white-space: nowrap; }
.window-status { position: relative; display: inline-grid; flex: 0 0 auto; grid-auto-columns: 1fr; grid-auto-flow: column; margin-left: auto; padding: 2px; border-radius: 999px; background: var(--ink-1000); font-size: var(--fs-micro); }
.window-status > i { position: absolute; top: 2px; bottom: 2px; left: calc(2px + var(--at) * (100% - 4px) / 3); width: calc((100% - 4px) / 3); border-radius: 999px; background: var(--ink-500); transition: left .6s var(--landing-ease), background .6s; }
.window-status[data-status='played'] > i { background: var(--verdigris-500); }
.window-status > span { position: relative; padding: 3px 9px; color: var(--color-text-muted); text-align: center; transition: color .4s; }
.window-status > span.is-active { color: var(--parchment-100); font-weight: 600; }
.window-scene__meta { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 8px 0 6px; color: var(--color-text-secondary); font-size: var(--fs-micro); }
.window-scene__meta span { display: inline-flex; align-items: center; gap: 5px; }
.window-scene__meta svg { width: 12px; height: 12px; }
.window-scene__text { margin: 0; color: var(--parchment-200); font-family: var(--font-serif); font-size: var(--fs-small); line-height: 1.6; }
.window-readiness { display: grid; gap: 8px; padding: 12px 18px 14px; border-top: 1px solid var(--ink-700); }
.window-readiness > span:first-child { color: var(--color-text-muted); font-family: var(--font-display); font-size: var(--fs-micro); letter-spacing: .08em; text-transform: uppercase; }
.window-readiness__bar { display: flex; height: 5px; overflow: hidden; border-radius: 3px; background: var(--ink-700); }
.window-readiness__bar i { transition: width .8s var(--landing-ease); }
.window-readiness__bar .is-played { background: var(--verdigris-400); }
.window-readiness__bar .is-ready { background: var(--slate-400); }
.window-readiness__counts { display: flex; gap: 14px; color: var(--color-text-secondary); font-size: var(--fs-micro); }
.window-readiness__counts span { display: inline-flex; align-items: center; gap: 5px; }
.window-readiness__counts span::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--ink-500); }
.window-readiness__counts .is-played::before { background: var(--verdigris-400); }
.window-readiness__counts .is-ready::before { background: var(--slate-400); }
.window-readiness__counts b { color: var(--parchment-100); }

/* World: a crop of a real atlas render, drifting slowly. */
.window-world__view { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--ink-1000); }
.window-world__view img { position: absolute; top: -30%; left: -32%; width: 165%; max-width: none; height: auto; animation: landing-pan 30s ease-in-out infinite alternate; }
@keyframes landing-pan { to { transform: translate(-5%, 3%) scale(1.07); } }
.window-world__tools { position: absolute; top: 12px; right: 12px; display: flex; align-items: center; gap: 2px; padding: 3px; border: 1px solid var(--ink-600); border-radius: var(--radius-md); background: color-mix(in srgb, var(--ink-1000) 82%, transparent); font-size: var(--fs-micro); }
.window-world__tools span { display: inline-flex; align-items: center; gap: 5px; padding: 5px 10px; color: var(--color-text-secondary); border-radius: var(--radius-sm); }
.window-world__tools .is-active { color: var(--brass-300); background: var(--brass-tint); }
.window-world__tools svg { width: 13px; height: 13px; }
.window-world__tools .window-world__icon { margin: 0 8px 0 6px; color: var(--color-text-secondary); }

/* Session: the initiative order stepping through turns. */
.window-session__head { display: flex; align-items: center; gap: 10px; padding: 14px 16px 12px; }
.window-session__round { display: grid; min-width: 58px; place-items: center; padding: 4px 10px; border: 1px solid var(--ink-500); border-radius: var(--radius-sm); }
.window-session__round small { color: var(--color-text-muted); font-family: var(--font-display); font-size: var(--fs-micro); letter-spacing: .08em; text-transform: uppercase; }
.window-session__round b { color: var(--brass-300); font-family: var(--font-display); font-size: var(--fs-h4); font-weight: 400; line-height: 1.1; animation: landing-arrive .6s var(--landing-ease) both; }
.window-session__add { display: grid; width: 36px; height: 36px; place-items: center; color: var(--parchment-200); border: 1px solid var(--ink-600); border-radius: var(--radius-sm); }
.window-session__add svg { width: 16px; height: 16px; }
.window-session__next { margin-left: auto; padding: 8px 14px; color: var(--brass-ink); border-radius: var(--radius-sm); background: var(--brass-500); font-size: var(--fs-micro); font-weight: 700; }
.window-session__list { display: grid; gap: 6px; margin: 0; padding: 0 12px 12px; list-style: none; }
.window-session__list li { display: grid; grid-template-columns: 38px minmax(0, 1fr) 30px minmax(90px, 30%); align-items: center; gap: 12px; padding: 8px 10px; border: 1px solid var(--ink-700); border-radius: var(--radius-sm); background: var(--ink-850); transition: border-color .5s var(--landing-ease), background .5s var(--landing-ease), opacity .5s; }
.window-session__list li.is-acting { border-color: var(--brass-500); background: var(--brass-tint); }
.window-session__list li.is-down { opacity: .45; }
.window-session__initiative { display: grid; height: 36px; place-items: center; color: var(--parchment-100); border: 1px solid var(--ink-500); font-family: var(--font-display); font-size: var(--fs-h4); transition: background .5s, color .5s, border-color .5s; }
.is-acting .window-session__initiative { color: var(--brass-ink); border-color: var(--brass-400); background: var(--brass-400); }
.window-session__name { display: grid; min-width: 0; overflow: hidden; color: var(--parchment-100); font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.window-session__name small { color: var(--brass-300); font-size: var(--fs-micro); font-weight: 500; }
.window-session__armour { display: grid; height: 32px; place-items: center; color: var(--parchment-200); border: 1.5px solid var(--parchment-700); border-radius: 6px 6px 50% 50% / 6px 6px 60% 60%; font-size: var(--fs-micro); }
.window-session__hp { display: grid; gap: 5px; color: var(--color-text-secondary); font-size: var(--fs-micro); }
.window-session__hp b { color: var(--parchment-100); font-family: var(--font-display); font-size: var(--fs-base); font-weight: 400; }
.window-session__hp > i { display: block; height: 5px; overflow: hidden; border-radius: 3px; background: var(--ink-700); }
.window-session__hp > i > i { display: block; height: 100%; background: var(--verdigris-400); transition: width .9s var(--landing-ease); }
.window-session__roll { display: flex; align-items: center; gap: 8px; margin: 0 12px 12px; padding: 10px 12px; color: var(--color-text-secondary); border: 1px dashed var(--ink-500); border-radius: var(--radius-sm); font-size: var(--fs-micro); }
.window-session__roll svg { width: 16px; height: 16px; color: var(--brass-400); }
.window-session__roll b { min-width: 2ch; margin-left: auto; color: var(--parchment-600); font-family: var(--font-display); font-size: var(--fs-h4); font-weight: 400; font-variant-numeric: var(--fvn-data); text-align: right; }
.window-session__roll b.is-settled { color: var(--parchment-100); animation: landing-settle .5s var(--landing-ease); }
.window-session__roll > svg { animation: landing-spin .45s var(--landing-ease); }
@keyframes landing-settle { from { transform: scale(1.35); color: var(--brass-300); } }
@keyframes landing-spin { from { transform: rotate(-200deg); } }

/* Players: what the party sees, with things arriving as the GM reveals them. */
.window-players__presence { display: flex; align-items: center; gap: 10px; padding: 12px 16px; color: var(--color-text-secondary); border-bottom: 1px solid var(--ink-700); font-size: var(--fs-micro); }
.window-players__avatars { display: flex; }
.window-players__avatars span { position: relative; display: grid; width: 28px; height: 28px; margin-left: -7px; place-items: center; color: var(--parchment-100); border: 2px solid var(--ink-900); border-radius: 50%; background: var(--ink-600); font-weight: 700; }
.window-players__avatars span:first-child { margin-left: 0; }
.window-players__avatars span::after { content: ''; position: absolute; right: -2px; bottom: -2px; width: 8px; height: 8px; border: 2px solid var(--ink-900); border-radius: 50%; background: var(--verdigris-400); }
.window-players__body { display: grid; gap: 12px; padding: 14px; }
.window-players__page { padding: 16px 18px; color: var(--paper-ink); border-radius: var(--radius-sm); background: var(--paper-200); }
.window-players__page strong { color: var(--paper-ink); font-family: var(--font-display); font-size: var(--fs-h4); font-weight: 400; }
.window-players__page p { margin: 6px 0 0; color: var(--paper-ink); font-family: var(--font-serif); font-size: var(--fs-small); line-height: 1.6; }
.window-players__feed { display: grid; gap: 8px; min-height: 132px; align-content: start; }
.window-card { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border: 1px solid var(--ink-600); border-radius: var(--radius-sm); background: var(--ink-800); opacity: 0; transform: translateY(12px); transition: opacity .7s var(--landing-ease), transform .7s var(--landing-ease); }
.window-card.is-shown { opacity: 1; transform: none; }
.window-card > span:last-child { display: grid; gap: 2px; }
.window-card strong { color: var(--parchment-100); }
.window-card small { color: var(--color-text-muted); font-size: var(--fs-micro); }
.window-card em { color: var(--parchment-200); font-family: var(--font-serif); }
.window-card--handout { border-color: var(--brass-600); background: linear-gradient(110deg, var(--brass-tint), var(--ink-800)); }
.window-card__seal, .window-card__icon { display: grid; width: 34px; height: 34px; flex: 0 0 auto; place-items: center; border-radius: 50%; }
.window-card__seal { color: var(--parchment-100); background: var(--oxide-500); }
.window-card__icon { color: var(--plum-400); background: var(--plum-tint); }
.window-card svg { width: 16px; height: 16px; }

/* --- Audience and questions: a warm room, not a black page ------------------ */
.landing-section { padding-block: clamp(72px, 9vw, 120px); }
/* Glows kept clear of the section edges, so the seams to the scene above
   and the questions below stay invisible. */
.landing-audience { background: radial-gradient(40% 38% at 22% 52%, color-mix(in srgb, var(--brass-600) 14%, transparent), transparent), var(--ink-1000); }
.landing-heading { margin: 0 0 clamp(36px, 5vw, 56px); color: var(--parchment-100); font-size: clamp(var(--fs-h3), 3.4vw, var(--fs-h2)); line-height: var(--lh-h2); }
.landing-audience__list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(20px, 3vw, 40px); margin: 0; padding: 0; list-style: none; }
.landing-audience__list li { padding: 28px 26px 30px; border: 1px solid color-mix(in srgb, var(--brass-600) 35%, transparent); border-radius: var(--radius-lg); background: color-mix(in srgb, var(--ink-900) 70%, transparent); transition: border-color .5s var(--landing-ease), transform .6s var(--landing-ease); }
.landing-audience__list li:hover { border-color: var(--brass-500); transform: translateY(-4px); }
.landing-audience__list svg { width: 26px; height: 26px; margin-bottom: 18px; color: var(--brass-400); }
.landing-audience__list h3 { margin: 0 0 8px; color: var(--parchment-100); font-size: var(--fs-h4); }
.landing-audience__list p { margin: 0; color: var(--parchment-400); font-family: var(--font-serif); font-size: var(--fs-lead); line-height: 1.55; }

.landing-section--faq { padding-top: 0; background: radial-gradient(36% 40% at 80% 48%, color-mix(in srgb, var(--slate-400) 8%, transparent), transparent), var(--ink-1000); }
.landing-faq { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 7fr); gap: 0 clamp(32px, 6vw, 88px); align-items: start; }
.landing-faq .landing-heading { margin: 0; }
.landing-faq__list { border-top: 1px solid var(--color-border); }
.landing-faq details { border-bottom: 1px solid var(--color-border-subtle); }
.landing-faq summary { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 18px 0; color: var(--parchment-100); cursor: pointer; font-size: var(--fs-lead); list-style: none; transition: color var(--duration-normal); }
.landing-faq summary::-webkit-details-marker { display: none; }
.landing-faq summary:hover { color: var(--brass-300); }
.landing-faq summary svg { width: 18px; height: 18px; flex: 0 0 auto; color: var(--parchment-700); transition: transform .5s var(--landing-ease); }
.landing-faq details[open] summary svg { transform: rotate(180deg); }
.landing-faq details p { margin: 0; padding: 0 40px 20px 0; color: var(--parchment-400); font-family: var(--font-serif); font-size: var(--fs-lead); line-height: 1.6; animation: landing-arrive .5s var(--landing-ease) both; }

/* --- Final call: the gateway's framed plate, on the desk painting --------- */
.landing-final {
  display: grid;
  place-items: center;
  padding: clamp(110px, 13vw, 180px) var(--landing-gutter);
  background:
    linear-gradient(to bottom, var(--ink-1000), transparent 30%, transparent 70%, var(--ink-1000)),
    linear-gradient(color-mix(in srgb, var(--ink-1000) 30%, transparent), color-mix(in srgb, var(--ink-1000) 30%, transparent)),
    url('/art/landing/gm-desk.jpg') center / cover no-repeat var(--ink-1000);
}
.landing-final__panel { position: relative; width: min(100%, 560px); padding: 44px clamp(20px, 5vw, 48px) 40px; text-align: center; border: 1px solid var(--brass-600); outline: 1px solid color-mix(in srgb, var(--brass-600) 45%, transparent); outline-offset: 5px; background: color-mix(in srgb, var(--ink-900) 94%, transparent); box-shadow: var(--shadow-elevated), 0 0 80px -20px color-mix(in srgb, var(--brass-500) 35%, transparent); }
.landing-final h2 { margin: 0 0 10px; color: var(--parchment-100); font-size: clamp(var(--fs-h3), 3vw, var(--fs-h2)); }
.landing-final p { margin: 0 0 28px; color: var(--parchment-400); font-family: var(--font-serif); font-size: var(--fs-lead); }
.landing-final .landing-actions { justify-content: center; }

/* --- Footer ------------------------------------------------------------------ */
.landing-footer { border-top: 1px solid var(--color-border-subtle); background: var(--ink-1000); }
.landing-footer__inner { display: grid; grid-template-columns: auto auto 1fr; align-items: start; gap: 32px 56px; padding-block: 40px; }
.landing-footer__brand { display: flex; align-items: flex-start; gap: 12px; color: var(--brass-400); }
.landing-footer__brand div { display: grid; gap: 2px; }
.landing-footer__brand strong { color: var(--parchment-100); font-family: var(--font-display); letter-spacing: .1em; text-transform: uppercase; }
.landing-footer__brand span { color: var(--color-text-muted); font-size: var(--fs-micro); }
.landing-footer__links { display: grid; gap: 8px; }
.landing-footer__links a { color: var(--color-text-secondary); font-size: var(--fs-mini); text-decoration: none; }
.landing-footer__links a:hover { color: var(--brass-300); }
.landing-footer__meta { display: grid; justify-items: end; gap: 6px; color: var(--color-text-muted); font-size: var(--fs-micro); text-align: right; }
.landing-footer__meta .gateway-status { justify-self: inherit; }

/* --- Narrow screens ----------------------------------------------------------- */
@media (max-width: 1020px) {
  .landing-nav { display: none; }
  .landing-scene__inner { grid-template-columns: minmax(0, 1fr); }
  .landing-scene__window { max-width: 680px; }
  .landing-scene__shade { background: linear-gradient(to bottom, var(--ink-1000) 0%, color-mix(in srgb, var(--ink-1000) 55%, transparent) 20%, color-mix(in srgb, var(--ink-1000) 55%, transparent) 75%, var(--ink-1000) 100%); }
  .landing-chips { justify-content: flex-start; }
  .landing-audience__list { grid-template-columns: 1fr; }
  .landing-faq { grid-template-columns: 1fr; }
  .landing-faq .landing-heading { margin-bottom: 24px; }
  .landing-footer__inner { grid-template-columns: 1fr 1fr; }
  .landing-footer__meta { grid-column: 1 / -1; justify-items: start; text-align: left; }
  .landing-footer__meta .gateway-status { justify-self: start; }
}
@media (max-width: 640px) {
  .landing { --landing-header: 58px; }
  .landing-brand span, .landing-header .language-switcher { display: none; }
  .landing-header__actions { gap: 12px; }
  .landing-hero { align-items: end; padding-bottom: 64px; }
  .landing-scene { padding-top: 96px; }
  .landing-chips li { padding: 7px 12px; font-size: var(--fs-micro); }
  .landing-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 32px; }
  .landing-stat:nth-child(3) { border-left: 0; }
  .window-modes span:not(.is-active) { display: none; }
  .window-scene header { flex-wrap: wrap; }
  .window-status { margin-left: 0; }
  .window-session__list li { grid-template-columns: 34px minmax(0, 1fr) 72px; }
  .window-session__armour { display: none; }
  .landing-footer__inner { grid-template-columns: 1fr; }
}

/* --- Gentle tier: reduced motion asked for ----------------------------------
   Nothing travels, zooms, tilts or spins; fades, counting figures and the
   windows' state changes stay. reset.css leaves the landing to this block. */
@media (prefers-reduced-motion: reduce) {
  html:has(.landing) { scroll-behavior: auto; }
  .landing--armed [data-reveal], .landing--armed .landing-chips [data-reveal] { transform: none; }
  .landing-hero__content > * { animation-name: landing-fade; }
  .landing-hero .landing-hero__backdrop, .window-world__view img, .window-session__roll > svg { animation: none; }
  .window-session__roll b.is-settled, .window-session__round b { animation-name: landing-fade; }
  .window-card { transform: none; }
  .landing-chips li:hover, .landing-audience__list li:hover { transform: none; }
  .landing-window { transform: none; }
}

/* Standalone launch page additions. */
:focus-visible { outline: 2px solid var(--brass-300); outline-offset: 5px; }
.skip-link { position: fixed; z-index: 200; top: 8px; left: 16px; padding: 12px 18px; color: var(--brass-ink); background: var(--brass-300); transform: translateY(-160%); }
.skip-link:focus { transform: none; }
.launch-eyebrow { margin: 0 0 20px; color: var(--brass-300); font-size: var(--fs-micro); letter-spacing: .13em; text-transform: uppercase; }
.launch-status { display: inline-flex; align-items: center; gap: 8px; color: var(--brass-300); }
.launch-status::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.landing-hero__content > :nth-child(4) { animation-delay: .5s; }
.landing-final__panel { max-width: 780px; }
.landing-final p { max-width: 52ch; margin-inline: auto; }
@media (max-width: 640px) {
  .landing-header .language-switcher { display: inline-flex; }
  .landing-header__inner { gap: 12px; }
  .landing-header__actions { gap: 10px; }
  .language-switcher button { min-width: 34px; min-height: 36px; }
  .landing-header .ui-button { min-height: 42px; }
  .landing-hero { min-height: max(650px, 92svh); }
}
