/* ═══════════════════════════════════════════════════════════════════════════
   Hozio Studio — Design Tokens (KEYSTONE)
   Hozio Design System · the one declared source of truth for themeable values

   THREE-LAYER MODEL (SPEC design-system-coherence §1):
     LAYER 1 — PRIMITIVES  raw, systematic scales. Components NEVER bind these
                           directly; semantic + component tokens alias them.
     LAYER 2 — SEMANTIC    the theme surface archetypes/recipes/widget bind to.
     LAYER 3 — COMPONENT   every per-component token, declared (was ~150
                           "phantoms" living only as inline var() fallbacks).

   BYTE-IDENTICAL DISCIPLINE (SPEC §5 gate):
     This rewrite is a pure refactor. Under the DEFAULT (Professional/light)
     archetype the computed output is unchanged. Achieved ADDITIVELY + with
     ALIASES — no primitive/semantic name that a component reads was renamed
     or revalued. Renamed primitives keep the OLD name as a back-compat alias
     (see assets/css/TOKENS-MIGRATION.md). Newly-declared component tokens are
     set to the exact inline fallback each component uses today, so dropping a
     fallback later is invisible.

   NAMING (SPEC §1.1): --{category}-{name}, lowercase-kebab. Categories:
     space fs fw lh tracking radius shadow border opacity z dur ease color font.

   Full token definitions and use cases:
   design-system/visual-design-system.md
   ═══════════════════════════════════════════════════════════════════════════ */

/* Track-2 D3 (surgical @layer): the whole token file is wrapped in
   `@layer tokens.base` so engine token DEFAULTS lose to the UNLAYERED per-client
   theme custom.css — the client owns brand via tokens (win-model). base.css and
   the .hzo-* components stay unlayered and are untouched. See layer-order.css. */
