/*
 * Ark design tokens.
 *
 * Ported from the ARKSOFT platform's dashboard sheet
 * (arksoft-platform/clients/admin/src/styles/globals.css, sections 1-4 and
 * the dark block). That sheet is now the upstream: the architecture, the
 * names and the values below are its, so a component authored in either
 * repository renders identically in the other. Re-sync by re-porting those
 * sections, not by hand-editing values here.
 *
 * Architecture (read top-down):
 *   1. PRIMITIVES — raw scales. Never reference these from a component.
 *   2. SEMANTICS  — purpose-named vars (--background, --primary, …). The
 *                   public API. Components reference these.
 *   3. SURFACES   — explicit elevation steps for layout chrome.
 *   4. SYSTEM     — typography, motion, radii, shadows.
 *   5. LEGACY     — the pre-port `--surface-bg` / `--text-color` / … names,
 *                   pointed at the semantics above. ark-surfaces.css,
 *                   ark-components.css, every *.razor.css and MudBlazor's
 *                   own theme still speak that vocabulary; section 5 is what
 *                   keeps them rendering. Nothing there introduces a colour.
 *
 * This file is plain CSS on purpose: App.razor links it directly for the
 * Blazor catalog, and the React catalog links it too (index.html) and maps it
 * onto Tailwind's @theme in theme/tailwind.css. Anything needing a Tailwind
 * directive (@theme, @layer, @custom-variant) belongs in that file, not here.
 *
 * Dark mode keys off BOTH `.dark` (the platform's selector, so ported
 * component CSS and the `dark:` variant work unchanged) and
 * `[data-theme="dark"]` (this catalog's own selector). ark-theme.js sets both.
 */

