/* Shared site theme: fonts, colors (light and dark), base styles.
   Included on every page: <link rel="stylesheet" href="/assets/theme.css">
   Pages use only these tokens and never declare colors of their own. */

:root {
  /* Fonts: the react.dev stacks. Optimistic is Meta's font and is not served here, so readers get the system
     UI font (SF Pro on Apple, Segoe UI on Windows, Roboto on Android) — nothing is downloaded. */
  --font-emoji: "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  --font-display: "Optimistic Display", -apple-system, ui-sans-serif, system-ui, sans-serif, var(--font-emoji);
  --font-body: "Optimistic Text", -apple-system, ui-sans-serif, system-ui, sans-serif, var(--font-emoji);
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;

  /* Surfaces and text of the default palette, «Океан»: one cool sea-blue family (hue ~205) under the cyan of the logo,
     the brand. Dark: the navy of the logo's square, cards a step above it.
     Three tiers: --bg (page) < --surface (cards, white) and --surface-2 (a calm step that reads against both).
     Text on every tier passes WCAG AA, checked by `npm run theme:contrast`. */
  --bg: #eef4f8;
  --surface: #ffffff;
  --surface-2: #e0ecf3;
  --ink: #0e1f2e;
  --ink-soft: #36495c;
  --ink-faint: #4e6276;
  --border: #c6d8e4;
  /* The outline of a control (input, chip, filter): 3:1 against the page, unlike the hairline --border */
  --border-strong: #66808f;
  /* Shadows are drawn in two tints, so a palette (below) recolours them without restating them: --shadow-tint for the
     lift of a card, --tile-tint for the deeper, coloured lift of a word tile */
  --shadow-tint: #0a2536;
  --tile-tint: #0b3a55;
  --shadow: 0 1px 2px color-mix(in srgb, var(--shadow-tint) 7%, transparent),
    0 8px 24px -12px color-mix(in srgb, var(--shadow-tint) 20%, transparent);
  /* A word tile on the page: the same lift as --shadow, a little deeper and tinted with the hue of the surfaces */
  --shadow-tile: 0 1px 2px color-mix(in srgb, var(--tile-tint) 8%, transparent),
    0 10px 26px -14px color-mix(in srgb, var(--tile-tint) 30%, transparent);
  /* A clickable plate under the pointer (.is-clickable): the same shadow, a step deeper, as the plate lifts */
  --shadow-hover: 0 2px 4px color-mix(in srgb, var(--shadow-tint) 8%, transparent),
    0 16px 32px -14px color-mix(in srgb, var(--shadow-tint) 30%, transparent);

  /* Palette: solid colour + soft background to pair with it. Vivid hues, each clearly apart from its neighbours
     (green ~103 vs mint ~157 vs teal ~187, blue ~214 vs indigo ~238 vs violet ~262, gold ~45 vs orange ~26 vs red ~5).
     Mint is the colour of das, apart from the cyan brand (~195) between blue (der) and teal. A solid hue
     is for coloured parts of words, set bold: 3:1 on every surface, like large text (scripts/check-contrast.mjs,
     docs/architecture/colour-tokens.md → ADR-6). Small regular-weight text in a colour takes an AA step of its hue
     (--teal-ink, --green-ink…, --accent, --good, --case-*-ink, --tense-*-ink): 4.5:1 with as little ink as it needs */
  --blue: #1f6fd6;   --blue-soft: #e6effc;
  --teal: #008a98;   --teal-soft: #e0f4f6;
  --red: #d23f31;    --red-soft: #fce9e6;
  --gold: #a07800;   --gold-soft: #fbf2d6;
  --indigo: #4044b8; --indigo-soft: #eaebfb;
  --green: #3b8f1c;  --green-soft: #eaf5e0;
  --mint: #008f66;   --mint-soft: #dff4ec;
  --plum: #b03aa6;   --plum-soft: #f8e8f6;
  --orange: #d95e00; --orange-soft: #fdecdc;
  --violet: #8350e8; --violet-soft: #f0eafd;
  --on-accent: #ffffff;

  /* Brand: the hue of the site itself (the logo, solid buttons, links, the current item), apart from the grammar hues
     above, which mean categories and stay the same in every palette. --brand is the solid hue (3:1, bold and large,
     fills under --on-accent), --brand-ink its AA step for small text (4.5:1), --brand-soft its pale tint */
  --brand: #0081ad;
  --brand-ink: #006a8f;
  --brand-soft: #dcf0f8;

  /* The page backdrop (NavLayout): four soft clouds in the corners, top-left, top-right, bottom-right, bottom-left.
     --cloud-strength scales their opacity. They stand still: --backdrop-motion names the animations that move them
     (`cloud-drift, cloud-breathe` in NavLayout), none by default; a moving backdrop runs on the clock ThemeInit sets
     (--clock), so a cloud goes on from where it was on the previous page instead of jumping back */
  --cloud-1: #00a3c4;
  --cloud-2: var(--brand);
  --cloud-3: #3a64c8;
  --cloud-4: #36b0d6;
  --cloud-strength: 1;
  --backdrop-motion: none;
  /* A band along the top edge of the site header: none by default, the Deutschland mode paints the flag */
  --header-stripe: none;
  --header-stripe-size: 3px;
  /* The site's name as the home page's title (PageHero `wordmark`): its letters take turns in three colours, all the
     title's own ink by default */
  --wordmark-1: var(--ink);
  --wordmark-2: var(--ink);
  --wordmark-3: var(--ink);
  /* …and an outline round every letter, drawn outside the glyph so it keeps the letter's colour: none by default */
  --wordmark-stroke-width: 0;
  --wordmark-stroke-color: var(--bg);

  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0b1520;
    --surface: #122030;
    --surface-2: #1a2b3d;
    --ink: #e6eef8;
    --ink-soft: #adbccf;
    --ink-faint: #8ea0b6;
    --border: #2c405a;
    --border-strong: #5e7590;
    --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 12px 28px -14px rgba(0, 0, 0, .6);
    --shadow-tile: var(--shadow);
    --shadow-hover: 0 2px 4px rgba(0, 0, 0, .35), 0 18px 36px -14px rgba(0, 0, 0, .75);

    --blue: #5ea2ff;   --blue-soft: #12223a;
    --teal: #33cdd8;   --teal-soft: #0a272b;
    --red: #ff7a6b;    --red-soft: #33150f;
    --gold: #f2c53d;   --gold-soft: #2e240a;
    --indigo: #8f98ff; --indigo-soft: #1a1d3d;
    --green: #7cd45c;  --green-soft: #142812;
    --mint: #3ed49b;   --mint-soft: #0a2a1f;
    --plum: #e87ade;   --plum-soft: #331430;
    --orange: #ff9640; --orange-soft: #33200c;
    --violet: #c58cff; --violet-soft: #26183d;
    --on-accent: #0e1116;
    --brand: #40c8ee;
    --brand-ink: #40c8ee;
    --brand-soft: #0a2836;
    --cloud-1: #1ab0cc;
    --cloud-3: #4a6fd6;
    --cloud-4: #2a8fb8;
    --spotlight: rgba(0, 0, 0, .62);

    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --bg: #0b1520;
  --surface: #122030;
  --surface-2: #1a2b3d;
  --ink: #e6eef8;
  --ink-soft: #adbccf;
  --ink-faint: #8ea0b6;
  --border: #2c405a;
  --border-strong: #5e7590;
  --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 12px 28px -14px rgba(0, 0, 0, .6);
  --shadow-tile: var(--shadow);
  --shadow-hover: 0 2px 4px rgba(0, 0, 0, .35), 0 18px 36px -14px rgba(0, 0, 0, .75);

  --blue: #5ea2ff;   --blue-soft: #12223a;
  --teal: #33cdd8;   --teal-soft: #0a272b;
  --red: #ff7a6b;    --red-soft: #33150f;
  --gold: #f2c53d;   --gold-soft: #2e240a;
  --indigo: #8f98ff; --indigo-soft: #1a1d3d;
  --green: #7cd45c;  --green-soft: #142812;
  --mint: #3ed49b;   --mint-soft: #0a2a1f;
  --plum: #e87ade;   --plum-soft: #331430;
  --orange: #ff9640; --orange-soft: #33200c;
  --violet: #c58cff; --violet-soft: #26183d;
  --on-accent: #0e1116;
  --brand: #40c8ee;
  --brand-ink: #40c8ee;
  --brand-soft: #0a2836;
  --cloud-1: #1ab0cc;
  --cloud-3: #4a6fd6;
  --cloud-4: #2a8fb8;
  --spotlight: rgba(0, 0, 0, .62);

  color-scheme: dark;
}

