/* ==========================================================================
   TradeHound — tokens.css
   "Moss and bone" — olive base, ochre accent.

   The single source of colour, elevation, focus and radius for the whole app.
   Import it once, before any component CSS:

       <link rel="stylesheet" href="tokens.css">

   and set the mode class on <html> before first paint so there's no flash:

       <script>
         document.documentElement.classList.add(
           matchMedia("(prefers-color-scheme: dark)").matches ? "dark-mode" : "light-mode"
         );
       </script>

   Nothing else in the app declares a colour.
   Token names follow Untitled UI v8 conventions so this file can be dropped
   into a Tailwind v4 project later without renaming anything.

   Layers:
     1. Primitives   --color-{ramp}-{stop}     25 → 950
     2. Semantics    --color-{role}-{variant}  light on :root, dark on .dark-mode
     3. App tokens   --th-*                    TradeHound-specific, collision-safe

   Rules of use:
     - Author UI against layer 2 and 3 only. Never reference a primitive
       directly in component CSS — that's what makes dark mode free. A
       --color-{ramp}-{stop} in a component file is always a bug: it is a value
       that will not survive the next theme, and it is how dark mode rots.
     - Reach for the role that describes the JOB, not the one whose colour
       happens to look right today. A disabled control wants bg-disabled even
       when that resolves to the same hex as bg-secondary.
     - Variant separator is an underscore (_hover, _alt), matching Untitled UI.
     - Dark mode is a class, not a media query. Put .dark-mode on <html> or on
       any subtree you want inverted — a light popover over a dark page is just
       .light-mode on the popover.
     - Need something this file doesn't name? Add it HERE as a --th-* token
       with a sentence saying what it is for. Do not inline it in a component.

   Two neutral ramps: Moss drives light, Ash drives dark. See the note above
   the Ash ramp for why, and the DARK section for how it's wired.

   Migrating to Tailwind v4 later: wrap the :root primitive block in @theme,
   leave everything else as-is. Diff against a CLI-generated theme.css first —
   v8 may define semantic tokens this file doesn't.
   ========================================================================== */

