// Every token-declaring selector is wrapped in :where() so it contributes zero
// specificity. A consumer's own root-level token override (specificity 0,1,0)
// then wins in light mode, OS-dark, and forced dark alike, independent of
// stylesheet load order. The library's own light-to-dark switching still
// resolves correctly by source order, since the dark blocks come after the
// light ones at equal (zero) specificity.
:where(:root) {
  --color-primary-50: #ecf3f9;
  --color-primary-100: #d1e3f0;
  --color-primary-200: #abcbe3;
  --color-primary-300: #7dafd4;
  --color-primary-400: #4b91c3;
  --color-primary-500: #3674a1;
  --color-primary-600: #2a5b7e;
  --color-primary-700: #204560;
  --color-primary-800: #162f41;
  --color-primary-900: #0d1c26;

  --color-secondary-50: #f3f5fa;
  --color-secondary-100: #dce1ec;
  --color-secondary-200: #bbc4d8;
  --color-secondary-300: #93a1bf;
  --color-secondary-400: #687aa5;
  --color-secondary-500: #506086;
  --color-secondary-600: #404c6a;
  --color-secondary-700: #313b51;
  --color-secondary-800: #232938;
  --color-secondary-900: #151922;

  --color-neutral-0: #ffffff;
  --color-neutral-50: #f9fafb;
  --color-neutral-100: #f3f4f6;
  --color-neutral-200: #e5e7eb;
  --color-neutral-300: #d1d5db;
  --color-neutral-400: #9ca3af;
  --color-neutral-500: #6b7280;
  --color-neutral-600: #4b5563;
  --color-neutral-700: #374151;
  --color-neutral-800: #1f2937;
  --color-neutral-900: #111827;
  --color-neutral-950: #030712;

  --color-success-50: #f0fdf4;
  --color-success-100: #dcfce7;
  --color-success-200: #bbf7d0;
  --color-success-500: #22c55e;
  --color-success-600: #16a34a;
  --color-success-700: #15803d;

  --color-warning-50: #fffbeb;
  --color-warning-100: #fef3c7;
  --color-warning-200: #fde68a;
  --color-warning-500: #f59e0b;
  --color-warning-600: #d97706;
  --color-warning-700: #b45309;

  --color-error-50: #fef2f2;
  --color-error-100: #fee2e2;
  --color-error-200: #fecaca;
  --color-error-500: #ef4444;
  --color-error-600: #dc2626;
  --color-error-700: #b91c1c;

  --color-info-50: #ecfeff;
  --color-info-100: #cffafe;
  --color-info-200: #a5f3fc;
  --color-info-500: #06b6d4;
  --color-info-600: #0891b2;
  --color-info-700: #0e7490;

  --color-text-primary: var(--color-neutral-900);
  --color-text-secondary: var(--color-neutral-600);
  --color-text-tertiary: var(--color-neutral-400);
  --color-text-disabled: var(--color-neutral-400);
  --color-text-inverse: var(--color-neutral-0);
  --color-text-link: var(--color-primary-600);
  --color-text-link-hover: var(--color-primary-800);

  // Two-tier surfaces: bg-canvas is the page, bg-base is component surfaces on
  // it (inputs, cards, accordion, popovers). In dark mode bg-base lifts above
  // bg-canvas so surfaces don't vanish into the page.
  --color-bg-canvas: var(--color-neutral-0);
  --color-bg-base: var(--color-neutral-0);
  --color-bg-subtle: var(--color-neutral-50);
  --color-bg-stripe: var(--color-neutral-50);
  // Zebra-stripe fill for table rows: a mid-tone between the base row and the
  // header tint so striped rows read as lighter than the header, not identical to
  // it. Dark mode overrides the ratio to stay equally subtle.
  --color-bg-stripe-subtle: color-mix(
    in srgb,
    var(--color-bg-base) 30%,
    var(--color-bg-stripe)
  );
  --color-bg-muted: var(--color-neutral-100);
  // Soft neutral fill for placeholder surfaces (e.g. avatar initials) when no
  // image is set; light enough to sit gently on a white page
  --color-bg-emphasis: var(--color-neutral-100);
  --color-bg-elevated: var(--color-neutral-0);
  --color-bg-overlay: rgba(0, 0, 0, 0.5);

  // Tooltips float over arbitrary content, so their surface is a unique tone that
  // never matches a page or palette colour in either theme; the translucent
  // hairline border separates it from same-tone backgrounds.
  --color-tooltip-surface: #1a1b21;
  --color-tooltip-border: rgba(255, 255, 255, 0.15);

  // Interactive lift layers for hover and active/selected fills. Light surfaces
  // are all near-white and never collapse onto these shades, so solid muted
  // tones read cleanly. Dark mode swaps them for translucent washes (see the
  // dark overrides) because its surfaces all collapse onto the same neutrals,
  // where a solid fill would vanish into whatever it sits on.
  --color-state-hover: var(--color-neutral-100);
  --color-state-active: var(--color-neutral-200);

  --color-border-subtle: var(--color-neutral-200);
  --color-border-default: var(--color-neutral-200);
  --color-border-strong: var(--color-neutral-400);
  // Dividers are a translucent wash, like the state fills, so hairline rules
  // inside a surface read evenly on base, elevated, and hover tones alike.
  --color-divider: rgba(0, 0, 0, 0.1);
  --color-border-focus: var(--color-primary-500);

  // brand-default/-hover/-active are the brand colour as a surface (solid bg
  // under white text); needs 4.5:1 vs white. brand-text is the brand colour as
  // a foreground on a non-brand surface; needs 4.5:1 vs bg-base and flips
  // lighter in dark mode.
  --color-brand-default: var(--color-primary-600);
  --color-brand-hover: var(--color-primary-700);
  --color-brand-active: var(--color-primary-800);
  --color-brand-text: var(--color-primary-700);
  --color-brand-subtle: var(--color-primary-50);
  --color-brand-muted: var(--color-primary-100);

  --color-brand-secondary-default: var(--color-secondary-500);
  --color-brand-secondary-hover: var(--color-secondary-600);
  --color-brand-secondary-active: var(--color-secondary-700);
  --color-brand-secondary-text: var(--color-secondary-700);
  --color-brand-secondary-subtle: var(--color-secondary-50);
  --color-brand-secondary-muted: var(--color-secondary-100);

  // *-text is the status hue as a foreground on its own *-subtle/-muted wash
  // (badge, tag, toast). It needs 4.5:1 vs that wash and flips lighter in dark
  // mode, mirroring --color-brand-text.
  --color-success-default: var(--color-success-600);
  --color-success-subtle: var(--color-success-50);
  --color-success-muted: var(--color-success-100);
  --color-success-text: var(--color-success-700);

  --color-warning-default: var(--color-warning-600);
  --color-warning-subtle: var(--color-warning-50);
  --color-warning-muted: var(--color-warning-100);
  --color-warning-text: var(--color-warning-700);

  --color-error-default: var(--color-error-600);
  --color-error-subtle: var(--color-error-50);
  --color-error-muted: var(--color-error-100);
  --color-error-text: var(--color-error-700);

  --color-info-default: var(--color-info-600);
  --color-info-subtle: var(--color-info-50);
  --color-info-muted: var(--color-info-100);
  --color-info-text: var(--color-info-700);

  // Pure RGB primaries for the picker's hue wheel and saturation/value
  // gradient. Intrinsic to the picker, not themeable; kept here so component
  // SCSS stays literal-free.
  --color-picker-hue-red: #ff0000;
  --color-picker-hue-yellow: #ffff00;
  --color-picker-hue-green: #00ff00;
  --color-picker-hue-cyan: #00ffff;
  --color-picker-hue-blue: #0000ff;
  --color-picker-hue-magenta: #ff00ff;
  --color-picker-sv-white: #ffffff;
  --color-picker-sv-black: #000000;
  --color-picker-thumb-halo: rgba(0, 0, 0, 0.25);
}