/* ---------- Palettes ----------
   The site's look in one place: a palette restates only the base layer — the surfaces, the text, the borders, the
   shadow tints, the brand hue, the badge and the backdrop clouds. The grammar hues (--blue … --violet) and everything
   built on them (der/die/das, cases, tenses) mean categories and stay the same in every palette; so do the roles below,
   which derive from the base. The palette is <html data-palette="…">, set before paint by ThemeInit from the reader's
   choice (the palette menu in the site header); without it, or without scripts, the default (ocean) above applies.
   Since ThemeInit always sets data-theme too, a palette's light block is `:not([data-theme="dark"])` and its dark one
   `[data-theme="dark"]`, with no prefers-color-scheme copy. Every palette passes `npm run theme:contrast` in both themes.
   Adding one: a light and a dark block here, its entry in src/lib/palettes.ts (name, swatch), its names in site*.json. */

/* «Индиго»: the site's first look — calm indigo surfaces (hue ~230) with a teal brand (the colour of das until das
   moved to mint) */
:root[data-palette="indigo"]:not([data-theme="dark"]) {
  --bg: #f1f2f8;
  --surface: #ffffff;
  --surface-2: #e6e8f6;
  --ink: #1e2230;
  --ink-soft: #454b5e;
  --ink-faint: #5d647a;
  --border: #d6d9e8;
  --border-strong: #7a8199;
  --shadow-tint: #141e32;
  --tile-tint: #283276;
  --brand: var(--teal);
  --brand-ink: var(--teal-ink);
  --brand-soft: var(--teal-soft);
  --cloud-1: var(--brand);
  --cloud-2: var(--blue);
  --cloud-3: var(--indigo);
  --cloud-4: color-mix(in oklab, var(--plum) 45%, var(--blue));
}
:root[data-palette="indigo"][data-theme="dark"] {
  --bg: #14161d;
  --surface: #1c1f29;
  --surface-2: #272b3b;
  --ink: #e9ebf3;
  --ink-soft: #b4b9ca;
  --ink-faint: #979db3;
  --border: #353a4c;
  --border-strong: #6d7592;
  --brand: var(--teal);
  --brand-ink: var(--teal-ink);
  --brand-soft: var(--teal-soft);
  --cloud-1: var(--brand);
  --cloud-2: var(--blue);
  --cloud-3: var(--indigo);
  --cloud-4: color-mix(in oklab, var(--plum) 45%, var(--blue));
}

/* «Светлая»: near-neutral, react.dev-like — white cards on a pale grey, crisp borders, a cyan-blue brand */
:root[data-palette="clean"]:not([data-theme="dark"]) {
  --bg: #f3f4f6;
  --surface: #ffffff;
  --surface-2: #e8ebef;
  --ink: #16181d;
  --ink-soft: #404652;
  --ink-faint: #5a616e;
  --border: #d8dce2;
  --border-strong: #757c89;
  --shadow-tint: #11151c;
  --tile-tint: #1c2633;
  --brand: #087ea4;
  --brand-ink: #086f91;
  --brand-soft: #e2f3f9;
  --cloud-1: var(--brand);
  --cloud-2: #6b7a90;
  --cloud-3: #9aa6b5;
  --cloud-4: var(--brand);
}
:root[data-palette="clean"][data-theme="dark"] {
  --bg: #111316;
  --surface: #1a1d22;
  --surface-2: #252930;
  --ink: #eceef1;
  --ink-soft: #b5bac3;
  --ink-faint: #979da8;
  --border: #33373f;
  --border-strong: #6c7380;
  --brand: #58c4dc;
  --brand-ink: #58c4dc;
  --brand-soft: #0d2a33;
  --cloud-1: var(--brand);
  --cloud-2: #56606e;
  --cloud-3: #3a414c;
  --cloud-4: var(--brand);
}

/* «Мята»: fresh mint surfaces (green-cyan, not the grey «swamp») with an emerald brand */
:root[data-palette="mint"]:not([data-theme="dark"]) {
  --bg: #ecf6f2;
  --surface: #ffffff;
  --surface-2: #d6ede5;
  --ink: #10231e;
  --ink-soft: #354f48;
  --ink-faint: #4c6760;
  --border: #c6e0d7;
  --border-strong: #688980;
  --shadow-tint: #0b3328;
  --tile-tint: #0d4a3a;
  --brand: #0a8a6c;
  --brand-ink: #07715a;
  --brand-soft: #d9f2ea;
  --cloud-1: var(--brand);
  --cloud-2: #1aa6b0;
  --cloud-3: #6bbf59;
  --cloud-4: #3fb894;
}
:root[data-palette="mint"][data-theme="dark"] {
  --bg: #0c1613;
  --surface: #13201c;
  --surface-2: #1b2e29;
  --ink: #e4f2ed;
  --ink-soft: #a8c3bb;
  --ink-faint: #89a79e;
  --border: #273f38;
  --border-strong: #5b7a71;
  --brand: #3fd1a6;
  --brand-ink: #3fd1a6;
  --brand-soft: #0a2a21;
  --cloud-1: var(--brand);
  --cloud-2: #1fb3bf;
  --cloud-3: #5fae4e;
  --cloud-4: #2a9a7a;
}

