/**
 * Semantic intent tokens — single source of truth for both light and
 * dark modes via the CSS-native `light-dark()` function.
 *
 * Mode resolution: `:root` declares `color-scheme: light dark` so the
 * UA picks the matching branch from `light-dark()` automatically. The
 * manual toggle classes `:root.light` / `:root.dark` only override the
 * `color-scheme` (no token duplication needed) — `light-dark()` re-
 * resolves on its own.
 *
 * Browser support: Chrome 123+, Firefox 120+, Safari 17.5+ — Baseline
 * Newly Available since 2024-05.
 */

@theme {
  /* === SURFACE ===
     Four-level elevation ladder (L·0 → L·3). Each step sits visually
     above the one below — themes can differentiate them by color (e.g.
     cream → lighter cream → near-white → white) or rely on shadows
     alone when the palette ceiling is reached (as in the neutral default
     where base and overlay are both white).

     LIGHT-MODE SPREAD (2026-07). In light mode `base` sits at the white
     ceiling, so every other rung has to differentiate DOWNWARD — and the
     ramp gave it almost nothing to work with: quiet/elevated were ΔL 0.01
     and 0.02 from base, against 0.03 and 0.08 in dark mode. A tinted
     in-flow surface with no border and no shadow was therefore effectively
     invisible in light mode, which is why components kept reaching for a
     border just to make a surface visible at all (the chat bubble, the
     table-cell progress track). Fixed at the ramp rather than per token —
     `neutral-25` 0.99 → 0.985 and `neutral-50` 0.98 → 0.965 — so quiet,
     elevated and subtle all gain spread without any semantic moving and
     without a new token landing on an occupied value. All five themes share
     those L values (only the hue differs), so the change reaches every
     theme at once. Measured: text-tertiary on the new elevated is 11.32:1,
     far above AA; style/contrast.test.ts is the gate. Guarded below by
     style/semantic.test.ts, which asserts the reading surfaces stay
     mutually distinct in BOTH modes — the failure mode here is silent, a
     collapsed rung looks exactly like a working one in a screenshot. */
  /* L·1 — base: the page itself. Content, cards, and reading surfaces
     sit at this level. */
  --color-surface-base: light-dark(var(--color-neutral-0), var(--color-neutral-900));
  /* L·0 — quiet: the ground/table beneath the page. Softest in-page
     tint; tint alone signals "own zone" without border or shadow. */
  --color-surface-quiet: light-dark(var(--color-neutral-25), var(--color-neutral-850));
  /* L·2 — elevated: lifted surfaces (Popover, Menu, Select dropdown).
     Sits above the page with shadow + meaningful Z-index. */
  --color-surface-elevated: light-dark(var(--color-neutral-50), var(--color-neutral-800));
  /* L·3 — overlay: highest surfaces (Dialog, Drawer, Sheet, Toast).
     Full shadow + backdrop dimming. */
  --color-surface-overlay: light-dark(var(--color-neutral-0), var(--color-neutral-850));
  /* `surface-hover` / `-active` are the hover/press steps for elements resting
     on a READING surface (base/quiet/elevated) — a menu item, a table row.
     `surface-interactive` is a resting FILL one step in from the page (a filled
     Input, a Slider track, the Tab list). Those two ladders start at different
     rungs, so they need their own hover step: `surface-interactive` already sits
     at neutral-100, which is exactly where `surface-hover` lands in light mode —
     `bg-surface-interactive hover:bg-surface-hover` was a silent no-op, and in
     dark mode `surface-active` collapses onto `surface-interactive` the same
     way. `-interactive-hover` continues the fill's own ladder: one step further
     from the page in light, one step toward the light in dark. Guarded by
     style/semantic.test.ts so the pair can never collapse again. */
  --color-surface-interactive: light-dark(var(--color-neutral-100), var(--color-neutral-700));
  --color-surface-interactive-hover: light-dark(
    var(--color-neutral-200),
    var(--color-neutral-650)
  );
  --color-surface-hover: light-dark(var(--color-neutral-100), var(--color-neutral-750));
  --color-surface-active: light-dark(var(--color-neutral-200), var(--color-neutral-700));
  --color-surface-disabled: light-dark(var(--color-neutral-100), var(--color-neutral-800));
  --color-surface-selected: light-dark(var(--color-primary-50), var(--color-primary-900));
  /* A RESTING tint only — never a hover step. It resolves to exactly
     `surface-elevated`, so `hover:bg-surface-subtle` is invisible on every
     elevated surface (Popover, Menu, Select dropdown, elevated Card). That
     shipped across 8 components until 2026-07-26; the hover idiom moved to
     `surface-hover`, and variants-lint now errors on any hover fill naming a
     reading surface. Its in-page-zone role was superseded by `surface-quiet`
     (see docs/VARIANT-CONTRACT.md "The surface ladder"), which is why it has no rung of its own
     left — prefer `surface-quiet` for a tinted zone and `surface-elevated`
     for a raised one. Kept for the resting uses that read correctly against
     a border (readonly/disabled fields, list rows, code chips). */
  --color-surface-subtle: light-dark(var(--color-neutral-50), var(--color-neutral-800));
  --color-surface-inverted: light-dark(var(--color-neutral-900), var(--color-neutral-100));
  /* Skeleton wave-shimmer highlight (Skeleton animation="wave"). A translucent
     white glint that sweeps across `surface-interactive`; lower alpha in dark
     mode so it reads as a subtle sheen, not a flash. light-dark() keeps it
     mode-aware so the wave needs no `dark:` override. */
  --color-skeleton-shimmer: light-dark(oklch(1 0 0 / 0.5), oklch(1 0 0 / 0.1));

  /* === TEXT ===
     primary/secondary/tertiary are the informative-text ramp: each clears
     WCAG AA 4.5:1 on every reading surface (base/quiet/elevated/overlay/subtle)
     in both modes — measured by style/contrast.test.ts ("informative text on
     reading surfaces"). tertiary was shifted darker (light) for exactly this.

     quaternary is a MARK-ONLY token — placeholders, dense-grid marks (calendar
     day cells, kbd hints), disabled glyphs, decoration. It sits at the AA edge
     on reading surfaces (4.58–4.85:1 light) and drops BELOW AA on interactive/
     pressed surfaces (4.19/3.49) and hard below it under the docs Rooms skin
     (docs-softer, 1.96:1). Never use it for body text — reach for tertiary. The
     contrast test asserts it only against the 3:1 UI-component floor, not 4.5. */
  --color-text-primary: light-dark(var(--color-neutral-900), var(--color-neutral-100));
  --color-text-inverted: light-dark(var(--color-neutral-0), var(--color-neutral-900));
  --color-text-secondary: light-dark(var(--color-neutral-700), var(--color-neutral-300));
  --color-text-tertiary: light-dark(var(--color-neutral-600), var(--color-neutral-300));
  --color-text-quaternary: light-dark(var(--color-neutral-500), var(--color-neutral-400));
  /* Disabled text — the same stop in both modes. WCAG 1.4.3 exempts inactive
     controls, so the old value was not a violation, but at neutral-300 / -600 it
     measured roughly 1.5:1 in light and 2:1 in dark: a disabled field's label is
     the one part that still has to say what the field IS, and it was effectively
     invisible. Now held to the 3:1 UI floor by style/contrast.test.ts across
     every theme × mode × reading surface plus the disabled fill — that test is
     the number, not this comment.

     Deliberately still the weakest rung of the text ramp, so "disabled" stays
     legible without stopping being a signal. Two consequences, both accepted:
     it shares its light-mode value with text-quaternary (two roles, not two
     steps of one ladder — but see the Calendar entry in technical-debt, where
     they meet), and the floor covers the token alone, not what a component
     composes on top of it (an `opacity-*` wrapper can undo it). */
  --color-text-disabled: light-dark(var(--color-neutral-500), var(--color-neutral-500));
  /* Link ink — the resting colour of an inline text link on a reading
     surface. Aliases the primary intent's `-text` role, not the base intent
     token: the base is tuned as a fill and misses AA as text on calm grounds
     (which is why variants-lint bans `text-primary`), while `-text` is the
     ramp stop measured to clear AA 4.5 as text on every reading surface in
     both modes across all six themes — style/contrast.test.ts ("intent text
     roles on reading surfaces") is the number. Mode- and theme-awareness ride
     along: `primary-text` is light-dark() at its definition and every theme
     re-tunes the primary ramp, so this alias needs neither its own branch nor
     a `dark:` override. A token of its own (rather than spelling
     `text-primary-text` at the call sites) keeps links an independent lever —
     a consumer can restyle links without touching the primary intent, exactly
     the on-primary/on-fill split below. Like every ink in this section it
     answers reading surfaces only; a link sitting on a solid intent fill
     pairs with the on-colors below instead.

     Until 2026-08-18 this token did not exist: auth's five link call sites
     spelled `text-text-link` into a theme-driven namespace with no such key,
     Tailwind emitted no CSS for the class, and every auth link rendered in
     whatever colour it inherited (#86 — the `text-2xs` bug class). Guarded by
     style/semantic.test.ts. */
  --color-text-link: var(--color-primary-text);
  /* The on-colors below pair text with a *fill* rather than a surface.
     text-on-dark and text-on-fill answer fills that are dark in light
     mode and light in dark mode, so the label has to travel the opposite
     way — white, then near-black. They are deliberately NOT aliased to one
     another (`text-on-fill: var(--color-text-on-dark)`), even though
     they carry the same value today — they answer to different fills and
     must stay independently overridable:

       - text-on-dark is the partner of the avatar identity palette, whose 12
         slots hold ONE lightness per mode (0.45 / 0.72) by construction.
       - text-on-fill is the partner of the intent fills, whose ramps every
         theme re-tunes, and which move again on hover/active.

     Aliasing would couple them asymmetrically: a consumer re-tuning the avatar
     palette's on-color would silently repaint every filled Button/Badge label.
     Their equality is a consequence of both fill families straddling the same
     lightness midpoint — not a definition. */
  --color-text-on-dark: light-dark(var(--color-neutral-0), var(--color-neutral-900));
  /* The label colour for ANY solid intent fill — primary, secondary, success,
     danger, info, neutral. Named for the *role* (a fill) rather than for one
     intent, because that is what it does: it is composed onto all of them.

     Until 2026-07-31 this role was carried by `--color-text-on-primary`, whose
     name promised something narrower than its job. That mismatch was not
     cosmetic — it handed consumers the wrong lever. Retheming primary invites
     you to retune "the on-primary colour", and doing so silently repainted the
     labels of every other intent too: on a channel-scoped orange primary, a
     `success` filled Badge rendered dark-orange text on dark green (~1.5:1).

     `--color-text-on-primary` still exists and still works — it now defaults to
     this token and governs the primary fills alone, so overriding it does what
     its name says. Themes that want to move every solid label at once override
     this one instead.

     Dark mode pairs the *lighter* -400/-500 intent fills with dark text (the
     Material-3 `onPrimary` pattern). White here was unconditional until
     2026-07-14, which put 125 of the 126 dark-mode intent fills under WCAG AA
     — down to 1.51:1, and getting *worse* on press. The mode-aware branch
     clears all 108 fills this token governs; `warning` is not one of them —
     its fill is light in BOTH modes, so it carries its own non-mode-aware
     on-color below (`--color-text-on-warning`). */
  --color-text-on-fill: light-dark(var(--color-neutral-0), var(--color-neutral-900));
  /* The primary fill's own label colour. Defaults to the shared on-fill value,
     so nothing moves unless a theme says so; override it to repaint the primary
     fills WITHOUT touching success/danger/neutral/secondary/info. */
  --color-text-on-primary: var(--color-text-on-fill);
  /* Warning's own on-color. Warning is the one intent whose fill stays a
     light amber in BOTH modes (base/hover/active ride L 0.59–0.82), so unlike
     text-on-primary this token is deliberately NOT mode-aware — the label is
     a warm dark in both modes. It rides the warning ramp's own 950 stop
     rather than a neutral, so theme re-hues (forest 60, sunset 92) flow
     through and the label reads as part of the swatch instead of soot on top
     of it. Until 2026-07-20 filled warning paired with `text-on-surface` — a
     *surface* token that flips light in dark mode — which put all 18
     dark-mode warning fills at 1.51–2.80:1. Measured across every theme ×
     mode × state by style/contrast.test.ts. */
  --color-text-on-warning: var(--color-warning-950);
  --color-text-on-surface: light-dark(var(--color-neutral-900), var(--color-neutral-100));

  /* === PRIMARY INTENT ===
     emphasis flips to light shades in dark mode so `text-*-emphasis`
     stays legible against dark surfaces.

     `-text` is the intent in its SECOND job. The base token is tuned as a
     fill — a surface with `text-on-fill` sitting on it — and read as text on
     a calm ground it misses AA: measured across all six themes, the base
     stops bottom out at 4.08:1 (primary, dark, surface-elevated) and 2.05:1
     (warning, light — yellow on white, reachable by no stop of a yellow
     ramp). `-text` is the same hue at the nearest ramp stop that clears AA
     4.5 as text on EVERY reading surface and on the intent's own `-subtle`
     (an Alert's ground), in both modes, in the worst of the six themes —
     chosen by measurement (style/contrast.test.ts is the number, not this
     comment), not taste, so it is the smallest visual step that is safe.

     Two text tiers on purpose, not a duplicate: `-text` still reads as the
     colour (danger text stays red); `-emphasis` is the near-ink tier for
     strong statements and doubles as a fill. Same split as Radix's steps
     11/12. The base token is for fills only — variants-lint errors on
     `text-<intent>` in a tv() config.

     `neutral` has no `-text` on purpose: its base already clears AA as text
     on every ground in every theme (measured 5.29/5.20 at worst) because the
     chassis ramp was text-tuned from the start — a role that would alias the
     base is the kind of duplicate the ramp/alias revert just paid for.

     primary's dark stop lands at exactly 4.50 in the worst case
     (rose/own-subtle) — zero headroom, held by the gate; if a rose retune
     ever trips it, the stop moves to -300, not the bar. */
  --color-primary: light-dark(var(--color-primary-600), var(--color-primary-500));
  --color-primary-hover: light-dark(var(--color-primary-700), var(--color-primary-400));
  --color-primary-active: light-dark(var(--color-primary-800), var(--color-primary-300));
  --color-primary-subtle: light-dark(var(--color-primary-50), var(--color-primary-900));
  --color-primary-text: light-dark(var(--color-primary-700), var(--color-primary-400));
  --color-primary-emphasis: light-dark(var(--color-primary-900), var(--color-primary-200));

  /* === SECONDARY INTENT === */
  --color-secondary: light-dark(var(--color-secondary-500), var(--color-secondary-400));
  --color-secondary-hover: light-dark(var(--color-secondary-600), var(--color-secondary-300));
  --color-secondary-active: light-dark(var(--color-secondary-700), var(--color-secondary-200));
  --color-secondary-subtle: light-dark(var(--color-secondary-50), var(--color-secondary-900));
  --color-secondary-text: light-dark(var(--color-secondary-600), var(--color-secondary-400));
  --color-secondary-emphasis: light-dark(var(--color-secondary-800), var(--color-secondary-200));

  /* === NEUTRAL INTENT ===
     Themeable chrome. Takes the warm-neutral ramp's lightness + chroma
     PROFILE — purpose-tuned so that both white-on-fill (bg-neutral) and
     neutral-on-surface (text-neutral) contrast hold across light/dark — and
     re-tints only the HUE per theme via `--neutral-chrome-hue`. Because the
     lightness never moves, every WCAG tradeoff baked into the warm-neutral
     ramp is preserved exactly; only the temperature follows the theme.

     `--neutral-chrome-hue` defaults to 240 (:root, below), so the library
     default reads as a cool grey matching its cool chassis. Each theme
     overrides it to its accent temperature; rooms-docs.css re-pins the neutral
     intent to the warm ramp directly. Uses the same relative-color syntax
     already relied on by `--color-interactive-*` below. */
  --color-neutral: light-dark(
    oklch(from var(--color-warm-neutral-500) l c var(--neutral-chrome-hue)),
    oklch(from var(--color-warm-neutral-400) l c var(--neutral-chrome-hue))
  );
  --color-neutral-hover: light-dark(
    oklch(from var(--color-warm-neutral-600) l c var(--neutral-chrome-hue)),
    oklch(from var(--color-warm-neutral-300) l c var(--neutral-chrome-hue))
  );
  --color-neutral-active: light-dark(
    oklch(from var(--color-warm-neutral-700) l c var(--neutral-chrome-hue)),
    oklch(from var(--color-warm-neutral-200) l c var(--neutral-chrome-hue))
  );
  --color-neutral-subtle: light-dark(
    oklch(from var(--color-warm-neutral-50) l c var(--neutral-chrome-hue)),
    oklch(from var(--color-warm-neutral-900) l c var(--neutral-chrome-hue))
  );
  --color-neutral-emphasis: light-dark(
    oklch(from var(--color-warm-neutral-800) l c var(--neutral-chrome-hue)),
    oklch(from var(--color-warm-neutral-200) l c var(--neutral-chrome-hue))
  );

  /* === SUCCESS INTENT === */
  --color-success: light-dark(var(--color-success-500), var(--color-success-400));
  --color-success-hover: light-dark(var(--color-success-600), var(--color-success-300));
  --color-success-active: light-dark(var(--color-success-700), var(--color-success-200));
  --color-success-subtle: light-dark(var(--color-success-50), var(--color-success-900));
  --color-success-text: light-dark(var(--color-success-600), var(--color-success-400));
  --color-success-emphasis: light-dark(var(--color-success-800), var(--color-success-200));

  /* === WARNING INTENT === */
  --color-warning: light-dark(var(--color-warning-500), var(--color-warning-400));
  --color-warning-hover: light-dark(var(--color-warning-600), var(--color-warning-300));
  --color-warning-active: light-dark(var(--color-warning-700), var(--color-warning-200));
  --color-warning-subtle: light-dark(var(--color-warning-50), var(--color-warning-900));
  /* warning's light text stop is -800: the only rung of a yellow ramp that
     reads on white. It lands amber-brown — that is not a compromise but what
     every AA-clean system does with yellow text (the fill stays yellow). */
  --color-warning-text: light-dark(var(--color-warning-800), var(--color-warning-400));
  --color-warning-emphasis: light-dark(var(--color-warning-800), var(--color-warning-200));

  /* === DANGER INTENT === */
  --color-danger: light-dark(var(--color-danger-500), var(--color-danger-400));
  --color-danger-hover: light-dark(var(--color-danger-600), var(--color-danger-300));
  --color-danger-active: light-dark(var(--color-danger-700), var(--color-danger-200));
  --color-danger-subtle: light-dark(var(--color-danger-50), var(--color-danger-900));
  /* danger's light stop IS the base stop — red already reads on paper. Dark
     needs -300: sRGB red is so dim that even -400 misses on the lightened
     elevated/subtle panels (4.25 at worst). */
  --color-danger-text: light-dark(var(--color-danger-500), var(--color-danger-300));
  --color-danger-emphasis: light-dark(var(--color-danger-800), var(--color-danger-200));

  /* === INFO INTENT === */
  --color-info: light-dark(var(--color-info-500), var(--color-info-400));
  --color-info-hover: light-dark(var(--color-info-600), var(--color-info-300));
  --color-info-active: light-dark(var(--color-info-700), var(--color-info-200));
  --color-info-subtle: light-dark(var(--color-info-50), var(--color-info-900));
  --color-info-text: light-dark(var(--color-info-600), var(--color-info-400));
  --color-info-emphasis: light-dark(var(--color-info-800), var(--color-info-200));

  /* === CHART CATEGORICAL PALETTE ===
     An *ordered* series palette for data visualization (the charts/ family),
     distinct from the single-role intent tokens above: chart series 0 maps to
     --color-chart-1, series 1 to --color-chart-2, and so on, cycling for more
     series than colors. Built on the foundation hue ramps so light-dark()
     resolves dark mode automatically; ordered for maximal adjacent-hue
     separation (blue → green → amber → violet → cyan → red). Living in the
     --color-* namespace means Tailwind also generates fill-chart-1 /
     stroke-chart-1 / bg-chart-1 utilities for legends and static marks. */
  --color-chart-1: light-dark(var(--color-primary-600), var(--color-primary-400));
  --color-chart-2: light-dark(var(--color-success-600), var(--color-success-400));
  --color-chart-3: light-dark(var(--color-warning-500), var(--color-warning-400));
  --color-chart-4: light-dark(var(--color-secondary-500), var(--color-secondary-400));
  --color-chart-5: light-dark(var(--color-info-500), var(--color-info-400));
  --color-chart-6: light-dark(var(--color-danger-500), var(--color-danger-400));

  /* === AVATAR IDENTITY PALETTE ===
     An *unordered* identity palette: Avatar's `randomColor` hashes a name to a
     fixed slot, so the same person always keeps the same hue. Deliberately NOT
     the chart palette and NOT the intent tokens:

       - chart-* only has 6 slots and derives from the intent ramps, so a brand
         that retunes `secondary` would silently reshuffle people's identities.
         Its dark values are the *-400 tints (L≈0.66) — light enough that white
         initials drop to ~2.6:1, below AA. Charts colour marks; avatars carry
         text on top, which is a different contrast contract.
       - intent tokens are semantic (a person is not "danger").

     Construction: a single lightness per mode, 12 hues at an even 30° spacing.
     Because OKLCH lightness is perceptual, holding L constant means every slot
     shares one guaranteed contrast partner — `--color-text-on-dark`, which
     flips white → neutral-900 with the mode exactly as these fills flip dark →
     light. So legibility is a property of the construction, not 12 separate
     checks. Even spacing also beats the 15 hardcoded hex values this replaced,
     which clustered (red/orange/amber/yellow within ~20°) and blurred when
     avatars sat side by side.

     L=0.45 (light) / L=0.72 (dark) mirror the foundation ramps' *-700 / *-300
     steps, so the palette reads as part of the same chassis. Rebrand by
     overriding these 12 tokens; the text partner follows automatically. */
  --color-avatar-1: light-dark(oklch(0.45 0.13 25), oklch(0.72 0.12 25));
  --color-avatar-2: light-dark(oklch(0.45 0.13 55), oklch(0.72 0.12 55));
  --color-avatar-3: light-dark(oklch(0.45 0.13 85), oklch(0.72 0.12 85));
  --color-avatar-4: light-dark(oklch(0.45 0.13 115), oklch(0.72 0.12 115));
  --color-avatar-5: light-dark(oklch(0.45 0.13 145), oklch(0.72 0.12 145));
  --color-avatar-6: light-dark(oklch(0.45 0.13 175), oklch(0.72 0.12 175));
  --color-avatar-7: light-dark(oklch(0.45 0.13 205), oklch(0.72 0.12 205));
  --color-avatar-8: light-dark(oklch(0.45 0.13 235), oklch(0.72 0.12 235));
  --color-avatar-9: light-dark(oklch(0.45 0.13 265), oklch(0.72 0.12 265));
  --color-avatar-10: light-dark(oklch(0.45 0.13 295), oklch(0.72 0.12 295));
  --color-avatar-11: light-dark(oklch(0.45 0.13 325), oklch(0.72 0.12 325));
  --color-avatar-12: light-dark(oklch(0.45 0.13 355), oklch(0.72 0.12 355));

  /* === LIVE / "NOW" ACCENT ===
     Single-purpose accent for live/now markers — the Calendar current-time
     line and dot, and future live/recording indicators. Red is the
     convention (Google Calendar et al.), but the *purpose* is not `danger`:
     a now-line states "you are here", not "something is wrong", and the two
     must stay independently themeable. Defaults ride the danger foundation
     ramp, so dark mode and per-theme danger re-tunes flow through
     automatically; override `--color-live` alone to restyle live indicators
     without touching error styling. */
  --color-live: light-dark(var(--color-danger-500), var(--color-danger-400));

  /* === BORDERS ===
     border-hairline is the quietest tier — structural
     trennlinien (row dividers, Card header/footer separators, inline
     section dividers). Sits below border-subtle, which is now reserved
     for quiet container outlines (e. g. Popover). */
  --color-border-hairline: light-dark(rgb(0 0 0 / 0.08), rgb(255 255 255 / 0.06));
  --color-border-subtle: light-dark(var(--color-neutral-200), var(--color-neutral-700));
  --color-border-default: light-dark(var(--color-neutral-300), var(--color-neutral-600));
  --color-border-emphasis: light-dark(var(--color-neutral-400), var(--color-neutral-500));
  --color-border-strong: light-dark(var(--color-neutral-500), var(--color-neutral-400));

  /* === INTERACTIVE STATES === */
  --color-interactive-hover: oklch(from var(--color-primary-500) l c h / 0.1);
  --color-interactive-active: oklch(from var(--color-primary-500) l c h / 0.2);
  --color-interactive-focus: light-dark(var(--color-primary-500), var(--color-primary-400));
  --color-interactive-disabled: light-dark(var(--color-neutral-200), var(--color-neutral-700));

  /* === FEEDBACK ===
     Mapped onto the intent palette so they automatically follow the
     light/dark resolution above. */
  --color-feedback-info: var(--color-info);
  --color-feedback-info-subtle: var(--color-info-subtle);
  --color-feedback-success: var(--color-success);
  --color-feedback-success-subtle: var(--color-success-subtle);
  --color-feedback-warning: var(--color-warning);
  --color-feedback-warning-subtle: var(--color-warning-subtle);
  --color-feedback-error: var(--color-danger);
  --color-feedback-error-subtle: var(--color-danger-subtle);

  /* === SHADOWS ===
     Dark mode uses higher alpha to compensate for low contrast against
     dark surfaces. light-dark() may wrap ONLY the per-layer <color> —
     it is a color function, and layers must stay top-level
     comma-separated. Wrapping the whole multi-layer list made every
     `box-shadow: var(--blocks-shadow-*)` invalid at computed-value time
     (shadows silently rendered as none, library-wide) — verified in
     chromium before the 2026-07-13 fix.

     The shadow tint (`--blocks-shadow-tint`) is an oklch L C H triplet
     WITHOUT the alpha channel — declared on `:root` (not inside @theme)
     because it is a raw partial value, not a standalone design token.
     Default is pure black (0 0 0). Themes can override the tint to warm
     their shadow palette — e.g. editorial sets it to a dark brown so
     shadows blend with cream surfaces instead of reading as cool
     smudges. */
  --color-shadow-xs: 0 1px 2px 0
    light-dark(
      oklch(var(--blocks-shadow-tint) / 0.05),
      oklch(var(--blocks-shadow-tint) / 0.2)
    );
  --color-shadow-sm:
    0 1px 3px 0
      light-dark(
        oklch(var(--blocks-shadow-tint) / 0.1),
        oklch(var(--blocks-shadow-tint) / 0.3)
      ),
    0 1px 2px -1px
      light-dark(
        oklch(var(--blocks-shadow-tint) / 0.1),
        oklch(var(--blocks-shadow-tint) / 0.3)
      );
  --color-shadow-base:
    0 4px 6px -1px
      light-dark(
        oklch(var(--blocks-shadow-tint) / 0.1),
        oklch(var(--blocks-shadow-tint) / 0.4)
      ),
    0 2px 4px -2px
      light-dark(
        oklch(var(--blocks-shadow-tint) / 0.1),
        oklch(var(--blocks-shadow-tint) / 0.4)
      );
  --color-shadow-md:
    0 10px 15px -3px
      light-dark(
        oklch(var(--blocks-shadow-tint) / 0.1),
        oklch(var(--blocks-shadow-tint) / 0.4)
      ),
    0 4px 6px -4px
      light-dark(
        oklch(var(--blocks-shadow-tint) / 0.1),
        oklch(var(--blocks-shadow-tint) / 0.4)
      );
  --color-shadow-lg:
    0 20px 25px -5px
      light-dark(
        oklch(var(--blocks-shadow-tint) / 0.1),
        oklch(var(--blocks-shadow-tint) / 0.5)
      ),
    0 8px 10px -6px
      light-dark(
        oklch(var(--blocks-shadow-tint) / 0.1),
        oklch(var(--blocks-shadow-tint) / 0.5)
      );
}