:root {
    /* ── 1. PRIMITIVES ──────────────────────────────────────────────── */

    /* Neutrals — a cool blue-grey chassis, not true greys. */
    --neutral-0: #ffffff;
    --neutral-50: #f5f7f8; /* light canvas */
    --neutral-100: #edf2f3; /* light panel */
    --neutral-200: #e7edef; /* light raised */
    --neutral-300: #c8d5d9; /* light border */
    --neutral-400: #9aacb4;
    --neutral-500: #6b7880; /* light muted text */
    --neutral-600: #52636d; /* light secondary text */
    --neutral-700: #3a4a54;
    --neutral-800: #263640; /* dark border */
    --neutral-850: #18242d; /* dark raised */
    --neutral-900: #121c24; /* dark panel */
    --neutral-950: #0e161d;
    --neutral-1000: #0b1117; /* dark canvas */

    /* Brand — ARKSOFT teal. The 600 stop is the approved brand primary
       (#2a6572); 700/800 are its hover and active steps (#1f4b54 /
       #17373e). The rest of the ramp interpolates the same hue and chroma
       so soft fills and dark-mode text stay on-brand. 600 is the
       workhorse; 400 is what dark mode uses. */
    --brand-50: oklch(0.965 0.012 214.5);
    --brand-100: oklch(0.930 0.024 214.5);
    --brand-200: oklch(0.880 0.038 214.5);
    --brand-300: oklch(0.800 0.052 214.5);
    --brand-400: oklch(0.690 0.060 214.5);
    --brand-500: oklch(0.582 0.064 214.5);
    --brand-600: oklch(0.474 0.064 214.5); /* #2a6572 */
    --brand-700: oklch(0.412 0.058 214.5); /* #1f4b54 */
    --brand-800: oklch(0.348 0.050 214.5); /* #17373e */
    --brand-900: oklch(0.285 0.040 214.5);
    --brand-950: oklch(0.210 0.030 214.5);

    /* Secondary + tertiary — the lime and purple brand hues. The
       `--saffron-*` names are the platform's; only the hue is ours. */
    --saffron-400: #b3d049;
    --saffron-500: #9cbd2b;
    --saffron-600: #809c23;
    --tertiary-500: #6a329c;
    --tertiary-400: #8b57bd;
    /* Two steps lighter again. The 500 stop is ~2.1:1 on the dark canvas and
       the 400 stop reaches only ~3.8:1, so neither clears AA for the small
       text that wears the purple (category counts, panel titles). This stop
       does, at ~5.9:1, and is the same hue. Dark mode only — on the light
       canvas it is the 500 stop that reads and this one that fails. */
    --tertiary-300: #a975d6;

    /* Status scales. The 600 stop is the light-mode colour; 500 is the
       lighter step dark mode uses so the tint still reads on graphite. */
    --success-500: #22c55e;
    --success-600: #16a34a;
    --warning-500: #f59e0b;
    --warning-600: #d97706;
    --info-500: #38bdf8;
    --info-600: #0ea5e9;
    --danger-500: #ef4444;
    --danger-600: #dc2626;

    /* Status "quads" — the bg/ink/edge triples a status tag or inline
       banner wears: a pale fill with the dark ink of the same hue, not an
       alpha wash of the solid colour. Theme-invariant on purpose — a pale
       tag on graphite still reads. */
    --success-bg: #d1fadf;
    --success-ink: #067647;
    --success-edge: #3be479;
    --warning-bg: #fef3c7;
    --warning-ink: #b45309;
    --warning-edge: #faa94b;
    --danger-bg: #fee2e2;
    --danger-ink: #b91c1c;
    --danger-edge: #ea7e7e;
    --info-bg: #e0f2fe;
    --info-ink: #075985;
    --info-edge: #67caf6;

    /* ── 2. SEMANTICS (light) ───────────────────────────────────────── */
    --background: var(--neutral-50);
    --foreground: #17242c;

    --card: var(--neutral-0);
    --card-foreground: #17242c;
    --popover: var(--neutral-0);
    --popover-foreground: #17242c;

    --primary: var(--brand-600);
    /* Derived from the active brand stop so an accent swap re-tones these
       too. The `from <color>` relative-colour syntax resolves at runtime. */
    --primary-foreground: oklch(from var(--brand-600) 0.990 0.005 h);
    --primary-hover: var(--brand-700);
    --primary-soft: oklch(from var(--brand-600) l c h / 0.10);

    /* Theme-independent. For content sitting on imagery or a dark scrim
       (caption text, overlay action icons) and for the thumb of a filled
       control — white stays legible in both themes, so these are
       intentionally NOT flipped in the dark block. */
    --overlay: oklch(0 0 0 / 0.55);
    --overlay-foreground: oklch(1 0 0);

    --secondary: var(--neutral-100);
    --secondary-foreground: var(--neutral-900);

    --muted: var(--neutral-100);
    /* --neutral-600, not the muted stop: that one is only ~4.0:1 on the
       light canvas, and this token also backs placeholders and chevrons
       that mask it to 60% alpha. */
    --muted-foreground: var(--neutral-600);

    /* Accent = hover chip, one step darker than --muted / --secondary. */
    --accent: var(--neutral-200);
    --accent-foreground: var(--neutral-800);
    --saffron: var(--saffron-500);
    --saffron-foreground: #2c3a08;
    /* The lime, as ink on a page surface rather than as a fill. The 500 stop is
       a light colour — 2.0:1 on the light canvas — so a lime *label* or hairline
       needs its own value, dark here and light in the dark block. This is the
       same split the status quads make between `--warning` and `--warning-ink`.
       Use --saffron for a fill, --saffron-ink for text and borders. */
    --saffron-ink: #5c7018;

    --destructive: var(--danger-600);
    --destructive-foreground: oklch(0.990 0.005 20);

    --success: var(--success-600);
    --success-foreground: oklch(0.990 0.005 162);
    --warning: var(--warning-600);
    --warning-foreground: var(--neutral-950);
    --info: var(--info-600);
    --info-foreground: oklch(0.990 0.005 232);

    /* A teal-tinted hairline, not a grey one. */
    --border: rgb(42 101 114 / 0.14);
    --border-strong: var(--neutral-300);
    --input: var(--neutral-300);
    --ring: var(--brand-600);

    /* ── 3. SURFACES — explicit elevation. Use these instead of mixing
       card/muted/accent ad-hoc.
       Light: canvas → tier-2 panel → tier-3 popover/sticky → tier-4 hover.
       Each tier is one perceptual step distinct so cards visually float
       above the canvas instead of merging into a hairline-edged plane. */
    --surface-1: var(--neutral-50); /* canvas */
    --surface-2: var(--neutral-0); /* sidebar, panels */
    --surface-3: var(--neutral-0); /* cards, popovers, sticky chrome */
    --surface-4: var(--neutral-100); /* hover, raised */
    --surface-1-hover: var(--neutral-100);
    --surface-2-hover: var(--neutral-50);

    /* ── Charts — the three brand hues first (teal, lime, purple), then
       info/warning to round out a five-series ladder. ───────────────── */
    --chart-1: var(--brand-600); /* teal   #2a6572 */
    --chart-2: var(--saffron-500); /* lime   #9cbd2b */
    --chart-3: var(--tertiary-500); /* purple #6a329c */
    --chart-4: var(--info-600); /* sky    #0ea5e9 */
    --chart-5: var(--warning-600); /* amber  #d97706 */
    --chart-grid: rgb(42 101 114 / 0.18);

    /* ── 4. SYSTEM ──────────────────────────────────────────────────── */
    /* One face for everything — Public Sans. The display/body split is
       kept as two names so call sites don't change; they resolve to the
       same family. */
    --font-display: 'Public Sans', Arial, ui-sans-serif, system-ui, 'Segoe UI', sans-serif;
    --font-sans: 'Public Sans', Arial, ui-sans-serif, system-ui, 'Segoe UI', sans-serif;
    --font-mono: 'Consolas', 'SF Mono', ui-monospace, Menlo, 'Liberation Mono', monospace;
    /* Body uses tabular numerals so times, tokens and costs don't jitter
       between digits. */
    --font-feature-default: 'tnum';
    --font-feature-tabular: 'tnum';

    /* Four radius steps; 2xl extends the same ramp. */
    --radius: 12px;
    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 18px;
    --radius-xl: 24px;
    --radius-2xl: 30px;

    --ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000);
    --ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000);
    --ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000);
    --duration-fast: 120ms;
    --duration-default: 200ms;
    --duration-slow: 320ms;

    /* Neutral shadows — cast in pure black so they read as a cool shadow
       on any chassis (no warm tint bleeding into the canvas). */
    --shadow-xs: 0 1px 2px 0 oklch(0 0 0 / 0.05);
    --shadow-sm: 0 1px 2px 0 oklch(0 0 0 / 0.06),
                 0 1px 3px 0 oklch(0 0 0 / 0.07);
    --shadow-md: 0 4px 6px -1px oklch(0 0 0 / 0.08),
                 0 2px 4px -2px oklch(0 0 0 / 0.06);
    --shadow-lg: 0 10px 15px -3px oklch(0 0 0 / 0.10),
                 0 4px 6px -4px oklch(0 0 0 / 0.06);
    --shadow-lift: 0 12px 32px -16px oklch(0 0 0 / 0.22),
                   0 4px 8px -4px oklch(0 0 0 / 0.12);

    /* Top-edge highlight — a whisper, not 2014-era glassmorphism gloss.
       Only present on surfaces that explicitly opt in. */
    --highlight-top: inset 0 1px 0 oklch(1 0 0 / 0.14);

    /* Display-weight tracking applied to hero headings and page titles. */
    --tracking-display: -0.025em;
    --tracking-tight: -0.015em;

    --color-scheme: light;
    color-scheme: light;
}