/* «Золото»: the look of the Glossarion logo — a gilded G on a night-blue square, a small four-point star on its ring.
   The material is «Рама», all of it CSS gradients and shadows (no images): plates are panels in a double gold frame —
   a gradient frame in the border box and an engraved hairline inside (--plate-fill, --plate-line, --plate-shadow); the
   main action is a gold plate with a gold ring around it (--fill-accent with --raise); the other buttons and pills are
   plaques in a thin gold edge (--iron-*); fields are plain wells with a gold edge (--field-*); the site header is a bar
   with a gold line under it (--bar-*). Categories keep their colours as enamel in a gold setting (--enamel-*: level
   badges, case chips), and a word in a mixed list glows in the colour of its part of speech, a noun in gold. Headings
   are set in a book serif and a page's title is gilded (the rules after these blocks). The material tokens exist only
   in this palette: a component applies them in its own rule under :root[data-palette="gold"] (`:global(…)` in a CSS
   module or an .astro style), so every other palette stays exactly as it was. Dark: the night of the logo; light: the
   parchment of its open book, with bronze for gold. Words, translations and examples stay plain text, and the grammar
   hues stay flat — gold means the brand, a hue means a category. The brand gold sits next to --gold (B2, the future
   tense): they meet only as a link beside a bold label. */