// Dark mode: applied when the OS prefers dark, unless forced light via
// `<html data-theme="light">`. `<html data-theme="dark">` forces dark.
@mixin dark-color-tokens {
  --color-text-primary: var(--color-neutral-50);
  --color-text-secondary: var(--color-neutral-300);
  --color-text-tertiary: var(--color-neutral-500);
  --color-text-disabled: var(--color-neutral-500);
  --color-text-inverse: var(--color-neutral-900);
  --color-text-link: var(--color-primary-300);
  --color-text-link-hover: var(--color-primary-100);

  // Canvas is the deepest page tone; bg-base and up lift component surfaces,
  // striped rows, floating surfaces, and hover states above it.
  --color-bg-canvas: var(--color-neutral-950);
  --color-bg-base: var(--color-neutral-800);
  --color-bg-subtle: var(--color-neutral-700);
  --color-bg-stripe: var(--color-neutral-900);
  // The dark base-to-stripe gap reads stronger than the light one, so weight the
  // stripe mix toward the base row to keep zebra striping subtle.
  --color-bg-stripe-subtle: color-mix(
    in srgb,
    var(--color-bg-base) 62.5%,
    var(--color-bg-stripe)
  );
  --color-bg-elevated: var(--color-neutral-700);
  // Opaque muted surface for static fills (disabled fields, slider/progress
  // tracks, skeletons). Hover/active fills route through the translucent
  // --color-state-* tokens instead, so they never collide with this shade.
  --color-bg-muted: var(--color-neutral-700);
  --color-bg-emphasis: var(--color-neutral-600);

  // White wash so an interactive lift reads on any dark surface, including the
  // neutral-700 tier where bg-muted/-subtle/-elevated all coincide. This is the
  // fix that lets dropdown/menu/dialog hovers lift off their elevated surfaces.
  --color-state-hover: rgba(255, 255, 255, 0.08);
  --color-state-active: rgba(255, 255, 255, 0.14);

  // Borders stay clear of every bg-* shade so they stay visible. subtle mixes
  // neutral-700/-800 to sit between card and cell backgrounds; default can't go
  // darker without colliding with bg-subtle/-elevated (both neutral-700).
  --color-border-subtle: color-mix(
    in srgb,
    var(--color-neutral-700),
    var(--color-neutral-800)
  );
  --color-border-default: var(--color-neutral-400);
  --color-border-strong: var(--color-neutral-300);
  // Dividers flip to a light wash so the rule stays visible on every dark tier
  --color-divider: rgba(255, 255, 255, 0.12);

  // Surface roles step one shade lighter than light mode so the button clears
  // WCAG 1.4.11 (3:1) on the near-black canvas while keeping a white label
  // above 4.5:1.
  --color-brand-default: var(--color-primary-500);
  --color-brand-hover: var(--color-primary-600);
  --color-brand-active: var(--color-primary-700);
  --color-brand-text: var(--color-primary-300);
  --color-brand-subtle: rgba(75, 145, 195, 0.1);
  --color-brand-muted: rgba(75, 145, 195, 0.2);

  // The secondary surface does not lighten in dark mode: its 500 shade is dark
  // enough that a white label clears 4.5:1 in both modes. The text token flips
  // lighter (700 to 200) to stay readable on the dark elevated popover, and the
  // washes re-tint to a low-alpha secondary hue so they darken enough for light
  // text.
  --color-brand-secondary-text: var(--color-secondary-200);
  --color-brand-secondary-subtle: rgba(104, 122, 165, 0.1);
  --color-brand-secondary-muted: rgba(104, 122, 165, 0.2);

  // Light pastels become unreadable behind light text in dark mode. Re-tint as
  // a low-alpha wash of the saturated *-500 hue so the surface darkens enough
  // for white text.
  --color-success-subtle: rgba(34, 197, 94, 0.15);
  --color-success-muted: rgba(34, 197, 94, 0.25);
  --color-warning-subtle: rgba(245, 158, 11, 0.15);
  --color-warning-muted: rgba(245, 158, 11, 0.25);
  --color-error-subtle: rgba(239, 68, 68, 0.15);
  --color-error-muted: rgba(239, 68, 68, 0.25);
  --color-info-subtle: rgba(6, 182, 212, 0.15);
  --color-info-muted: rgba(6, 182, 212, 0.25);

  // The *-700 shades are unreadable on the dark translucent washes above; flip
  // to the light *-200 pastels so status text keeps 4.5:1.
  --color-success-text: var(--color-success-200);
  --color-warning-text: var(--color-warning-200);
  --color-error-text: var(--color-error-200);
  --color-info-text: var(--color-info-200);
}

@media (prefers-color-scheme: dark) {
  :where(:root:not([data-theme='light'])) {
    @include dark-color-tokens;
  }
}

:where(:root[data-theme='dark']) {
  @include dark-color-tokens;
  color-scheme: dark;
}
