/**
 * Design tokens - the whole theming contract.
 *
 * Personalisation is THREE independent axes, set as attributes on <html>:
 *   data-theme  the visual personality; the catalogue lives in
 *               js/lib/themes.js, the tokens in the THEMES section below
 *   data-mode   light | dark                           (brightness)
 *   data-font   system | rounded | serif | playful | mono
 *
 * Keeping them independent is what lets someone have the kids theme in dark
 * mode with a serif face, instead of a fixed list of combinations.
 *
 * Every colour is defined here on :root first. Theme and mode blocks only
 * REDEFINE tokens - no component ever hardcodes a colour, so a new theme is a
 * block of variables rather than a rewrite.
 */

:root {
  /* ---- Font stacks ----
     Each stack ends with a CJK system-font list. Browsers fall back per glyph,
     so Latin text uses the decorative face while Chinese, Japanese and Korean
     text automatically drops through to a font that actually has those glyphs.
     Decorative Latin faces ship no CJK coverage, so without this tail every
     CJK user would see tofu boxes. System CJK fonts are used rather than Noto
     web fonts to avoid a multi-megabyte download. */
  --cjk-stack: "PingFang SC", "Hiragino Sans", "Hiragino Kaku Gothic ProN",
               "Yu Gothic UI", "Microsoft YaHei UI", "Microsoft YaHei",
               "Malgun Gothic", "Apple SD Gothic Neo", "Noto Sans CJK SC",
               "Noto Sans CJK JP", "Noto Sans CJK KR", "Source Han Sans SC";
  --system-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
                  "Helvetica Neue", Arial, sans-serif;

  --font-ui: var(--system-stack), var(--cjk-stack);
  --font-display: var(--font-ui);
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Consolas,
               "Liberation Mono", monospace, var(--cjk-stack);

  /* ---- Type scale ---- */
  --fs-xs: 0.6875rem;
  --fs-sm: 0.8125rem;
  --fs-base: 0.9375rem;
  --fs-md: 1.0625rem;
  --fs-lg: 1.25rem;
  --fs-xl: 1.5rem;
  --fs-2xl: 2rem;
  --fs-3xl: 2.75rem;
  --lh-tight: 1.2;
  --lh-normal: 1.5;
  --lh-relaxed: 1.7;
  --fw-normal: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;
  --letter-display: -0.01em;

  /* ---- Spacing (4px base) ---- */
  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4rem;

  /* ---- Shape ---- */
  --radius-sm: 4px;
  --radius: 8px;
  --radius-lg: 14px;
  --radius-xl: 22px;
  --radius-pill: 999px;
  --border-width: 1px;
  /* Solid everywhere except where a theme says otherwise. Childish draws every
     outline dashed, and that is a property of the theme in exactly the way its
     colours are — expressing it any other way would mean a stylesheet per
     theme, which is the thing this token file exists to avoid. */
  --border-style: solid;

  /* ---- Light palette (the base every theme starts from) ---- */
  --bg: #f6f7fb;
  --surface: #ffffff;
  --surface-2: #f1f2f7;
  --surface-3: #e7e9f0;
  --overlay: rgba(15, 18, 34, 0.45);

  --text: #171a2b;
  --text-muted: #5b6076;
  --text-subtle: #878ca3;
  --text-inverse: #ffffff;

  --border: #e2e4ed;
  /* Not decorative: an input's boundary is what marks it as a control, and the
     surface behind it is nearly the same colour as the page. WCAG 1.4.11 asks
     for 3:1 on non-text UI boundaries. */
  --border-strong: #8b8d97;

  --accent: #6366f1;
  --accent-hover: #5457e0;
  --accent-soft: #eef0fe;
  --accent-contrast: #ffffff;
  /* The accent used as TEXT (links, active chips, badges). A colour vivid
     enough to be a good fill is often too light to read at 4.5:1, so the two
     roles get separate tokens. Themes override this where they diverge. */
  --accent-text: var(--accent);

  /* Chosen to clear 4.5:1 against white, the vintage cream surface, and their
     own soft tint - status text is often shown on the tint, inside a badge. */
  --danger: #c22222;
  --danger-soft: #fee2e2;
  --success: #117f3a;
  --success-soft: #dcfce7;
  --warning: #9f5704;
  --warning-soft: #fef3c7;
  --info: #026ea5;
  --info-soft: #e0f2fe;

  /* Calendar-specific */
  --cal-grid-line: var(--border);
  --cal-day-bg: var(--surface);
  --cal-day-outside: var(--surface-2);
  --cal-today-ring: var(--accent);
  --cal-weekend-bg: var(--surface-2);
  --cal-holiday: #be123c;
  --cal-holiday-soft: #ffe4e6;
  --cal-incharge-ring: #f59e0b;

  /* ---- Elevation ---- */
  --shadow-sm: 0 1px 2px rgba(16, 20, 40, 0.06);
  --shadow: 0 2px 8px rgba(16, 20, 40, 0.08), 0 1px 2px rgba(16, 20, 40, 0.04);
  --shadow-lg: 0 12px 32px rgba(16, 20, 40, 0.14), 0 2px 8px rgba(16, 20, 40, 0.06);

  /* ---- Motion ---- */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --dur-fast: 120ms;
  --dur: 200ms;

  /* ---- Layout ---- */
  --sidebar-w: 264px;
  --header-h: 60px;
  --content-max: 1600px;
}

