/*
  Resolutics design tokens (ADR-0006, docs/design/design-language.md).

  Two layers, and the separation is the point:
    1. Primitives (--rl-*)  — raw palette and scale values. Nothing outside this file uses them.
    2. Semantic tokens      — roles like --surface or --danger. Components use only these, so a theme
                              can remap meaning without restyling a single component.

  Raw hex or px in a component is review-blocking (.claude/rules/blazor.md).

  Both themes must pass WCAG 2.2 AA (docs/design/design-language.md: non-negotiable), and since
  roadmap row 28 that is asserted rather than asserted-by-comment: TokenContrastTests parses this file,
  resolves every var() to its primitive, and computes WCAG relative-luminance contrast for both themes.
  It runs in the unit project (tests/Resolutics.UnitTests), so every slice's gate enforces it and so
  does every push's automatic step (ADR-0021).

  What that measurement found, on values that had stood since the first screen: every text pair clears
  4.5:1 comfortably, and --border was 1.23:1. See --border-strong below.

  The character cast's slots and asset contract are in docs/design/design-language.md ("The cast");
  its drawings are placeholders until the in-house art arrives.
*/

:root {
  /* ---- Primitives ------------------------------------------------------- */

  /* Warm violet: the "friendly frame, professional content" direction. */
  --rl-violet-100: #ede7ff;
  --rl-violet-300: #b39dff;
  --rl-violet-500: #6b4ce6;
  --rl-violet-700: #4a2fb0;

  --rl-warm-50: #faf7f5;
  --rl-warm-100: #f2ecf5;
  --rl-warm-200: #e5dfe9;

  --rl-plum-900: #16121d;
  --rl-plum-800: #211a2b;
  --rl-plum-700: #332a42;
  --rl-plum-500: #5c5368;
  --rl-plum-300: #b3a8c2;
  --rl-plum-100: #f2edf7;
  --rl-plum-950: #1a1024;

  /*
    The one primitive that serves both themes. A mid grey-violet clears 3:1 against every surface in
    light AND dark (measured minimum 3.72:1), which is why --border-strong is one value rather than
    two — see its semantic token below.
  */
  --rl-plum-400: #7d7788;

  --rl-ink-900: #221b2e;

  --rl-red-500: #c62828;
  --rl-red-700: #a01c1c;
  --rl-red-300: #ff8a80;
  --rl-red-100: #ffbcb5;

  --rl-green-600: #2e7d32;
  --rl-green-300: #a5d6a7;

  /* ---- Semantic tokens: light (the default) ----------------------------- */

  --surface: var(--rl-warm-50);
  --surface-raised: #ffffff;
  --surface-sunken: var(--rl-warm-100);

  --ink: var(--rl-ink-900);
  --ink-muted: var(--rl-plum-500);
  --ink-on-accent: #ffffff;

  --accent: var(--rl-violet-500);
  --accent-strong: var(--rl-violet-700);
  --accent-subtle: var(--rl-violet-100);

  --danger: var(--rl-red-500);
  --danger-strong: var(--rl-red-700);
  --success: var(--rl-green-600);

  /*
    Two border tokens, because they do two jobs and WCAG treats them differently.

    --border is the quiet separator: a table's row rule, a card's edge, a section divider. It is
    decorative, SC 1.4.11 exempts it, and darkening it would turn every dense screen into a
    spreadsheet grid.

    --border-strong is the boundary of anything a person operates — an input, a select, a textarea, a
    quiet button, a toolbar tool. SC 1.4.11 (Non-text Contrast, AA) requires 3:1 for "visual
    information required to identify user interface components", and the outline of a text box is
    exactly that. Every control in this product drew itself with --border until roadmap row 28, which
    is to say at 1.23:1 in light and 1.24:1 in dark: an invisible boundary, in both themes, since the
    first screen. Nobody saw it because contrast is arithmetic and nothing was doing the arithmetic.
  */
  --border: var(--rl-warm-200);
  --border-strong: var(--rl-plum-400);
  --focus-ring: var(--rl-violet-500);
  --focus-ring-width: 2px;
  --focus-ring-offset: 2px;

  --shadow-raised: 0 1px 2px rgb(34 27 46 / 8%), 0 8px 24px rgb(34 27 46 / 8%);

  /*
    The ground a QR symbol is printed on. Deliberately identical in both themes and deliberately not
    derived from --surface-*: a QR code has to stay dark-on-light to scan reliably, so this is a
    functional requirement rather than a styling choice. It is a token so that the design-system pass
    cannot invert it by remapping a surface. (The symbol's own ink is baked into the generated image,
    which is an <img> and so cannot read custom properties.)
  */
  --qr-ground: #ffffff;

  /* ---- Scales: shared by both themes ------------------------------------ */

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;

  /* Generous radii — the rounded geometry the design language asks for. */
  --radius-sm: 0.375rem;
  --radius-md: 0.625rem;
  --radius-lg: 1rem;
  --radius-pill: 9999px;

  /*
    ---- The layout scale, and the breakpoints (roadmap row 28, tech-debt #22) ------------------

    A CSS custom property CANNOT be used in a media query condition — `@media (min-width: var(--bp-md))`
    is invalid in every shipping browser, and `@custom-media` is not shipped either. So the breakpoint
    scale is DECLARED HERE IN WORDS and SPELLED AS A LITERAL at each use, with the name in a comment
    beside it. There are exactly two, and every media query in this repository uses one of them:

        --bp-md   40rem  (640px)  one column becomes two; the shell's actions stop wrapping
        --bp-lg   64rem (1024px)  the comfortable desktop measure

    Two is the fewest that expresses phone / tablet / desktop. A third arrives when a screen needs it
    and not before (AGENTS.md Principle 1). Mobile-first: the unqualified rule is the narrow one, and
    a `min-width` query widens it.

    Five slices shipped screens that met UI-003 "without a media query" — intrinsic `auto-fit` grids
    and flex wrapping — each recording that inventing this scale belonged here. Those grids stay:
    intrinsic layout is better than a breakpoint wherever it can do the job, and these two exist for
    the cases it cannot, where a fixed track (a timeline's 11rem label column) has to collapse.
  */
  --layout-measure: 60rem;
  --layout-gutter: var(--space-4);

  /*
    WCAG 2.2 SC 2.5.8 (Target Size, Minimum) asks for 24x24 CSS pixels. This is 44px — the figure
    every platform's own guidance lands on — applied as BOTH min-block-size and min-inline-size,
    because 2.5.8 is a bounding box and a control that is tall and narrow fails it just as surely.
  */
  --target-min: 2.75rem;

  /*
    The vertical rhythm of one row of data, shared by the ticket table and the card layout beside it
    (roadmap row 28a, SEA-006).

    Row 28 proposed this token and dropped it, because nothing consumed it and a token with no reader
    is the scaffolding this repository treats as a defect. Its reader is the card/list pair: the two
    shapes show the same rows and must breathe the same way, and "density" is the one property that
    would otherwise be written twice and drift. Its value is what `.rl-table` already used, so no
    table in the product changes.
  */
  --density-row: var(--space-2);

  --font-sans: "Segoe UI Variable", "Segoe UI", system-ui, -apple-system, "Helvetica Neue", sans-serif;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.25rem;
  --text-xl: 1.75rem;

  --transition-fast: 120ms ease;

  /*
    The character cast (design-language.md, "The cast"). Each drawing ships a light and a dark file,
    and which one shows is a token the theme blocks remap — so the toggle wins in both directions and
    no component CSS mentions a theme.
  */
  --cast-size: 10rem;
  --cast-light-display: block;
  --cast-dark-display: none;
}