:root {
  /* Drives native UI: form controls, scrollbars, the canvas behind the page. */
  color-scheme: light;

  /* ------------------------------------------------------------------
     1. PRIMITIVES
     ------------------------------------------------------------------ */

  /* Moss — neutral, light mode. Mapped to `gray` so every surface, border
     and text token inherits the olive cast without touching the semantic
     layer. On a bone page the olive reads as paper stock. */
  --color-gray-25: #fbfcf8;
  --color-gray-50: #f7f8f2;
  --color-gray-100: #eff0e7;
  --color-gray-200: #e2e4d6;
  --color-gray-300: #cbcebb;
  --color-gray-400: #afb49d;
  --color-gray-500: #8e9579;
  --color-gray-600: #6e7659;
  --color-gray-700: #525941;
  --color-gray-800: #363b2c;
  --color-gray-900: #24281e;
  --color-gray-950: #1b1e17;

  /* Ash — neutral, dark mode. The same olive cast that reads as paper stock on
     a light page reads as a green-brown wash across a dark one, so dark mode
     runs on a warm grey instead: R and G held equal with blue pulled back 6-13
     points depending on the stop, so the shell sits at a true 60° warm hue with
     roughly 45% of Moss's chroma — enough warmth to belong under ochre, not
     enough to read as olive.

     Every stop is luminance-matched to its Moss counterpart, so this is a hue
     swap, not a lightness change — every contrast ratio validated against Moss
     holds here unchanged. */
  --color-ash-25: #fcfcf9;
  --color-ash-50: #f8f8f4;
  --color-ash-100: #f0f0ea;
  --color-ash-200: #e3e3db;
  --color-ash-300: #cdcdc3;
  --color-ash-400: #b2b2a6;
  --color-ash-500: #939386;
  --color-ash-600: #737367;
  --color-ash-700: #57574c;
  --color-ash-800: #3a3a31;
  --color-ash-900: #272720;
  --color-ash-950: #1d1d17;

  /* Ochre — brand */
  --color-brand-25: #fefbf3;
  --color-brand-50: #fbf4e2;
  --color-brand-100: #f5e6c2;
  --color-brand-200: #edd59b;
  --color-brand-300: #dcbe74;
  --color-brand-400: #c4a75c;
  --color-brand-500: #b08f45;
  --color-brand-600: #9c7b35;
  --color-brand-700: #7e622a;
  --color-brand-800: #5e4a20;
  --color-brand-900: #3c2f14;
  --color-brand-950: #29200d;

  /* Fern — success / gain */
  --color-success-25: #f8fbf6;
  --color-success-50: #eff6eb;
  --color-success-100: #d8e9d0;
  --color-success-200: #bcdaaf;
  --color-success-300: #a2c98e;
  --color-success-400: #8cb577;
  --color-success-500: #6d9860;
  --color-success-600: #4f7a47;
  --color-success-700: #3e6138;
  --color-success-800: #2c4529;
  --color-success-900: #1b2b19;
  --color-success-950: #121d11;

  /* Clay — error / loss */
  --color-error-25: #fef8f6;
  --color-error-50: #faede9;
  --color-error-100: #f3d8cf;
  --color-error-200: #e8beb0;
  --color-error-300: #dda491;
  --color-error-400: #ce8a74;
  --color-error-500: #b96c55;
  --color-error-600: #a04e3e;
  --color-error-700: #813e31;
  --color-error-800: #5f2d24;
  --color-error-900: #3d1d17;
  --color-error-950: #2a130f;

  /* Terracotta — warning. Deliberately separate from Clay: ochre is the
     accent and can't also mean caution. */
  --color-warning-25: #fefaf6;
  --color-warning-50: #fcf2e9;
  --color-warning-100: #f8e3d0;
  --color-warning-200: #f0ccac;
  --color-warning-300: #e4b187;
  --color-warning-400: #d5966b;
  --color-warning-500: #c48153;
  --color-warning-600: #b5714a;
  --color-warning-700: #935a38;
  --color-warning-800: #6e4429;
  --color-warning-900: #4a2d1b;
  --color-warning-950: #331e12;

  /* ------------------------------------------------------------------
     2. SEMANTICS — light
     ------------------------------------------------------------------ */

  /* Backgrounds.
     Note: shifted one stop warmer than Untitled UI's default, which puts
     white on bg-primary. Here the page is Moss 100 and cards are Moss 50;
     white is reserved for raised chrome (see --th-bg-elevated). */
  --color-bg-primary: var(--color-gray-50);
  --color-bg-primary_alt: var(--color-gray-50);
  --color-bg-primary_hover: var(--color-gray-100);
  --color-bg-primary-solid: var(--color-gray-900);
  --color-bg-secondary: var(--color-gray-100);
  --color-bg-secondary_alt: var(--color-gray-100);
  --color-bg-secondary_hover: var(--color-gray-200);
  --color-bg-secondary-solid: var(--color-gray-600);
  --color-bg-tertiary: var(--color-gray-200);
  --color-bg-quaternary: var(--color-gray-300);
  --color-bg-active: var(--color-gray-100);
  --color-bg-disabled: var(--color-gray-100);
  --color-bg-disabled_subtle: var(--color-gray-50);
  --color-bg-overlay: rgb(36 40 30 / 0.7);

  --color-bg-brand-primary: var(--color-brand-50);
  --color-bg-brand-primary_alt: var(--color-brand-50);
  --color-bg-brand-secondary: var(--color-brand-100);
  --color-bg-brand-section: var(--color-brand-800);
  --color-bg-brand-section_subtle: var(--color-brand-700);
  /* Solid brand sits at 700, not 600. Ochre 600 on bone only reaches ~3.8:1,
     which fails AA for a 14px button label. 600 is still correct for text,
     icons and hairline borders on a light page. */
  --color-bg-brand-solid: var(--color-brand-700);
  --color-bg-brand-solid_hover: var(--color-brand-800);
  --color-bg-brand-solid_pressed: var(--color-brand-900);

  --color-bg-success-primary: var(--color-success-50);
  --color-bg-success-secondary: var(--color-success-100);
  --color-bg-success-solid: var(--color-success-600);
  --color-bg-error-primary: var(--color-error-50);
  --color-bg-error-secondary: var(--color-error-100);
  --color-bg-error-solid: var(--color-error-600);
  --color-bg-warning-primary: var(--color-warning-50);
  --color-bg-warning-secondary: var(--color-warning-100);
  --color-bg-warning-solid: var(--color-warning-600);

  /* Foregrounds — icons and non-text marks. Kept distinct from text-*
     because an icon can carry less contrast than a glyph at the same size. */
  --color-fg-primary: var(--color-gray-900);
  --color-fg-secondary: var(--color-gray-700);
  --color-fg-secondary_hover: var(--color-gray-800);
  --color-fg-tertiary: var(--color-gray-600);
  --color-fg-tertiary_hover: var(--color-gray-700);
  --color-fg-quaternary: var(--color-gray-500);
  --color-fg-quaternary_hover: var(--color-gray-600);
  --color-fg-quinary: var(--color-gray-400);
  --color-fg-quinary_hover: var(--color-gray-500);
  --color-fg-senary: var(--color-gray-300);
  --color-fg-white: #ffffff;
  --color-fg-disabled: var(--color-gray-400);
  --color-fg-disabled_subtle: var(--color-gray-300);
  --color-fg-brand-primary: var(--color-brand-600);
  --color-fg-brand-primary_alt: var(--color-brand-600);
  --color-fg-brand-secondary: var(--color-brand-500);
  --color-fg-success-primary: var(--color-success-600);
  --color-fg-success-secondary: var(--color-success-500);
  --color-fg-error-primary: var(--color-error-600);
  --color-fg-error-secondary: var(--color-error-500);
  --color-fg-warning-primary: var(--color-warning-600);
  --color-fg-warning-secondary: var(--color-warning-500);

  /* Text */
  --color-text-primary: var(--color-gray-900);
  --color-text-primary_on-brand: var(--color-brand-25);
  --color-text-secondary: var(--color-gray-700);
  --color-text-secondary_hover: var(--color-gray-800);
  --color-text-secondary_on-brand: var(--color-brand-200);
  --color-text-tertiary: var(--color-gray-600);
  --color-text-tertiary_hover: var(--color-gray-700);
  --color-text-tertiary_on-brand: var(--color-brand-200);
  --color-text-quaternary: var(--color-gray-500);
  --color-text-quaternary_on-brand: var(--color-brand-300);
  --color-text-white: #ffffff;
  --color-text-disabled: var(--color-gray-500);
  --color-text-placeholder: var(--color-gray-500);
  --color-text-placeholder_subtle: var(--color-gray-300);
  --color-text-brand-primary: var(--color-brand-900);
  --color-text-brand-secondary: var(--color-brand-700);
  --color-text-brand-tertiary: var(--color-brand-600);
  --color-text-brand-tertiary_alt: var(--color-brand-600);
  --color-text-success-primary: var(--color-success-600);
  --color-text-error-primary: var(--color-error-600);
  --color-text-warning-primary: var(--color-warning-600);

  /* Borders */
  --color-border-primary: var(--color-gray-300);
  --color-border-secondary: var(--color-gray-200);
  --color-border-tertiary: var(--color-gray-100);
  --color-border-disabled: var(--color-gray-300);
  --color-border-disabled_subtle: var(--color-gray-200);
  --color-border-brand: var(--color-brand-300);
  --color-border-brand_alt: var(--color-brand-600);
  --color-border-success: var(--color-success-300);
  --color-border-error: var(--color-error-300);
  --color-border-error_subtle: var(--color-error-300);
  --color-border-warning: var(--color-warning-300);

  /* Focus */
  --color-focus-ring: var(--color-brand-500);
  --color-focus-ring-error: var(--color-error-500);

  /* ------------------------------------------------------------------
     3. APP TOKENS — light
     Prefixed --th-* so a future theme.css can never overwrite them.
     ------------------------------------------------------------------ */

  /* Raised chrome: modals, popovers, dropdowns. The one place white lives. */
  --th-bg-elevated: #ffffff;

  /* On --color-bg-brand-section. That band is dark in BOTH modes (deep ochre
     on light, raised neutral on dark), so its content is light in both — and
     neither existing role covers that: text-primary is dark in light mode,
     text-primary_on-brand is dark in dark mode because it is sized for the
     light ochre SOLID fill, not for this. Added when the auth split panel
     needed it. Lowest here is the chart line at 4.71:1.
     Anything sitting on a section uses these, not the text-* roles. */
  --th-text-on-section: var(--color-brand-25);
  --th-text-on-section_muted: var(--color-brand-200);
  --th-border-on-section: var(--color-brand-700);
  --th-line-on-section: var(--color-brand-300);
  --th-surface-on-section: color-mix(in srgb, var(--color-brand-25) 9%, transparent);

  /* Row selection. Its own token rather than --color-bg-brand-primary: that
     stop is sized for a small badge, and across a full-bleed table row the
     same fill reads as a stripe of colour rather than a state. Mixed live off
     the solid accent so it tracks the brand in both modes, and paired with an
     accent left edge in the component layer — the edge carries the signal, the
     fill only has to hint. Calibrated against plain row hover (1.31:1 over the
     surface): selected rests at 1.12:1, clearly quieter than hover, and rises
     to 1.28:1 when hovered so a selected row still responds to the pointer. */
  --th-row-selected: color-mix(in srgb, var(--color-bg-brand-solid) 6%, var(--color-bg-primary));
  --th-row-selected_hover: color-mix(in srgb, var(--color-bg-brand-solid) 13%, var(--color-bg-primary));
  --th-row-selected-edge: var(--color-bg-brand-solid);

  /* P&L. Aliased to the semantic roles rather than the ramps, so if you
     ever ship a blue/orange colourblind mode you change it in one place. */
  --th-gain: var(--color-text-success-primary);
  --th-gain-bg: var(--color-bg-success-primary);
  --th-gain-border: var(--color-border-success);
  --th-loss: var(--color-text-error-primary);
  --th-loss-bg: var(--color-bg-error-primary);
  --th-loss-border: var(--color-border-error);
  --th-breakeven: var(--color-text-tertiary);
  --th-breakeven-bg: var(--color-bg-tertiary);

  /* Equity curve uses the accent, never the gain colour — the line is a
     path over time, not a directional value. */
  --th-equity-line: var(--color-brand-600);
  --th-chart-grid: var(--color-gray-200);
  --th-chart-axis: var(--color-gray-500);

  /* Categorical series — setups, sessions, instruments, tags. Never
     directional. Ordered by mutual distinguishability: a two-series chart
     should use 1 and 4, not 1 and 3. Series 4 is adjacent to Clay, so pair
     it with a dash pattern or marker shape when it sits near P&L figures. */
  --th-chart-1: #5b7a8c; /* slate */
  --th-chart-2: #7a5468; /* plum */
  --th-chart-3: #4f7f72; /* patina */
  --th-chart-4: #b5714a; /* terracotta */
  --th-chart-5: #7c8071; /* stone */
  --th-chart-6: #8a6a9e; /* iris */

  /* ------------------------------------------------------------------
     Elevation. Tinted with the light shell's own ink rather than neutral
     black, so a shadow over Moss reads as depth instead of grime. Steps map
     to intent, not to pixels: xs hairline lift (inputs, buttons, cards),
     sm resting card, md dropdown or popover, lg drawer or sheet, xl modal.
     ------------------------------------------------------------------ */
  --th-shadow-xs: 0 1px 2px rgb(36 40 30 / .08);
  --th-shadow-sm: 0 1px 3px rgb(36 40 30 / .10), 0 1px 2px rgb(36 40 30 / .06);
  --th-shadow-md: 0 4px 8px -2px rgb(36 40 30 / .10), 0 2px 4px -2px rgb(36 40 30 / .06);
  --th-shadow-lg: 0 12px 20px -6px rgb(36 40 30 / .16);
  --th-shadow-xl: 0 20px 32px -8px rgb(36 40 30 / .20);

  /* Focus rings. Mixed live off --color-focus-ring, so they follow the mode
     without being redeclared in .dark-mode — the only tokens in this file that
     get to be defined once. Compose with a shadow rather than replacing it:
        box-shadow: var(--th-shadow-xs), var(--th-ring);
     --th-ring-neutral is for controls with no brand colour of their own
     (secondary buttons, plain inputs); --th-ring-error for invalid fields. */
  --th-ring: 0 0 0 4px color-mix(in srgb, var(--color-focus-ring) 24%, transparent);
  --th-ring-neutral: 0 0 0 4px color-mix(in srgb, var(--color-fg-quinary) 28%, transparent);
  --th-ring-error: 0 0 0 4px color-mix(in srgb, var(--color-focus-ring-error) 26%, transparent);

  /* Checkbox and radio glyphs. data: URIs cannot read custom properties, so
     these are the one place in the file where a brand hex is written out by
     hand — they must be re-inked if Ochre ever changes. Light uses Ochre 600,
     dark uses Ochre 400, matching --color-fg-brand-primary in each mode. */
  --th-check-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M10 3L4.5 8.5L2 6' stroke='%239c7b35' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --th-check-dash: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2.5 6H9.5' stroke='%239c7b35' stroke-width='1.7' stroke-linecap='round'/%3E%3C/svg%3E");
  --th-radio-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Ccircle cx='6' cy='6' r='3' fill='%239c7b35'/%3E%3C/svg%3E");

  /* ------------------------------------------------------------------
     Radii — Tailwind v4 native namespace, so these survive migration too.
     ------------------------------------------------------------------ */
  --radius-xs: 4px;
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 10px;
  --radius-xl: 12px;
  --radius-2xl: 16px;
  --radius-full: 9999px;
}