/* CJK glyphs are visually denser and need more leading to stay readable. */
:root[data-script="cjk"] {
  --lh-normal: 1.65;
  --lh-relaxed: 1.85;
  --letter-display: 0;
}

/* ============================================================
   MODE: dark
   Only redefines colour tokens; every measurement stays put.
   ============================================================ */

:root[data-mode="dark"] {
  --bg: #0e1017;
  --surface: #171a24;
  --surface-2: #1e2230;
  --surface-3: #272c3d;
  --overlay: rgba(0, 0, 0, 0.65);

  --text: #e8eaf2;
  --text-muted: #a2a8bd;
  --text-subtle: #757b92;
  --text-inverse: #0e1017;

  --border: #2a2f40;
  --border-strong: #5c6176;

  --accent: #818cf8;
  --accent-hover: #949dfa;
  --accent-soft: #1e2140;
  --accent-contrast: #0e1017;

  --danger: #f87171;
  --danger-soft: #3b1d1d;
  --success: #4ade80;
  --success-soft: #14321f;
  --warning: #fbbf24;
  --warning-soft: #3a2c11;
  --info: #38bdf8;
  --info-soft: #12293a;

  --cal-day-bg: var(--surface);
  --cal-day-outside: #12141c;
  --cal-weekend-bg: #13161f;
  --cal-holiday: #fb7185;
  --cal-holiday-soft: #3b1721;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 16px 40px rgba(0, 0, 0, 0.6);
}

/* ============================================================
   THEMES
   ============================================================

   ADDING ONE: append a block here, then add a line to js/lib/themes.js.
   Two edits, and tests/catalog.test.js fails if you make only one.

   A block redefines tokens; it never adds new ones. Everything already has a
   value on :root above, so the smallest useful theme is three declarations:

       :root[data-theme="ocean"] {
         --accent: #0e7490;
         --accent-hover: #0b5f77;
         --accent-soft: #e0f2fe;
       }

   Two traps, both of which have bitten this file before:

   * A DARK BLOCK IS NOT OPTIONAL ONCE YOU TOUCH A COLOUR. Theme and mode
     blocks have equal specificity, and the theme block is written first, so a
     light-mode value silently wins in dark mode unless the dark block restates
     it. That is how the vintage holiday colour once dropped to 2.08:1.

   * OVERRIDE A BACKGROUND AND YOU OWN THE TEXT ON IT. tests/contrast.test.js
     runs WCAG AA across ~23 token pairs, in both modes, for every theme in the
     registry — so a new theme is checked from the moment it is registered,
     without anyone adding it to a list.
   ============================================================ */

/* --- Minimal: quiet greys, tight corners, restrained shadows --- */
:root[data-theme="minimal"] {
  --accent: #3f3f46;
  --accent-hover: #27272a;
  --accent-soft: #f4f4f5;
  --radius: 6px;
  --radius-lg: 8px;
  --radius-xl: 12px;
  --shadow: 0 1px 3px rgba(0, 0, 0, 0.07);
  --shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.1);
  --bg: #fafafa;
  --surface-2: #f4f4f5;
}
:root[data-theme="minimal"][data-mode="dark"] {
  --accent: #d4d4d8;
  --accent-hover: #e4e4e7;
  --accent-soft: #27272a;
  --accent-contrast: #18181b;
  --bg: #09090b;
  --surface: #141416;
  --surface-2: #1c1c1f;
}