@layer tokens.base {

/* ═══════════════════════════════════════════════════════════════════════════
   LAYER 1 — PRIMITIVES  (raw scales — components never bind these directly)
   ═══════════════════════════════════════════════════════════════════════════ */
:root {

    /* ── Space (4-based ramp) ──────────────────────────────────────────────
       SPEC §1.2 systematic t-shirt scale: 4 8 12 16 24 32 40 48 64 80 96.
       NOTE on byte-identical: the existing engine t-shirt names ship at their
       historical px (xs=4, sm=8, md=16, lg=24, xl=48, 2xl=64, 3xl=80) and are
       read by ~330 component sites. Renaming/revaluing them would break output,
       so the historical names are preserved AS-IS (they remain the canonical
       home for those px). The scale is COMPLETED additively: the missing
       systematic steps (12px, 96px) and clean t-shirt companions for the `-2`
       interlopers are added; the interlopers become back-compat aliases.
       The full renumber to the spec's literal name→px table is deferred to the
       component-migration phase (it is not byte-safe here). */
    --space-2xs:    4px;     /* = --space-xs (systematic alias for 4px)      */
    --space-xs:     4px;     /* historical: 4px  (spec 2xs)  — keep value    */
    --space-sm:     8px;     /* historical: 8px  (spec xs)   — keep value    */
    --space-smd:    12px;    /* NEW — the missing 12px systematic step       */
    --space-md:     16px;    /* 16px — matches spec md                       */
    --space-lg:     24px;    /* 24px — matches spec lg                       */
    --space-xl:     48px;    /* historical: 48px (spec 3xl)  — keep value    */
    --space-2xl:    64px;    /* historical: 64px (spec 4xl)  — keep value    */
    --space-3xl:    80px;    /* historical: 80px (spec 5xl)  — keep value    */
    --space-4xl:    96px;    /* NEW — the missing 96px systematic step       */

    /* Interloper cleanup: give 32/40/56 real t-shirt homes, alias the `-2`
       names to them (SPEC §1.2 "drop the --space-lg-2 interlopers"). */
    --space-lg-plus:  32px;  /* clean home for 32px (was --space-lg-2)       */
    --space-xl-minus: 40px;  /* clean home for 40px (was --space-xl-2)       */
    --space-2xl-minus:56px;  /* clean home for 56px (was --space-2xl-2)      */
    --space-lg-2:   var(--space-lg-plus);    /* back-compat alias → 32px     */
    --space-xl-2:   var(--space-xl-minus);   /* back-compat alias → 40px     */
    --space-2xl-2:  var(--space-2xl-minus);  /* back-compat alias → 56px     */

    /* ── Font size (modular ladder ~1.2 ratio) — SPEC §1.2 ─────────────────
       NEW primitive ladder incl. the missing 13/14/15 small-text steps.
       The semantic --fs-body/-h1..-h6 (Layer 2) stay RESPONSIVE (base.css
       remaps them per breakpoint) and are NOT aliased onto this static ladder
       — that would drop the hand-tuned responsive behavior. The ladder is
       available for future component adoption. */
    --fs-50:  12px;
    --fs-75:  13px;   /* small-text step */
    --fs-100: 14px;   /* small-text step */
    --fs-200: 16px;
    --fs-300: 18px;
    --fs-400: 20px;
    --fs-500: 24px;
    --fs-600: 30px;
    --fs-700: 36px;
    --fs-800: 48px;
    --fs-900: 60px;

    /* ── Font weight (numeric) — SPEC §1.2 ────────────────────────────────
       One weight vocabulary. --fw-400..800 are canonical; the historical
       named weights (--fw-regular/medium/semibold/bold) remain as aliases. */
    --fw-400: 400;
    --fw-500: 500;
    --fw-600: 600;
    --fw-700: 700;
    --fw-800: 800;                    /* NEW — heaviest step (Bold archetype) */
    --fw-regular:  var(--fw-400);     /* back-compat alias                    */
    --fw-medium:   var(--fw-500);     /* back-compat alias                    */
    --fw-semibold: var(--fw-600);     /* back-compat alias                    */
    --fw-bold:     var(--fw-700);     /* back-compat alias                    */

    /* ── Line height (NEW — fills gap) — SPEC §1.2 ────────────────────────── */
    --lh-none:    1;
    --lh-tight:   1.1;
    --lh-snug:    1.25;
    --lh-normal:  1.5;
    --lh-relaxed: 1.7;

    /* ── Letter-spacing / tracking (NEW) — SPEC §1.2 ──────────────────────── */
    --tracking-tight:  -0.02em;
    --tracking-normal: 0;
    --tracking-wide:   0.05em;
    --tracking-wider:  0.1em;

    /* ── Radius — SPEC §1.2 (0/1/2/3/full) ────────────────────────────────
       Canonical numeric steps; the historical --radius-input/-card/-pill
       names are preserved as Layer-2 semantic aliases (see below).
       Historical px: input=8, card=12. Spec starting px: 1=6, 2=12, 3=20.
       To stay byte-identical --radius-1 is set to the CURRENT control px (8)
       so the --radius-control alias resolves identically; the spec's 6px
       retune happens in the archetype phase (values tunable, structure locked
       per SPEC §6). */
    --radius-0:    0;
    --radius-1:    8px;      /* control radius — historical --radius-input px */
    --radius-2:    12px;     /* panel radius   — historical --radius-card px  */
    --radius-3:    20px;
    --radius-full: 9999px;

    /* ── Shadow / elevation ladder — SPEC §1.2 (0..4) ─────────────────────── */
    --shadow-0: none;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
    --shadow-lg: 0 10px 30px rgba(0, 0, 0, 0.12);
    --shadow-xl: 0 18px 48px rgba(0, 0, 0, 0.16);
    /* Numeric aliases (spec 0..4) onto the historical named ladder. */
    --shadow-1: var(--shadow-sm);
    --shadow-2: var(--shadow-md);
    --shadow-3: var(--shadow-lg);
    --shadow-4: var(--shadow-xl);

    /* ── Border width (NEW) — SPEC §1.2 ───────────────────────────────────── */
    --border-0: 0;
    --border-1: 1px;
    --border-2: 2px;
    --border-3: 3px;

    /* ── Opacity (NEW) — SPEC §1.2 ────────────────────────────────────────── */
    --opacity-disabled: 0.5;
    --opacity-muted:    0.65;
    --opacity-scrim:    0.9;

    /* ── Z-index (100-spaced so infills fit) — SPEC §1.2 ──────────────────
       Canonical --z-100..700; historical semantic z-names kept as aliases
       (Layer 2 below) at their historical integer values for byte-identity. */
    --z-100: 10;    /* sticky   */
    --z-200: 20;    /* header   */
    --z-300: 30;    /* drawer   */
    --z-400: 40;    /* overlay  */
    --z-500: 50;    /* modal    */
    --z-600: 60;    /* popover  */
    --z-700: 70;    /* toast    */

    /* ── Duration — SPEC §1.2 (dur-1..4) ──────────────────────────────────
       Canonical --dur-*; historical --duration-* kept as aliases (Layer 2). */
    --dur-1: 120ms;
    --dur-2: 200ms;
    --dur-3: 300ms;
    --dur-4: 450ms;

    /* ── Easing — SPEC §1.2 ──────────────────────────────────────────────── */
    --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-out:      cubic-bezier(0.16, 1, 0.3, 1);
    --ease-in-out:   cubic-bezier(0.65, 0, 0.35, 1);   /* NEW */
    --ease-spring:   cubic-bezier(0.34, 1.56, 0.5, 1);
}


/* ═══════════════════════════════════════════════════════════════════════════
   LAYER 2 — SEMANTIC  (the theme surface archetypes / recipes / widget bind to)

   CRITICAL: the color model (--brand/--accent/--emphasis families and their
   OKLCH-derived variants) keeps its EXACT names + values — the PHP derivation
   pipeline (includes/) and Layer-3 tokens consume them by name. Do NOT rename
   or revalue anything in the color block; new roles are ADDED as aliases.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {

    /* ── Brand — primary identity color + paired variants ──────────────────
       --brand-text is brand used as TEXT on light backgrounds. Defaults to
       --brand when brand passes 4.5:1 contrast on white; Claude Code overrides
       to a darker derived value if it fails during setup. --brand-deep is the
       darkest shade in the brand family — footers / deep sections. */
    --brand:                 #114899;
    --brand-hover-on-light:  #0A2552;
    --brand-hover-on-dark:   #2A6BCF;
    --brand-pale:            color-mix(in srgb, var(--brand) 10%, white);
    --brand-deep:            #071B3F;
    --brand-text:            #114899;
    --text-on-brand:         #FFFFFF;

    /* Trap-pair rename (SPEC §1.3): --color-brand-ink (brand-AS-ink) vs
       --color-on-brand (ink-ON-brand). Added as aliases; old names kept. */
    --color-brand-ink: var(--brand-text);      /* brand used as ink on light  */
    --color-on-brand:  var(--text-on-brand);   /* ink placed on a brand fill  */

    /* ── Accent — CTA/button color + paired variants ───────────────────────
       --accent-text is accent used as TEXT on light backgrounds (≥4.5:1 on
       white). Light accents get a much darker --accent-text to stay readable. */
    --accent:                 #A5DC76;
    --accent-hover-on-light:  #7EC142;
    --accent-hover-on-dark:   #CDE8A8;
    --accent-pale:            color-mix(in srgb, var(--accent) 10%, white);
    --accent-text:            #4A7A32;
    --text-on-accent:         #1F2937;
    --color-on-accent: var(--text-on-accent);  /* ink placed on an accent fill */

    /* ── Emphasis — decorative accent for inline marks/brackets/pullquotes.
       Defaults to accent (pop); override per client for a distinct hue. */
    --emphasis:               var(--accent);

    /* ── Brand/accent semantic aliases (SPEC §1.3 --color-brand/-accent) ──── */
    --color-brand:   var(--brand);
    --color-accent:  var(--accent);
    --color-emphasis:var(--emphasis);

    /* ── Ink — ONE ink vocabulary. SPEC §1.3 collapses the doubled
       --text-* / --on-surface-* systems onto one canonical set. Both name
       families are kept working: --text-heading/-body/-muted are canonical;
       --on-surface* and the --color-ink* / --color-on-surface* roles alias
       them. (Do NOT introduce a second source of truth.) */
    --text-heading: #1F2937;
    --text-body:    #374151;
    --text-muted:   #6B7280;
    --color-ink:        var(--text-heading);   /* SPEC role: primary ink       */
    --color-ink-muted:  var(--text-muted);     /* SPEC role: muted ink         */
    --color-placeholder: #9CA3AF;              /* NEW — kills 3× copy-pasted    */

    /* ── Backgrounds ───────────────────────────────────────────────────────*/
    --bg-page:         #FFFFFF;
    --bg-alt:          #F9FAFB;
    --bg-dark-section: var(--brand);
    --color-bg:     var(--bg-page);            /* SPEC role alias              */
    --color-bg-alt: var(--bg-alt);             /* SPEC role alias              */

    /* ── Surfaces — semantic elevated-panel tokens (quality-rules §1.22).
       Components express panel backgrounds + on-panel ink through these so a
       dark archetype can re-theme every floating surface from :root in one
       place. Defaults equal the light literals they replaced. */
    --surface:           #FFFFFF;   /* elevated panels: cards, modals, drawers */
    --surface-2:         #F9FAFB;   /* secondary: table headers, wells, code   */
    --on-surface:        var(--text-heading);
    --on-surface-body:   var(--text-body);   /* KEPT: written by archetype.php  */
    --on-surface-muted:  var(--text-muted);
    --surface-border:    var(--border);
    /* SPEC §1.3 --color-surface / -surface-2 / -on-surface role aliases. */
    --color-surface:    var(--surface);
    --color-surface-2:  var(--surface-2);
    --color-on-surface: var(--on-surface);

    /* ── Border & focus ────────────────────────────────────────────────────*/
    --border:     #E5E7EB;
    --focus-ring: var(--brand);
    --color-border: var(--border);             /* SPEC role alias              */
    --color-focus:  var(--focus-ring);         /* SPEC role alias              */

    /* ── Navigation links (header nav, mobile menu, mega menu) ──────────────*/
    --nav-link:       #111111;            /* near-black nav links at rest */
    --nav-link-hover: var(--brand);

    /* ── Utility bar links (contact strip above main nav) ──────────────────
       Defaults assume a dark-background utility bar; .hzo-utility-bar--light
       flips these locally for a pale-bg bar. */
    --utility-link:       rgba(255, 255, 255, 0.85);
    --utility-link-hover: #FFFFFF;

    /* ── Footer links (light footer variant; dark footer uses white rgba) ───*/
    --footer-link:       var(--text-muted);
    --footer-link-hover: var(--brand);

    /* ── Semantic state — each role with an -ink pair + -on-* partner (SPEC
       §1.3 foreground-pairing rule). error/success historical names kept;
       warning/info folded in from the ex-separate utility-color-tokens.css.
       The -ink partners equal the darker "*-text" values the components use
       today (declared in Layer 3 too as --error-text etc.). */
    --error:      #DC2626;
    --error-bg:   #FEF2F2;
    --error-ink:  #991B1B;                     /* NEW pair (= --error-text)    */
    --success:    #16A34A;
    --success-bg: #F0FDF4;
    --success-ink:#166534;                     /* NEW pair (= --success-text)  */
    --warning:    #D97706;                     /* folded from utility set      */
    --warning-bg: #FFFBEB;
    --warning-ink:#92400E;                     /* NEW pair (= --warning-text)  */
    --info:       #2563EB;                      /* folded from utility set      */
    --info-bg:    #EFF6FF;
    --info-ink:   #1E40AF;                      /* NEW pair                     */
    /* SPEC §1.1 fold-in: warning/info previously lived in
       components/_base/utility-color-tokens.css. Declared here (identical
       values) as the one home; the --color-* names below keep that file's
       consumers resolving byte-identically. */
    --color-warning:        var(--warning);
    --color-warning-bg:     var(--warning-bg);
    --color-info:           var(--info);
    --color-info-bg:        var(--info-bg);
    --color-warm-highlight: #FFF8E5;
    /* SPEC §1.3 canonical --color-error/-success role aliases + -ink pairs. */
    --color-error:      var(--error);
    --color-error-bg:   var(--error-bg);
    --color-error-ink:  var(--error-ink);
    --color-success:    var(--success);
    --color-success-bg: var(--success-bg);
    --color-success-ink:var(--success-ink);

    /* ── Fonts (SPEC §1.3 --font-heading/-body/-number) ────────────────────*/
    --font-heading: "DM Serif Display", Georgia, "Times New Roman", serif;
    --font-body:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    --font-number:  "DM Serif Display", Georgia, "Times New Roman", serif;

    /* ── Typography scale (editable by the Hozio Studio Live design widget) ──
       Size: per-step base sizes consumed via calc() by the heading/body
       selectors. The 7-zone responsive ladder (base.css) redefines --fs-* at
       each breakpoint; both real headings and visual-heading classes read the
       same tokens. Three scale multipliers resize globally/per-group without
       touching per-step values — all default to 1.
       These --fs-body/-h1..-h6 are the SEMANTIC (responsive) sizes; the static
       --fs-50..900 ladder in Layer 1 is the primitive scale. */
    --hzo-type-scale:    1;   /* Overall text size  */
    --hzo-heading-scale: 1;   /* Headings only      */
    --hzo-body-scale:    1;   /* Body/label text    */

    --fs-body: 16px;
    --fs-h1:   32px;
    --fs-h2:   24px;
    --fs-h3:   20px;
    --fs-h4:   17px;
    --fs-h5:   14px;
    --fs-h6:   12px;

    /* Display size — the one step ABOVE h1, used by .hzo-display for the
       top-of-page statement. It was the only size in the system living as a
       hardcoded clamp() inside a selector (_base/typography.css), which meant
       the design widget could not reach it, an archetype could not retune it,
       and a client could only override it by re-declaring the whole rule.
       Wave S tokenizes it at EXACTLY its historical value — clamp(2.25rem,
       5vw, 5rem) — so computed output is unchanged; typography.css now reads
       var(--fs-display) with that same clamp as its inline fallback.
       Unlike --fs-h1..h6 this is viewport-fluid, so base.css's per-breakpoint
       ladder does not (and must not) remap it. */
    --fs-display: clamp(2.25rem, 5vw, 5rem);

    /* Body weight. --font-weight-heading is intentionally UNSET: it is the
       widget hook that, when set, collapses ALL heading weights to one value.
       Left unset so each heading level keeps its tuned weight via var()
       fallback (see Layer 3 --h1-weight..--h6-weight). Declaring it here would
       change every heading — so it stays unset by design. */
    --font-weight-body: 400;

    /* ── Shape roles (SPEC §1.3) ──────────────────────────────────────────
       radius-control = --radius-1 · radius-panel = --radius-2 · pill = full.
       Historical --radius-input/-card/-pill kept as aliases (byte-identical:
       input=8→--radius-1=8, card=12→--radius-2=12, pill=9999→--radius-full). */
    --radius-control: var(--radius-1);
    --radius-panel:   var(--radius-2);
    --radius-input:   var(--radius-control);   /* alias, historical name       */
    --radius-card:    var(--radius-panel);     /* alias, historical name       */
    --radius-pill:    var(--radius-full);      /* alias, historical name       */

    /* ── Depth roles (SPEC §1.3) ──────────────────────────────────────────
       elevation-rest = --shadow-1 · elevation-float = --shadow-3. */
    --elevation-rest:  var(--shadow-1);
    --elevation-float: var(--shadow-3);

    /* ── Motion (SPEC §1.3) ───────────────────────────────────────────────
       --transition-base is the ONE documented duration alias (~93 consumers
       in primitives.css / design-widget.css); it reads the --dur-2 scale.
       Historical --duration-* names kept as aliases at their scale values. */
    --duration-base:  var(--dur-2);            /* alias → 200ms (= --dur-2)     */
    --duration-slow:  400ms;                    /* KEPT at historical 400ms —
                                                   NOT aliased to --dur-4 (450ms):
                                                   20 --duration-slow consumers
                                                   must stay byte-identical. */
    --transition-base: var(--duration-base);

    /* ── Z-index semantic names (SPEC §1.3) — aliases onto --z-100..700 ─────*/
    --z-sticky-bar: var(--z-100);
    --z-header:     var(--z-200);
    --z-drawer:     var(--z-300);
    --z-overlay:    var(--z-400);
    --z-modal:      var(--z-500);
    --z-popover:    var(--z-600);
    --z-toast:      var(--z-700);

    /* ── Content layer z-index (Wave S) ────────────────────────────────────
       The ladder above governs CHROME and starts at 10. Layering INSIDE a
       section — a decorative fill behind the copy, a card lifted over the
       band below it — needs a vocabulary an order of magnitude lower, and it
       was missing, which is why component sheets reach for a bare `z-index:1`.
       Three names, no more: anything needing a fourth is chrome.
       Utilities: .hzo-z-behind / -base / -above in _base/overlap.css. */
    --z-behind: -1;
    --z-base:    0;
    --z-above:   1;

    /* ── Content widths ────────────────────────────────────────────────────*/
    --container-max-width: 1350px;
    --prose-max-width:     65ch;

    /* Measure ladder (Wave S) — line length by role. --measure-65 IS
       --prose-max-width's value; the alias exists so headline (45ch) and
       reference (75ch) measures have names on the same scale instead of
       being written as one-off px max-widths in patterns.
       Utilities: .hzo-measure-45/-65/-75 in _base/measure.css. */
    --measure-45: 45ch;
    --measure-65: var(--prose-max-width);
    --measure-75: 75ch;

    /* Overlap / pull scale (Wave S) — how far an element breaks out of its
       section. Steps 1-3 reuse the --space ladder so overlaps stay in the
       same rhythm as padding; step 4 is the deliberate statement move and has
       no --space equivalent (nothing else in the system is 120px).
       NOT responsive — the mobile clamp lives in the .hzo-pull-* CLASS, in
       _base/overlap.css. Reading --pull-4 from an inline style hard-codes
       120px at 375px, which is the documented inline-style trap. */
    --pull-1: var(--space-xl);    /* 48px */
    --pull-2: var(--space-2xl);   /* 64px */
    --pull-3: var(--space-3xl);   /* 80px */
    --pull-4: 120px;
}


