/* ============================================================================
   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 */

  /* == Rich footer presentation =============================================
     Tacet and Swage intentionally keep separate semantic palettes. These
     values mirror the approved Web Lab presentation exactly; component CSS
     consumes the tokens and must not redeclare raw colors locally. */
  --footer-tacet-bg-light: #fbfbf8;
  --footer-tacet-bg-soft-light: #f3f4f1;
  --footer-tacet-bg-lift-light: #fff;
  --footer-tacet-ink-light: #687080;
  --footer-tacet-ink-strong-light: #172033;
  --footer-tacet-ink-muted-light: #687080;
  --footer-tacet-rule-light: #dbe1eb;
  --footer-tacet-bg-dark: var(--beige-800);
  --footer-tacet-bg-soft-dark: color-mix(
    in oklch,
    var(--beige-800),
    var(--beige-900) 36%
  );
  --footer-tacet-bg-lift-dark: color-mix(
    in oklch,
    var(--beige-700),
    var(--beige-800) 48%
  );
  --footer-tacet-ink-dark: var(--beige-300);
  --footer-tacet-ink-strong-dark: var(--beige-100);
  --footer-tacet-ink-muted-dark: color-mix(
    in oklch,
    var(--beige-300),
    transparent 24%
  );
  --footer-tacet-rule-dark: color-mix(
    in oklch,
    var(--beige-300),
    transparent 72%
  );
  --footer-tacet-backdrop-dark: radial-gradient(
    ellipse 58% 48% at 10% 100%,
    color-mix(in oklch, var(--beige-700), transparent 68%) 0%,
    color-mix(in oklch, var(--beige-800), transparent 82%) 38%,
    transparent 76%
  );
  --footer-swage-bg-light: #fbfbf8;
  --footer-swage-bg-soft-light: #f3f4f1;
  --footer-swage-bg-lift-light: #fff;
  --footer-swage-ink-light: #687080;
  --footer-swage-ink-strong-light: #172033;
  --footer-swage-ink-muted-light: #687080;
  --footer-swage-rule-light: #dbe1eb;
  --footer-swage-bg-dark: #07090d;
  --footer-swage-bg-soft-dark: #0a0f16;
  --footer-swage-bg-lift-dark: #101722;
  --footer-swage-ink-dark: #aab7cc;
  --footer-swage-ink-strong-dark: #f7f9fc;
  --footer-swage-ink-muted-dark: #aab7cc;
  --footer-swage-rule-dark: #2e3a51;
  --footer-highlight: var(--beige-50);
  --footer-rich-surface-shadow:
    inset 0 1px 0 color-mix(in oklch, var(--footer-highlight), transparent 80%),
    0 -1rem 2.25rem -1.5rem rgb(18 15 12 / 20%);
  --footer-anchor-surface-shadow:
    inset 0 1px 0 color-mix(in oklch, var(--footer-highlight), transparent 80%),
    0 -0.75rem 1.5rem -1rem rgb(18 15 12 / 28%);
  --footer-toggle-track-shadow:
    inset 0 1px 1px rgb(18 15 12 / 18%),
    0 1px 0 color-mix(in oklch, var(--footer-highlight), transparent 88%);
  --footer-toggle-thumb-shadow:
    0 0.45rem 0.85rem -0.25rem rgb(18 15 12 / 32%),
    inset 0 1px 0 color-mix(in oklch, var(--footer-highlight), transparent 72%);
  --footer-main-seam-shadow: 0 1.25rem 3rem rgb(18 15 12 / 16%);

  /* == 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: var(--tacet-orange);
  --primary-foreground: var(--beige-50);
  --secondary: var(--beige-200);
  --muted: var(--beige-200);
  --muted-foreground: var(--ink-muted);
  --accent: var(--tacet-orange);
  --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);
  /* --border-strong: one step up the beige scale from --border, for a rule that
     needs a touch more presence than a hairline (e.g. the eyebrow name underline). */
  --border-strong: var(--beige-400);
  --outline: var(--beige-300);
  --ring: var(--tacet-orange);

  /* == 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);
  --tacet-orange: oklch(69% 0.19 56);
  --org: var(--tacet-orange);
  --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. */
  --tacet-orange-on-light: oklch(47% 0.18 56);
  --org-on-light: var(--tacet-orange-on-light);
  --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 */
  --hero-catalog-center-gutter: clamp(1.5rem, 2vw, 1.875rem);
  --hero-catalog-eyebrow-gap: 0.45rem;
  --hero-catalog-copy-size: clamp(0.8rem, 0.95vw, 0.95rem);
  --hero-catalog-panel-duration: 220ms;
  --hero-catalog-on-solid: var(--beige-50);
  --hero-catalog-muted-on-solid: var(--beige-100);
  --hero-catalog-agent-dark-surface: var(--beige-300);
  --hero-catalog-agent-dark-muted: var(--beige-700);
  --hero-catalog-agent-dark-action: var(--beige-700);
  --hero-catalog-dark-ink: var(--ink-deep);

  /* == 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 */

  /* == Radius scale ==========================================================
     Tailwind v4 maps --radius-* to rounded-* utilities. Tacet keeps square
     as the default posture, then allows the Proto packet/panel radius ladder
     as named tokens instead of raw px literals. */
  --tacet-radius-none: 0;
  --tacet-radius-xs: 0.125rem; /* 2px */
  --tacet-radius-sm: 0.25rem; /* 4px */
  --tacet-radius-md: 0.375rem; /* 6px */
  --tacet-radius-lg: 0.5rem; /* 8px, Proto panel/card default */
  --tacet-radius-xl: 0.75rem; /* 12px */
  --tacet-radius-2xl: 1rem; /* 16px */
  --tacet-radius-full: 9999px;

  /* == Elevation / shadows ===================================================
     Tailwind v4 maps --shadow-* to shadow-* utilities. The named Tacet scale
     is derived from /proto: quiet ambient casts for packet panels, plus hard
     offset shadows for controls. Legacy --_shadow-1..5 aliases stay live. */
  --tacet-shadow-xs: 0 1px 2px rgb(0 0 0 / 8%);
  --tacet-shadow-sm: 0 10px 28px -24px rgb(0 0 0 / 42%);
  --tacet-shadow-md: 0 12px 28px -26px rgb(0 0 0 / 48%);
  --tacet-shadow-lg: 0 18px 46px rgb(0 0 0 / 10%);
  --tacet-shadow-xl: 0 22px 70px
    color-mix(in oklch, var(--ink-deep), transparent 12%);
  --tacet-shadow-2xl: 0 28px 90px
    color-mix(in oklch, var(--ink-deep), transparent 8%);
  --tacet-shadow-inset-top: inset 0 1px 0 rgb(255 255 255 / 32%);
  --tacet-shadow-hard-sm: 3px 3px 0
    color-mix(in oklch, var(--border), transparent 22%);
  --tacet-shadow-hard-md: 6px 6px 0 var(--foreground);
  --tacet-shadow-hard-lg: 10px 10px 0
    color-mix(in oklch, var(--border), transparent 22%);
  --_shadow-1: var(--tacet-shadow-xs);
  --_shadow-2: var(--tacet-shadow-sm);
  --_shadow-3: var(--tacet-shadow-md);
  --_shadow-4: var(--tacet-shadow-hard-md);
  --_shadow-5: var(--tacet-shadow-hard-lg);

  /* == 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;
  /* Disclosure/menu choreography: shared by home and non-home navigation. */
  --duration-menu: 300ms;
  --duration-menu-content: 200ms;
  --delay-menu-content: 80ms;
  --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-menu: cubic-bezier(0.32, 0.72, 0, 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 (/workflows 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.
     Every solid swatch maintains at least 4.5:1 contrast with --cat-on and
     stays perceptually separate from the red Recently Added status signal.
     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: #595959;
  --cat-on: #fff;
  --cat-all: #1a1a1a;
  --cat-erp: #1e40af;
  --cat-crm: #2563eb;
  --cat-marketing: #554900;
  --cat-hrms: #7c3aed;
  --cat-scm: #0e7490;
  --cat-fin: #14532d;
  --cat-pm: #6b21a8;
  --cat-health: #047857;
  --cat-edu: #4f46e5;
  --cat-retail: #a21caf;
  --cat-mfg: #0f766e;
  --cat-legal: #4338ca;
  --cat-govt: #1e3a5f;
  --cat-it: #115e59;
  --cat-support: #0369a1;
  --cat-realestate: #3f6212;
  --cat-hotel: #7e22ce;
  --cat-food: #166534;
  --cat-transport: #1d4ed8;
  --cat-agri: #15803d;
  --cat-media: #9333ea;
  --cat-energy: #4d7c0f;
  --cat-bank: #155e75;
  --cat-insure: #3730a3;
  --cat-ngo: #065f46;
  --cat-salon: #86198f;
  --cat-sports: #365314;
  --cat-events: #6d28d9;
  --cat-warehouse: #134e4a;
  --cat-workflow: #5b21b6;
  --cat-analytics: #075985;
  --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: var(--tacet-orange);
  --primary-foreground: var(--beige-50);
  --secondary: var(--beige-950);
  --muted: var(--beige-800);
  --muted-foreground: var(--ink-light-muted);
  --accent: var(--tacet-orange);
  --destructive: oklch(55% 0.21 28);
  --border: var(--beige-800);
  /* --border-strong steps toward the foreground (beige-700, one lighter than the
     beige-800 hairline) so a slightly-heavier rule stays visible on the dark bg. */
  --border-strong: var(--beige-700);
  --outline: var(--beige-800);
  --ring: var(--tacet-orange);

  /* 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. */
  --tacet-orange-on-light: var(--tacet-orange);
  --org-on-light: var(--tacet-orange-on-light);
  --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 cinematic CTA 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);
  --footer-rich-surface-shadow:
    inset 0 1px 0 color-mix(in oklch, var(--beige-200), transparent 88%),
    0 -1rem 2.25rem -1.5rem rgb(0 0 0 / 78%);
  --footer-anchor-surface-shadow:
    inset 0 1px 0 color-mix(in oklch, var(--beige-200), transparent 88%),
    0 -0.85rem 1.4rem -0.85rem rgb(0 0 0 / 82%);
  --footer-main-seam-shadow:
    0 1px 0 color-mix(in oklch, var(--beige-200), transparent 84%),
    0 1.35rem 2rem -0.9rem rgb(0 0 0 / 82%);

  /* 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 — same Tacet ladder, tuned for dark surfaces */
  --tacet-shadow-xs: 0 1px 2px rgb(0 0 0 / 32%);
  --tacet-shadow-sm: 0 10px 28px -24px rgb(0 0 0 / 58%);
  --tacet-shadow-md: 0 12px 28px -26px rgb(0 0 0 / 64%);
  --tacet-shadow-lg: 0 18px 46px rgb(0 0 0 / 38%);
  --tacet-shadow-xl: 0 22px 70px rgb(0 0 0 / 52%);
  --tacet-shadow-2xl: 0 28px 90px rgb(0 0 0 / 58%);
  --tacet-shadow-inset-top: inset 0 1px 0
    color-mix(in oklch, var(--beige-50), transparent 84%);
  --tacet-shadow-hard-sm: 3px 3px 0
    color-mix(in oklch, var(--beige-50) 10%, transparent);
  --tacet-shadow-hard-md: 6px 6px 0
    color-mix(in oklch, var(--beige-50) 10%, transparent);
  --tacet-shadow-hard-lg: 10px 10px 0
    color-mix(in oklch, var(--beige-50) 10%, transparent);
  --_shadow-1: var(--tacet-shadow-xs);
  --_shadow-2: var(--tacet-shadow-sm);
  --_shadow-3: var(--tacet-shadow-md);
  --_shadow-4: var(--tacet-shadow-hard-md);
  --_shadow-5: var(--tacet-shadow-hard-lg);
}

/* == 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) */
  }
}