/* --- Kids: big soft shapes, high-contrast primaries --- */
:root[data-theme="kids"] {
  --accent: #ff5a8a;
  --accent-hover: #f43f6f;
  --accent-soft: #ffe4ec;
  /* White on this pink is only 2.97:1. The theme's own dark brown reaches
     4.57:1 and keeps the pink, rather than dulling it to suit white text. */
  --accent-contrast: #3d2a1e;
  --accent-text: #b03e5f;
  --radius: 14px;
  --radius-lg: 22px;
  --radius-xl: 30px;
  --radius-pill: 999px;
  --bg: #fff8ec;
  --surface: #ffffff;
  --surface-2: #fff1dd;
  --surface-3: #ffe4c4;
  --border: #ffd9b0;
  --border-strong: #bb8b5a;
  --text: #3d2a1e;
  --text-muted: #7a5c47;
  --cal-weekend-bg: #fff1dd;
  --cal-today-ring: #ff5a8a;
  --fw-medium: 600;
  --fw-semibold: 700;
  --fw-bold: 800;
  --shadow: 0 3px 0 rgba(61, 42, 30, 0.09);
  --shadow-lg: 0 10px 0 rgba(61, 42, 30, 0.1);
}
:root[data-theme="kids"][data-mode="dark"] {
  --bg: #241a2e;
  --surface: #322542;
  --surface-2: #3d2d50;
  --surface-3: #4a3760;
  --border: #4d3a63;
  --border-strong: #836d9b;
  --text: #ffeef5;
  --text-muted: #d3b8e0;
  --accent: #ff7fa5;
  --accent-hover: #ff99b8;   /* lighter on hover, as a dark surface expects */
  --accent-soft: #4a2438;
  /* The theme block above sets a deep pink for text on white; on this dark
     surface it drops to 2.5:1, so dark mode takes the light pink back. Same
     trap as the vintage holiday colour - a theme-level value tuned for light
     mode wins on source order unless dark mode restates it. */
  --accent-text: #ff7fa5;
  --cal-weekend-bg: #2b2038;
}

/* --- Colourful: saturated violet/teal, generous curves --- */
:root[data-theme="colourful"] {
  --accent: #7c3aed;
  --accent-hover: #6d28d9;
  --accent-soft: #f3e8ff;
  --radius: 12px;
  --radius-lg: 18px;
  --radius-xl: 26px;
  --bg: #f5f3ff;
  --surface: #ffffff;
  --surface-2: #ede9fe;
  --surface-3: #ddd6fe;
  --border: #ddd6fe;
  --border-strong: #998dc6;
  --text: #2e1065;
  --text-muted: #6d5b9e;
  --cal-weekend-bg: #f3effe;
  --shadow: 0 4px 14px rgba(124, 58, 237, 0.14);
  --shadow-lg: 0 16px 40px rgba(124, 58, 237, 0.22);
}
:root[data-theme="colourful"][data-mode="dark"] {
  --bg: #16082e;
  --surface: #22103f;
  --surface-2: #2d1652;
  --surface-3: #3a1d68;
  --border: #3d2070;
  --border-strong: #7755b0;
  --text: #f0e7ff;
  --text-muted: #bda6e8;
  --accent: #a78bfa;
  --accent-hover: #bda5fb;
  --accent-soft: #2f1a55;
  --cal-weekend-bg: #1c0c37;
}

/* --- Vintage: warm paper, muted ink, hairline rules --- */
:root[data-theme="vintage"] {
  --accent: #9a6b3f;
  --accent-hover: #7f5730;
  --accent-soft: #f3e7d6;
  --radius-sm: 2px;
  --radius: 3px;
  --radius-lg: 5px;
  --radius-xl: 8px;
  --radius-pill: 4px;
  --bg: #f2ebdd;
  --surface: #fbf6ea;
  --surface-2: #efe6d4;
  --surface-3: #e5d9c2;
  --border: #ddceb2;
  --border-strong: #9f8c6e;
  --accent-text: #885f38;
  --text: #3a3026;
  --text-muted: #6f6252;
  --text-subtle: #96887a;
  --cal-weekend-bg: #ece2ce;
  --cal-holiday: #9c2c2c;
  --shadow: 0 1px 2px rgba(58, 48, 38, 0.14);
  --shadow-lg: 0 6px 20px rgba(58, 48, 38, 0.2);
  --letter-display: 0.01em;
}
:root[data-theme="vintage"][data-mode="dark"] {
  --bg: #1e1a15;
  --surface: #29231c;
  --surface-2: #332b22;
  --surface-3: #40362a;
  --border: #443a2d;
  --border-strong: #7d7160;
  --text: #ece0cc;
  --text-muted: #b3a488;
  --accent: #d0a878;
  --accent-hover: #dfbd94;
  --accent-soft: #382d20;
  --accent-contrast: #1e1a15;
  --accent-text: #d0a878;
  --cal-weekend-bg: #241f19;
  /* Without these, the light theme's #9c2c2c leaks into dark mode (equal
     specificity, later in the file) and holidays drop to 2.08:1. */
  --cal-holiday: #fb7185;
  --cal-holiday-soft: #3b1721;
}

