/* ═══════════════════════════════════════════════════════════
   HELHEIMRS — Design tokens
   Dark ("Helheim") is the default. Frost is the light mode.
   Every text pair below is checked against its real surface; the ratios in
   the comments are measured (WCAG 2.x relative luminance), not estimated.
   ═══════════════════════════════════════════════════════════ */

@font-face { font-family: 'Estedad'; src: url('../assets/fonts/Estedad-Bold.woff2') format('woff2'); font-weight: 700; font-display: swap; }
@font-face { font-family: 'Estedad'; src: url('../assets/fonts/Estedad-ExtraBold.woff2') format('woff2'); font-weight: 800; font-display: swap; }
@font-face { font-family: 'Estedad'; src: url('../assets/fonts/Estedad-Black.woff2') format('woff2'); font-weight: 900; font-display: swap; }
/* Self-hosted Elder Futhark subset: no platform serif carries U+16A0–16F8,
   so a blocked Google Fonts request would turn every rune ornament into tofu. */
@font-face { font-family: 'Noto Sans Runic'; src: url('../assets/fonts/NotoSansRunic-Runic.woff2') format('woff2'); font-weight: 400; font-display: swap; unicode-range: U+16A0-16F8; }

/* Vazirmatn carries every word that is not a heading, so it is self-hosted too
   (OFL 1.1): one variable file per script, 400–900. When it came from Google the
   most common real state for this audience was Estedad + Tahoma on one screen —
   two different zeros on one card, and a «·» that Tahoma draws exactly like ۰. */
@font-face { font-family: 'Vazirmatn'; src: url('../assets/fonts/Vazirmatn-Arabic.woff2') format('woff2'); font-weight: 400 900; font-display: swap;
  unicode-range: U+0600-06FF, U+0750-077F, U+200C-200E, U+2010-2011, U+204F, U+2E41, U+FB50-FDFF, U+FE70-FE74, U+FE76-FEFC; }