/*
 * ── 5. LEGACY ARK NAMES ─────────────────────────────────────────────────
 *
 * The vocabulary this catalog used before the port. Each line points an old
 * name at a value section 1-4 already defines; no colour is introduced here.
 * Names that resolve through a semantic which itself flips (--foreground,
 * --surface-1, --primary, …) are declared once — the dark block re-tones them
 * for free. Only the handful with no flipping equivalent are repeated in that
 * block.
 *
 * A new component should reach for the section 2-4 names. These stay so the
 * existing sheets, MudBlazor's ArkTheme and every *.razor.css keep working.
 */
:root {
    /* Brand */
    --brand-primary: var(--brand-600);
    --brand-secondary: var(--saffron-500);
    --brand-tertiary: var(--tertiary-500);

    /* Neutrals — stock greys, kept literal: these are not part of the
       blue-grey chassis and nothing in sections 1-4 replaces them. */
    --gray-50: #f3f4f5;
    --gray-200: rgba(242, 242, 242, 1);
    --gray-700: #374151;
    --gray-800: #1f2937;

    /* Semantic brand */
    --primary-color: var(--primary);
    --primary-hover-color: var(--primary-hover);
    --primary-active-color: var(--brand-800);

    --secondary-color: var(--saffron-500);
    /* Lightens on hover rather than darkening to the 600 stop. The lime is a
       light fill wearing dark ink, and the darker stop pulled the pair down to
       3.9:1; going the other way keeps the label clear of AA in both themes. */
    --secondary-hover-color: var(--saffron-400);

    --tertiary-color: var(--tertiary-500);
    --tertiary-hover-color: #55287d; /* darken(#6a329c, 8%) */

    /* State — the quads are already section-1 names; only the old
       `-text` / `-border` spellings need pointing at them. */
    --success-color: var(--success);
    --success-text: var(--success-ink);
    --success-border: var(--success-edge);

    --warning-color: var(--warning);
    --warning-text: var(--warning-ink);
    --warning-border: var(--warning-edge);

    --danger-color: var(--destructive);
    --danger-text: var(--danger-ink);
    --danger-border: var(--danger-edge);

    --info-color: var(--info);
    --info-text: var(--info-ink);
    --info-border: var(--info-edge);

    /* Sizing. --box-shadow is the card elevation the platform gives a panel;
       --shadow-brand stays the deeper lift, for the few surfaces that really
       float. Both flip with the theme; the old brand-tinted values are gone. */
    --box-shadow: var(--shadow-sm);
    --shadow-brand: var(--shadow-lift);
    --motion-fast: var(--duration-fast);

    /* Spacing. Deliberately NOT mapped into Tailwind's @theme (see
       theme/tailwind.css): in Tailwind v4 the spacing namespace also backs
       the sizing utilities, so a --spacing-sm entry makes `max-w-sm`
       resolve to 8px instead of 24rem. Blazor CSS reads these directly and
       is unaffected. */
    --spacing-xs: 4px;
    --spacing-sm: 8px;
    --spacing-md: 16px;
    --spacing-lg: 24px;

    /* Layout */
    --sidebar-width: 270px;
    --sidebar-width-collapsed: 59px;
    --topbar-height: 60px;
    --breadcrumb-height: 40px;
    --page-title-height: 40px;

    --container-padding-x: var(--spacing-md);
    --container-padding-mobile: var(--spacing-md);
    --container-padding-tablet: var(--spacing-lg);
    --container-padding-desktop: var(--spacing-lg);
    --mobile-xs: 320px;
    --gutter-x: 1.5rem;

    /* Typography */
    --font-family-base: var(--font-sans);
    --font-family-heading: var(--font-display);
    --font-family-body: var(--font-sans);
    --font-family-mono: var(--font-mono);
    --font-size-base: 12px;
    --font-weight-normal: 400;
    --font-weight-bold: 600;

    /* Gradient */
    --brand-gradient-start: var(--primary);
    --brand-gradient-end: var(--tertiary-500);

    /* Menu icons */
    --menu-icon-color: var(--muted-foreground);
    --menu-icon-color-hover: var(--primary-hover);
    --menu-icon-color-active: var(--primary);
    --menu-icon-color-selected: var(--tertiary-500);
    --menu-link-color-selected: #ffffff;

    /* Text */
    --text: var(--foreground);
    --text-color: var(--foreground);
    --text-header: var(--foreground);
    --text-secondary: var(--muted-foreground);
    --text-muted: var(--neutral-500);

    /* Borders */
    --border-color: var(--border);
    --button-border: var(--border-strong);
    --border-color-secondary: rgba(106, 50, 156, 0.20);

    /* Surfaces, mapped onto the platform's four elevation tiers rather than
       onto the literals this catalog used before the port. Both of the old
       raised names land on tier 4 — the platform draws one raised step, not
       two, and collapsing them is what makes a table stripe here the same
       shade as one in the platform.

       Declared once, not per theme: every tier below already flips in the
       dark block, so these follow it. */
    --surface-bg: var(--surface-1);
    --surface-subtle: var(--surface-4);
    --surface-bg-2: var(--surface-4);
    /* Chrome that floats over content — the app bar, a rail, a specimen head.
       The platform's own translucency: the card tier at 85%, over whatever is
       behind it, with the blur supplied by the element. Relative-colour syntax
       keeps it tracking --card through the theme flip. */
    --surface-glass: oklch(from var(--card) l c h / 0.85);
    --surface-glass-strong: oklch(from var(--card) l c h / 0.92);
    --grid-header-bg: var(--surface-4);
    --grid-header-line: var(--border-strong);

    /* Atmospheric page background. The port replaced the old three-channel
       mesh with the platform's single soft glow in the brand colour; the
       token name stays because app.css and the React shell read it. */
    --workspace-mesh:
        radial-gradient(ellipse 60% 40% at 15% -5%, oklch(from var(--brand-600) l c h / 0.10), transparent 70%);

    /* Hover / selection */
    --hover-surface: rgba(42, 101, 114, 0.10);
    --selection: rgba(156, 189, 43, 0.15);

    /* Drawer brand row and component-count badge: the only drawer surfaces
       MainLayout.razor.css styles itself (literal elements, not ::deep into
       MudDrawer's own markup). The drawer's background, inactive nav text
       and icon colours are owned by MudBlazor's theme engine (see
       ArkTheme.PaletteLight/PaletteDark) — no token needed here. */
    --drawer-text: var(--foreground);
    --drawer-count: var(--primary);
}