/* --- Ocean: cool blue-greens, calm and low-contrast in feel --- */
:root[data-theme="ocean"] {
  --accent: #0e7490;
  --accent-hover: #0b5f77;
  --accent-soft: #daf1f7;
  --accent-text: #0b5f77;
  --radius: 10px;
  --radius-lg: 16px;
  --radius-xl: 22px;
  --bg: #eef7fa;
  --surface: #ffffff;
  --surface-2: #e3f1f6;
  --surface-3: #cfe6ee;
  --border: #c3dfe8;
  --border-strong: #6a94a1;
  --text: #102c33;
  --text-muted: #4a6a73;
  --text-subtle: #6b878e;
  --cal-weekend-bg: #e3f1f6;
  --cal-today-ring: #0e7490;
  --shadow: 0 1px 3px rgba(16, 44, 51, 0.09);
  --shadow-lg: 0 10px 26px rgba(16, 44, 51, 0.14);
}
:root[data-theme="ocean"][data-mode="dark"] {
  --bg: #071a20;
  --surface: #0f2830;
  --surface-2: #16343d;
  --surface-3: #1e424d;
  --border: #204a56;
  --border-strong: #6d97a4;
  --text: #ddf1f7;
  --text-muted: #9dc0ca;
  --accent: #4fc4dd;
  --accent-hover: #7ad4e7;
  --accent-soft: #10333d;
  --accent-contrast: #04161b;
  /* The light block's deep teal reads 2.2:1 on this surface; equal specificity
     and earlier in the file means it would win without this line. */
  --accent-text: #4fc4dd;
  --cal-weekend-bg: #0b222a;
}

/* --- Forest: deep greens on warm off-white, quiet and natural --- */
:root[data-theme="forest"] {
  --accent: #2f6f43;
  --accent-hover: #245736;
  --accent-soft: #dcefe1;
  --accent-text: #245736;
  --radius: 8px;
  --radius-lg: 14px;
  --radius-xl: 20px;
  --bg: #f3f6ef;
  --surface: #ffffff;
  --surface-2: #e9f0e5;
  --surface-3: #dae5d4;
  --border: #cddcc6;
  --border-strong: #71876a;
  --text: #1c2a1f;
  --text-muted: #4f6551;
  --text-subtle: #6f8272;
  --cal-weekend-bg: #e9f0e5;
  --cal-today-ring: #2f6f43;
  --shadow: 0 1px 3px rgba(28, 42, 31, 0.09);
  --shadow-lg: 0 10px 26px rgba(28, 42, 31, 0.14);
}
:root[data-theme="forest"][data-mode="dark"] {
  --bg: #0d150f;
  --surface: #16211a;
  --surface-2: #1d2b21;
  --surface-3: #26372a;
  --border: #2b3d30;
  --border-strong: #74907b;
  --text: #e2eee4;
  --text-muted: #a6bfab;
  --accent: #6dc189;
  --accent-hover: #8bd2a3;
  --accent-soft: #17301f;
  --accent-contrast: #08120a;
  --accent-text: #6dc189;
  --cal-weekend-bg: #111b13;
}

/* ============================================================
   FONT AXIS
   Independent of theme. Every stack keeps the CJK tail so a
   decorative Latin face never leaves CJK text as tofu boxes.
   ============================================================ */

/* --- Childish: butter yellow, pink dashed outlines, everything round ---
   A calendar a seven-year-old would draw. The dashed outline is the whole
   idea, and it is why --border-style exists: nothing else in the app wants a
   different line, and a theme that can only change colour cannot get near
   this. Text is deep violet rather than pink — pink on pink is exactly the
   trap the contrast suite exists to catch. */