/*
  Dark theme. Applied when the viewer's system prefers dark AND they have not explicitly chosen light.
  Guarding on :not([data-theme="light"]) is what lets the manual toggle win in both directions.

  THE NEXT TWO BLOCKS ARE THE SAME VALUES WRITTEN TWICE, and they have to be: one is inside a media
  query and one is not, and no CSS selector list spans that boundary. A token added to one and missed
  in the other gives a product whose system dark theme and its manual dark theme are different themes
  — a difference nobody would see, because seeing it means changing an OS setting and a toggle in the
  same session. TokenThemeParityTests asserts the two blocks declare the same properties with the same
  values, so the duplication is held by a gate rather than by care (roadmap row 28).
*/
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --surface: var(--rl-plum-900);
    --surface-raised: var(--rl-plum-800);
    --surface-sunken: #100d16;

    --ink: var(--rl-plum-100);
    --ink-muted: var(--rl-plum-300);
    --ink-on-accent: var(--rl-plum-950);

    --accent: var(--rl-violet-300);
    --accent-strong: #cbbcff;
    --accent-subtle: var(--rl-plum-700);

    --danger: var(--rl-red-300);
    --danger-strong: var(--rl-red-100);
    --success: var(--rl-green-300);

    --border: var(--rl-plum-700);
    --border-strong: var(--rl-plum-400);
    --focus-ring: var(--rl-violet-300);

    --shadow-raised: 0 1px 2px rgb(0 0 0 / 40%), 0 8px 24px rgb(0 0 0 / 32%);

    --cast-light-display: none;
    --cast-dark-display: block;
  }
}

/* An explicit choice always wins over the system preference. */
:root[data-theme="dark"] {
  --surface: var(--rl-plum-900);
  --surface-raised: var(--rl-plum-800);
  --surface-sunken: #100d16;

  --ink: var(--rl-plum-100);
  --ink-muted: var(--rl-plum-300);
  --ink-on-accent: var(--rl-plum-950);

  --accent: var(--rl-violet-300);
  --accent-strong: #cbbcff;
  --accent-subtle: var(--rl-plum-700);

  --danger: var(--rl-red-300);
  --danger-strong: var(--rl-red-100);
  --success: var(--rl-green-300);

  --border: var(--rl-plum-700);
  --border-strong: var(--rl-plum-400);
  --focus-ring: var(--rl-violet-300);

  --shadow-raised: 0 1px 2px rgb(0 0 0 / 40%), 0 8px 24px rgb(0 0 0 / 32%);

  --cast-light-display: none;
  --cast-dark-display: block;
}
