/* ============================================================================
   TOKENS — ERP.AI Design System (Brutalist)
   Dark-mode-aware tokens. Static tokens (fonts, type scale, radii, easings)
   live in @theme (base.njk). This file holds values that change light ↔ dark.

   Light-first: :root = light palette (for Tailwind compat), html.dark = dark overrides.
   The flash-prevention script in base.njk defaults preference to light when unset.

   Colors in oklch(L% C H) — perceptually uniform, Tailwind v4-native.
   Beige scale is calibrated around a #faf9f5-adjacent paper anchor while
   keeping hue inside the 78–82 beige band. Lightness is lifted and chroma is
   muted through the dark half so the scale reads beige, not khaki/olive.
   ============================================================================ */

:root {
  /* == Beige scale — raw palette layer =======================================
     11-step Tailwind-shaped ramp. Beige-50 is the off-white paper anchor
     (#fbf9f5, visually adjacent to #faf9f5). The family tapers hue 82→78
     while lifting dark lightness and reducing chroma so dark-mode surfaces
     stay warm beige instead of drifting green/olive. Scale values are
     invariant across themes; the semantic tokens below alias scale steps and
     flip per mode (html.dark overrides). Mirrors the scale in
     packages/tokens/src/core.css.
     ============================================================== */
  --beige-50: oklch(98.2% 0.0054 82); /* #fbf9f5 — off-white paper anchor */
  --beige-100: oklch(97% 0.0065 82); /* #f7f5f0 */
  --beige-200: oklch(94.5% 0.01 82); /* #f0ece5 */
  --beige-300: oklch(91% 0.012 81.5); /* #e5e1d9 */
  --beige-400: oklch(86% 0.014 81); /* #d6d0c7 */
  --beige-500: oklch(69% 0.032 78); /* #a79986 */
  --beige-600: oklch(54% 0.036 78); /* #7a6c57 */
  --beige-700: oklch(42% 0.028 78); /* #564b3c */
  --beige-800: oklch(34% 0.012 79); /* #3b3731 */
  --beige-900: oklch(24% 0.01 78.5); /* #221f1a */
  --beige-950: oklch(16% 0.008 78); /* #0f0d09 */

  /* == Inks — raw ink layer ==================================================
     Second raw layer alongside the beige scale. Hue 78°, low chroma
     (≤0.012). Body text reads as "rich warm gray" on cream surfaces, not
     as a tinted shade of the surface (the chroma divergence vs the scale
     is what defines the ink-on-cream feel). Theme-CONSTANT — light and
     dark each pick a different ink stop; no html.dark overrides on
     --ink-* itself. Mirrors the inks declared in DESIGN.md frontmatter
     and packages/tokens/src/core.css. Semantic text tokens below alias
     these. */
  --ink-deep: oklch(15% 0.012 78);
  --ink-mid: oklch(41% 0.008 78);
  --ink-muted: oklch(44% 0.008 78);
  --ink-nav: oklch(30% 0.008 78);
  --ink-light: oklch(95% 0.005 78);
  --ink-light-mid: oklch(62% 0.008 78);
  --ink-light-muted: oklch(57% 0.008 78);

  /* == Footer surface ========================================================
     Footer flips per mode, both lifted one step away from the page tier:
       Light: beige-300 (paper-tinted, L 91) bg with beige-950
              (muted warm black, L 16) ink → ΔL ~75, passes AAA.
       Dark:  beige-800 (soft dark beige, L 34) bg with beige-200 (paper, L 94.5)
              ink → contrast ~14:1, passes AAA.
     Light bg = same scale step as --border, so the top-border between
     content and footer becomes near-invisible (intentional softer seam).
     The dark-mode override lives under html.dark below.

     Light --footer is beige-300 — one step lighter than the legacy
     beige-400 value. Adopted during the 2026-05 top-design redesign
     batch (P1-P4) and ratified as permanent on 2026-05-13 after P6
     /byoa shipped on the same palette. Footer still sits one tier
     heavier than --darker (beige-200) so the bottom-of-page seam
     reads as a distinct band.
     ============================================================== */
  --footer: var(--beige-300); /* light mode — paper-tinted */
  --on-footer: var(--beige-950); /* light mode — muted warm black ink */

  /* == ERP.AI Color System (Light Mode) ======================================
     Surfaces alias the beige scale. Text tokens alias the ink layer (the
     low-chroma hue-78 grays above) — that's why body text reads as ink on
     cream, not as a tinted shade of the surface.

     Light palette sits one step lighter than the legacy values —
     page bg near-white (beige-50), card/alt surfaces beige-200,
     borders beige-300. Adopted across the 2026-05 top-design batch
     (P1 Proto → P4 Startups) and ratified as permanent on 2026-05-13
     after P6 /byoa shipped on the same palette. Dark mode uses the
     same paper-muted beige scale via the overrides below. */
  --background: var(--beige-50);
  --foreground: var(--ink-deep);
  /* --card is a semantic alias for --background. Cards inherit the page bg
     in both modes (light: near-white beige-50; dark: muted dark beige-900).
     The alias survives so .ds-bg-card / Tailwind's bg-card utility carry
     semantic meaning; the value is the page's bg. */
  --card: var(--background);
  --primary: oklch(55% 0.21 28);
  --primary-foreground: var(--beige-50);
  --secondary: var(--beige-200);
  --muted: var(--beige-200);
  --muted-foreground: var(--ink-muted);
  --accent: oklch(55% 0.21 28);
  --destructive: oklch(48% 0.19 28);
  /* --border (element envelope) and --outline (focus ring) hold the same
     value today, but they cover distinct affordances — keep separate so a
     future redesign of either tier doesn't have to undo a coupled alias.
     beige-300 on beige-50 bg = ΔL ~8.7, still clearly visible as 1px lines. */
  --border: var(--beige-300);
  --outline: var(--beige-300);
  --ring: oklch(55% 0.21 28);

  /* == ERP.AI Palette (constant across themes) =============================== */
  --red: oklch(55% 0.21 28);
  --grn: oklch(73% 0.196 148);
  --ylw: oklch(75% 0.176 84);
  --pur: oklch(66% 0.18 287);
  --org: oklch(67% 0.21 45);
  --gold: oklch(68% 0.04 72);

  /* Text-on-light-background brand variants — the base brand palette is
     tuned to pop against dark backgrounds; on the cream --background all
     five hues land at 2–3.7:1 which fails WCAG 1.4.3 (AA 4.5:1) for text.
     These `-on-light` tokens hold a darker, same-hue variant for use in
     `color:` on light surfaces. In dark mode they alias back to the base
     brand so no per-theme branching is required at call sites. */
  --org-on-light: oklch(48% 0.21 45);
  --grn-on-light: oklch(45% 0.196 148);
  --pur-on-light: oklch(40% 0.18 287);
  --gold-on-light: oklch(42% 0.04 72);
  --red-on-light: oklch(42% 0.19 28);

  /* == Hero-catalog component tokens =========================================
     Branded values exclusive to the home hero (.hero-catalog) — kept here so
     all values in components.css go through the token system. Theme-constant
     where applicable; the dark-mode-only ones are overridden in html.dark
     below. */
  --hero-hover-ochre: #ffc649; /* warm amber, deliberately warmer than --ylw */

  /* == Semantic aliases (inverted for light mode per DESIGN.md) ==============
     --dark / --darker both alias beige-100 so the alternation-band rhythm
     is very subtle against the beige-50 page bg (ΔL ~1.7). The two tokens
     currently collapse to the same value — they'll separate again if a
     future tier needs space between them. (History: --dark was beige-200,
     --darker was beige-300 before the 2026-05 top-design batch dropped
     both to beige-100; permanent as of 2026-05-13.) */
  --dark: var(--beige-100);
  --darker: var(--beige-100);
  /* --cream and --text-l are historical aliases that resolved to the same
     value as --foreground in both modes. Kept as live aliases (rather than
     deleted) for template back-compat; new CSS should reach for --foreground
     directly. */
  --cream: var(--foreground);
  --text-l: var(--foreground);
  --text-m: var(--ink-mid);
  --nav-link: var(--ink-nav);
  /* Off-white paper anchor (#fbf9f5), used as light text on dark sections. */
  --text-d: var(--beige-50);

  /* == Surface system ========================================================
     All surfaces alias the beige scale. --surface-container-highest used to
     be an off-scale L 84.5 literal (between beige-300 and beige-400) for an
     intermediate elevation tier; collapsed to var(--beige-300) so the system
     no longer holds any off-scale color.

     Elevated surface tier sits one step lighter than the legacy
     values — most went beige-300 → beige-200. --surface-dim is one
     step further (beige-200 → beige-100) so cards on page bg read as
     a "merged" subtle elevation (ΔL 2.5 against bg) rather than a
     distinct band. --surface-bright was already at beige-100; the
     dim/bright tiers currently collapse on light mode and will be
     reseparated if a future surface needs an even lighter tier.
     Adopted in the 2026-05 top-design batch; permanent as of
     2026-05-13. */
  --surface-dim: var(--beige-100);
  --surface-bright: var(--beige-100);
  --surface-container: var(--beige-200);
  --surface-container-highest: var(--beige-200);
  --surface-invert: var(--beige-900); /* warm dark — was oklch(15% 0.012 78) gray */

  /* == Elevation / shadows (prefixed — @theme maps --shadow-* → --_shadow-*) = */
  --_shadow-1: 0 1px 3px 1px rgb(0 0 0 / 6%), 0 1px 2px rgb(0 0 0 / 8%);
  --_shadow-2: 0 2px 6px 2px rgb(0 0 0 / 6%), 0 1px 2px rgb(0 0 0 / 8%);
  --_shadow-3: 0 4px 8px 3px rgb(0 0 0 / 6%), 0 1px 3px rgb(0 0 0 / 8%);
  --_shadow-4: 5px 5px 0px var(--ink-deep);
  --_shadow-5: 6px 6px 0px var(--ink-deep);

  /* == Spacing scale (used by custom CSS via var(); TW uses --spacing multiplier) */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  /* Exceptional half-step: 14px, the only off-grid value in the spacing
     scale. Added so .btn--xl's vertical padding (chosen to match the home
     hero CTA, hero-catalog.njk's .hero-cta) stays on tokens instead of
     escaping to a raw px value. Don't extend the pattern (no --space-1-5,
     no --space-5) — prefer the 4px-grid stops above when adding new sizes. */
  --space-3-5: 0.875rem;
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;

  /* == Type scale (named by role — see README) =============================== */
  /* Theme-agnostic: don't override per dark/light. Apps can map these into a
     Tailwind v4 @theme block to generate utility classes if needed. */
  --fs-micro: 0.5rem; /*  8px — decorative-only counters/marks; not communicative text */
  --fs-caption: 0.5625rem; /*  9px — absolute minimum communicative text */
  --fs-label: 0.625rem; /* 10px — short labels */
  --fs-chip: 0.6875rem; /* 11px — chip labels and compact tags */
  --fs-xs: 0.75rem; /* 12px — preferred small text and meta floor */
  --fs-meta: 0.8125rem; /* 13px — hero stat labels, compact meta */
  --fs-btn: 0.875rem; /* 14px — buttons, inputs (also "sm") */
  --fs-body: 1rem; /* 16px — base body */
  --fs-subhead: 1.125rem; /* 18px — sub-headings, card metrics */
  --fs-title: 1.25rem; /* 20px — card titles, step numbers */
  --fs-display: 1.5rem; /* 24px — section stats, lg headings */
  --fs-h1: 2.25rem; /* 36px — h1 / page titles (static) */
  --fs-section: clamp(2rem, 4vw, 3rem); /* 32–48px — section headlines */
  /* Hero scale — container-query clamp (cqi), re-enabled 2026-05-16 via
     design-elevation. Was clamp(3rem, 7.5vw, 6.25rem) viewport-fluid. cqi
     resolves against the hero container, protecting sticky nav + dropdown
     z-index. Mirrors --text-hero in apps' tailwind.input.css @theme. */
  --fs-hero: clamp(2rem, 10cqi, 4.5rem);
  --fs-ghost: clamp(72px, 12vw, 140px); /* decorative ghost text */

  /* == Border widths (1 / 2 / 3px) =========================================== */
  /* Brutalist default: --base = sm (1px). Apps that want thicker primitives
     can override --border-width-base in a later-loaded local token layer. */
  --border-width-sm: 1px;
  --border-width-md: 2px;
  --border-width-lg: 3px;
  --border-width-thin: var(--border-width-sm); /* alias → 1px */
  --border-width-base: var(--border-width-sm); /* alias → 1px */

  /* == Focus / outline ======================================================= */
  /* Width + offset for :focus-visible. Color comes from --outline (dark-aware). */
  --outline-width: 2px;
  --outline-offset: 2px;

  /* == Theme-constant accents ================================================
     Same value in light and dark modes. Yellow stays yellow, so text on it
     must stay dark — --accent-yellow-fg is the WCAG-safe foreground for any
     element with --accent-yellow as its background. */
  --accent-yellow: oklch(94% 0.18 95);
  --accent-yellow-fg: var(--ink-deep);

  /* == Durations + easings (no TW4 theme namespace — used by custom CSS) ===== */
  --duration-fast: 150ms;
  --duration-normal: 250ms;
  --duration-slow: 400ms;
  --duration-slower: 600ms;
  --ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --ease-decelerate: cubic-bezier(0, 0, 0, 1);
  --ease-accelerate: cubic-bezier(0.3, 0, 1, 1);
  --ease-angular: cubic-bezier(0.4, 0, 0, 1);
  --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* == Cinematic motion vocabulary ===========================================
     Layered on top of the duration/ease primitives above. Powers "signature
     moments" — scroll-triggered SVG draws, staggered grid reveals, clip-path
     typographic unmasks — that complement the baseline reveal / reveal-up
     vocabulary. Used by web-lab's scroll-choreography.css (proto.njk peak
     moments); shared across all @lab/tokens consumers. */
  /* Stagger intervals — multiplied by --stagger-index in transition-delay.
     The default in utilities.css is 80ms (== --stagger-mid). */
  --stagger-fast: 40ms; /* dense grids (9+ cells), table rows */
  --stagger-mid: 80ms; /* default — matches utilities.css baseline */
  --stagger-slow: 120ms; /* coarse grids (4–6 cells), stack layers */
  /* Cinematic durations — used where --duration-slow would feel rushed. */
  --duration-cinema: 1200ms; /* SVG path draws, multi-step sequences */
  --duration-signature: 1600ms; /* hero typographic reveal, peak moments */
  /* Signature easings — top-design "no ease/linear" mandate. */
  --ease-signature: cubic-bezier(0.16, 1, 0.3, 1); /* expo-out — typographic reveal */
  --ease-quart-out: cubic-bezier(0.25, 1, 0.5, 1); /* quart-out — supporting reveals */
  --ease-expo-in-out: cubic-bezier(0.87, 0, 0.13, 1); /* expo-in-out — paired entrances */
  /* Continuous scroll progress — set 0..1 by observer.js scroll-progress hook;
     consumers read in calc() to drive transforms or fill states tied to
     viewport position. Defaults to 0 so static rendering is safe. */
  --scroll-progress: 0;

  /* == Z-index ===============================================================
     Aligned with @lab/tokens / erphq/build-host. Names describe what's at each
     layer in this codebase, not generic stacking-context concepts. */
  --z-base: 1; /* default flow */
  --z-content: 3; /* lifted content within flow (decorative dots, accent ribbons) */
  --z-raised: 10; /* surface lifted above siblings */
  --z-popover: 11; /* popover / dropdown panels anchored to a parent */
  --z-sidebar: 40; /* fixed app-shell layers */
  --z-nav: 50; /* sticky / fixed navigation bar */
  --z-sticky: 60; /* sticky table headers, scroll-locked CTAs */
  --z-overlay: 100; /* full-viewport overlays */
  --z-modal: 200; /* dialogs, alerts — elevates above navbar */
  --z-skip: 9999; /* skip-link — must clear everything else */

  /* == Layout offsets — single source of truth for the sticky-nav stack ====
     The two primitives (nav-height, audience-bar) match the rendered heights
     of nav-01.njk's nav element and the audience-bar.njk strip. Everything
     downstream is derived: --chrome-height (the height of the fixed chrome
     unit, audience bar + nav stacked) and --scroll-stack (chrome + 16px
     breathing room for hash anchors).

     Consumers:
       - sections/nav/nav-01.njk spacer reads --chrome-height / --nav-height
       - sub-nav stickiness reads --chrome-height
       - base.css scroll-margin-top reads --scroll-stack
       - view-transitions.js#scrollToHash reads --nav-height + --audience-bar
       - catalog.js filter-jump reads --nav-height

     Mobile (< 640px): the audience bar stacks to two rows (FOR HUMANS over
     FOR AGENTS), so --audience-bar grows to 56px there. The sm-up override
     lives at the end of this file. --chrome-height + --scroll-stack are
     calc()s, so they recalculate automatically when --audience-bar flips.

     Change the primitives only; the derivations keep everything in sync. */
  --nav-height: 48px;
  --audience-bar: 56px; /* mobile: 2 stacked rows (px-2 + 11px×2 + 1px border) */
  --chrome-height: calc(var(--nav-height) + var(--audience-bar)); /* 104px mobile, 84px sm+ */
  --scroll-stack: calc(var(--chrome-height) + 16px); /* 120px mobile, 100px sm+ */

  /* == Catalog category palette ============================================
     Per-category swatches surfaced as --btn-color on .catalog-filter-btn
     hover. Theme-independent: a category keeps its identity in light + dark.
     Add a new category by adding both the row here and the CSS rule in
     components.css. Default fallback (--cat-default) covers any [data-filter]
     value without a dedicated row — there shouldn't be any in steady state. */
  --cat-default: #888;
  --cat-on: #fff;
  --cat-all: #1a1a1a;
  --cat-erp: #e84230;
  --cat-crm: #2563eb;
  --cat-hrms: #7c3aed;
  --cat-scm: #0891b2;
  --cat-fin: #16a34a;
  --cat-pm: #ea580c;
  --cat-health: #dc2626;
  --cat-edu: #4f46e5;
  --cat-retail: #d946ef;
  --cat-mfg: #525252;
  --cat-legal: #78350f;
  --cat-govt: #1e3a5f;
  --cat-it: #0f766e;
  --cat-support: #b45309;
  --cat-realestate: #9a3412;
  --cat-hotel: #a16207;
  --cat-food: #c2410c;
  --cat-transport: #1d4ed8;
  --cat-agri: #15803d;
  --cat-media: #9333ea;
  --cat-energy: #ca8a04;
  --cat-bank: #0e7490;
  --cat-insure: #4338ca;
  --cat-ngo: #059669;
  --cat-salon: #be185d;
  --cat-sports: #65a30d;
  --cat-events: #e11d48;
  --cat-warehouse: #57534e;
  --cat-workflow: #6d28d9;
  --cat-analytics: #0284c7;
  --cat-combo: #374151;
}