:root[data-theme="childish"] {
  --bg: #fdf5a8;
  --surface: #fdf2f8;
  --surface-2: #fce7f3;
  --surface-3: #fbcfe8;
  --text: #4c1d95;
  --text-muted: #6d28d9;
  --text-subtle: #8b5cf6;
  --border: #f9a8d4;
  --border-strong: #c2418a;
  --border-style: dashed;
  --accent: #5b21b6;
  --accent-hover: #4c1d95;
  --accent-soft: #ede9fe;
  --accent-contrast: #ffffff;
  --accent-text: #5b21b6;
  --radius: 14px;
  --radius-lg: 20px;
  --radius-xl: 28px;
  --cal-day-bg: #fdf2f8;
  --cal-weekend-bg: #fce7f3;
  --cal-day-outside: #fdf5a8;
  --cal-today-ring: #db2777;
  --cal-holiday: #a21caf;
  --cal-holiday-soft: #fae8ff;
}
:root[data-theme="childish"][data-mode="dark"] {
  --bg: #2a2140;
  --surface: #382c53;
  --surface-2: #443465;
  --surface-3: #523f78;
  --text: #fdf2f8;
  --text-muted: #e9d5ff;
  --text-subtle: #c4b5fd;
  --border: #7c5fb0;
  --border-strong: #a98fd6;
  --accent: #f9a8d4;
  --accent-hover: #fbcfe8;
  --accent-soft: #4a2b5e;
  --accent-contrast: #3b0764;
  --accent-text: #f9a8d4;
  --cal-day-bg: #382c53;
  --cal-weekend-bg: #31264a;
  --cal-day-outside: #2a2140;
  --cal-holiday: #f0abfc;
  --cal-holiday-soft: #4a2352;
}

/* --- Retro: 70s print. Mustard, rust and chocolate, no curves ---
   Square corners, two-pixel rules and a hard offset shadow instead of a
   blur, because the look comes from cheap colour printing rather than from
   glass. Every status colour is restated: the defaults are tuned for white and
   go muddy on this cream. */
:root[data-theme="retro"] {
  --bg: #f4e3c1;
  --surface: #fdf6e6;
  --surface-2: #f0dfba;
  --surface-3: #e6d0a3;
  --text: #3b2412;
  --text-muted: #6b4a25;
  --text-subtle: #8a6a3f;
  --border: #c9a86a;
  --border-strong: #8a6a33;
  --border-width: 2px;
  --accent: #a83208;
  --accent-hover: #8c2906;
  --accent-soft: #fbe3d4;
  --accent-contrast: #fdf6e6;
  --accent-text: #a83208;
  --radius-sm: 0px;
  --radius: 2px;
  --radius-lg: 3px;
  --radius-xl: 4px;
  --radius-pill: 4px;
  --danger: #a81b1b;
  --danger-soft: #fbdede;
  --success: #0f6b33;
  --success-soft: #dcf3e2;
  --warning: #7a4405;
  --warning-soft: #fbeccb;
  --info: #05627f;
  --info-soft: #d9eef5;
  --cal-day-bg: #fdf6e6;
  --cal-weekend-bg: #f0dfba;
  --cal-day-outside: #f4e3c1;
  --cal-today-ring: #a83208;
  --cal-holiday: #9a3412;
  --cal-holiday-soft: #fde8d7;
}
:root[data-theme="retro"][data-mode="dark"] {
  --bg: #241a10;
  --surface: #33261a;
  --surface-2: #3f2f20;
  --surface-3: #4d3a27;
  --text: #fdf0d8;
  --text-muted: #dcc19a;
  --text-subtle: #b79a72;
  --border: #6b5236;
  --border-strong: #a1855c;
  --accent: #f97b46;
  --accent-hover: #fb9a6f;
  --accent-soft: #4a2a17;
  --accent-contrast: #241a10;
  --accent-text: #f97b46;
  --danger: #f08a8a;
  --danger-soft: #452020;
  --success: #69cf90;
  --success-soft: #173a26;
  --warning: #e8ae4b;
  --warning-soft: #42300f;
  --info: #6cc5e8;
  --info-soft: #123441;
  --cal-day-bg: #33261a;
  --cal-weekend-bg: #2b2015;
  --cal-day-outside: #241a10;
  --cal-holiday: #fca27a;
  --cal-holiday-soft: #48281a;
}