/* Shadow tint — declared on :root rather than inside @theme because
   it is a raw oklch L C H partial, not a standalone design token.
   Themes override this to warm their shadow palette. */
:root {
  --blocks-shadow-tint: 0 0 0;

  /* Hue of the neutral intent chrome (bg-neutral / text-neutral / borders).
     The neutral intent (above) keeps the warm-neutral ramp's lightness but
     takes its hue from here. Default 240 = cool grey, matching the default
     cool chassis. Each theme overrides this to its accent temperature;
     rooms-docs.css re-pins the neutral intent to the warm ramp instead. */
  --neutral-chrome-hue: 240;
}

/* Body styling — `color-scheme` activates the UA's auto pick between
   light and dark; the toggle classes only override the scheme. */
body {
  color: var(--color-text-primary);
  background-color: var(--color-surface-base);
}

:root {
  color-scheme: light dark;
}

:root.light {
  color-scheme: light;
}

:root.dark {
  color-scheme: dark;
}

/* High-contrast media adjustments — runs *in addition* to the
   light-dark() resolution above. light-dark() within the overrides
   keeps the high-contrast values mode-aware. */
@media (prefers-contrast: more) {
  :root {
    --color-text-primary: light-dark(var(--color-neutral-900), var(--color-neutral-0));
    --color-text-secondary: light-dark(var(--color-neutral-800), var(--color-neutral-200));
    /* hairline becomes a real border in high-contrast — otherwise structural
       trennlinien (table rows, Card dividers) disappear entirely. */
    --color-border-hairline: light-dark(var(--color-neutral-700), var(--color-neutral-300));
    --color-border-default: light-dark(var(--color-neutral-900), var(--color-neutral-900));
    --color-interactive-focus: light-dark(var(--color-neutral-900), var(--color-neutral-900));
    --color-secondary: light-dark(var(--color-secondary-700), var(--color-secondary-700));
    /* The dark branch was -700 like the light one, which is backwards: on the
       dark surfaces a DARKER neutral means LESS contrast — text-neutral
       measured 1.49:1 in the mode that asked for more (found by adversarial
       review of the intent-text-role change; the normal-cascade gate strips
       @media blocks by design and could not see it). -200 steps one rung
       lighter than the normal dark value's -400-derived resting tone, the
       same direction every other override in this block takes. */
    --color-neutral: light-dark(
      oklch(from var(--color-warm-neutral-700) l c var(--neutral-chrome-hue)),
      oklch(from var(--color-warm-neutral-200) l c var(--neutral-chrome-hue))
    );
  }
}