:root[data-palette="gold"]:not([data-theme="dark"]) {
  --font-display: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif, var(--font-emoji);
  --bg: #f4eddd;
  --surface: #fffdf8;
  --surface-2: #efe7d4;
  --ink: #18222f;
  --ink-soft: #46505c;
  --ink-faint: #5c6470;
  --border: #e3d3ad;
  --border-strong: #8c7a55;
  --shadow-tint: #3a2a0c;
  --tile-tint: #4a3410;
  --shadow: 0 1px 2px rgba(58, 42, 12, .08), 0 0 0 1px rgba(184, 134, 46, .16),
    0 10px 26px -14px rgba(58, 42, 12, .32);
  --shadow-tile: var(--shadow);
  --shadow-hover: 0 0 0 1px rgba(184, 134, 46, .55), 0 0 22px -8px rgba(201, 149, 62, .55),
    0 16px 32px -14px rgba(58, 42, 12, .38);
  --brand: #94671a;
  --brand-ink: #7a5410;
  --brand-soft: #f3e5c4;
  /* The head row of a table: a step of the bronze instead of the indigo, which sank too deep on the warm cards */
  --table-head-bg: color-mix(in srgb, var(--brand) 11%, var(--surface));
  /* The material, «Рама» (see the block comment above; components use these only under [data-palette="gold"]) */
  /* The gold of a frame: light on the top left corner and across the middle, like the ring of the logo */
  --gold-frame: linear-gradient(135deg, #e9c779, #7a5114 35%, #c9953e 65%, #6b460f);
  /* The setting of a small piece (an enamel badge): lighter on top */
  --gold-setting: linear-gradient(180deg, #f6dc9c, #a8762a);
  /* The thin gap between a control and the gold ring around it: the colour the control sits on */
  --ring-gap: var(--surface);
  /* The main action: a bronze plate in a lighter gold edge (white letters need the darker metal on parchment) */
  --fill-accent: linear-gradient(180deg, #a87a2a, #8c6118 55%, #74500f) padding-box,
    linear-gradient(180deg, #f0d48a, #5c3d0a) border-box;
  --metal-text: none;
  --raise: 0 0 0 1px var(--ring-gap), 0 0 0 2px rgba(201, 149, 62, .55), 0 10px 24px -12px rgba(150, 105, 30, .6);
  --plate-fill: linear-gradient(180deg, #fffdf8, #f6eedb) padding-box, var(--gold-frame) border-box;
  --plate-line: 1px solid rgba(150, 105, 30, .22);
  --plate-shadow: 0 14px 30px -18px rgba(58, 42, 12, .45);
  /* The other buttons and pills: a light plaque in a thin gold edge and a gold ring */
  --iron-fill: linear-gradient(180deg, #fffaf0, #efe4cb) padding-box, linear-gradient(180deg, #c9953e, #7a5114) border-box;
  --iron-edge: transparent;
  --iron-raise: 0 0 0 1px var(--ring-gap), 0 0 0 2px rgba(201, 149, 62, .3);
  --field-fill: #fffdf8;
  --field-edge: #d9c38f;
  --field-sink: inset 0 1px 2px rgba(70, 45, 10, .12);
  --bar-fill: linear-gradient(180deg, #fffaf0, #f4ecd9);
  --bar-edge: 0 1px 0 #c9953e, 0 8px 18px -12px rgba(58, 42, 12, .5);
  --engrave: none;
  /* A divider between the parts of a card or a dialog: a gold line that fades out at both ends */
  --rule-line: linear-gradient(90deg, transparent, rgba(154, 106, 28, .6) 12%, rgba(154, 106, 28, .6) 88%, transparent);
  --heading-metal: linear-gradient(180deg, #b07f27 0%, #8a5f16 45%, #5c3f0b 58%, #8a6019 78%, #6e4c10 100%);
  /* Enamel in a gold setting (level badges, case chips): the category's own colour is the enamel */
  --enamel-base: #ffffff;
  --enamel-tint: 14%;
  --enamel-tint-hi: 22%;
  --enamel-ink: 100%;
  /* A noun glows gold in a list that mixes parts of speech */
  --lex-noun: #c9953e;
  /* Badges and counters are gold coins: dark ink on gold in both themes */
  --badge-bg: #d9a94f;
  --badge-ink: #2a1a03;
  --cloud-1: #d9b56a;
  --cloud-2: #8fb6d0;
  --cloud-3: #c9a24e;
  --cloud-4: #e3cb8f;
  --wordmark-1: #7a5410;
  --wordmark-2: #7a5410;
  --wordmark-3: #7a5410;
}
:root[data-palette="gold"][data-theme="dark"] {
  --font-display: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif, var(--font-emoji);
  --bg: #0a1322;
  --surface: #111d30;
  --surface-2: #1a2840;
  --ink: #ede7d8;
  --ink-soft: #bab3a2;
  --ink-faint: #a39b88;
  --border: #3a3a33;
  --border-strong: #8a7444;
  --shadow: inset 0 1px 0 rgba(255, 236, 190, .07), 0 0 0 1px rgba(201, 162, 78, .2),
    0 14px 32px -16px rgba(0, 0, 0, .85);
  --shadow-tile: var(--shadow);
  --shadow-hover: inset 0 1px 0 rgba(255, 236, 190, .1), 0 0 0 1px rgba(227, 182, 90, .6),
    0 0 28px -6px rgba(227, 182, 90, .38), 0 18px 36px -14px rgba(0, 0, 0, .9);
  --brand: #e3b65a;
  --brand-ink: #e3b65a;
  --brand-soft: #2a2212;
  --on-accent: #0a1322;
  --gold-frame: linear-gradient(135deg, #f6dc9c, #8a5c1c 35%, #e3b65a 65%, #7a5114);
  --gold-setting: linear-gradient(180deg, #f6dc9c, #a8762a);
  --ring-gap: var(--bg);
  --fill-accent: linear-gradient(180deg, #f3d58f, #d6a24b 60%, #b98734) padding-box,
    linear-gradient(180deg, #fff1c4, #7a5114) border-box;
  --metal-text: none;
  --raise: 0 0 0 1px var(--ring-gap), 0 0 0 2px rgba(201, 149, 62, .55), 0 10px 24px -12px rgba(227, 182, 90, .6);
  --plate-fill: linear-gradient(180deg, #13223a, #0c1727) padding-box, var(--gold-frame) border-box;
  --plate-line: 1px solid rgba(227, 182, 90, .2);
  --plate-shadow: 0 20px 40px -24px #000;
  --iron-fill: linear-gradient(180deg, #1a2a44, #0f1a2c) padding-box, linear-gradient(180deg, #e3b65a, #7a5114) border-box;
  --iron-edge: transparent;
  --iron-raise: 0 0 0 1px var(--ring-gap), 0 0 0 2px rgba(201, 149, 62, .3);
  --field-fill: #0c1727;
  --field-edge: #5a4a2a;
  --field-sink: inset 0 1px 3px rgba(0, 0, 0, .5);
  --bar-fill: linear-gradient(180deg, #13223a, #0c1727);
  --bar-edge: 0 1px 0 #c9953e, 0 10px 24px -12px #000;
  --engrave: none;
  --rule-line: linear-gradient(90deg, transparent, rgba(217, 169, 79, .7) 12%, rgba(217, 169, 79, .7) 88%, transparent);
  --heading-metal: linear-gradient(180deg, #fff3c4 0%, #f0cf7a 34%, #c9953e 54%, #a06c22 62%, #e8c06a 84%, #c9953e 100%);
  --enamel-base: #0a1322;
  --enamel-tint: 30%;
  --enamel-tint-hi: 52%;
  --enamel-ink: 70%;
  --lex-noun: #e3b65a;
  /* Badges and counters are gold coins: dark ink on gold in both themes */
  --badge-bg: #d9a94f;
  --badge-ink: #2a1a03;
  --cloud-1: #c9953e;
  --cloud-2: #1a6fa8;
  --cloud-3: #0e3b66;
  --cloud-4: #b8862e;
  --cloud-strength: .8;
  --wordmark-1: #e3b65a;
  --wordmark-2: #e3b65a;
  --wordmark-3: #e3b65a;
}
/* The theme's own plates and pills (grammar topic UI) in the material; a clickable plate keeps its gold frame under the
   pointer and glows instead of taking a solid border */
:root[data-palette="gold"] :is(.topic-intro, dialog.topic-sheet) {
  background: var(--plate-fill);
  border-color: transparent;
  box-shadow: var(--plate-shadow);
}
:root[data-palette="gold"] .topic-intro { outline: var(--plate-line); outline-offset: -5px; }
:root[data-palette="gold"] :is(.topic-video, .topic-cheat, .topic-sheet-close) {
  background: var(--iron-fill);
  border-color: var(--iron-edge);
  box-shadow: var(--iron-raise);
}
@media (hover: hover) {
  /* `body` lifts the rule over a component's own gold plate rule (an .astro one carries its scope attribute) */
  :root[data-palette="gold"] body .is-clickable:hover { box-shadow: var(--shadow-hover); }
  :root[data-palette="gold"] :is(.topic-video, .topic-cheat):hover { border-color: var(--accent); }
}
/* The colour key of the cases: enamel in a gold setting, like the level badges */
:root[data-palette="gold"] .ck {
  border: 1px solid transparent;
  border-radius: 4px;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--hue) var(--enamel-tint-hi), var(--enamel-base)),
      color-mix(in srgb, var(--hue) var(--enamel-tint), var(--enamel-base))) padding-box,
    var(--gold-setting) border-box;
  color: color-mix(in srgb, var(--hue) var(--enamel-ink), #ffffff);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .18), 0 1px 2px rgba(0, 0, 0, .3);
}
:root[data-palette="gold"] .ck.nom { --hue: var(--case-nom); }
:root[data-palette="gold"] .ck.akk { --hue: var(--case-akk); }
:root[data-palette="gold"] .ck.dat { --hue: var(--case-dat); }
:root[data-palette="gold"] .ck.gen { --hue: var(--case-gen); }
/* A page's title, gilded: the metal drawn through the letters. A coloured part inside it (der / die / das) keeps its own
   colour; drop-shadow, not text-shadow, since the letters themselves are transparent */
:root[data-palette="gold"] h1 {
  background: var(--heading-metal);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 1px 0 rgba(0, 0, 0, .35));
}

/* ---------- The Deutschland mode ----------
   Not a palette but a mode on top of any of them: <html data-mode="deutschland">, switched in the palette menu and kept
   apart from the palette choice (src/lib/palettes.ts). It is dark only: switching it on puts the page into the dark
   theme (ThemeInit, setDeutschland) and hides the theme toggle; switching it off brings back the reader's own theme.
   Schwarz-Rot-Gold — the black page, the flag's red as the brand, its gold for the badges (black on gold), the flag as a
   band on top of the header («Deutsch» on the home page keeps one colour, the ink: the flag's three by turns was too much), levels in three
   flag pairs, and the backdrop clouds in red and gold, drifting. It restates the whole base layer, so the palette under
   it doesn't show through; the block comes after the default dark one and the palettes' (same specificity), so the mode
   wins. The brand red sits next to the coral red of die in the dark theme; they meet only as a link beside a bold
   article. */
:root[data-mode="deutschland"] {
  --flag-black: #000000;
  --flag-red: #dd0000;
  --flag-gold: #ffce00;
  /* The flag's black on the black page: a dark grey that still shows (the header band) */
  --flag-black-shade: #3a3a3e;
  --bg: #0e0e0f;
  --surface: #19191b;
  --surface-2: #252528;
  --ink: #f3f3f3;
  --ink-soft: #bdbdc2;
  --ink-faint: #9d9da3;
  --border: #343437;
  --border-strong: #6e6e74;
  --shadow: 0 1px 2px rgba(0, 0, 0, .3), 0 12px 28px -14px rgba(0, 0, 0, .6);
  --shadow-tile: var(--shadow);
  --shadow-hover: 0 2px 4px rgba(0, 0, 0, .35), 0 18px 36px -14px rgba(0, 0, 0, .75);
  --brand: #ff4b40;
  --brand-ink: #ff6a60;
  --brand-soft: #3a110e;
  --badge-bg: var(--flag-gold);
  --badge-ink: #121212;
  --on-accent: #0e0e0f;
  /* The black is the page itself; gold top-left, red top-right and bottom-left, a deeper gold bottom-right; slowly
     drifting */
  --cloud-1: var(--flag-gold);
  --cloud-2: var(--flag-red);
  --cloud-3: #b89400;
  --cloud-4: var(--flag-red);
  --backdrop-motion: cloud-drift, cloud-breathe;
  /* black would vanish on the dark page: the band's first third is the dark grey */
  --header-stripe: linear-gradient(to right, var(--flag-black-shade) 0 33.4%, var(--flag-red) 0 66.7%, var(--flag-gold) 0);
  /* Levels in three flag pairs: A black on gold, B white on red, C gold on black */
  --level-a1-bg: var(--flag-gold);  --level-a1-ink: var(--flag-black);
  --level-a2-bg: var(--flag-gold);  --level-a2-ink: var(--flag-black);
  --level-b1-bg: var(--flag-red);   --level-b1-ink: #ffffff;
  --level-b2-bg: var(--flag-red);   --level-b2-ink: #ffffff;
  --level-c1-bg: var(--flag-black); --level-c1-ink: var(--flag-gold);
  --level-c2-bg: var(--flag-black); --level-c2-ink: var(--flag-gold);
  /* Breadcrumbs: the path in red, the page you are on in gold */
  --crumb-link: var(--brand-ink);
  --crumb-current: var(--flag-gold);

  color-scheme: dark;
}

/* The palette menu's swatches (PaletteMenu): each palette's brand, plate (--surface-2) and badge in its light theme,
   and the flag for the Deutschland mode; the same whichever palette is on */
:root {
  --swatch-indigo-a: #008a98; --swatch-indigo-b: #e6e8f6; --swatch-indigo-c: #bfe2e6;
  --swatch-clean-a: #087ea4;  --swatch-clean-b: #e8ebef;  --swatch-clean-c: #c2dfe9;
  --swatch-ocean-a: #0081ad;  --swatch-ocean-b: #e0ecf3;  --swatch-ocean-c: #bddeea;
  --swatch-mint-a: #0a8a6c;   --swatch-mint-b: #d6ede5;   --swatch-mint-c: #c0e2da;
  --swatch-gold-a: #94671a;   --swatch-gold-b: #ede3cd;   --swatch-gold-c: #e4d2b1;
  --swatch-deutschland-a: #000000; --swatch-deutschland-b: #dd0000; --swatch-deutschland-c: #ffce00;
}

/* Semantic tokens: they point at the palette, so they follow the theme automatically */
:root {
  /* Gender and number: der · die · das · Plural · no article */
  --m: var(--blue);    --m-soft: var(--blue-soft);
  --f: var(--red);     --f-soft: var(--red-soft);
  --n: var(--mint);    --n-soft: var(--mint-soft);
  --pl: var(--orange); --pl-soft: var(--orange-soft);
  /* No article: neutral on purpose, "nothing" gets no colour */
  --zero: var(--ink-soft); --zero-soft: var(--surface-2);
  /* Definiteness: one hue in two strengths, kept apart from the gender colours.
     The definite article (der/die/das) is the full plum, the indefinite one (ein/eine) a quieter step of it */
  --def: var(--plum);   --def-soft: var(--plum-soft);
  --indef: color-mix(in srgb, var(--def) 70%, var(--ink-faint));
  --indef-soft: color-mix(in srgb, var(--plum-soft) 70%, var(--surface-2));

  /* Cases (the user's rule: Akkusativ green, Dativ red). Nominativ is the indigo of the surfaces (the starting form),
     Genitiv violet: plum is taken by --def, orange by the Plural, gold is too close to it. Dativ is a hair deeper than the
     red of die, so a Dativ label is still told from a feminine article. In a table the case colours the row head /
     label, the gender colours the article: never both on one element.
     Tenses: where on the time line (the tense scale, the Plusquamperfekt timeline, the tense topics): the past indigo,
     the moment of speaking green, the future gold, the same three everywhere.
     Both families are vivid hues for what is bold or large (labels, row heads, names, dots, chips: 3:1). Small
     regular-weight text in their colour takes the -ink step: the same hue with as little --ink as AA (4.5:1) needs */
  --case-nom: var(--indigo); --case-nom-soft: var(--indigo-soft);
  --case-akk: var(--green);  --case-akk-soft: var(--green-soft);
  --case-dat: color-mix(in srgb, var(--red) 55%, var(--ink)); --case-dat-soft: var(--red-soft);
  --case-gen: var(--violet); --case-gen-soft: var(--violet-soft);
  --tense-past: var(--indigo); --tense-past-soft: var(--indigo-soft);
  --tense-now: var(--green);   --tense-now-soft: var(--green-soft);
  --tense-future: var(--gold); --tense-future-soft: var(--gold-soft);
  /* The axes of the verb map (VerbMap.astro): Verbtyp, Valenz, Verbformen — hues apart from the tenses and the cases */
  --verb-type: var(--blue);     --verb-type-soft: var(--blue-soft);
  --verb-valency: var(--teal);  --verb-valency-soft: var(--teal-soft);
  --verb-forms: var(--violet);  --verb-forms-soft: var(--violet-soft);
  /* The AA steps of the hues (minimum ink per hue, light theme; in the dark theme the mix only lightens) */
  --indigo-ink: var(--indigo);
  --green-ink: color-mix(in srgb, var(--green) 74%, var(--ink));
  --gold-ink: color-mix(in srgb, var(--gold) 74%, var(--ink));
  --red-ink: color-mix(in srgb, var(--red) 84%, var(--ink));
  --teal-ink: color-mix(in srgb, var(--teal) 74%, var(--ink));
  --case-nom-ink: var(--indigo-ink); --case-akk-ink: var(--green-ink);
  --case-dat-ink: var(--red-ink);    --case-gen-ink: color-mix(in srgb, var(--violet) 70%, var(--ink));
  --tense-past-ink: var(--indigo-ink); --tense-now-ink: var(--green-ink); --tense-future-ink: var(--gold-ink);

  /* Part of speech (lexeme type) of a word: the tint and glow of its card, only in lists that mix parts of speech
     (a topic's words, a semantic-group card; WordList, `mixesLexemes`). Hues no article uses: a noun is neutral (der/die/
     das/Plural already colour it), a verb violet, an adjective or adverb green (one quality colour). Phrases and function
     words get none */
  --lex-noun: var(--border-strong); --lex-noun-soft: var(--surface-2);
  --lex-verb: var(--violet);        --lex-verb-soft: var(--violet-soft);
  --lex-adj: var(--green);          --lex-adj-soft: var(--green-soft);
  --lex-adv: var(--lex-adj);        --lex-adv-soft: var(--lex-adj-soft);

  /* A card's CEFR level pill (CardMeta): its fill and text per level. By default A1 green, A2 teal, B1 indigo, B2 gold
     (each hue on its -soft), C1/C2 a plain chip; the Deutschland mode folds them into three flag pairs */
  --level-a1-bg: var(--green-soft);  --level-a1-ink: var(--green);
  --level-a2-bg: var(--teal-soft);   --level-a2-ink: var(--teal);
  --level-b1-bg: var(--indigo-soft); --level-b1-ink: var(--indigo);
  --level-b2-bg: var(--gold-soft);   --level-b2-ink: var(--gold);
  --level-c1-bg: var(--surface-2);   --level-c1-ink: var(--ink-soft);
  --level-c2-bg: var(--surface-2);   --level-c2-ink: var(--ink-soft);

  /* Breadcrumbs (Crumbs.astro): the links of the path and the page itself */
  --crumb-link: var(--accent);
  --crumb-current: var(--ink-soft);

  /* UI */
  --accent: var(--brand-ink); --accent-soft: var(--brand-soft);
  /* The material of a solid control (a main button, a switched-on toggle, a progress bar), used as `background:` — never
     `background-color:`, since a palette may make it a gradient: flat accent by default, gold metal in «Золото». Text on
     it is --on-accent */
  --fill-accent: var(--accent);
  /* A quieter step of the accent: the titles of what belongs to a sense (government, examples), the prepositional line */
  --accent-muted: color-mix(in srgb, var(--accent) 48%, var(--ink-soft));
  /* The current item of a list (page, section being read): a tint of the accent that shows on both backgrounds */
  --accent-current: color-mix(in srgb, var(--accent) 16%, transparent);
  /* Star dust of the Glossarion G: the light gold tint of a home column under the pointer and its small four-point
     stars (HomeLanding). Gold in every palette and theme: the logo's colour, not the brand's */
  --stardust: var(--gold);
  --stardust-tint: color-mix(in srgb, var(--gold-soft) 70%, transparent);
  /* States of a row, a button or a word: a step of the accent mixed into --surface, so it shows in both themes. Never the
     -soft tints for a state: in the dark theme they are darker than --surface and a hover drawn with them vanishes.
     Each is told apart from --surface and keeps text readable on it (`npm run theme:contrast`) */
  --hover-bg: color-mix(in srgb, var(--accent) 14%, var(--surface));     /* under the pointer */
  --pressed-bg: color-mix(in srgb, var(--accent) 22%, var(--surface));   /* switched on, chosen, the item you are on */
  --highlight-bg: color-mix(in srgb, var(--accent) 32%, var(--surface)); /* what sounds now: a sung word, a playing sentence */
  --good: var(--green-ink);
  --bad: var(--red);

  /* Roles: what a page asks for instead of picking a surface and a text colour itself. They point at the tokens above,
     so both themes follow. Pages never mix their own bg + ink pairs: the pairs here are the checked ones. */
  /* Header cell of a table: strong ink on a clearly tinted, still light indigo step (the tint is the table's frame, not a label colour);
     the grammar topic tables use it in src/components/tables/TablePlate.module.css */
  --table-head-bg: color-mix(in srgb, var(--indigo) 14%, var(--surface));
  --table-head-ink: var(--ink);
  /* A tile (an example, a pair, a step, a plate of a guide) lying on a card or a dialog (--surface): a whisper of
     --surface-2, with a --border outline */
  --tile-bg: color-mix(in srgb, var(--surface-2) 55%, var(--surface));
  /* A badge: the round holder of an icon or a number, a small tag or counter. It sits on a card and on a tile alike,
     so it is a clear step of the brand hue, never the pale --accent-soft that melts into --surface-2 and --tile-bg
     (both are as light as it); the separation from --surface and --tile-bg is checked by `npm run theme:contrast` */
  --badge-bg: color-mix(in srgb, var(--brand) 26%, var(--surface));
  --badge-ink: color-mix(in srgb, var(--brand-ink) 86%, var(--ink));
  /* A chip, filter or small control: --surface-2 with an outline that is visible without hovering */
  --chip-bg: var(--surface-2);
  --chip-ink: var(--ink);
  /* An accented note, answer or result sitting on the page: the accent's soft tint thinned out with the surface (+ --shadow) */
  --callout-bg: color-mix(in srgb, var(--accent-soft) 45%, var(--surface));
  /* A hairline between rows and blocks */
  --divider: var(--border);
  /* A German example inside Russian prose (.de-ex, below): a chip of ink thinned out with whatever lies under it, so it
     shows on the page, a card, a tile and a callout, in both themes */
  --example-bg: color-mix(in srgb, var(--ink) 8%, transparent);
  --example-ink: var(--ink);

  /* Motion */
  --ease: cubic-bezier(.2, .7, .2, 1);
  --dur-fast: .15s;
  --dur: .3s;
  --dur-slow: .6s;
  /* A clickable plate (.is-clickable, below): how far it lifts under the pointer and how far it sinks when pressed */
  --plate-lift: -2px;
  --plate-press: .98;

  /* Dialogs: corner radius, lifted shadow and the dimmed, blurred page behind them */
  --radius-dialog: 22px;
  /* A popover or dropdown lifted over the page */
  --shadow-pop: 0 18px 50px -20px rgba(0, 0, 0, .45), var(--shadow);
  --shadow-dialog: 0 30px 80px -30px rgba(0, 0, 0, .45), var(--shadow);
  --backdrop: color-mix(in srgb, var(--ink) 32%, transparent);
  /* The page tour (src/components/tour/): the dimmed page around the highlighted control. Darkens in both themes (a
     tint of --ink would lighten the dark one); the dark theme takes a deeper step so the hole still reads */
  --spotlight: rgba(0, 0, 0, .45);

  /* The site header (src/components/site/SiteHeader.astro): its height and the side padding of its row, which spans the
     whole window (the logo at the left edge, the links and the theme toggle at the right one); the width of a page's
     column is --site-width */
  --site-header-h: 60px;
  --site-width: 960px;
  --site-gutter: 16px; /* 24px from 1024px up, see below */

  /* Space kept above an anchor target: the sticky site header plus room for sticky in-page navigation */
  --anchor-offset: calc(var(--site-header-h) + 72px);

  /* Icons (lucide, 24-unit grid): sizes and line weight */
  --icon-xs: 14px;
  --icon-sm: 16px;
  --icon-md: 20px;
  --icon-lg: 24px;
  --icon-xl: 32px;
  --icon-stroke: 2;

  /* A list's controls (the search, the toolbar buttons, «Слушать подряд»): one height and one step between them, across
     and down, on every screen (46px is past the 44px touch target) */
  --control-h: 46px;
  --control-gap: 8px;
}
@media (max-width: 1023px) {
  :root { --site-header-h: 56px; }
}
/* The same on every page, with a side list or without: the logo never moves between pages */
@media (min-width: 1024px) {
  :root { --site-gutter: 24px; }
}

/* Icon contract: every icon is a lucide glyph rendered by src/components/Icon.tsx as
   <svg class="ui-icon" data-size="xs|sm|md|lg|xl" [data-filled]>. Size and stroke come only from the
   tokens above, color is currentColor (set it on the parent). data-filled fills solid glyphs (play, pause). */
.ui-icon {
  width: var(--icon-size, var(--icon-md));
  height: var(--icon-size, var(--icon-md));
  flex: none;
  stroke-width: var(--icon-stroke);
  vertical-align: middle;
}
.ui-icon[data-size="xs"] { --icon-size: var(--icon-xs); }
.ui-icon[data-size="sm"] { --icon-size: var(--icon-sm); }
.ui-icon[data-size="lg"] { --icon-size: var(--icon-lg); }
.ui-icon[data-size="xl"] { --icon-size: var(--icon-xl); }
.ui-icon[data-filled] { fill: currentColor; }

/* Base */
*, *::before, *::after { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  line-height: 1.55;
}
h1, h2, h3 { font-family: var(--font-display); text-wrap: balance; }

/* A German example inside Russian prose: a chip, so the eye finds it at once (a change of font alone did not show).
   Used by every explanation of the dictionary (InlineText: `code` in a note) and by the grammar topics, whose inline
   examples are <span class="de-in"> or <span class="mono"> in a paragraph or a list item. A long sentence wraps, and
   each line keeps its own rounded chip */
.de-ex,
:is(p, li) > :is(.de-in, .mono) {
  padding: .06em .36em;
  border-radius: 6px;
  background: var(--example-bg);
  color: var(--example-ink);
  font-family: var(--font-body);
  font-style: normal;
  font-weight: 500;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
.de-ex b, .de-ex strong { font-weight: 700; color: var(--accent); }

/* Mobile: keep font sizes stable in landscape and drop the grey tap flash on iOS */
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

/* The page's scrollbar keeps its place even when a dialog switches page scrolling off (overflow: hidden), so the page
   behind an opening dialog doesn't jump sideways by the scrollbar's width */
html { scrollbar-gutter: stable; }

/* Smooth in-page anchor navigation that stops below sticky headers */
html {
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--anchor-offset) + env(safe-area-inset-top, 0px));
}

/* Transitions for everything interactive. :where() keeps specificity at zero,
   so any page rule that sets its own transition wins. */
:where(a, button, input, select, textarea, summary, label, [role="button"], [tabindex]) {
  transition:
    color var(--dur-fast) var(--ease),
    background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    box-shadow var(--dur) var(--ease),
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease),
    outline-color var(--dur-fast) var(--ease);
}

/* A clickable plate: a card, tile or block that opens something (a dialog, a page). One look on the whole site, in the
   app's components and in the grammar topics alike. The plate keeps its own resting look (its border, --shadow); the
   class adds only the reaction: under the pointer it lifts by --plate-lift, its border takes the accent and the shadow
   deepens (--shadow-hover); pressed, it sinks to --plate-press; the keyboard focus is an accent ring. A plate whose colour
   means something (der/die/das, a category) sets --plate-accent to it, and the border and ring take that colour.
   translate/scale, not transform: the scroll-in "rise" animation of a topic's blocks holds transform and would swallow
   the lift. A plate that does nothing never gets the class: what doesn't react to a click doesn't react to the pointer.
   The `html` in front lifts the rules (0,2,1) over the plate's own resting look, which in an .astro component is scoped
   as `.plate[data-astro-cid-…]` (0,2,0) and is loaded after this file. */
html .is-clickable {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition:
    color var(--dur-fast) var(--ease),
    background-color var(--dur-fast) var(--ease),
    border-color var(--dur-fast) var(--ease),
    box-shadow var(--dur) var(--ease),
    translate var(--dur) var(--ease),
    scale var(--dur-fast) var(--ease),
    outline-color var(--dur-fast) var(--ease);
}
@media (hover: hover) {
  html .is-clickable:hover {
    translate: 0 var(--plate-lift);
    border-color: var(--plate-accent, var(--accent));
    box-shadow: var(--shadow-hover);
  }
}
html .is-clickable:active { scale: var(--plate-press); }
html .is-clickable:focus-visible { outline: 2px solid var(--plate-accent, var(--accent)); outline-offset: 2px; }

/* Keyframes shared by all pages */
@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}
@keyframes fade {
  from { opacity: 0; }
  to { opacity: 1; }
}
/* A soft ring that breathes out from a control the reader hasn't tried yet (a guide's hint) */
@keyframes glow {
  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
  70%, 100% { box-shadow: 0 0 0 10px color-mix(in srgb, var(--accent) 0%, transparent); }
}

/* Sections fade up as they scroll into view (scroll-driven, no JS;
   browsers without support simply show them) */
@supports (animation-timeline: view()) {
  section {
    animation: rise linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 140px;
  }
  /* A grammar topic's section is a jump target of its table of contents: the browser aims a jump at the section's
     box as drawn, so a section still lowered by its rise would make the jump overshoot. There the section stays put
     and its blocks rise instead. */
  /* Inside a dialog the scroller is the dialog's own body: a section at its bottom (a folded «Примеры») could never
     scroll far enough to finish its rise and stayed half transparent. Dialogs fade in as a whole instead. */
  dialog section { animation: none; }
  .topic-page .docs-main section { animation: none; }
  .topic-page .docs-main section > * {
    animation: rise linear both;
    animation-timeline: view();
    animation-range: entry 0% entry 140px;
  }
}

/* Respect the OS "reduce motion" setting everywhere */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* A clickable plate still shows its border and shadow, but doesn't move */
  :root { --plate-lift: 0px; --plate-press: 1; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0s !important;
    transition-duration: .01ms !important;
  }
}

/* ---------- Grammar topics: shared UI ----------
   The raw HTML topic pages (content/grammar/) draw their controls with these classes, so a topic's navigation,
   buttons and dialogs look and behave like the rest of the site. The topic's own visualization stays page-local.
   Icons inside them are inline lucide glyphs with the .ui-icon contract (a topic page can't use Icon.tsx). */

/* Sticky row of section links under the top of the page; scrolls sideways inside itself on a phone. This is how a
   standalone artifact shows it: on the site the topic shell ([topic].astro) takes the row out and lists its links in
   «На этой странице». */
.topic-nav {
  position: sticky;
  top: env(safe-area-inset-top, 0px);
  z-index: 20;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--border);
}
.topic-nav-inner {
  max-width: var(--topic-width, 960px);
  margin-inline: auto;
  padding: 8px 20px;
  display: flex;
  gap: 4px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.topic-nav-inner::-webkit-scrollbar { display: none; }
.topic-nav a {
  flex: none;
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: 0 12px;
  border-radius: 999px;
  border: 1px solid transparent;
  color: var(--ink-soft);
  font: 600 13px / 1 var(--font-body);
  text-decoration: none;
  white-space: nowrap;
}
@media (hover: hover) {
  .topic-nav a:hover { border-color: var(--border); color: var(--accent); }
}
.topic-nav a:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
@media (pointer: coarse) {
  .topic-nav a { min-height: 44px; }
}

/* The head of every topic: one template, so topics don't differ. Markup:
   <header class="topic-hero"> [.topic-eyebrow «Урок N», only when the topic belongs to a video lesson] <h1> [.topic-lead]
   [.topic-video] </header>. Title, lead and lesson pill live here only; a topic never restyles them. */
.topic-hero {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding: 20px 0 24px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.topic-eyebrow {
  font: 700 12px / 1 var(--font-display);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--accent);
}
.topic-hero h1 {
  margin: 0;
  font: 800 clamp(28px, 5vw, 40px) / 1.12 var(--font-display);
  color: var(--ink);
  text-wrap: balance;
}
.topic-lead {
  margin: 0;
  color: var(--ink-soft);
  font-size: 16px;
  line-height: 1.55;
}
.topic-hero .topic-video, .topic-hero > .topic-cheat, .topic-hero .topic-cheats { margin-top: 6px; }

/* The intro card of a topic that belongs to a family (the tense topics): the same two parts in the same order on every
   page, each a heading, a short plain paragraph and one tiny example (German, Russian, English, each on its own line).
   <div class="topic-intro"><div class="topic-intro-part"><h2>…</h2><p>…</p>
   <div class="topic-intro-ex"><div class="de" lang="de">…</div><div class="tr">…</div><div class="en" lang="en">…</div></div>
   </div>…</div>. A topic never restyles it; its own colour classes inside (<b class="…">) still apply. */
.topic-intro {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr));
  gap: 16px 28px;
  margin-bottom: 8px;
  padding: 18px 22px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: var(--shadow);
}
.topic-intro-part { min-width: 0; }
.topic-intro-part h2 {
  margin: 0 0 6px;
  font: 700 16px / 1.3 var(--font-display);
  color: var(--ink);
}
.topic-intro-part p { margin: 0; font-size: 15px; line-height: 1.6; }
.topic-intro-ex {
  margin-top: 10px;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--tile-bg);
}
.topic-intro-ex .de { font-family: var(--font-display); font-style: italic; font-size: 15px; color: var(--ink); }
.topic-intro-ex .tr { margin-top: 2px; font-size: 13.5px; color: var(--ink-soft); }
.topic-intro-ex .en { font-size: 13px; color: var(--ink-faint); }
@media (max-width: 640px) { .topic-intro { padding: 16px; } }

/* Tabs inside one topic (two sub-pages): underlined text tabs on a hairline, as the part-of-speech tabs of a card.
   <div class="topic-tabs" role="tablist"><button class="topic-tab" role="tab" aria-selected="true" data-tab="x">…</button></div>;
   the panels are the topic's sections with data-tab-panel="x" and [hidden] when inactive; the topic's own script switches
   them and fires «topictab» on document (the «На этой странице» list follows it). */
.topic-tabs {
  display: flex;
  gap: 22px;
  overflow-x: auto;
  scrollbar-width: none;
  border-bottom: 1px solid var(--border);
}
.topic-tabs::-webkit-scrollbar { display: none; }
.topic-tab {
  position: relative;
  flex: none;
  min-height: 44px;
  padding: 0 2px;
  border: 0;
  background: none;
  color: var(--ink-soft);
  font: 600 15px var(--font-body);
  white-space: nowrap;
  cursor: pointer;
}
.topic-tab::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transition: transform var(--dur) var(--ease);
}
.topic-tab[aria-selected="true"] { color: var(--ink); }
.topic-tab[aria-selected="true"]::after { transform: scaleX(1); }
@media (hover: hover) {
  .topic-tab[aria-selected="false"]:hover { color: var(--accent); }
}
.topic-tab:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: 6px; }
[data-tab-panel][hidden] { display: none !important; }

/* The colour key of the cases, under the title of a case topic (Kasus, Akkusativ, Dativ, Genitiv): one colour per case,
   the same on every page. <div class="case-key"><span class="ck nom">Nominativ · кто?</span>…</div>. A topic never
   restyles it */
.case-key { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 20px; }
.ck { border-radius: 999px; padding: 4px 12px; background: var(--surface-2); font: 700 13px / 1.4 var(--font-mono); }
.ck.nom { color: var(--case-nom); }
.ck.akk { color: var(--case-akk); }
.ck.dat { color: var(--case-dat); }
.ck.gen { color: var(--case-gen); }

/* Pill link to the source video lesson, under the topic's title */
.topic-video {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  align-self: flex-start;
  min-height: 40px;
  margin-top: 16px;
  padding: 0 16px 0 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow);
  font: 600 14px / 1 var(--font-body);
  text-decoration: none;
}
.topic-video .ui-icon { color: var(--bad); }
@media (hover: hover) {
  .topic-video:hover { border-color: var(--accent); color: var(--accent); }
}
.topic-video:active { transform: scale(.96); }
.topic-video:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (pointer: coarse) {
  .topic-video { min-height: 44px; }
}

/* Pill button that opens a cheat sheet of the topic (a .topic-sheet dialog with a basic table, e.g. the personal pronouns
   by case): the lesson pill's shape, the accent icon. <button class="topic-cheat" data-open="<dialog id>">. A topic never
   restyles it */
.topic-cheat {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  align-self: flex-start;
  min-height: 40px;
  padding: 0 16px 0 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow);
  font: 600 14px / 1 var(--font-body);
  text-align: left;
  cursor: pointer;
}
.topic-cheat .ui-icon { color: var(--accent); }
@media (hover: hover) {
  .topic-cheat:hover { border-color: var(--accent); color: var(--accent); }
}
.topic-cheat:active { transform: scale(.96); }
.topic-cheat:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (pointer: coarse) {
  .topic-cheat { min-height: 44px; }
}
/* Several cheat sheets in one topic: the pills in a row that wraps (<div class="topic-cheats">) */
.topic-cheats { display: flex; flex-wrap: wrap; gap: 8px; }

/* Dialog with a list of examples: centered modal on desktop, full-screen page on phones — the same shell as the
   story dialog of a vocabulary card. Markup: <dialog class="topic-sheet"> → .topic-sheet-head (.topic-sheet-title
   with <b> and <span>, then the round close button .topic-sheet-close with an X icon, as in the app's dialogs)
   → .topic-sheet-body. */
dialog.topic-sheet {
  width: min(720px, calc(100% - 32px));
  max-height: min(88dvh, 860px);
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-dialog);
  background: var(--surface);
  color: var(--ink);
  box-shadow: var(--shadow-dialog);
  overflow: hidden;

  opacity: 0;
  transform: translateY(18px) scale(.97);
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease),
    overlay var(--dur) allow-discrete,
    display var(--dur) allow-discrete;
}
dialog.topic-sheet[open] { display: flex; flex-direction: column; opacity: 1; transform: none; }
@starting-style {
  dialog.topic-sheet[open] { opacity: 0; transform: translateY(18px) scale(.97); }
}
dialog.topic-sheet::backdrop {
  background: transparent;
  -webkit-backdrop-filter: blur(0);
  backdrop-filter: blur(0);
  transition:
    background var(--dur) var(--ease),
    backdrop-filter var(--dur) var(--ease),
    overlay var(--dur) allow-discrete,
    display var(--dur) allow-discrete;
}
dialog.topic-sheet[open]::backdrop {
  background: var(--backdrop);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}