/* ═══════════════════════════════════════════════════════════════════════════
   LAYER 3 — COMPONENT TOKENS
   Every per-component token, DECLARED (was a "phantom" living only as an inline
   var(--x, fallback) in components/**). Each value equals its current effective
   default — the exact inline fallback the component uses today — so computed
   output is unchanged and components can later drop their fallbacks invisibly.
   Values are expressed as var(--semantic/-primitive) wherever the fallback did.

   NOT DECLARED HERE (intentionally, to stay byte-identical / correct):
     • Genuinely-ambiguous phantoms whose inline fallback DISAGREES between
       call-sites — declaring one value would change the other. Deferred to the
       component-migration phase: --btn-radius, --card-hover-shadow,
       --footer-gap, --footer-legal-gap, --heading-letter-spacing,
       --input-padding, --nav-header-shadow.
       (--btn-primary-hover LEFT this list at PF-042. Deferring it did not keep
       the engine "correct" — it shipped both disagreeing values, neither of
       which passed WCAG AA. Read that as a caution about the rest of the list:
       "ambiguous, so leave it undeclared" preserves the ambiguity as a live
       fleet-wide behaviour rather than resolving it.)
     • Intentionally-unset widget hook: --font-weight-heading (see Layer 2).
     • Per-instance DATA vars set inline in HTML style= or by JS (not themeable
       design tokens): --band-image(-pos), --hzo-bg-* and -pos-* (responsive image
       data), --hzo-compare-pos (JS slider), --fluentform-input-select-height
       (set by the FluentForms vendor plugin).
   ═══════════════════════════════════════════════════════════════════════════ */