@font-face { font-family: 'Vazirmatn'; src: url('../assets/fonts/Vazirmatn-Latin.woff2') format('woff2'); font-weight: 400 900; 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+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
/* Until Vazirmatn arrives the page is set in Tahoma, scaled to Vazirmatn's
   average Persian advance (measured over a sentence of UI copy: .511 vs .533 em)
   and given its vertical metrics, so the swap does not re-wrap a single line. */
@font-face { font-family: 'Vazirmatn Fallback'; src: local('Tahoma'); size-adjust: 96%; ascent-override: 107%; descent-override: 56%; line-gap-override: 0%; }
/* Code, keys, hex values and dice notation: a monospace with a real lowercase
   and a slashed zero, so --bg-elev never reads --BG-ELEV and 1d8 never ID8 (OFL 1.1). */
@font-face { font-family: 'JetBrains Mono'; src: url('../assets/fonts/JetBrainsMono-Latin.woff2') format('woff2'); font-weight: 400 600; font-display: swap; unicode-range: U+0000-00FF, U+2000-206F, U+2190-2193, U+2212; }
/* The English interface's display voice: chamfered terminals that answer
   --clip-facet and the runic wordmark (OFL 1.1). Persian never reaches it. */
@font-face { font-family: 'Chakra Petch'; src: url('../assets/fonts/ChakraPetch-SemiBold-Latin.woff2') format('woff2'); font-weight: 600; font-display: swap; unicode-range: U+0000-00FF, U+2000-206F; }
@font-face { font-family: 'Chakra Petch'; src: url('../assets/fonts/ChakraPetch-Bold-Latin.woff2') format('woff2'); font-weight: 700 900; font-display: swap; unicode-range: U+0000-00FF, U+2000-206F; }
/* Cinzel survives only as the inscription face of an English name set beside
   its Persian (spell and monster names), never for code, keys or numbers (OFL 1.1). */
@font-face { font-family: 'Cinzel'; src: url('../assets/fonts/Cinzel-Latin.woff2') format('woff2'); font-weight: 500 700; font-display: swap; unicode-range: U+0000-00FF, U+2000-206F; }

:root {
  /* ── Brand palette (fixed, theme-independent) ── */
  --void: #0A0A0B;
  --basalt: #1A1B1D;
  --basalt-2: #2A2C2F;
  --basalt-3: #3A3D41;
  --emerald: #2FD39A;
  --emerald-soft: #7BE6C0;
  --jade: #0F6B4F;
  --jade-deep: #084235;
  --frost: #EDEFEA;
  --ember: #C23A2B;
  --ember-soft: #E0654F;

  /* ── Semantic (dark / Helheim) ── */
  --bg: var(--void);
  --bg-elev: var(--basalt);
  --bg-elev-2: var(--basalt-2);
  --bg-elev-3: var(--basalt-3);
  --bg-veil: rgba(10,10,11,.72);
  --fg: #D9DCD6;               /* body text — 14.3:1 on void, 12.4:1 on basalt */
  --fg-strong: var(--frost);   /* headings, values */
  /* Three ranks of grey that read as three ranks: muted and faint sit 2.3
     contrast points apart, so a secondary line and a timestamp are not one grey. */
  --fg-muted: #A9ADA6;         /* secondary text — 8.7:1 void, 7.6:1 basalt, 6.1:1 basalt-2 */
  --fg-faint: #8F948E;         /* smallest real text — 6.4:1 void, 5.6:1 basalt, 4.5:1 basalt-2 */
  /* NOT text: runes, dividers, crumb separators. It is the faint grey, so a
     reader with low vision sees these characters whether or not the markup
     calls them decoration (4.5:1 up to basalt-2). On the lit end of a stone
     slab (#34373B) the faint grey falls to 3.9:1, so slabs take their own. */
  --ornament: var(--fg-faint);
  --ornament-on-stone: #A3A8A2; /* 4.9:1 on #34373B, the lightest stone face */
  /* The edge of anything you type into or tick. --line-strong is a divider
     (1.5:1), which left an empty form reading as labels over nothing;
     this one is ≥ 3:1 against every ground a control sits on (WCAG 1.4.11). */
  --control-edge: #7A7F79;     /* 4.8:1 void, 4.2:1 basalt, 3.4:1 basalt-2 */
  --accent: var(--emerald);
  --accent-fg: #07110D;        /* text sitting on --emerald-grad — ≥ 7.3:1 down to 70% of its height */
  --accent-2: var(--jade);
  --accent-text: #4BE2AE;      /* emerald tuned for text on dark — 12.1:1 on void */
  /* Runes are the brand's voice, but they are still characters someone has to
     read. Dimming them with opacity put them under 4.5:1 — badly so in frost
     mode, where the accent is dark ink on a pale ground and .8 came out at
     4.32:1. They are dimmed to a colour instead, one that keeps its contrast
     on the page, on a card and on the session hero's tinted ground. */
  --rune-lit: #3BAC85;         /* 7.0:1 on void, 6.1:1 on basalt */
  --line: rgba(237,239,234,.10);
  --line-strong: rgba(237,239,234,.16);
  --line-glow: rgba(47,211,154,.45);
  /* A letter avatar is a hex: a ground a step off every surface it sits on
     (stones and cards are --bg-elev-2 and below), inside a 1px carved rim.
     The rim is the line colour over whatever is behind, so it holds anywhere. */
  --avatar-ground: var(--bg-elev-3);
  --avatar-rim: var(--line-strong);
  --danger: #EA7A66;           /* 5.3:1 on stone, 4.8:1 on the danger-tag tint */
  --danger-bg: rgba(194,58,43,.14);
  --danger-edge: rgba(234,122,102,.7);

  /* ── Light hierarchy. Emerald is LIGHT, not paint: spend it on one live
     thing per view. --glow = live/primary, --glow-soft = hover answer,
     --glow-strong = hero moments only, --glow-inset = ring inside a clipped shape. ── */
  --glow: 0 0 18px rgba(47,211,154,.35), 0 0 48px rgba(47,211,154,.14);
  --glow-soft: 0 0 12px rgba(47,211,154,.2);
  --glow-strong: 0 0 10px rgba(47,211,154,.7), 0 0 34px rgba(47,211,154,.45), 0 0 90px rgba(47,211,154,.2);
  --glow-inset: inset 0 0 0 1px rgba(47,211,154,.5), inset 0 0 22px rgba(47,211,154,.18);
  --glow-inset-soft: inset 0 0 0 1px var(--line-glow), inset 0 0 18px rgba(47,211,154,.12);
  /* the lift an overlay takes from its UNCLIPPED parent (a toast stack, a raven note) */
  --lift: drop-shadow(0 18px 28px rgba(0,0,0,.55)) drop-shadow(0 0 1px rgba(47,211,154,.25));

  /* ── Stone. Carved, not floating: --shadow-stone is inset only, because
     clip-path clips outer shadows and every consumer is clipped.
     Use --shadow-drop as a filter on an UNCLIPPED wrapper when lift is needed. ── */
  --shadow-stone: inset 0 1px 0 rgba(255,255,255,.06), inset 0 -34px 52px -34px rgba(0,0,0,.88), inset 0 -1px 0 rgba(0,0,0,.55);
  --shadow-drop: drop-shadow(0 18px 24px rgba(0,0,0,.5));
  /* the grain of the rock, so a slab reads as stone and not as a grey card. It
     used to be two hard-edged cut planes across every slab, and a straight
     diagonal band read as laminated plastic (in Frost, a white sheen). A still
     fractal noise at a few percent carries the stone instead; the lit top edge
     is --shadow-stone's 1px inset. */
  --stone-face: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .07 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  /* The slab's middle is #1E2022: 1.21:1 against the void, so a card stands off
     the ground by value and not only by its 10% hairline. (#1A1B1D was 1.15:1,
     and the fog took the rest.) */
  --stone-grad: var(--stone-face), linear-gradient(160deg, #2A2C30 0%, #1E2022 45%, #151618 100%);
  --stone-grad-2: var(--stone-face), linear-gradient(160deg, #34373B 0%, #25272A 50%, #1A1B1D 100%);
  /* A short ramp: the label band (top 70%) stays light enough for the ink
     (7.3:1 at #22B585, never under 4.7:1 at the very bottom), and the jade
     lives in the bevel shadow, where no descender lands. */
  --emerald-grad: linear-gradient(180deg, #34D9A0 0%, #22B585 70%, #178F69 100%);
  --grain-opacity: .05;
  --fog-color: 120,140,135;
  --fog-opacity: .4;
  --mode-light: 0;

  /* Ticks and radios are drawn, not clipped: a clip-path cut the old hex's
     border into broken segments at 1.3:1. These are whole hexes with a
     1.5px rim, one set per theme. */
  --check-off: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'><path d='M11 1.6 19.4 6.3V15.7L11 20.4 2.6 15.7V6.3Z' fill='%23111214' stroke='%23A9ADA6' stroke-width='1.5' stroke-linejoin='round'/></svg>");
  --check-hover: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'><path d='M11 1.6 19.4 6.3V15.7L11 20.4 2.6 15.7V6.3Z' fill='%23111214' stroke='%237BE6C0' stroke-width='1.5' stroke-linejoin='round'/></svg>");
  --check-on: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'><path d='M11 1.6 19.4 6.3V15.7L11 20.4 2.6 15.7V6.3Z' fill='%232FD39A' stroke='%232FD39A' stroke-width='1.5' stroke-linejoin='round'/><path d='M6.8 11.2 9.6 14 15.3 8.1' fill='none' stroke='%2307110D' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  --radio-on: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'><path d='M11 1.6 19.4 6.3V15.7L11 20.4 2.6 15.7V6.3Z' fill='%23111214' stroke='%232FD39A' stroke-width='1.5' stroke-linejoin='round'/><path d='M11 6.4 15 8.7V13.3L11 15.6 7 13.3V8.7Z' fill='%232FD39A'/></svg>");
  --check-bad: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'><path d='M11 1.6 19.4 6.3V15.7L11 20.4 2.6 15.7V6.3Z' fill='%23111214' stroke='%23EA7A66' stroke-width='2' stroke-linejoin='round'/></svg>");
  --select-caret: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8'><path d='M1 1l5 5 5-5' fill='none' stroke='%23A9ADA6' stroke-width='1.5'/></svg>");

  /* ── Type ── */
  /* The self-hosted Vazirmatn comes first; its metric twin holds the layout
     while it loads; Tahoma (on every Windows, good Persian) catches the rest.
     system-ui is after Tahoma on purpose: on Windows it is Segoe UI, whose
     Persian is cramped and badly spaced. */
  --font-display: 'Estedad', 'Vazirmatn', 'Vazirmatn Fallback', 'Tahoma', sans-serif;
  --font-body: 'Vazirmatn', 'Vazirmatn Fallback', 'Tahoma', system-ui, sans-serif;
  /* The self-hosted JetBrains Mono is Latin only, and a system mono sets Persian
     letter by letter, unjoined: Persian in a JSON field or the raw audit data
     falls through to Vazirmatn, joined, while the code around it stays mono. */
  --font-mono: 'JetBrains Mono', 'Vazirmatn', 'Vazirmatn Fallback', ui-monospace, 'SF Mono', 'Cascadia Mono', Menlo, Consolas, monospace;
  --font-rune: 'Noto Sans Runic', 'Segoe UI Historic', 'BabelStone Runic', serif;
  --font-latin: 'Cinzel', 'Georgia', serif;   /* decorative English names only — see .latin-display */
  /* One scale, every step ≥ 1.18× the one under it at every width, so on a
     phone the page title, a section heading and a card headline are three
     sizes, not one 32px. The ladder: hero › page › h2 (3xl) › h3 (xl) ›
     card title (lg) › body (md) › meta (xs). 2xl sits between xl and 3xl for
     article and stat-block headings. */
  --fs-2xs: .75rem;            /* 12px — absolute floor for Persian UI labels */
  --fs-xs: .8125rem;           /* 13 — meta, hints, timestamps */
  --fs-sm: .875rem;            /* 14 — controls, secondary copy */
  --fs-md: 1rem;               /* 16 — body */
  --fs-lg: 1.1875rem;          /* 19 — card titles, h4 */
  --fs-xl: 1.4375rem;          /* 23 — h3 */
  --fs-2xl: 1.75rem;           /* 28 — article h2, stat-block names */
  --fs-3xl: clamp(2rem, 1.35rem + 1.8vw, 2.625rem);     /* 32 → 42 — h2 */
  --fs-page: clamp(2.5rem, 1.6rem + 2.8vw, 3.5rem);     /* 40 → 56 — every page's H1 */
  --fs-4xl: var(--fs-page);                              /* retired: kept as an alias */
  --fs-hero: clamp(3rem, 1.6rem + 5.6vw, 5.25rem);      /* 48 → 84 — the home gate only */
  --lh-body: 1.85;
  --lh-ui: 1.5;                /* controls, meta rows, chips, tables, timestamps */
  --lh-display: 1.4;           /* Persian display: Estedad's gaf and kaf need the lead */
  --lh-tight: 1.25;
  /* `ch` is the width of Vazirmatn's Latin zero, wider than the average Persian
     letter: 68ch came out at 85–90 Persian characters a line. 34em is ≈ 70. */
  --measure: 34em;
  /* one ornament scale, so the same rune is not eleven sizes */
  --rune-sm: .95rem;
  --rune-md: 1.25rem;
  --rune-lg: 1.6rem;

  /* ── Space (4pt, with one sanctioned half-step) ── */
  --s-half: 6px;
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 24px;
  --s-6: 32px; --s-7: 48px; --s-8: 64px; --s-9: 96px; --s-10: 144px;
  --gutter: clamp(16px, 4vw, 48px);
  --max: 1280px;
  /* the fixed chrome, named once so sticky bars and scroll padding agree with it.
     Installed on an iPhone the page runs under the status bar (viewport-fit=cover,
     web/routes.ts): the header grows by that inset (--safe-t, 0 everywhere else),
     and --hdr-h, which everything placed under the header reads, grows with it */
  --hdr-in: 68px;
  --safe-t: env(safe-area-inset-top, 0px);
  --hdr-h: calc(var(--hdr-in) + var(--safe-t));
  --bnav-h: 64px;
  --ctl-h: 40px;               /* one height for every header control */
  --fab: 64px;
  /* where a sticky page bar may sit: under the header, never beneath it */
  --sticky-top: calc(var(--hdr-h) + var(--s-2));

  /* ── Shape ── */
  --r-0: 0px; --r-1: 2px; --r-2: 4px; --r-pill: 999px;
  --facet: 14px;
  /* The pointed arch is the mark's roof, 32° (the brand mark is 33°). As a
     polygon its shoulders sat at 22% of the HEIGHT, so the angle followed the
     box: 29° on the home feature, 14° on a wide hero or a phone, 30° on a
     portrait. --mask-arch is the same roof drawn once (a 64×640 cap, rise 20 on
     a half-width of 32 = 32°) and scaled by the WIDTH alone, so every arch on
     the site has one angle whatever its proportions:
       -webkit-mask: var(--mask-arch); mask: var(--mask-arch);
     (it covers a box up to ten times as tall as it is wide). --clip-arch is
     kept for what still names it; wherever it meets the mask, the mask's
     steeper roof is the one that shows. */
  --mask-arch: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 640'><path d='M0 20L32 0L64 20V640H0Z'/></svg>") top center / 100% auto no-repeat;
  --clip-arch: polygon(50% 0, 100% 22%, 100% 100%, 0 100%, 0 22%);
  --clip-hex: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);

  /* ── Motion ──
     Curves by intent, not by taste:
     --ease-out    entrances and reveals (fast start, long settle)
     --ease-press  anything the reader's own click started: it moves on frame one
     --ease-exit   leaving: accelerates away
     --ease-spring slams and pops, a touch of overshoot
     --ease-stone  hover answers
     --ease-heavy  autonomous weight only (≥ 800 ms, nobody clicked) — its flat
                   start reads as lag directly after a click. */
  --ease-stone: cubic-bezier(.2,.8,.2,1);
  --ease-out: cubic-bezier(.16,1,.3,1);
  --ease-press: cubic-bezier(.3,.7,.4,1);
  --ease-exit: cubic-bezier(.4,0,1,1);
  --ease-spring: cubic-bezier(.2,1.3,.4,1);
  --ease-heavy: cubic-bezier(.7,0,.2,1);
  --t-fast: 150ms;             /* press, colour */
  --t-ui: 260ms;               /* open / close UI */
  --t-slow: 480ms;             /* reveals, dialogs */
  --t-hero: 1400ms;
  --t-exit: 160ms;             /* exits ≈ 0.6 × the entrance */
  /* The busy ring (components.css .btn[aria-busy], the admin's ⋯): six
     rune-cuts for a 14px masked circle, stepped round a sixth of a turn at a
     time. Six equal cuts stepped by a sixth land on themselves, so the ring
     stood still; now the lead cut is whole and the rest fade behind it, and
     each step is seen to turn. currentColor is the colour where it is drawn. */
  --busy-ring: conic-gradient(currentColor 0 30deg, transparent 0 60deg,
    color-mix(in srgb, currentColor 22%, transparent) 0 90deg, transparent 0 120deg,
    color-mix(in srgb, currentColor 36%, transparent) 0 150deg, transparent 0 180deg,
    color-mix(in srgb, currentColor 52%, transparent) 0 210deg, transparent 0 240deg,
    color-mix(in srgb, currentColor 70%, transparent) 0 270deg, transparent 0 300deg,
    color-mix(in srgb, currentColor 86%, transparent) 0 330deg, transparent 0);

  /* ── Z ── */
  --z-nav: 50; --z-tray: 80; --z-modal: 100; --z-portal: 200; --z-raven: 210; --z-cursor: 300;

  color-scheme: dark;
}
:root[lang="en"] {
  --font-display: 'Chakra Petch', 'Estedad', 'Vazirmatn', 'Vazirmatn Fallback', sans-serif;
  --lh-display: 1.2;
  --measure: 60ch;
}
/* Contrast Themes set every gradient to none, so the ring opts out of the
   adjustment where it is drawn (forced-color-adjust: none) and is cut here in
   system colours: the cuts in the button text colour, fading toward the button
   face, and the gaps filled with the face rather than left clear. Drawn over a
   kept url() texture (the sign-in panel) a ring with clear gaps vanished in a
   light theme, black on dark; this one carries its own contrast (A11Y-TYPE-R9-4). */
@media (forced-colors: active) {
  :root {
    --busy-ring: conic-gradient(ButtonText 0 30deg, ButtonFace 0 60deg,
      color-mix(in srgb, ButtonText 45%, ButtonFace) 0 90deg, ButtonFace 0 120deg,
      color-mix(in srgb, ButtonText 56%, ButtonFace) 0 150deg, ButtonFace 0 180deg,
      color-mix(in srgb, ButtonText 67%, ButtonFace) 0 210deg, ButtonFace 0 240deg,
      color-mix(in srgb, ButtonText 78%, ButtonFace) 0 270deg, ButtonFace 0 300deg,
      color-mix(in srgb, ButtonText 89%, ButtonFace) 0 330deg, ButtonFace 0);
  }
}
@media (max-width: 56.25em) { :root { --hdr-in: 60px; } }
@media (pointer: coarse) { :root { --ctl-h: 44px; } }

/* var() inside a custom property is substituted where the property is DECLARED.
   A :root-level polygon would therefore bake in --facet:14px and silently ignore
   every per-element override (.btn 8px, .chip 6px, .tip 8px …). Declaring the
   polygons on every element re-computes them against that element's own --facet.
   --facet-edges is the same trick for the border: a clip-path cuts the box, but
   a CSS border is drawn only along the straight sides, so every chamfer was an
   open corner. These two background layers draw the missing diagonal in --bd,
   1px wide, just inside the cut. Put them first in a faceted element's
   background: `background: var(--facet-edges), <its surface>`. */
*, *::before, *::after {
  --clip-facet: polygon(0 0, calc(100% - var(--facet)) 0, 100% var(--facet), 100% 100%, var(--facet) 100%, 0 calc(100% - var(--facet)));
  --clip-facet-2: polygon(var(--facet) 0, 100% 0, 100% calc(100% - var(--facet)), calc(100% - var(--facet)) 100%, 0 100%, 0 var(--facet));
  --facet-edges:
    linear-gradient(to bottom left, transparent calc(50% - .5px), var(--bd, transparent) calc(50% - .5px) calc(50% + 1px), transparent calc(50% + 1px)) top right / var(--facet) var(--facet) no-repeat border-box,
    linear-gradient(to top right, transparent calc(50% - .5px), var(--bd, transparent) calc(50% - .5px) calc(50% + 1px), transparent calc(50% + 1px)) bottom left / var(--facet) var(--facet) no-repeat border-box;
}

/* ── Frost (light) mode ──
   Designed, not inverted. The material is hoarfrost on pale stone: a cool grey
   ground, near-white slabs that stand 1.22:1 off it with a real edge, and jade
   ink. Light on pale stone is a hairline, never a blur — an emerald glow on
   #E6E8E2 reads as a mint smudge, not as light. Only the d20 keeps a halo. */
/* ── Declaring dark support, so no browser rewrites the colours for us ──
   A forced dark mode (Samsung Internet's "Dark mode", Chrome's Auto Dark) decides
   whether to repaint a page by asking whether the stylesheet answers
   prefers-color-scheme at all. This sheet answered it nowhere, so the site was
   classified as light-only and inverted on the phone: the basalt portal turned
   pale silver, the Gatekeeper went grey, and the emerald buttons turned dark with
   white labels. The `color-scheme` property alone was not enough — that one is
   read by Chrome's implementation, not Samsung's.

   Every value below is exactly what :root already declares, so this changes
   nothing about how the site looks. It exists to be found. Scoped
   :not([data-theme="light"]) so choosing Frost still wins on a dark OS. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: var(--void);
    --bg-elev: var(--basalt);
    --fg: #D9DCD6;
    --line: rgba(237,239,234,.10);
  }
}

:root[data-theme="light"] {
  --bg: #E3E6E0;
  --bg-elev: #FBFBF9;          /* 1.22:1 off the ground, plus its edge */
  --bg-elev-2: #F1F3EF;        /* a plate set into a slab (chips, tags, seats) */
  --bg-elev-3: #FFFFFF;        /* the top-most float */
  --bg-veil: rgba(227,230,224,.8);
  --fg: #1F2220;               /* 12.7:1 on the ground */
  --fg-strong: #0E100F;
  --fg-muted: #4E544F;         /* 6.2:1 ground, 7.5:1 slab */
  --fg-faint: #5F655F;         /* 4.7:1 ground, 5.8:1 slab, 5.4:1 plate */
  --ornament-on-stone: #5F655F;
  --control-edge: #7C817B;     /* 3.2:1 ground, 3.8:1 slab */
  --accent: var(--jade);
  --accent-fg: #F4FBF8;
  --accent-2: var(--emerald);
  --accent-text: #0C5A42;      /* 6.5:1 ground, 7.9:1 slab */
  --rune-lit: #0C5A42;         /* 6.5:1 on the page ground */
  --line: rgba(24,36,34,.14);
  --line-strong: rgba(24,36,34,.24);
  --line-glow: rgba(15,107,79,.45);
  --avatar-ground: #E3E7E0;    /* a step under the card paper: pressed into it */
  --danger: #A62E21;           /* 5.5:1 ground, 6.7:1 slab */
  --danger-bg: rgba(194,58,43,.08);
  --danger-edge: rgba(166,46,33,.7);
  --glow: 0 0 0 1px rgba(15,107,79,.35);
  --glow-soft: 0 0 0 1px rgba(15,107,79,.22);
  --glow-strong: 0 0 0 1px rgba(15,107,79,.55), 0 0 0 4px rgba(15,107,79,.1);
  --glow-inset: inset 0 0 0 1px rgba(15,107,79,.5);
  --glow-inset-soft: inset 0 0 0 1px rgba(15,107,79,.3);
  --lift: drop-shadow(0 12px 24px rgba(28,44,52,.18)) drop-shadow(0 0 1px rgba(28,44,52,.2));
  --shadow-stone: inset 0 1px 0 #FFFFFF, inset 0 -1px 0 rgba(24,36,34,.06);
  /* cold blue-grey, not green: the shadow of frost, not of a lamp */
  --shadow-drop: drop-shadow(0 10px 18px rgba(28,44,52,.12));
  /* Frost's grain is a cold ink, not white: white grain on a white slab is nothing */
  --stone-face: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 .11 0 0 0 0 .17 0 0 0 0 .2 0 0 0 .05 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  --stone-grad: var(--stone-face), linear-gradient(160deg, #FFFFFF 0%, #FBFBF9 45%, #F4F5F1 100%);
  --stone-grad-2: var(--stone-face), linear-gradient(160deg, #FFFFFF 0%, #F6F7F3 50%, #ECEEE9 100%);
  /* The gradient itself must carry the contrast: --accent-fg is near-white and
     #F4FBF8 on raw emerald is 1.8:1. Jade-dark keeps every primary control ≥ 5:1. */
  --emerald-grad: linear-gradient(180deg, #117A56 0%, var(--jade-deep) 100%);
  --grain-opacity: .03;
  --fog-color: 188,200,206;
  --fog-opacity: .15;
  --mode-light: 1;
  --check-off: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'><path d='M11 1.6 19.4 6.3V15.7L11 20.4 2.6 15.7V6.3Z' fill='%23FFFFFF' stroke='%234E544F' stroke-width='1.5' stroke-linejoin='round'/></svg>");
  --check-hover: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'><path d='M11 1.6 19.4 6.3V15.7L11 20.4 2.6 15.7V6.3Z' fill='%23FFFFFF' stroke='%230F6B4F' stroke-width='1.5' stroke-linejoin='round'/></svg>");
  --check-on: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'><path d='M11 1.6 19.4 6.3V15.7L11 20.4 2.6 15.7V6.3Z' fill='%230F6B4F' stroke='%230F6B4F' stroke-width='1.5' stroke-linejoin='round'/><path d='M6.8 11.2 9.6 14 15.3 8.1' fill='none' stroke='%23F4FBF8' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  --radio-on: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'><path d='M11 1.6 19.4 6.3V15.7L11 20.4 2.6 15.7V6.3Z' fill='%23FFFFFF' stroke='%230F6B4F' stroke-width='1.5' stroke-linejoin='round'/><path d='M11 6.4 15 8.7V13.3L11 15.6 7 13.3V8.7Z' fill='%230F6B4F'/></svg>");
  --check-bad: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 22'><path d='M11 1.6 19.4 6.3V15.7L11 20.4 2.6 15.7V6.3Z' fill='%23FFFFFF' stroke='%23A62E21' stroke-width='2' stroke-linejoin='round'/></svg>");
  --select-caret: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8'><path d='M1 1l5 5 5-5' fill='none' stroke='%234E544F' stroke-width='1.5'/></svg>");
  color-scheme: light;
}