/* --- Paper: the quiet one. Monochrome, hairlines, no shadow at all ---
   A second minimal, further along than Minimal is: the accent is the text
   colour, so nothing on the page competes with the words on it. Square, flat,
   and the only colour in it is the holiday marker. */
:root[data-theme="paper"] {
  --bg: #f2f1ee;
  --surface: #fbfaf8;
  --surface-2: #eceae5;
  --surface-3: #e0ddd6;
  --text: #1c1b19;
  --text-muted: #57544e;
  --text-subtle: #807c74;
  --border: #d6d3cc;
  --border-strong: #78746c;
  --accent: #1c1b19;
  --accent-hover: #3a3833;
  --accent-soft: #eceae5;
  --accent-contrast: #fbfaf8;
  --accent-text: #1c1b19;
  --radius-sm: 0px;
  --radius: 0px;
  --radius-lg: 0px;
  --radius-xl: 0px;
  --radius-pill: 0px;
  --shadow-sm: none;
  --shadow: none;
  --cal-day-bg: #fbfaf8;
  --cal-weekend-bg: #eceae5;
  --cal-day-outside: #f2f1ee;
  --cal-today-ring: #1c1b19;
  --cal-holiday: #8a1f1f;
  --cal-holiday-soft: #f5e2e2;
}
:root[data-theme="paper"][data-mode="dark"] {
  --shadow-sm: none;
  --shadow: none;
  --bg: #141413;
  --surface: #1e1e1c;
  --surface-2: #282826;
  --surface-3: #333330;
  --text: #f2f1ee;
  --text-muted: #b5b3ad;
  --text-subtle: #8f8d87;
  --border: #3d3d39;
  --border-strong: #8a8a83;
  --accent: #f2f1ee;
  --accent-hover: #ffffff;
  --accent-soft: #2e2e2b;
  --accent-contrast: #141413;
  --accent-text: #f2f1ee;
  --cal-day-bg: #1e1e1c;
  --cal-weekend-bg: #191918;
  --cal-day-outside: #141413;
  --cal-holiday: #f0a5a5;
  --cal-holiday-soft: #3a2020;
}

/* --- Bloom: the flowery one. Rose and lilac on warm white, leaf green ---
   Soft without going pastel — the deep rose carries the text weight, and
   success borrows a leaf green so the one non-rose colour on screen still
   belongs to the garden. */
:root[data-theme="bloom"] {
  --bg: #fdf4f7;
  --surface: #ffffff;
  --surface-2: #fbe9f0;
  --surface-3: #f6d7e3;
  --text: #3f1d33;
  --text-muted: #6e3d5b;
  --text-subtle: #98657f;
  --border: #f0c4d6;
  --border-strong: #b2748f;
  --accent: #a83a6f;
  --accent-hover: #8e2f5d;
  --accent-soft: #fbe4ee;
  --accent-contrast: #ffffff;
  --accent-text: #a83a6f;
  --radius: 12px;
  --radius-lg: 20px;
  --radius-xl: 28px;
  --success: #2f6b2f;
  --success-soft: #e2f2df;
  --cal-day-bg: #ffffff;
  --cal-weekend-bg: #fbe9f0;
  --cal-day-outside: #fdf4f7;
  --cal-today-ring: #a83a6f;
  --cal-holiday: #b02655;
  --cal-holiday-soft: #fde4ec;
}
:root[data-theme="bloom"][data-mode="dark"] {
  --bg: #241626;
  --surface: #312033;
  --surface-2: #3d2941;
  --surface-3: #4b334f;
  --text: #fbe9f0;
  --text-muted: #dcbccd;
  --text-subtle: #b795a8;
  --border: #5c4061;
  --border-strong: #a07caa;
  --accent: #f2a0c4;
  --accent-hover: #f7bcd6;
  --accent-soft: #46243a;
  --accent-contrast: #2a1224;
  --accent-text: #f2a0c4;
  --success: #84cf84;
  --success-soft: #1e3a1e;
  --cal-day-bg: #312033;
  --cal-weekend-bg: #2a1b2c;
  --cal-day-outside: #241626;
  --cal-holiday: #f5a3bb;
  --cal-holiday-soft: #452029;
}

/* --- Midnight: deep indigo and old gold, at its best in the dark ---
   The one theme designed dark first and adapted to light rather than the
   other way round, which is why its light mode is the restrained half. Gold on
   near-black is the pairing it exists for. */