/* ==========================================================================
   DARK
   Not an inversion. Accents lighten and desaturate going dark, because a
   saturated mid-tone that reads confidently on bone turns muddy on near-black.
   Gain and loss lighten too, so a screen of red rows doesn't vibrate during a
   losing week.

   Neutrals resolve to Ash here, not Moss. In dark mode identity is carried by
   ochre, fern and clay; the shell's job is to stay out of the way for eight
   hours. Because Ash is luminance-matched to Moss, this block is otherwise
   identical to what it was — only the ramp name changed.
   ========================================================================== */

.dark-mode {
  color-scheme: dark;

  /* Backgrounds. Page is Ash 950, cards are Ash 900 — surface sits above
     page in both modes, so elevation logic never flips. */
  --color-bg-primary: var(--color-ash-900);
  --color-bg-primary_alt: var(--color-ash-900);
  --color-bg-primary_hover: var(--color-ash-800);
  --color-bg-primary-solid: var(--color-ash-800);
  --color-bg-secondary: var(--color-ash-950);
  --color-bg-secondary_alt: var(--color-ash-950);
  --color-bg-secondary_hover: var(--color-ash-800);
  --color-bg-secondary-solid: var(--color-ash-600);
  --color-bg-tertiary: var(--color-ash-800);
  --color-bg-quaternary: var(--color-ash-700);
  --color-bg-active: var(--color-ash-800);
  --color-bg-disabled: var(--color-ash-800);
  --color-bg-disabled_subtle: var(--color-ash-900);
  --color-bg-overlay: rgb(24 23 22 / 0.8);

  --color-bg-brand-primary: var(--color-brand-900);
  --color-bg-brand-primary_alt: var(--color-ash-800);
  --color-bg-brand-secondary: var(--color-brand-800);
  --color-bg-brand-section: var(--color-ash-800);
  --color-bg-brand-section_subtle: var(--color-ash-950);
  /* Light mode goes darker on interaction, dark mode goes lighter. Both
     read as the button being pressed into the surface. */
  --color-bg-brand-solid: var(--color-brand-400);
  --color-bg-brand-solid_hover: var(--color-brand-300);
  --color-bg-brand-solid_pressed: var(--color-brand-200);

  --color-bg-success-primary: var(--color-success-900);
  --color-bg-success-secondary: var(--color-success-800);
  --color-bg-success-solid: var(--color-success-600);
  --color-bg-error-primary: var(--color-error-900);
  --color-bg-error-secondary: var(--color-error-800);
  --color-bg-error-solid: var(--color-error-600);
  --color-bg-warning-primary: var(--color-warning-900);
  --color-bg-warning-secondary: var(--color-warning-800);
  --color-bg-warning-solid: var(--color-warning-600);

  /* Foregrounds */
  --color-fg-primary: var(--color-ash-25);
  --color-fg-secondary: var(--color-ash-300);
  --color-fg-secondary_hover: var(--color-ash-100);
  --color-fg-tertiary: var(--color-ash-400);
  --color-fg-tertiary_hover: var(--color-ash-300);
  --color-fg-quaternary: var(--color-ash-400);
  --color-fg-quaternary_hover: var(--color-ash-300);
  --color-fg-quinary: var(--color-ash-500);
  --color-fg-quinary_hover: var(--color-ash-400);
  --color-fg-senary: var(--color-ash-600);
  --color-fg-disabled: var(--color-ash-500);
  --color-fg-disabled_subtle: var(--color-ash-600);
  --color-fg-brand-primary: var(--color-brand-400);
  --color-fg-brand-primary_alt: var(--color-ash-300);
  --color-fg-brand-secondary: var(--color-brand-500);
  --color-fg-success-primary: var(--color-success-400);
  --color-fg-success-secondary: var(--color-success-500);
  --color-fg-error-primary: var(--color-error-400);
  --color-fg-error-secondary: var(--color-error-500);
  --color-fg-warning-primary: var(--color-warning-400);
  --color-fg-warning-secondary: var(--color-warning-500);

  /* Text. Note _on-brand flips to a dark ochre: the solid button is a light
     fill in dark mode, so its label has to be dark. */
  --color-text-primary: var(--color-ash-50);
  --color-text-primary_on-brand: var(--color-brand-900);
  --color-text-secondary: var(--color-ash-300);
  --color-text-secondary_hover: var(--color-ash-200);
  --color-text-secondary_on-brand: var(--color-brand-800);
  --color-text-tertiary: var(--color-ash-400);
  --color-text-tertiary_hover: var(--color-ash-300);
  --color-text-tertiary_on-brand: var(--color-brand-800);
  --color-text-quaternary: var(--color-ash-400);
  --color-text-quaternary_on-brand: var(--color-brand-700);
  --color-text-disabled: var(--color-ash-500);
  --color-text-placeholder: var(--color-ash-500);
  --color-text-placeholder_subtle: var(--color-ash-700);
  --color-text-brand-primary: var(--color-ash-50);
  --color-text-brand-secondary: var(--color-brand-300);
  --color-text-brand-tertiary: var(--color-brand-400);
  --color-text-brand-tertiary_alt: var(--color-ash-50);
  --color-text-success-primary: var(--color-success-400);
  --color-text-error-primary: var(--color-error-400);
  --color-text-warning-primary: var(--color-warning-400);

  /* Borders */
  --color-border-primary: var(--color-ash-700);
  --color-border-secondary: var(--color-ash-800);
  --color-border-tertiary: var(--color-ash-800);
  --color-border-disabled: var(--color-ash-700);
  --color-border-disabled_subtle: var(--color-ash-800);
  --color-border-brand: var(--color-brand-400);
  --color-border-brand_alt: var(--color-ash-700);
  --color-border-success: var(--color-success-400);
  --color-border-error: var(--color-error-400);
  --color-border-error_subtle: var(--color-error-400);
  --color-border-warning: var(--color-warning-400);

  --color-focus-ring: var(--color-brand-400);
  --color-focus-ring-error: var(--color-error-400);

  /* App tokens */
  --th-bg-elevated: var(--color-ash-800);
  --th-text-on-section: var(--color-ash-50);
  --th-text-on-section_muted: var(--color-ash-300);
  --th-border-on-section: var(--color-ash-700);
  --th-line-on-section: var(--color-brand-400);
  --th-surface-on-section: color-mix(in srgb, var(--color-ash-50) 7%, transparent);
  --th-chart-grid: var(--color-ash-800);
  --th-chart-axis: var(--color-ash-500);
  --th-equity-line: var(--color-brand-400);

  --th-chart-1: #8aaec0;
  --th-chart-2: #b08ca0;
  --th-chart-3: #7fb3a5;
  --th-chart-4: #d79e7c;
  --th-chart-5: #a9ad9c;
  --th-chart-6: #b79ecb;

  /* Elevation goes to true black in dark mode: there is no ink to tint with,
     and a coloured shadow over a near-black surface just muddies it. Opacities
     run higher because a shadow has less room to separate from its backdrop. */
  --th-shadow-xs: 0 1px 2px rgb(0 0 0 / .34);
  --th-shadow-sm: 0 1px 3px rgb(0 0 0 / .40), 0 1px 2px rgb(0 0 0 / .30);
  --th-shadow-md: 0 6px 12px -3px rgb(0 0 0 / .45), 0 2px 5px -2px rgb(0 0 0 / .35);
  --th-shadow-lg: 0 16px 28px -10px rgb(0 0 0 / .55);
  --th-shadow-xl: 0 26px 44px -12px rgb(0 0 0 / .62);

  --th-check-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M10 3L4.5 8.5L2 6' stroke='%23c4a75c' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --th-check-dash: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M2.5 6H9.5' stroke='%23c4a75c' stroke-width='1.7' stroke-linecap='round'/%3E%3C/svg%3E");
  --th-radio-glyph: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Ccircle cx='6' cy='6' r='3' fill='%23c4a75c'/%3E%3C/svg%3E");
}