/*
 * DARK MODE — values flip; semantic names stay.
 *
 * Both selectors carry a `:root` prefix so each has attribute/class-level
 * specificity. A bare `[data-theme="dark"]` or `.dark` ties with a plain
 * `:root` block, and any later-loading sheet that reasserts a token on
 * `:root` would win that tie on source order and silently discard the dark
 * value. The extra `:root` outranks such a reassertion instead of racing it.
 */
:root.dark,
:root[data-theme="dark"] {
    /* The same cool blue-grey graphite, canvas through panel. */
    --background: var(--neutral-1000);
    --foreground: #e8f0f3;

    --card: var(--neutral-900);
    --card-foreground: #e8f0f3;
    --popover: var(--neutral-850);
    --popover-foreground: #e8f0f3;

    /* The 600 stop is only ~2.4:1 on #0b1117 and this token is used as
       text and icon colour, not just as a fill. The 400 stop is the same
       hue two steps lighter, which clears AA and still reads as brand
       teal. */
    --primary: var(--brand-400);
    --primary-foreground: var(--neutral-1000);
    --primary-hover: var(--brand-300);
    --primary-soft: oklch(from var(--brand-400) l c h / 0.18);

    --secondary: var(--neutral-850);
    --secondary-foreground: #e8f0f3;

    --muted: var(--neutral-850);
    /* The secondary text stop, not the muted one (#82949d): consumers mask
       this to 60% alpha for placeholders and chevrons, and the muted stop
       does not survive that against the graphite canvas. */
    --muted-foreground: #a9bac2;

    --accent: var(--neutral-800);
    --accent-foreground: #e8f0f3;
    --saffron: var(--saffron-500);
    --saffron-foreground: #12180a;
    --saffron-ink: var(--saffron-400);

    --destructive: var(--danger-500);
    --destructive-foreground: oklch(0.990 0.005 20);

    --success: var(--success-500);
    --warning: var(--warning-500);
    --info: var(--info-500);

    --border: rgb(137 174 186 / 0.18);
    --border-strong: #314650;
    --input: #314650;
    --ring: var(--brand-400);

    --surface-1: var(--neutral-1000);
    --surface-2: var(--neutral-900);
    --surface-3: var(--neutral-850);
    --surface-4: var(--neutral-800);
    --surface-1-hover: var(--neutral-950);
    --surface-2-hover: var(--neutral-850);

    --chart-1: var(--brand-400);
    --chart-2: var(--saffron-400);
    --chart-3: var(--tertiary-400);
    --chart-4: var(--info-500);
    --chart-5: var(--warning-500);
    --chart-grid: rgb(137 174 186 / 0.22);

    --highlight-top: inset 0 1px 0 oklch(1 0 0 / 0.06);

    --shadow-sm: 0 1px 2px 0 oklch(0 0 0 / 0.20),
                 0 1px 3px 0 oklch(0 0 0 / 0.24);
    --shadow-md: 0 4px 6px -1px oklch(0 0 0 / 0.28),
                 0 2px 4px -2px oklch(0 0 0 / 0.20);
    --shadow-lg: 0 10px 15px -3px oklch(0 0 0 / 0.34),
                 0 4px 6px -4px oklch(0 0 0 / 0.22);
    --shadow-lift: 0 16px 36px -18px oklch(0 0 0 / 0.55),
                   0 6px 12px -6px oklch(0 0 0 / 0.35);

    /* Legacy names with no flipping equivalent in sections 1-4. */
    /* Same reasoning as dark --primary: the brand purple is a fill colour on
       the light canvas but this token is also used as small text, and the 500
       stop does not survive graphite. */
    --tertiary-color: var(--tertiary-300);
    --tertiary-hover-color: var(--tertiary-400);
    --text-muted: #82949d;
    --border-color-secondary: rgba(169, 117, 214, 0.26);
    --workspace-mesh:
        radial-gradient(ellipse 60% 40% at 15% -5%, oklch(from var(--brand-500) l c h / 0.12), transparent 70%);
    --hover-surface: rgba(255, 255, 255, 0.07);
    --selection: rgba(156, 189, 43, 0.12);
    --drawer-text: #ffffff;
    --drawer-count: var(--saffron-500);

    --color-scheme: dark;
    color-scheme: dark;
}

/*
 * System-preference fallback. ark-theme.js (Blazor) and use-ark-theme.ts
 * (React) both stamp `data-theme` and `.dark` from a synchronous <head>
 * script before first paint, so this block only covers the case where that
 * script never runs. It sets `color-scheme` alone rather than restating all
 * of the values above: duplicating them is how the pre-port sheet ended up
 * maintaining its dark palette in two places.
 */
@media (prefers-color-scheme: dark) {
    :root:not([data-theme]):not(.dark) {
        color-scheme: dark;
    }
}