:root[data-theme="midnight"] {
  --bg: #eef0f7;
  --surface: #ffffff;
  --surface-2: #e4e7f2;
  --surface-3: #d5daea;
  --text: #161a2e;
  --text-muted: #4a5170;
  --text-subtle: #767d99;
  --border: #c6cce1;
  --border-strong: #6b7392;
  --accent: #2c3766;
  --accent-hover: #1f2850;
  --accent-soft: #e0e4f3;
  --accent-contrast: #ffffff;
  --accent-text: #2c3766;
  --radius: 10px;
  --radius-lg: 16px;
  --cal-day-bg: #ffffff;
  --cal-weekend-bg: #e4e7f2;
  --cal-day-outside: #eef0f7;
  --cal-today-ring: #9a7b2f;
  --cal-holiday: #8a5a10;
  --cal-holiday-soft: #faedd3;
}
:root[data-theme="midnight"][data-mode="dark"] {
  --bg: #0b1020;
  --surface: #141b30;
  --surface-2: #1c2440;
  --surface-3: #263050;
  --text: #e9ecf8;
  --text-muted: #b3bad4;
  --text-subtle: #8d95b3;
  --border: #2c3760;
  --border-strong: #7884ad;
  --accent: #e3c07a;
  --accent-hover: #eed4a0;
  --accent-soft: #2a2417;
  --accent-contrast: #0b1020;
  --accent-text: #e3c07a;
  --cal-day-bg: #141b30;
  --cal-weekend-bg: #111728;
  --cal-day-outside: #0b1020;
  --cal-today-ring: #e3c07a;
  --cal-holiday: #f0b3b3;
  --cal-holiday-soft: #3a1e1e;
}

:root[data-font="system"] {
  --font-ui: var(--system-stack), var(--cjk-stack);
  --font-display: var(--system-stack), var(--cjk-stack);
}
:root[data-font="rounded"] {
  --font-ui: "Nunito", var(--system-stack), var(--cjk-stack);
  --font-display: "Quicksand", "Nunito", var(--system-stack), var(--cjk-stack);
}
:root[data-font="serif"] {
  --font-ui: "Lora", Georgia, "Times New Roman", serif, var(--cjk-stack);
  --font-display: "Lora", Georgia, serif, var(--cjk-stack);
}
:root[data-font="playful"] {
  --font-ui: "Fredoka", "Nunito", var(--system-stack), var(--cjk-stack);
  --font-display: "Fredoka", "Nunito", var(--system-stack), var(--cjk-stack);
  --letter-display: 0.005em;
}
:root[data-font="mono"] {
  --font-ui: var(--font-mono);
  --font-display: var(--font-mono);
}

/* Each theme carries a default face, applied only when the user has not
   chosen one explicitly (data-font="auto"). */
:root[data-font="auto"][data-theme="kids"],
:root[data-font="auto"][data-theme="colourful"] {
  --font-ui: "Nunito", var(--system-stack), var(--cjk-stack);
  --font-display: "Fredoka", "Quicksand", var(--system-stack), var(--cjk-stack);
}
:root[data-font="auto"][data-theme="vintage"] {
  --font-ui: "Lora", Georgia, serif, var(--cjk-stack);
  --font-display: "Lora", Georgia, serif, var(--cjk-stack);
}
:root[data-font="auto"][data-theme="bloom"] {
  --font-ui: "Lora", Georgia, serif, var(--cjk-stack);
  --font-display: "Lora", Georgia, serif, var(--cjk-stack);
}
:root[data-font="auto"][data-theme="childish"] {
  --font-ui: "Nunito", var(--system-stack), var(--cjk-stack);
  --font-display: "Fredoka", "Quicksand", var(--system-stack), var(--cjk-stack);
}
/* Retro and Paper both want the typewriter, for opposite reasons: one is
   imitating a printed thing, the other is refusing to decorate. */
:root[data-font="auto"][data-theme="retro"],
:root[data-font="auto"][data-theme="paper"] {
  --font-ui: var(--font-mono);
  --font-display: var(--font-mono);
}

/* ============================================================
   Accessibility
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast: 0ms;
    --dur: 0ms;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

@media (prefers-contrast: more) {
  :root {
    --border: var(--border-strong);
    --text-muted: var(--text);
  }
}