@starting-style {
  dialog.topic-sheet[open]::backdrop { background: transparent; backdrop-filter: blur(0); }
}
html:has(dialog.topic-sheet[open]) { overflow: hidden; }

.topic-sheet-head {
  flex: none;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 14px;
  padding: 14px 14px 14px 18px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.topic-sheet-close {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink-soft);
  cursor: pointer;
}
@media (hover: hover) {
  .topic-sheet-close:hover { color: var(--ink); border-color: var(--ink-faint); }
}
.topic-sheet-close:active { transform: scale(.92); }
.topic-sheet-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (pointer: coarse) {
  .topic-sheet-close { width: 44px; height: 44px; }
}
.topic-sheet-title { display: grid; gap: 1px; min-width: 0; }
.topic-sheet-title b { font: 600 20px / 1.15 var(--font-display); color: var(--c, var(--ink)); }
.topic-sheet-title span { font-size: 12px; color: var(--ink-soft); }
/* the gloss under the title: the Russian, then the English on its own line, quieter (never «RU / EN» on one line) */
.topic-sheet-title .en { color: var(--ink-faint); }
.topic-sheet-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 18px clamp(18px, 5vw, 32px) calc(24px + env(safe-area-inset-bottom, 0px));
  display: flex;
  flex-direction: column;
  gap: 10px;
  animation: fade var(--dur) var(--ease) both;
}
@media (max-width: 640px) {
  dialog.topic-sheet {
    width: 100%;
    max-width: 100%;
    height: 100dvh;
    max-height: 100dvh;
    margin: 0;
    border: 0;
    border-radius: 0;
    transform: translateY(100%);
  }
  dialog.topic-sheet[open] { transform: none; }
  @starting-style {
    dialog.topic-sheet[open] { transform: translateY(100%); }
  }
  .topic-sheet-head { padding-top: calc(14px + env(safe-area-inset-top, 0px)); }
}

@media print {
  .topic-nav, .topic-video, .topic-cheat, .topic-tabs { display: none; }
}