:root {

    /* ── Typography roles (base.css / _base) ──────────────────────────────── */
    --h1-color: var(--text-heading);   --h1-scale: 1;   --h1-weight: 700;
    --h2-color: var(--text-heading);   --h2-scale: 1;   --h2-weight: 700;
    --h3-color: var(--text-heading);   --h3-scale: 1;   --h3-weight: 600;
    --h4-color: var(--text-heading);   --h4-scale: 1;   --h4-weight: 600;
    --h5-color: var(--text-heading);   --h5-scale: 1;   --h5-weight: 500;
    --h6-color: var(--text-heading);   --h6-scale: 1;   --h6-weight: 600;
    --body-line-height:    1.6;
    --body-letter-spacing: normal;
    --heading-color-on-dark: #fff;
    --heading-transform:     none;
    --link-decoration:       underline;
    --eyebrow-size:     15px;
    --eyebrow-tracking: 0.7px;

    /* ── Buttons ───────────────────────────────────────────────────────────*/
    --btn-padding-x:        32px;
    --btn-padding-y:        14px;
    --btn-weight:           var(--fw-semibold, 600);
    /* Button COLOR roles — DECLARED as of Track-2 D3 (@layer made this safe).
       Each value equals buttons.css's own inline var(--btn-*, …) fallback, so a
       client that does NOT remap them is byte-identical; a client that DOES remap
       them in its (UNLAYERED) custom.css WINS over this LAYERED tokens.base
       default — e.g. the Hozio dev theme sets secondary/outline/ghost → var(--accent)
       ("the secondary family uses the green accent, not the navy brand"). Before
       @layer an engine :root declaration here clobbered that remap (green→navy),
       which is why S1 deferred them; the tokens.base layer now loses to unlayered
       custom.css, so they can rejoin the declared source of truth.
       PF-042 — --btn-primary-hover is now DECLARED. It was previously left
       undeclared on purpose, described here as an "ambiguous phantom" because
       the two call sites carry different inline fallbacks
       (--accent-hover-on-light on bare .hzo-btn:hover, --accent-text on
       .hzo-btn--primary:hover) and declaring it would change one of them.

       Leaving it undeclared did not resolve that ambiguity, it SHIPPED it: a
       site got one of two different hover colours depending on whether the
       author happened to write the variant class, and NEITHER had ever been
       contrast-checked. Both were failing. Measured in Chromium against a real
       :hover at 1440x900 on a live client, engine v1.7.0:

           bare .hzo-btn   #ffffff on #53b188 = 2.62:1   severe AA failure
           --primary       #ffffff on #208760 = 4.47:1   AA failure by 0.03

       It is worse at the engine's OWN default accent #A5DC76, where
       --accent-hover-on-light resolves to #7EC142 and white on it is 2.19:1.
       .hzo-btn flips its label to white on hover on the assumption that the fill
       darkens enough to carry white ink — buttons.css states that verbatim at
       both call sites — and the assumption was never checked and does not hold
       for a light or mid accent. The rest state is derived by the OKLCH pipeline
       and audited; the hover state was not derived at all, so white ink threw
       away exactly the work paired_text_for_background() does to pick DARK ink
       for a light accent. Every contrast check in the design system, including
       the smart-contrast algorithm and the §3.5 verification list, looks only at
       REST.

       The fix is PF-042's "cheapest correct": declare the fill so both call
       sites agree, and pair it with the ink already proven against the accent
       family at rest instead of a hardcoded #fff. For the engine default,
       #1F2937 on #7EC142 = 6.70:1 (pass); 5.60:1 was measured on the client this
       was found on, with the fill still visibly darkening. Both inline fallbacks
       in buttons.css are now unreachable and are left in place as a record of
       what each path used to resolve to.

       ⚠ AN IMPROVEMENT, NOT A PROOF — do not read this as "hover is AA
       everywhere now". --text-on-accent comes from paired_text_for_background(),
       which flips ink at relative luminance 0.5. That threshold is itself wrong:
       white and #1F2937 are equal at relLum ~0.224, so the flip systematically
       over-picks white. An accent sitting just above 0.5 gets dark ink on a
       hover fill dark enough to land near 4.2:1. The real fix is PF-042 option 1
       — derive the hover PAIR the way the rest pair is derived, with a corrected
       flip threshold — which is a helpers/color.php change and is NOT done here.
       A hover-state row on the §3.5 verification checklist is the other half. */
    --btn-primary-bg:         var(--accent);
    --btn-primary-text:       var(--text-on-accent);
    --btn-primary-hover:      var(--accent-hover-on-light);
    --btn-primary-hover-text: var(--text-on-accent);
    --btn-secondary-bg:       var(--brand);
    --btn-secondary-text:     var(--text-on-brand);
    --btn-secondary-hover:    var(--brand-hover-on-light);
    --btn-outline-color:      var(--brand);
    --btn-ghost-color:        var(--brand);
    --btn-ghost-hover:        var(--brand-pale);
    /* Tertiary (Wave S) — the quiet filled tier. Deliberately brand-free: it
       reads the NEUTRAL family so it can never compete with the primary. The
       -hover pair is left to buttons.css's color-mix fallback so it follows
       whatever a client sets --btn-tertiary-bg/-text to, rather than freezing
       one derived value here. */
    --btn-tertiary-bg:        var(--bg-alt);
    --btn-tertiary-text:      var(--text-heading);
    --btn-tertiary-border:    var(--border);
    --btn-tertiary-hover-border: var(--text-muted);
    --btn-danger-bg:          var(--error);
    --btn-danger-hover:       #B91C1C;
    --btn-on-dark-bg:         #fff;
    --btn-on-dark-text:       var(--brand);
    --btn-on-dark-accent:     #fff;

    /* ── Card ──────────────────────────────────────────────────────────────*/
    --card-bg:              var(--surface);   /* single source of truth for panel bg (was literal #fff); --surface = #FFFFFF, so byte-identical today */
    --card-border:          var(--border);
    --card-padding:         var(--space-lg);
    --card-radius:          var(--radius-card);
    --card-shadow:          var(--shadow-sm);
    --card-elevated-shadow: var(--shadow-md);

    /* ── Badge ─────────────────────────────────────────────────────────────*/
    --badge-radius: var(--radius-pill);
    --badge-weight: var(--fw-semibold, 600);

    /* ── Input / form ──────────────────────────────────────────────────────*/
    --input-bg:     #fff;
    --input-border: var(--border);
    --input-radius: var(--radius-input);
    --border-light: var(--border);
    --qty-input-width: 3ch;

    /* ── State text (dark-ink partners; = the -ink pairs in Layer 2) ───────*/
    --error-text:   #991B1B;
    --success-text: #166534;
    --warning-text: #92400E;

    /* ── Back-to-top ───────────────────────────────────────────────────────*/
    --back-to-top-bg:       var(--brand);
    --back-to-top-bg-hover: var(--brand-hover-on-light);
    --back-to-top-color:    var(--text-on-brand);
    --z-back-to-top:        15;
    --z-social-proof:       15;   /* floating rating pill — peer of back-to-top, below the whole overlay ladder (carried from Tallo's base) */

    /* ── Story / media band ────────────────────────────────────────────────*/
    --band-aspect:     16 / 9;
    /* --band-copy-width is the TEXT MEASURE, not the panel width (PF-063 —
       it used to be applied as a bare max-width on a 64px-padded box, so 44ch
       bought ~28 characters). media-band.css adds --band-panel-padding back
       into the max-width, so this number is characters of copy. */
    --band-copy-width:    44ch;
    --band-panel-padding: var(--space-2xl);
    --band-min-height: 460px;
    --band-panel-bg:   var(--bg-dark-section);
    --band-radius:     var(--radius-card);
    --band-image-pos:  center;

    /* ── Bento ─────────────────────────────────────────────────────────────*/
    --bento-gap:         var(--space-lg);
    --bento-primary-col: 1.6fr;

    /* ── Carousel ──────────────────────────────────────────────────────────*/
    --carousel-dot-color:           var(--border);
    --carousel-dot-active-color:    var(--brand);
    --carousel-dot-on-image:        rgba(255, 255, 255, 0.45);
    --carousel-dot-active-on-image: #fff;
    --carousel-ring-color:          var(--carousel-dot-active-color, var(--brand));
    --carousel-fade-duration:       500ms;
    --carousel-ring-duration:       6000ms;

    /* ── Connector (steps / timeline spine helpers) ───────────────────────── */
    --connector-color:  var(--border);
    --connector-mask:   var(--bg-page);
    --connector-offset: 24px;
    --connector-style:  solid;
    --connector-width:  2px;

    /* ── Clamp / decor / embed / map / marquee ─────────────────────────────*/
    --clamp-lines:  2;
    --decor-width:  220px;
    --embed-aspect: 16 / 9;
    --map-aspect:   16 / 9;
    --map-radius:   var(--radius-card);
    --marquee-fade: 64px;
    --marquee-gap:  var(--space-xl);

    /* ── Footer ────────────────────────────────────────────────────────────*/
    --footer-bg:                 transparent;
    --footer-bg-light:           var(--bg-alt);
    --footer-text:               #fff;
    --footer-text-light:         var(--text-body);
    --footer-heading-dark:       #fff;
    --footer-heading-light:      var(--text-heading);
    --footer-legal-text-dark:    rgba(255,255,255,0.65);
    --footer-legal-text-light:   var(--text-muted);
    --footer-link-base-dark:     rgba(255,255,255,0.85);
    --footer-link-dark:          rgba(255,255,255,0.8);
    --footer-link-hover-dark:    #fff;
    --footer-social-link:        var(--accent, currentColor);
    --footer-social-link-hover:  var(--text-on-accent, #fff);
    --footer-social-bg-hover:    var(--accent-hover-on-dark, rgba(255,255,255,0.1));

    /* ── Header / desktop-nav ──────────────────────────────────────────────*/
    --header-height-desktop:        80px;
    --header-height-mobile:         72px;
    --header-condensed-scale:       0.85;
    --header-logo-condensed-scale:  0.85;
    --nav-header-bg:                #fff;
    --nav-header-shadow-scrolled:   var(--nav-header-shadow, 0 2px 10px rgba(0, 0, 0, 0.10));
    --nav-dropdown-bg:              var(--surface, #fff);
    --nav-dropdown-shadow:          0 12px 40px rgba(0,0,0,0.10), 0 2px 8px rgba(0,0,0,0.04);
    --nav-dropdown-link-hover-bg:   var(--bg-alt);

    /* ── Mobile nav ────────────────────────────────────────────────────────*/
    --nav-mobile-panel-bg:      var(--surface, #fff);
    --nav-mobile-footer-bg:     var(--bg-alt);
    --nav-mobile-overlay-bg:    rgba(0, 0, 0, 0.5);
    --nav-mobile-divider-color: var(--border);
    --nav-mobile-link-color:    var(--text-body);
    --nav-mobile-link-hover-bg: var(--bg-alt);
    --nav-mobile-trigger-color: var(--text-heading);

    /* ── Mega menu / mosaic ────────────────────────────────────────────────*/
    --mega-cols:  3;
    --hzo-mega-bg: var(--gradient-brand-sweep);
    --mosaic-bg: var(--brand-pale);
    --mosaic-c1: color-mix(in srgb, var(--brand) 25%, white);
    --mosaic-c2: color-mix(in srgb, var(--brand) 45%, white);
    --mosaic-c3: color-mix(in srgb, var(--brand) 65%, white);
    --mosaic-c4: color-mix(in srgb, var(--brand) 35%, white);

    /* ── Utility bar ───────────────────────────────────────────────────────*/
    --utility-bar-bg:                 var(--brand);
    --utility-bar-text:               #fff;
    --utility-bar-divider-color:      rgba(255,255,255,0.3);
    --utility-bar-padding:            7px 0;
    --utility-bar-light-bg:           var(--bg-alt);
    --utility-bar-light-text:         var(--text-body);
    --utility-bar-light-border-color: var(--border);
    --utility-light-link:             var(--text-muted);
    --utility-light-link-hover:       var(--brand);

    /* ── Lite video ────────────────────────────────────────────────────────*/
    --lite-video-play-bg:       var(--brand);
    --lite-video-play-bg-hover: var(--brand-hover-on-light);
    --lite-video-play-icon:     var(--text-on-brand);

    /* ── Ribbon ────────────────────────────────────────────────────────────*/
    --ribbon-bg:    var(--accent);
    --ribbon-color: var(--text-on-accent);

    /* ── Scroll row ────────────────────────────────────────────────────────*/
    --scroll-card-width: clamp(240px, 74vw, 320px);
    --scroll-gap:        var(--space-lg);
    --scroll-fade-color: var(--bg-page);
    --scroll-fade-width: 48px;

    /* ── Scrim / sticky / surface-dark ─────────────────────────────────────*/
    --scrim-color:      var(--brand-deep);
    --hzo-section-scrim:60%;
    --sticky-bar-bg:    var(--bg-page);
    --surface-dark-bg:  var(--bg-dark-section);

    /* Scrim strength ladder (Wave S). --hzo-section-scrim above is the live
       knob every scrim reads; these are the three NAMED stops to set it to,
       so "make the photo breathe" stops being a hand-picked percentage.
         weak    the photo is the subject, copy is short and large
         base    the shipped default — safe over an unknown photo
         strong  copy-heavy band, or a busy/light photo
       --scrim-base is EXACTLY the historical default, so
       `--hzo-section-scrim: var(--scrim-base)` is a no-op by construction.
       Reachable as classes: .hzo-scrim--weak / --base / --strong in
       _base/gradient-scrims.css assign these three, so the ladder is a class on
       the section rather than a percentage in an inline style.
       AA is NOT guaranteed by any of these: contrast depends on the photo.
       Check the rendered band, never the token. */
    --scrim-weak:   35%;
    --scrim-base:   60%;
    --scrim-strong: 82%;

    /* The 135° brand sweep (Wave S). ONE definition of the fleet's diagonal
       brand wash, read by .hzo-mega-cta (via --hzo-mega-bg) and by
       .hzo-cta-band--bg-gradient, both of which used to hand-roll it. Stop
       order is brand → brand-deep because that is what those two shipped;
       retinting --brand retints both.
       The five siblings this shipped with (--gradient-accent-sweep,
       --gradient-veil-top/-bottom, --gradient-fade-page/-alt) were removed
       before v1.10.0 was tagged: nothing read them and nothing could, and the
       veils duplicated .hzo-scrim--top/--bottom, which are better (live
       strength knob, retintable, and they flatten on mobile). Re-add a gradient
       here WITH the selector that reads it, never ahead of one. */
    --gradient-brand-sweep: linear-gradient(135deg, var(--brand), var(--brand-deep));

    /* ── Section edges (Wave S) ────────────────────────────────────────────
       Parameterized section-boundary treatments — _base/section-edges.css.
       --edge-color must be set PER INSTANCE to the ADJACENT section's surface;
       the --bg-page default is only correct when the next section is the
       default white one. Getting this wrong is the single failure mode: the
       edge reads as a stripe instead of as an interlock.
       --edge-size sizes --diagonal / --curve / --arch / the flat shelf.
       --edge-angle sizes --angled / --angled-rev ONLY, and it costs height: the
       rise is width × tan(angle), so 6deg is ~39px at 375 and ~202px at 1920.
       Always pair an --angled edge with .hzo-section--edge-pad; 2-4deg is the
       range that reads as a slope rather than a wedge. Arithmetic table and the
       scrollbar caveat: _base/section-edges.css. */
    --edge-color:  var(--bg-page);
    --edge-size:   64px;
    --edge-angle:  6deg;
    --edge-radius: var(--radius-3);

    /* ── Stat (Wave S) ─────────────────────────────────────────────────────
       --stat-align is the site-wide alignment knob for .hzo-stat. It ships at
       `center` — identical to the value that was hardcoded in stat.css — so
       nothing moves. Set it to `left` once, per client, for the left-aligned
       metric treatment; the --rule / --boxed modifiers in stat.css are the
       per-instance escalation. See the note in stat.css on why the DEFAULT was
       not flipped fleet-wide. */
    --stat-align:       center;
    --stat-rule-color:  var(--accent);
    --stat-rule-width:  3px;
    --stat-rule-gap:    var(--space-md);
    --stat-box-bg:      var(--surface);
    --stat-box-border:  var(--border);
    --stat-box-radius:  var(--radius-panel);
    --stat-box-padding: var(--space-lg);

    /* ── Card link marker (Wave S) ─────────────────────────────────────────
       The resting affordance on .hzo-card--link's title. --card-link-marker is
       the pseudo-element's `content`: the empty string DRAWS the arrow (the
       box is sized and masked by the rule), `none` removes it entirely for a
       card family that carries its own affordance. */
    --card-link-marker:       "";
    --card-link-marker-color: var(--accent-text);

    /* ── Tiles (category grid) ─────────────────────────────────────────────*/
    --tile-aspect: 5 / 4.5;
    --tile-gap:    6px;
    --tile-radius: var(--radius-card);

    /* ── Timeline ──────────────────────────────────────────────────────────*/
    --timeline-gap:          var(--space-xl);
    --timeline-indent:       var(--space-lg-2);
    --timeline-marker-color: var(--brand);
    --timeline-marker-ring:  var(--bg-page);
    --timeline-marker-size:  14px;
    --timeline-spine-color:  var(--border);

    /* ── Feature-overlap / misc motion ─────────────────────────────────────*/
    --overlap-rise:        var(--space-xl);
    --icon-slide-distance: 4px;

    /* ── Wave / section divider ────────────────────────────────────────────*/
    --wave-fill:      var(--bg-alt);
    --wave-height:    70px;
    --wave-height-lg: 100px;
    --wave-duration:  12s;
}


/* ═══════════════════════════════════════════════════════════════════════════
   MODE AXIS (dark mode) — POPULATED  (SPEC §1.3 / §4 / §6, Axis B)
   Dark mode was a fast-follow (SPEC §6, Kyle 2026-07-13): the light/dark HOOK
   shipped first; the dark palette is now BUILT.

   The seam: a `mode` token sub-layer + `.hzo-mode-dark` body class + mode-aware
   OKLCH derivation. The dark values are NOT authored statically here — they are
   DERIVED PER-SITE from the effective brand+accent and written to the generated
   file  uploads/hozio-studio/css/tokens.mode.css  (helpers/archetype.php →
   regenerate_mode() → color\derive_dark_tokens()), scoped to .hzo-mode-dark and
   enqueued in the reserved `mode` slot (AFTER tokens.archetype.css, BEFORE
   tokens.derived.css — hozio-studio.php). That flips the Layer-2 --bg-page /
   --bg-alt / --surface(-2) / --text-* / --on-surface* / --border set (+ the few
   Layer-3 #fff-literal surfaces) to a low-L brand-tinted dark palette with
   WCAG-AA-paired inks. `light` (default) emits no file → light is byte-identical.

   This block stays EMPTY on purpose: dark values live in the generated,
   per-site file, NOT as static engine defaults (which would be one-size-fits-all
   and couldn't honor a client's brand hue).

   :root.hzo-mode-dark, .hzo-mode-dark {
       (dark palette — generated per-site into tokens.mode.css)
   }
   ═══════════════════════════════════════════════════════════════════════════ */

} /* @layer tokens.base — Track-2 D3 surgical wrap */