/* == Dark mode (opt-in via html.dark) =======================================
   Surfaces now use the paper-muted beige family (beige-800 / 900 / 950) for
   comparison instead of the prior near-neutral grayscale. Inks (--cream,
   *-foreground aliases) become the light end of the scale (beige-200 / 300).
   The L-17 mid-tier (formerly --muted, --surface-bright, --surface-container
   at oklch(17% 0 0)) collapses to step 800 (L 22) along with the L-20 border
   tier — the 11-step scale doesn't have an L 17 stop and the prior ΔL 3
   distinction was already subtle.
   ============================================================== */
html.dark {
  --background: var(--beige-900);
  --foreground: var(--beige-200);
  /* --card NOT redefined — alias to --background from :root cascades through. */
  --primary: oklch(55% 0.21 28);
  --primary-foreground: var(--beige-50);
  --secondary: var(--beige-950);
  --muted: var(--beige-800);
  --muted-foreground: var(--ink-light-muted);
  --accent: oklch(55% 0.21 28);
  --destructive: oklch(55% 0.21 28);
  --border: var(--beige-800);
  --outline: var(--beige-800);
  --ring: oklch(55% 0.21 28);

  /* Semantic aliases invert */
  --dark: var(--beige-900);
  /* --darker is the elevation tier above the page bg — beige-800 (L 22,
     tobacco). Pages alternate `bg-background` / `bg-darker` for vertical
     rhythm; making --darker a step LIGHTER than --background (L 15) gives
     each `bg-darker` section a subtle lift in dark mode (ΔL 7). Light mode
     keeps --darker at beige-300 (cream-tinted, ΔL 4 above --background).
     Caveat: --border in dark mode is also beige-800, so any --border border
     INSIDE a bg-darker section will be invisible against its parent bg.
     Use sparingly; prefer --border-strong tokens for borders on darker
     surfaces if you need them visible. */
  --darker: var(--beige-800);
  --cream: var(--foreground);
  --text-l: var(--ink-light);
  --text-m: var(--ink-light-mid);

  /* -on-light brand variants alias to the base palette in dark mode — the
     base palette already passes AA (5–7:1) against the dark backgrounds. */
  --org-on-light: var(--org);
  --grn-on-light: var(--grn);
  --pur-on-light: var(--pur);
  --gold-on-light: var(--gold);
  --red-on-light: var(--red);
  --nav-link: oklch(77% 0.01 78); /* off-scale ink: brighter than ink-light, dimmer than beige-50 */
  --text-d: var(--ink-deep);

  /* Surface system */
  --surface-dim: var(--beige-950);
  --surface-bright: var(--beige-800); /* L 17 → L 34 (elevation kept) */
  --surface-container: var(--beige-800);
  --surface-container-highest: var(--beige-800); /* L 20 → L 34 */
  --surface-invert: var(--beige-200);

  /* Footer in dark mode — muted dark-mid beige (beige-700, L42) sits one step
     lighter than --darker (beige-800, L34) so the footer reads as a
     distinct band against the cta-atsh closer (which paints --darker).
     beige-800 collapsed footer and CTA into one tone. Page bg → CTA →
     footer now steps L24 → L34 → L42, mirroring the light-mode ladder
     (beige-200 → beige-300 → beige-400). Paper-on-dark-mid (L94.5/L42)
     keeps comfortable contrast. */
  --footer: var(--beige-700);
  --on-footer: var(--beige-200);

  /* Hero-catalog warm-dark surfaces — hue 70 (warmer than the beige
     scale's hue 70°… actually the same hue but with custom L+C tuned
     for the home hero's "humans / agents" split. Not on the beige
     scale; component-scoped to .hero-catalog. */
  --hero-warm-dark-2: #302c26; /* humans half — L19, deepest tint */
  --hero-warm-dark-3: #24221e; /* agents half — L15, mid dark */

  /* AA-locked mid-gray for hero-catalog secondary text on the warm-dark
     humans surface (#302c26). Passes WCAG 1.4.3 at 4.5:1; #888 (L 57)
     was 4.09:1 — too close to the threshold. Don't swap to
     --ink-light-mid (L 62) without re-running contrast against #302c26. */
  --hero-text-m-dark: #9a9a9a;

  /* Shadows — brutalist hard shadows in dark mode */
  --_shadow-1: 0 1px 3px 1px rgb(0 0 0 / 30%), 0 1px 2px rgb(0 0 0 / 30%);
  --_shadow-2: 0 2px 6px 2px rgb(0 0 0 / 30%), 0 1px 2px rgb(0 0 0 / 30%);
  --_shadow-3: 0 4px 8px 3px rgb(0 0 0 / 30%), 0 1px 3px rgb(0 0 0 / 30%);
  --_shadow-4: 5px 5px 0px color-mix(in oklch, var(--beige-50) 10%, transparent);
  --_shadow-5: 6px 6px 0px color-mix(in oklch, var(--beige-50) 10%, transparent);
}

/* == Layout offsets — sm-up override =========================================
   From the sm: breakpoint up, the audience bar fits on a single line so it
   collapses back to its 36px slot. --chrome-height (104→84) and --scroll-stack
   (120→100) recalculate automatically because they're calc()s over this var. */
@media (min-width: 640px) {
  :root {
    --audience-bar: 36px; /* sm+: single-line bar (py-2 + 11px line + 1px border) */
  }
}