/* Optional: follow the OS when no class has been set explicitly. Drop this
   block if you'd rather dark mode be a stored user preference only. */
@media (prefers-color-scheme: dark) {
  :root:not(.light-mode):not(.dark-mode) {
    color-scheme: dark;
  }
}

/* ==========================================================================
   BASE
   The minimum needed for the tokens to actually show up. Everything here
   references layer 2 only.

   This is not a reset — bring your own (or none). Everything that could
   plausibly be restyled per component is wrapped in :where() so it carries
   zero specificity: a component rule always wins without !important, and
   without you having to know this file exists.
   ========================================================================== */

:where(body) {
  background-color: var(--color-bg-secondary);
  color: var(--color-text-primary);
  /* Keeps the scrollbar in the shell instead of the browser's default grey. */
  scrollbar-color: var(--color-border-primary) transparent;
}

:where(::placeholder) {
  color: var(--color-text-placeholder);
}

::selection {
  background-color: var(--color-bg-brand-secondary);
  color: var(--color-text-brand-primary);
}

/* Outline rather than box-shadow, so focus survives on elements that already
   own their box-shadow and on anything with overflow clipping. Components that
   want the softer ring opt in with var(--th-ring). */
:where(:focus-visible) {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

/* Native controls that aren't worth restyling — range, progress, unstyled
   checkboxes, spinners — still land on brand instead of the OS default blue. */
:where(input, textarea, select, button) {
  accent-color: var(--color-bg-brand-solid);
}

:where(hr) {
  border: 0;
  border-top: 1px solid var(--color-border-secondary);
}

/* The UA rule for [hidden] lives in a stylesheet with an XHTML default
   namespace, so it does not match inline <svg hidden> — the element keeps its
   attribute and keeps painting. Every icon-swap in the app depends on this
   working, so it is restated here as an author rule, which is namespace-free.
   Not wrapped in :where(): it must outrank a component's own display rule. */
[hidden] { display: none; }

/* Mode-crossing subtrees: a light popover over a dark page, or the reverse.
   Because .dark-mode / .light-mode only redeclare custom properties, dropping
   either class on any element re-themes everything inside it. Painting the
   background here means the subtree is opaque rather than inheriting the
   page's, which is what makes the inversion actually read. */
:where(.dark-mode, .light-mode) {
  background-color: var(--color-bg-secondary);
  color: var(--color-text-primary);
}
