/* SLASHED — core/tokens.css
   @layer slashed.tokens
   Core design tokens: color sources, semantic colors, type, spacing, radii, shadows, motion, z-index.
   Prefix: --sf-*; brand theming starts with six -source-light tokens. */

@layer slashed.tokens {

  /* ============================================================
     @property — BRAND COLORS (-source-light source tokens, animatable)
     Override these 6 tokens to rebrand — dark mode auto-derives.
     Optionally set --sf-color-X-source-dark for full control.
     ============================================================ */

  @property --sf-color-primary-source-light   { syntax: "<color>"; inherits: true; initial-value: oklch(0.47 0.27 264); }
  @property --sf-color-secondary-source-light { syntax: "<color>"; inherits: true; initial-value: oklch(0.22 0.04 264); }
  @property --sf-color-tertiary-source-light  { syntax: "<color>"; inherits: true; initial-value: oklch(0.42 0.22 295); }
  @property --sf-color-action-source-light    { syntax: "<color>"; inherits: true; initial-value: oklch(0.50 0.22 235); }
  @property --sf-color-neutral-source-light   { syntax: "<color>"; inherits: true; initial-value: oklch(0.52 0.025 260); }
  /* initial-value is 0.96 (not 0.99) so the +0.02/+0.04 surface offsets produce
     visually distinct levels in light mode. At 0.99 all lighter surfaces clamp
     to pure white and become indistinguishable. 0.96 gives: bg=0.98, inset=0.94,
     raised=1.0→white — all distinct. Consumers using near-1.0 values should rely
     on shadows rather than lightness for elevation. */
  @property --sf-color-base-source-light  { syntax: "<color>"; inherits: true; initial-value: oklch(0.96 0.006 250); }

  /* @property — STATUS COLORS (-source-light source tokens) */

  @property --sf-color-success-source-light { syntax: "<color>"; inherits: true; initial-value: oklch(0.50 0.16 145); }
  @property --sf-color-warning-source-light { syntax: "<color>"; inherits: true; initial-value: oklch(0.75 0.17 80);  }
  @property --sf-color-info-source-light    { syntax: "<color>"; inherits: true; initial-value: oklch(0.48 0.18 235); }
  @property --sf-color-danger-source-light  { syntax: "<color>"; inherits: true; initial-value: oklch(0.48 0.22 12);  }

  /* Plain :root mirrors — character-for-character identical to each @property
     initial-value above. Engines lacking @property support read the token value
     from here. Do NOT edit these independently from the initial-value strings. */
  :root {
    --sf-color-primary-source-light:   oklch(0.47 0.27 264);
    --sf-color-secondary-source-light: oklch(0.22 0.04 264);
    --sf-color-tertiary-source-light:  oklch(0.42 0.22 295);
    --sf-color-action-source-light:    oklch(0.50 0.22 235);
    --sf-color-neutral-source-light:   oklch(0.52 0.025 260);
    --sf-color-base-source-light:      oklch(0.96 0.006 250);
    --sf-color-success-source-light:   oklch(0.50 0.16 145);
    --sf-color-warning-source-light:   oklch(0.75 0.17 80);
    --sf-color-info-source-light:      oklch(0.48 0.18 235);
    --sf-color-danger-source-light:    oklch(0.48 0.22 12);
  }

  /* @property — DARK SOURCE TOKENS (-dark, animatable) */
  /* Registers the auto-computed dark counterparts as typed <color> so their
     resolved absolute value is inherited by child elements (e.g. a section
     with [data-theme="dark"]). Without @property these tokens inherit as raw
     text, and the nested var()-in-oklch-from chain fails type-checking on
     registered child properties.
     initial-value = dark-mode value derived from the formula in themes.css
     (clamp(0.65, 0.95 - l*0.5, 0.88) for brand/status; inverted for base).
     Consumers who set --sf-color-X-dark explicitly do not need to register it
     — their override is a plain OKLCH literal and passes type-checking directly. */
  @property --sf-color-primary-source-dark   { syntax: "<color>"; inherits: true; initial-value: oklch(0.715 0.243 264);  }
  @property --sf-color-secondary-source-dark { syntax: "<color>"; inherits: true; initial-value: oklch(0.84 0.036 264);   }
  @property --sf-color-tertiary-source-dark  { syntax: "<color>"; inherits: true; initial-value: oklch(0.74 0.198 295);   }
  @property --sf-color-action-source-dark    { syntax: "<color>"; inherits: true; initial-value: oklch(0.70 0.198 235);   }
  @property --sf-color-neutral-source-dark   { syntax: "<color>"; inherits: true; initial-value: oklch(0.69 0.0225 260);  }
  @property --sf-color-base-source-dark      { syntax: "<color>"; inherits: true; initial-value: oklch(0.22 0.003 250);   }
  @property --sf-color-success-source-dark   { syntax: "<color>"; inherits: true; initial-value: oklch(0.70 0.144 145);   }
  @property --sf-color-warning-source-dark   { syntax: "<color>"; inherits: true; initial-value: oklch(0.65 0.153 80);    }
  @property --sf-color-info-source-dark      { syntax: "<color>"; inherits: true; initial-value: oklch(0.71 0.162 235);   }
  @property --sf-color-danger-source-dark    { syntax: "<color>"; inherits: true; initial-value: oklch(0.71 0.198 12);    }

  /* @property — COMPUTED COLOR TOKENS (brand + status)
     Registers the computed tokens as typed <color> so CSS transitions can
     interpolate between light and dark values when [data-theme] changes.
     initial-value = light-mode value (safe fallback if nothing sets the token).
     Child-element theming works because [data-theme="dark"] in themes.css
     assigns var(--sf-color-X-dark) — now a registered typed <color> whose
     absolute value is inherited, so no multi-level var() resolution is needed. */
  @property --sf-color-primary   { syntax: "<color>"; inherits: true; initial-value: oklch(0.47 0.27 264); }
  @property --sf-color-secondary { syntax: "<color>"; inherits: true; initial-value: oklch(0.22 0.04 264); }
  @property --sf-color-tertiary  { syntax: "<color>"; inherits: true; initial-value: oklch(0.42 0.22 295); }
  @property --sf-color-action    { syntax: "<color>"; inherits: true; initial-value: oklch(0.50 0.22 235); }
  @property --sf-color-neutral   { syntax: "<color>"; inherits: true; initial-value: oklch(0.52 0.025 260); }
  @property --sf-color-base      { syntax: "<color>"; inherits: true; initial-value: oklch(0.96 0.006 250); }
  @property --sf-color-success   { syntax: "<color>"; inherits: true; initial-value: oklch(0.50 0.16 145); }
  @property --sf-color-warning   { syntax: "<color>"; inherits: true; initial-value: oklch(0.75 0.17 80);  }
  @property --sf-color-info      { syntax: "<color>"; inherits: true; initial-value: oklch(0.48 0.18 235); }
  @property --sf-color-danger    { syntax: "<color>"; inherits: true; initial-value: oklch(0.48 0.22 12);  }

  /* Plain :root mirrors for computed tokens — resolve to the -source-light source token
     so user overrides to --sf-color-X-source-light are respected in all browsers.
     Overridden by the @supports block in themes.css whenever dark mode is active. */
  :root {
    --sf-color-primary:   var(--sf-color-primary-source-light);
    --sf-color-secondary: var(--sf-color-secondary-source-light);
    --sf-color-tertiary:  var(--sf-color-tertiary-source-light);
    --sf-color-action:    var(--sf-color-action-source-light);
    --sf-color-neutral:   var(--sf-color-neutral-source-light);
    --sf-color-base:      var(--sf-color-base-source-light);
    --sf-color-success:   var(--sf-color-success-source-light);
    --sf-color-warning:   var(--sf-color-warning-source-light);
    --sf-color-info:      var(--sf-color-info-source-light);
    --sf-color-danger:    var(--sf-color-danger-source-light);
  }

  /* Mode flag — INTERNAL, not a public hook (SL-003: same "--sf-is-*" naming
     pattern as the public flags below, opposite contract — read here, don't
     set). Drives formula direction for non-color dark overrides. Set only by
     themes.css via [data-theme="dark"] and the prefers-color-scheme media
     query; every other read site (core/tokens.css, the configurator's power
     knobs) only reads it inside calc() expressions. Setting it directly
     desyncs it from color-scheme/[data-theme] and produces an inconsistent
     theme. */
  @property --sf-is-dark { syntax: "<integer>"; inherits: true; initial-value: 0; }

  /* No --sf-is-active/-current/-pressed/-open here: they registered an
     INTERACTION STATE FLAGS mechanism (inheritable custom properties set by
     .sf-is-active/.sf-is-open/etc for a consumer's own calc() to branch on)
     with zero consumers anywhere in this codebase, its demo, or the
     configurator beyond its own preview toggle — speculative surface,
     removed. Style off [aria-current]/[aria-expanded]/[aria-pressed]
     instead; see docs/states.md § "Prefer native state". */

  /* ============================================================
     FLUID SCALE ENGINE — generative inputs
     ------------------------------------------------------------
     The fluid type / space / display scales are computed at runtime
     from these scalars. Override any of them on :root and every
     clamp() recalibrates — no build step, no token regeneration.

       --sf-fluid-min-vw / --sf-fluid-max-vw   viewport range (rem, unitless)
                                               over which values interpolate.
       --sf-text-ratio-min / -max              modular ratio of the TYPE scale
                                               at min / max viewport (dual-ratio:
                                               subtler on mobile, larger on desktop).
       --sf-text-base-min / -max               --sf-text-m endpoints (rem, unitless).
       --sf-text-display-base-min / -max       --sf-text-display-s endpoints.
       --sf-space-ratio-min / -max             modular ratio of the SPACE scale.
       --sf-space-base-min / -max              --sf-space-m endpoints (rem, unitless).
       --sf-fluid-width                        the length every fluid clamp()
                                               interpolates against. Defaults to
                                               100vw (viewport-relative). Override
                                               to 100cqi on a container scope to make
                                               the type + space + display scales
                                               container-relative — see .sf-fluid-cq
                                               in core/layout.css (issue #497).

     Registered as <number> so they can be used as pow() exponents/operands
     and multiplied by 1rem in calc(). Requires CSS pow() (Chrome 125+,
     Safari 15.4+, Firefox 118+); the effective SLASHED floor is higher
     (Chrome 125 / Safari 18.0 / Firefox 129), set by the colour system —
     see browser floor. Plain :root mirrors
     below keep values readable; do NOT edit them independently. */
  @property --sf-fluid-min-vw          { syntax: "<number>"; inherits: true; initial-value: 22.5; }
  @property --sf-fluid-max-vw          { syntax: "<number>"; inherits: true; initial-value: 90; }
  @property --sf-text-ratio-min        { syntax: "<number>"; inherits: true; initial-value: 1.25; }
  @property --sf-text-ratio-max        { syntax: "<number>"; inherits: true; initial-value: 1.333; }
  @property --sf-text-base-min         { syntax: "<number>"; inherits: true; initial-value: 1; }
  @property --sf-text-base-max         { syntax: "<number>"; inherits: true; initial-value: 1.25; }
  @property --sf-text-display-base-min { syntax: "<number>"; inherits: true; initial-value: 2.4; }
  @property --sf-text-display-base-max { syntax: "<number>"; inherits: true; initial-value: 3; }
  @property --sf-space-ratio-min       { syntax: "<number>"; inherits: true; initial-value: 1.25; }
  @property --sf-space-ratio-max       { syntax: "<number>"; inherits: true; initial-value: 1.333; }
  @property --sf-space-base-min        { syntax: "<number>"; inherits: true; initial-value: 1; }
  @property --sf-space-base-max        { syntax: "<number>"; inherits: true; initial-value: 2; }

  /* Fluid interpolation driver — the length term every fluid clamp() below
     measures against. Universal syntax ("*") not "<length>": a registered
     <length> requires a computationally-independent initial-value, and 100vw
     (viewport-dependent) is not one. The real default lives on :root; an
     opt-in scope (e.g. .sf-fluid-cq) overrides it to 100cqi so the whole
     generative scale becomes container-relative without duplicating a single
     formula. */
  @property --sf-fluid-width           { syntax: "*"; inherits: true; }

  /* ── Output token @property registrations ──────────────────────────────────
     Radius + space: <length> syntax enables CSS transitions on layout values —
     border-radius/padding/gap etc. now interpolate instead of snapping.
     Shadow: syntax:"*" (no <shadow> type in spec); inherits:true so :root values
     cascade normally; registers the properties formally for DevTools inspection.

     initial-value ≠ :root default (by spec): a registered <length> requires a
     computationally-independent initial-value, so these carry `initial-value: 0`
     while their real defaults are the calc()-derived values set on :root below
     (see --sf-fluid-width above for the same constraint stated at length). One
     consequence worth flagging: once a property is registered, the initial
     value IS a value — so a fallback like `var(--sf-radius-m, 12px)` will NEVER
     fire; an unset --sf-radius-m resolves to the registered `0`, not to "no
     value". Author fallbacks against the token's :root default, not this 0. */

  @property --sf-radius-none  { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-radius-2xs   { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-radius-xs    { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-radius-s     { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-radius-m     { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-radius-l     { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-radius-xl    { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-radius-2xl   { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-radius-3xl   { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-radius-4xl   { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-radius-full  { syntax: "<length>"; inherits: true; initial-value: 9999px; }
  @property --sf-radius-pill  { syntax: "<length>"; inherits: true; initial-value: 9999px; }
  @property --sf-radius-outer { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-media-radius { syntax: "<length>"; inherits: true; initial-value: 0; }

  @property --sf-space-none       { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-space-px         { syntax: "<length>"; inherits: true; initial-value: 1px; }
  @property --sf-space-2xs        { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-space-xs         { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-space-s          { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-space-m          { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-space-l          { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-space-xl         { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-space-2xl        { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-space-3xl        { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-space-4xl        { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-gap              { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-content-gap      { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-gutter           { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-component-pad    { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-field-block      { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-section-pad--xs  { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-section-pad--s   { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-section-pad--m   { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-section-pad--l   { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-section-pad--xl  { syntax: "<length>"; inherits: true; initial-value: 0; }
  @property --sf-section-pad--2xl { syntax: "<length>"; inherits: true; initial-value: 0; }

  @property --sf-shadow-none      { syntax: "*"; inherits: true; }
  @property --sf-shadow-xs        { syntax: "*"; inherits: true; }
  @property --sf-shadow-s         { syntax: "*"; inherits: true; }
  @property --sf-shadow-m         { syntax: "*"; inherits: true; }
  @property --sf-shadow-l         { syntax: "*"; inherits: true; }
  @property --sf-shadow-xl        { syntax: "*"; inherits: true; }
  @property --sf-shadow-2xl       { syntax: "*"; inherits: true; }
  @property --sf-shadow-inner     { syntax: "*"; inherits: true; }
  @property --sf-text-shadow-none { syntax: "*"; inherits: true; }
  @property --sf-text-shadow-xs   { syntax: "*"; inherits: true; }
  @property --sf-text-shadow-s    { syntax: "*"; inherits: true; }
  @property --sf-text-shadow-m    { syntax: "*"; inherits: true; }
  @property --sf-text-shadow-l    { syntax: "*"; inherits: true; }
  @property --sf-text-shadow-xl   { syntax: "*"; inherits: true; }
  @property --sf-drop-shadow-xs   { syntax: "*"; inherits: true; }
  @property --sf-drop-shadow-s    { syntax: "*"; inherits: true; }
  @property --sf-drop-shadow-m    { syntax: "*"; inherits: true; }
  @property --sf-drop-shadow-l    { syntax: "*"; inherits: true; }
  @property --sf-drop-shadow-xl   { syntax: "*"; inherits: true; }
  @property --sf-shadow-glow      { syntax: "*"; inherits: true; }

  :root {
    --sf-fluid-min-vw:          22.5;
    --sf-fluid-max-vw:          90;
    --sf-fluid-width:           100vw;  /* interpolation driver; 100cqi on a container scope → container-relative fluid (#497) */
    --sf-text-ratio-min:        1.25;
    --sf-text-ratio-max:        1.333;
    --sf-text-base-min:         1;
    --sf-text-base-max:         1.25;
    --sf-text-display-base-min: 2.4;
    --sf-text-display-base-max: 3;
    --sf-space-ratio-min:       1.25;
    --sf-space-ratio-max:       1.333;
    --sf-space-base-min:        1;
    --sf-space-base-max:        2;
  }

  /* ============================================================
     DERIVED SEMANTIC TOKENS
     ============================================================ */

  :root {

    /* ----------------------------------------------------------
       Color scheme
       ---------------------------------------------------------- */
    --sf-color-scheme: light dark;

    /* ----------------------------------------------------------
       LumLocker — OKLCH L value used by the
       :root[data-lumlocker] override in core/themes.css.
       Locks the 4 brand colors (primary, secondary, tertiary, action)
       to one shared lightness while keeping their individual hue and
       chroma. Neutral and base are excluded — neutral is a desaturated
       grey (locking it to a brand L would make it chromatic) and base
       must remain near-white in light mode for the page background.

       --sf-lumlocker is the LIGHT-mode target. Dark mode uses
       --sf-lumlocker-dark, which defaults to the mirror of the light L
       around 0.59 — the midpoint between the light (~0.96) and dark
       (~0.22) page backgrounds — i.e. calc(1.18 - L). Mirroring around
       the background midpoint (not 0.5) is what keeps the lock's
       contrast against the surface equal in both themes; a naive 1 - L
       would leave the dark lock too dark to read. Clamped to a visible
       band. A single knob that works in both themes. Override either:
         :root { --sf-lumlocker: 0.55 }          (light)
         :root { --sf-lumlocker-dark: 0.82 }     (dark, breaks the mirror)
       ---------------------------------------------------------- */
    --sf-lumlocker: 0.65;
    --sf-lumlocker-dark: clamp(0.5, calc(1.18 - var(--sf-lumlocker)), 0.92);

    /* ----------------------------------------------------------
       Resolved color tokens — auto-switch via light-dark().
       Components reference these. Override the -source-light / -source-dark
       source tokens above to customise; or override these directly
       with your own light-dark() expression.
       ---------------------------------------------------------- */
    /* Surface alias (plain var — no IACVT, stays ungated) */
    --sf-color-surface: var(--sf-color-base);

    /* ----------------------------------------------------------
       Text — plain var aliases (ungated)
       ---------------------------------------------------------- */

    /* ----------------------------------------------------------
       Text-on-color — plain var aliases (ungated)
       ---------------------------------------------------------- */
    --sf-color-text--on-base:    var(--sf-color-text);

    /* Static fallbacks for engines that support oklch(from …) but not sign()
       (Chrome 125–137, Firefox 128–130). The sign() gate below overrides these
       with the exact auto-contrast formula when the engine supports it.
       Derived from the default palette at threshold 0.6: surfaces with L < 0.6
       get near-white text (0.95); warning (L 0.75) and code (on light inset)
       get near-black (0.1). Custom palettes must override --sf-color-text--on-*
       manually if their surface colours differ from the defaults. */
    --sf-color-text--on-primary:   oklch(0.95 0 0);
    --sf-color-text--on-secondary: oklch(0.95 0 0);
    --sf-color-text--on-tertiary:  oklch(0.95 0 0);
    --sf-color-text--on-action:    oklch(0.95 0 0);
    --sf-color-text--on-neutral:   oklch(0.95 0 0);
    --sf-color-text--on-success:   oklch(0.95 0 0);
    --sf-color-text--on-warning:   oklch(0.1  0 0);
    --sf-color-text--on-info:      oklch(0.95 0 0);
    --sf-color-text--on-danger:    oklch(0.95 0 0);
    --sf-color-text--on-inverse:   oklch(0.95 0 0);
    --sf-color-code-text:          oklch(0.1  0 0);

    /* ----------------------------------------------------------
       Borders — plain var aliases (ungated)
       ---------------------------------------------------------- */
    --sf-color-border--focus: var(--sf-color-action);

    /* ----------------------------------------------------------
       Links — plain var aliases and geometry (ungated)
       ---------------------------------------------------------- */
    --sf-color-link--disabled:  var(--sf-color-text--disabled);
    /* Underline geometry — consumed by a:link in core/base.css and by
       the .sf-link--* macros. `auto` defers to the font's own metrics;
       set an explicit length (e.g. 0.08em) for a uniform rule. */
    --sf-link-underline-offset:    0.15em;
    --sf-link-underline-thickness: auto;

    /* ----------------------------------------------------------
       Interactive states — plain var aliases (ungated)
       ---------------------------------------------------------- */
    --sf-color-bg--disabled: var(--sf-color-inset);
    --sf-color-code-bg:      var(--sf-color-inset);

    /* ----------------------------------------------------------
       Selection & backdrop — static values (ungated)
       ---------------------------------------------------------- */
    --sf-color-selection-text: inherit;
    --sf-color-mark-text:      inherit;
    /* Dim: classic semi-transparent black for modal backdrops, distinct from --sf-color-overlay */
    --sf-color-dim:            oklch(0 0 0 / 0.5);
    --sf-color-white:          oklch(100% 0 0);
    --sf-color-black:          oklch(0% 0 0);

    /* ----------------------------------------------------------
       Scrollbar
       ---------------------------------------------------------- */
    --sf-scrollbar-thumb: var(--sf-color-neutral);
    --sf-scrollbar-track: transparent;

    /* ----------------------------------------------------------
       Shadow strength — base opacity for light mode; auto-boosted by
       +0.17 in dark mode via --sf-is-dark. Override with a calc() to
       preserve the adaptation: calc(0.1 + var(--sf-is-dark) * 0.17).
       ---------------------------------------------------------- */
    --sf-shadow-strength:   calc(0.08 + var(--sf-is-dark) * 0.17);
    /* Shadow lightness: 0.15 is the default density. Independent token allows
       tuning shadow depth globally across light/dark and surfaces. */
    --sf-shadow-lightness:  0.15;
    /* ----------------------------------------------------------
       Shadow glow color — tint used by --sf-shadow-glow. Override to
       retint glows; opacity/dark-mode adaptation is controlled by
       --sf-shadow-strength.
       ---------------------------------------------------------- */
    --sf-shadow-glow-color: var(--sf-color-primary);

    /* ----------------------------------------------------------
       Opacity — disabled state effects
       ---------------------------------------------------------- */
    --sf-opacity-disabled:  0.45;

    /* ----------------------------------------------------------
       Focus / form colors
       ---------------------------------------------------------- */
    --sf-focus-ring-color:  var(--sf-color-action);
    --sf-focus-ring-shadow: 0 0 0 var(--sf-focus-ring-offset) var(--sf-color-bg, var(--sf-color-base-source-light, #fff)),
                            0 0 0 calc(var(--sf-focus-ring-offset) + var(--sf-focus-ring-width)) var(--sf-focus-ring-color);
    --sf-caret-color:       var(--sf-color-action);

  }
  /* ── @supports gate: light-dark() + oklch(from …) ──
     Safari 15.4 supports light-dark() but only adds oklch(from) in 16.4.
     Gating on both prevents Safari 15.x/16.x from parsing the derived
     color tokens and silently failing all base colors. */
  @supports (color: light-dark(white, black)) and (color: oklch(from red l c h)) {
    :root {

      /* ----------------------------------------------------------
         Resolved color tokens — auto-switch via light-dark().
         Dark auto-derivation formula (brand + status):
         clamp(0.65, 0.95 - l*0.5, 0.88) lightens dark-mode value relative to the light source.
         Surface inverts: clamp(0.16, 1.18 - l, 0.24) — near-white flips to near-dark.
         Override any --sf-color-X-dark to take full per-mode control.
         SL-001: this same clamp() formula is re-declared flat in themes.css
         (SECTION-LEVEL THEMING) so [data-theme] overrides on non-:root elements
         still resolve correctly — light-dark() only bakes at :root. Keep both
         copies in sync if the formula ever changes. */
      --sf-color-primary:   light-dark(var(--sf-color-primary-source-light),   var(--sf-color-primary-source-dark,   oklch(from var(--sf-color-primary-source-light)   clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));
      --sf-color-secondary: light-dark(var(--sf-color-secondary-source-light), var(--sf-color-secondary-source-dark, oklch(from var(--sf-color-secondary-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));
      --sf-color-tertiary:  light-dark(var(--sf-color-tertiary-source-light),  var(--sf-color-tertiary-source-dark,  oklch(from var(--sf-color-tertiary-source-light)  clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));
      --sf-color-action:    light-dark(var(--sf-color-action-source-light),    var(--sf-color-action-source-dark,    oklch(from var(--sf-color-action-source-light)    clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));
      --sf-color-neutral:   light-dark(var(--sf-color-neutral-source-light),   var(--sf-color-neutral-source-dark,   oklch(from var(--sf-color-neutral-source-light)   clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));
      --sf-color-base:      light-dark(var(--sf-color-base-source-light),      var(--sf-color-base-source-dark,      oklch(from var(--sf-color-base-source-light)      clamp(0.16, calc(1.18 - l),        0.24) calc(c * 0.5) h)));

      --sf-color-success: light-dark(var(--sf-color-success-source-light), var(--sf-color-success-source-dark, oklch(from var(--sf-color-success-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));
      --sf-color-warning: light-dark(var(--sf-color-warning-source-light), var(--sf-color-warning-source-dark, oklch(from var(--sf-color-warning-source-light) clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));

      --sf-color-info:    light-dark(var(--sf-color-info-source-light),    var(--sf-color-info-source-dark,    oklch(from var(--sf-color-info-source-light)    clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));
      --sf-color-danger:  light-dark(var(--sf-color-danger-source-light),  var(--sf-color-danger-source-dark,  oklch(from var(--sf-color-danger-source-light)  clamp(0.65, calc(0.95 - l * 0.5), 0.88) calc(c * 0.9) h)));

      /* ----------------------------------------------------------
         Text — light and dark require opposite formula directions,
         so each side of light-dark() references its source token.
         ---------------------------------------------------------- */
      --sf-color-text: light-dark(
        oklch(from var(--sf-color-neutral-source-light) clamp(0.05, calc(l - 0.4 - var(--sf-contrast-bias)), 0.35) c h),
        oklch(from var(--sf-color-neutral)       clamp(0.70, calc(l + 0.25 + var(--sf-contrast-bias)), 1)    c h)
      );
      --sf-color-text--muted: light-dark(
        oklch(from var(--sf-color-neutral-source-light) clamp(0.35, calc(l - var(--sf-contrast-bias)), 0.62) c h),
        oklch(from var(--sf-color-neutral)       clamp(0.48, calc(l + var(--sf-contrast-bias)), 0.74) c h)
      );
      --sf-color-text--subtle: light-dark(
        oklch(from var(--sf-color-neutral-source-light) clamp(0.15, calc(l - 0.25 - var(--sf-contrast-bias)), 0.45) c h),
        oklch(from var(--sf-color-neutral)       clamp(0.55, calc(l + 0.1 + var(--sf-contrast-bias)), 0.90) c h)
      );
      --sf-color-text--placeholder: light-dark(
        oklch(from var(--sf-color-neutral-source-light) clamp(0.45, calc(l + 0.15), 0.75) c h),
        oklch(from var(--sf-color-neutral)       clamp(0.35, calc(l - 0.1),  0.65) c h)
      );
      --sf-color-text--disabled: light-dark(
        oklch(from var(--sf-color-neutral-source-light) clamp(0.55, calc(l + 0.25), 0.82) c h),
        oklch(from var(--sf-color-neutral)       clamp(0.25, calc(l - 0.2),  0.55) c h)
      );
      --sf-color-text--inverse: light-dark(
        oklch(from var(--sf-color-neutral-source-light) clamp(0.85, calc(l + 0.4), 0.98) c h),
        oklch(from var(--sf-color-neutral)       clamp(0.05, calc(l - 0.4), 0.35) c h)
      );
      --sf-color-heading: light-dark(
        oklch(from var(--sf-color-neutral-source-light) clamp(0.05, calc(l - 0.4 - var(--sf-contrast-bias)), 0.35) c h),
        oklch(from var(--sf-color-neutral)       clamp(0.70, calc(l + 0.25 + var(--sf-contrast-bias)), 1)    c h)
      );

      /* ----------------------------------------------------------
         Borders — direction-dependent, reference source tokens.
         Light: borders are lighter than neutral (l + offset).
         Dark:  borders are darker  than neutral (l - offset).
         ---------------------------------------------------------- */
      --sf-color-border: light-dark(
        oklch(from var(--sf-color-neutral-source-light) clamp(0.70, calc(l + 0.35), 0.95) 0.005 h),
        oklch(from var(--sf-color-neutral)       clamp(0.25, calc(l - 0.3),  0.55) 0.005 h)
      );
      --sf-color-border--subtle: light-dark(
        oklch(from var(--sf-color-neutral-source-light) clamp(0.75, calc(l + 0.4),  0.97) 0.005 h),
        oklch(from var(--sf-color-neutral)       clamp(0.20, calc(l - 0.38), 0.45) 0.005 h)
      );
      --sf-color-border--strong: light-dark(
        oklch(from var(--sf-color-neutral-source-light) clamp(0.55, calc(l + 0.1),  0.85) 0.02  h),
        oklch(from var(--sf-color-neutral)       clamp(0.38, calc(l - 0.1),  0.65) 0.02  h)
      );

      /* ----------------------------------------------------------
         Links — derived from --sf-color-action (auto-adapts)
         ---------------------------------------------------------- */
      /* Links keep the action hue but CLAMP lightness toward a contrast-safe
         band — a ceiling in light mode, a floor in dark mode — so link text
         clears WCAG AA (4.5:1) on the page background for the default palette
         AND the large majority of brand overrides (a fixed offset alone only
         fixed the default). Lightness dominates OKLCH contrast but doesn't
         fully determine it: very high-chroma hues (saturated yellow/green) can
         still fall short even at a safe lightness — those remain the consumer's
         responsibility (see docs/theming.md → "Link contrast").

         NOTE: the consumer-facing :link rule in core/base.css uses
         `a:link` (not bare `a`) so its specificity matches WebKit's UA
         stylesheet `a:link { color: -webkit-link }`. Without that
         pseudo-class the framework's `--sf-color-link` value is
         silently ignored on unvisited anchors in WebKit and
         `-webkit-link` (≈ #00728f in dark mode) paints instead —
         regardless of how this token is computed. PR #73 and several
         follow-up attempts mistakenly chased the formula. */
      --sf-color-link:            light-dark(
        oklch(from var(--sf-color-action) clamp(0, min(l - 0.07, 0.48), 1) c h),
        oklch(from var(--sf-color-action) clamp(0.68, l, 1) c h)
      );
      --sf-color-link--hover:     light-dark(
        oklch(from var(--sf-color-action) clamp(0, min(l - 0.15, 0.40), 1) c h),
        oklch(from var(--sf-color-action) clamp(0, max(l + 0.10, 0.68), 1) c h)
      );
      --sf-color-link--active:    light-dark(
        oklch(from var(--sf-color-action) clamp(0, min(l - 0.21, 0.34), 1) c h),
        oklch(from var(--sf-color-action) clamp(0, max(l + 0.15, 0.74), 1) c h)
      );
      /* Visited link — 60° hue shift from action gives clearly distinct
         chroma without colliding with default tertiary (h ≈ 310). Same
         lightness clamp as the base link. If your brand puts action and
         tertiary close in hue, override directly:
           :root { --sf-color-link--visited: #6b46c1; } */
      --sf-color-link--visited:   light-dark(
        oklch(from var(--sf-color-action) clamp(0, min(l - 0.07, 0.48), 1) c calc(h + 60)),
        oklch(from var(--sf-color-action) clamp(0.68, l, 1) c calc(h + 60))
      );

      /* ----------------------------------------------------------
         Selection
         ---------------------------------------------------------- */
      --sf-color-selection-bg:   light-dark(
        oklch(from var(--sf-color-action-source-light) l c h / 0.28),
        oklch(from var(--sf-color-action-source-dark) clamp(0.62, calc(0.93 - l * 0.4), 0.78) c h / 0.55)
      );

      /* Alt selection — the opposite scheme's treatment, for a surface
         that deliberately inverts colours relative to the page (e.g. a
         dark card on a light page) where the default pairing above
         would land with poor contrast. Consumed by .sf-selection--alt
         (optional/utilities.css). */
      --sf-color-selection-bg--alt: light-dark(
        oklch(from var(--sf-color-action-source-dark) clamp(0.62, calc(0.93 - l * 0.4), 0.78) c h / 0.55),
        oklch(from var(--sf-color-action-source-light) l c h / 0.28)
      );
      --sf-color-selection-text--alt: inherit;

      /* ----------------------------------------------------------
         Status triplets — strong (direction-dependent, uses light-dark)
         danger = destructive actions, form validation errors, negative states
         ---------------------------------------------------------- */
      --sf-color-success-strong: light-dark(
        oklch(from var(--sf-color-success-source-light) calc(l - 0.15) c h),
        oklch(from var(--sf-color-success)       clamp(0.70, calc(l + 0.15), 1) c h)
      );
      --sf-color-warning-strong: light-dark(
        oklch(from var(--sf-color-warning-source-light) calc(l - 0.25) c h),
        oklch(from var(--sf-color-warning)       clamp(0.70, calc(l + 0.05), 1) c h)
      );
      --sf-color-info-strong: light-dark(
        oklch(from var(--sf-color-info-source-light) calc(l - 0.1) c h),
        oklch(from var(--sf-color-info)       clamp(0.70, calc(l + 0.15), 1) c h)
      );
      --sf-color-danger-strong: light-dark(
        oklch(from var(--sf-color-danger-source-light) calc(l - 0.1) c h),
        oklch(from var(--sf-color-danger)       clamp(0.70, calc(l + 0.15), 1) c h)
      );

    }
  }
  /* ── @supports gate: oklch(from …) relative color ── */
  @supports (color: oklch(from red l c h)) {
    :root {

      /* ----------------------------------------------------------
         Surfaces — derived from --sf-color-base (auto-adapts)
         ---------------------------------------------------------- */
      --sf-color-bg:      oklch(from var(--sf-color-base) calc(l + 0.02) c h);
      --sf-color-inset:   oklch(from var(--sf-color-base) calc(l - 0.02) c h);
      --sf-color-raised:  oklch(from var(--sf-color-base) calc(l + 0.04) c h);
      /* Overlay: high-opacity wash of the base color for light/dark mode safe layers */
      --sf-color-overlay: oklch(from var(--sf-color-base) l c h / 0.9);
      --sf-color-inverse: oklch(from var(--sf-color-base) calc(1 - l) c h);

      /* ----------------------------------------------------------
         Border alpha tokens
         ---------------------------------------------------------- */
      --sf-color-border--disabled: oklch(from var(--sf-color-border--subtle) l 0 h / 0.5);
      --sf-color-border--translucent: oklch(from var(--sf-color-neutral) l c h / 0.15);

      /* ----------------------------------------------------------
         Link alpha token
         ---------------------------------------------------------- */
      --sf-color-link--underline: oklch(from var(--sf-color-action) l c h / 0.3);

      /* ----------------------------------------------------------
         Interactive states — derived from --sf-color-neutral (auto-adapts)
         ---------------------------------------------------------- */
      --sf-color-bg--hover:    oklch(from var(--sf-color-neutral) l c h / 0.08);
      --sf-color-bg--active:   oklch(from var(--sf-color-neutral) l c h / 0.12);
      --sf-color-bg--selected: oklch(from var(--sf-color-action) l c h / 0.1);
      --sf-color-bg--focus:    oklch(from var(--sf-color-action) l c h / 0.06);

      /* ----------------------------------------------------------
         Selection & mark
         ---------------------------------------------------------- */
      --sf-color-mark-bg: oklch(from var(--sf-color-warning) l c h / 0.25);

      /* ----------------------------------------------------------
         Status triplets — subtle/muted/tint (alpha variants)
         bg/border use same formula both modes. -tint is the 5%
         near-transparent rung, mirroring the brand families'
         --sf-color-{family}-tint aliases (full 10-family coverage).
         ---------------------------------------------------------- */
      --sf-color-success-subtle: oklch(from var(--sf-color-success) l c h / 0.12);
      --sf-color-success-muted:  oklch(from var(--sf-color-success) l c h / 0.3);
      --sf-color-success-tint:   oklch(from var(--sf-color-success) l c h / 0.05);

      --sf-color-warning-subtle: oklch(from var(--sf-color-warning) l c h / 0.12);
      --sf-color-warning-muted:  oklch(from var(--sf-color-warning) l c h / 0.3);
      --sf-color-warning-tint:   oklch(from var(--sf-color-warning) l c h / 0.05);

      --sf-color-info-subtle:    oklch(from var(--sf-color-info) l c h / 0.12);
      --sf-color-info-muted:     oklch(from var(--sf-color-info) l c h / 0.3);
      --sf-color-info-tint:      oklch(from var(--sf-color-info) l c h / 0.05);

      --sf-color-danger-subtle:  oklch(from var(--sf-color-danger) l c h / 0.12);
      --sf-color-danger-muted:   oklch(from var(--sf-color-danger) l c h / 0.3);
      --sf-color-danger-tint:    oklch(from var(--sf-color-danger) l c h / 0.05);

      /* ----------------------------------------------------------
         Gradients — derived from brand colors (auto-adapt)
         All 4 core brand families (primary/secondary/tertiary/action)
         share the same darkening formula; --sf-gradient-brand is a
         separate decorative hue-shift option, independent of the
         colour axis.
         ---------------------------------------------------------- */
      --sf-gradient-primary:   linear-gradient(in oklch 135deg, var(--sf-color-primary), oklch(from var(--sf-color-primary) calc(l - 0.08) c h));
      --sf-gradient-secondary: linear-gradient(in oklch 135deg, var(--sf-color-secondary), oklch(from var(--sf-color-secondary) calc(l - 0.08) c h));
      --sf-gradient-tertiary:  linear-gradient(in oklch 135deg, var(--sf-color-tertiary), oklch(from var(--sf-color-tertiary) calc(l - 0.08) c h));
      --sf-gradient-action:    linear-gradient(in oklch 135deg, var(--sf-color-action), oklch(from var(--sf-color-action) calc(l - 0.08) c h));
      --sf-gradient-brand:     linear-gradient(in oklch 135deg, var(--sf-color-primary), oklch(from var(--sf-color-primary) l c calc(h + 30)));
      --sf-gradient-surface:   linear-gradient(in oklab 180deg, var(--sf-color-surface), var(--sf-color-bg));

      --sf-gradient-fade--r: linear-gradient(in oklch to right,  transparent, var(--sf-color-bg));
      --sf-gradient-fade--l: linear-gradient(in oklch to left,   transparent, var(--sf-color-bg));
      --sf-gradient-fade--t: linear-gradient(in oklch to top,    transparent, var(--sf-color-bg));
      --sf-gradient-fade--b: linear-gradient(in oklch to bottom, transparent, var(--sf-color-bg));

      /* ----------------------------------------------------------
         Shadow glow
         ---------------------------------------------------------- */
      --sf-shadow-glow: 0 0 15px 2px oklch(from var(--sf-shadow-glow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2), 0.7));

    }
  }

  /* ── @supports gate: oklch(from …) + sign() ──────────────────
     Chrome added oklch(from) in v119 but sign() only in v138
     (Mar 2026). Without this gate, Chrome 119–137 evaluates the
     outer block to true but IACVT-crashes on sign() inside oklch(),
     making all text-on-color and auto-contrast code text invisible. */
  @supports (color: oklch(from red l c h)) and (width: calc(1px * sign(1))) {
    :root {

      /* ----------------------------------------------------------
         Code text — auto-contrasts with --sf-color-code-bg.
         ---------------------------------------------------------- */
      /* Inline-code text colour. Auto-contrasts with --sf-color-code-bg using
         the same luminance formula as --sf-color-text--on-*. This prevents
         invisible text when code appears inside inverted-colour containers
         (e.g. sf-imposter with a dark background where inherited colour is
         near-white). Override with a tint value if desired. */
      --sf-color-code-text: oklch(from var(--sf-color-code-bg) clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);

      /* ----------------------------------------------------------
         Text-on-color — sign(var(--sf-contrast-threshold) - l) * 999 is mode-agnostic:
         auto-selects light or dark text based on background luminance.
         Uses resolved tokens — works for any user-supplied color.

         CONTRAST NOTE: Guarantees ≥ 3:1 (WCAG AA Large Text / UI).
         Colors in the mid-luminance range (L ≈ 0.52–0.67) may not
         reach 4.5:1 (AA Normal Text) regardless of threshold chosen —
         this is a mathematical limitation of any binary black/white
         decision. The SLASHED configurator will warn users when their
         brand colors fall in this range. For body text on colored
         backgrounds, override --sf-color-text--on-* manually.
         ---------------------------------------------------------- */
      --sf-color-text--on-primary:   oklch(from var(--sf-color-primary)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);
      --sf-color-text--on-secondary: oklch(from var(--sf-color-secondary) clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);
      --sf-color-text--on-tertiary:  oklch(from var(--sf-color-tertiary)   clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);
      --sf-color-text--on-action:    oklch(from var(--sf-color-action)     clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);
      --sf-color-text--on-neutral:   oklch(from var(--sf-color-neutral)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);
      --sf-color-text--on-success:   oklch(from var(--sf-color-success)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);
      --sf-color-text--on-warning:   oklch(from var(--sf-color-warning)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);
      --sf-color-text--on-info:      oklch(from var(--sf-color-info)       clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);
      --sf-color-text--on-danger:    oklch(from var(--sf-color-danger)     clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);
      --sf-color-text--on-inverse:   oklch(from var(--sf-color-inverse)    clamp(0.1, sign(var(--sf-contrast-threshold) - l) * 999, 0.95) 0 0);

    }
  }

  /* ============================================================
     COLOR PALETTE — numeric ramps, alpha variants + aliases

     Numeric palette steps (-50…-950), alpha variants (-a5…-a80),
     and semantic convenience aliases live in core as the single source
     of truth for the 6 brand colour families. Shade steps mix toward
     --sf-color-surface (tints) or --sf-color-text (shades); the base
     family inverts tint direction so the ramp reads light→dark regardless
     of the base surface value.
     ============================================================ */

  /* ── @supports gate: palette ramps + alpha aliases ── */
  @supports (color: oklch(from red l c h)) {
  :root {

    /* ----------------------------------------------------------
       Palette ramp lightness anchors — PUBLIC-ADVANCED
       Each numeric step is generated in OKLCH by pulling the family
       colour's own lightness a fixed fraction toward an ABSOLUTE target:
       tints (50-400) toward --sf-palette-tint-l, shades (600-950) toward
       --sf-palette-shade-l. 500 = the family colour itself. Because the
       targets are absolute (not the theme's surface/text tokens) and the
       pull is clamped (max()/min()) so a tint can never end darker than
       the base nor a shade lighter, the ramp is MONOTONIC light→dark for
       ANY source colour and any anchor configuration — it cannot fold.
       Per-step pull fractions and chroma taper are baked into each family
       below; these two knobs set how light the lightest / how dark the
       darkest step may reach. The `base` family keeps its own absolute
       ladder (near-white→near-black) and does not read these.
       ---------------------------------------------------------- */
    --sf-palette-tint-l:  0.97;
    --sf-palette-shade-l: 0.1;

    /* ----------------------------------------------------------
       primary
       ---------------------------------------------------------- */
    --sf-color-primary-50: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h);
    --sf-color-primary-100: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h);
    --sf-color-primary-200: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h);
    --sf-color-primary-300: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h);
    --sf-color-primary-400: oklch(from var(--sf-color-primary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h);
    --sf-color-primary-500: var(--sf-color-primary);
    --sf-color-primary-600: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h);
    --sf-color-primary-700: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h);
    --sf-color-primary-800: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h);
    --sf-color-primary-900: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h);
    --sf-color-primary-950: oklch(from var(--sf-color-primary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h);

    --sf-color-primary-a5:  oklch(from var(--sf-color-primary) l c h / 0.05);
    --sf-color-primary-a10: oklch(from var(--sf-color-primary) l c h / 0.10);
    --sf-color-primary-a30: oklch(from var(--sf-color-primary) l c h / 0.30);
    --sf-color-primary-a50: oklch(from var(--sf-color-primary) l c h / 0.50);
    --sf-color-primary-a80: oklch(from var(--sf-color-primary) l c h / 0.80);

    --sf-color-primary-superlight: var(--sf-color-primary-50);
    --sf-color-primary-xlight:     var(--sf-color-primary-200);
    --sf-color-primary-lighter:    var(--sf-color-primary-400);
    --sf-color-primary-darker:     var(--sf-color-primary-600);
    --sf-color-primary-xdark:      var(--sf-color-primary-800);
    --sf-color-primary-superdark:  var(--sf-color-primary-950);
    --sf-color-primary--hover:     var(--sf-color-primary-darker);
    --sf-color-primary--active:    var(--sf-color-primary-xdark);
    --sf-color-primary-subtle:     var(--sf-color-primary-a10);
    --sf-color-primary-muted:      var(--sf-color-primary-a30);
    --sf-color-primary-tint:      var(--sf-color-primary-a5);



    /* ----------------------------------------------------------
       secondary
       ---------------------------------------------------------- */
    --sf-color-secondary-50: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h);
    --sf-color-secondary-100: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h);
    --sf-color-secondary-200: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h);
    --sf-color-secondary-300: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h);
    --sf-color-secondary-400: oklch(from var(--sf-color-secondary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h);
    --sf-color-secondary-500: var(--sf-color-secondary);
    --sf-color-secondary-600: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h);
    --sf-color-secondary-700: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h);
    --sf-color-secondary-800: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h);
    --sf-color-secondary-900: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h);
    --sf-color-secondary-950: oklch(from var(--sf-color-secondary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h);

    --sf-color-secondary-a5:  oklch(from var(--sf-color-secondary) l c h / 0.05);
    --sf-color-secondary-a10: oklch(from var(--sf-color-secondary) l c h / 0.10);
    --sf-color-secondary-a30: oklch(from var(--sf-color-secondary) l c h / 0.30);
    --sf-color-secondary-a50: oklch(from var(--sf-color-secondary) l c h / 0.50);
    --sf-color-secondary-a80: oklch(from var(--sf-color-secondary) l c h / 0.80);

    --sf-color-secondary-superlight: var(--sf-color-secondary-50);
    --sf-color-secondary-xlight:     var(--sf-color-secondary-200);
    --sf-color-secondary-lighter:    var(--sf-color-secondary-400);
    --sf-color-secondary-darker:     var(--sf-color-secondary-600);
    --sf-color-secondary-xdark:      var(--sf-color-secondary-800);
    --sf-color-secondary-superdark:  var(--sf-color-secondary-950);
    --sf-color-secondary--hover:     var(--sf-color-secondary-darker);
    --sf-color-secondary--active:    var(--sf-color-secondary-xdark);
    --sf-color-secondary-subtle:     var(--sf-color-secondary-a10);
    --sf-color-secondary-muted:      var(--sf-color-secondary-a30);
    --sf-color-secondary-tint:      var(--sf-color-secondary-a5);



    /* ----------------------------------------------------------
       tertiary
       ---------------------------------------------------------- */
    --sf-color-tertiary-50: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h);
    --sf-color-tertiary-100: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h);
    --sf-color-tertiary-200: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h);
    --sf-color-tertiary-300: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h);
    --sf-color-tertiary-400: oklch(from var(--sf-color-tertiary) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h);
    --sf-color-tertiary-500: var(--sf-color-tertiary);
    --sf-color-tertiary-600: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h);
    --sf-color-tertiary-700: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h);
    --sf-color-tertiary-800: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h);
    --sf-color-tertiary-900: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h);
    --sf-color-tertiary-950: oklch(from var(--sf-color-tertiary) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h);

    --sf-color-tertiary-a5:  oklch(from var(--sf-color-tertiary) l c h / 0.05);
    --sf-color-tertiary-a10: oklch(from var(--sf-color-tertiary) l c h / 0.10);
    --sf-color-tertiary-a30: oklch(from var(--sf-color-tertiary) l c h / 0.30);
    --sf-color-tertiary-a50: oklch(from var(--sf-color-tertiary) l c h / 0.50);
    --sf-color-tertiary-a80: oklch(from var(--sf-color-tertiary) l c h / 0.80);

    --sf-color-tertiary-superlight: var(--sf-color-tertiary-50);
    --sf-color-tertiary-xlight:     var(--sf-color-tertiary-200);
    --sf-color-tertiary-lighter:    var(--sf-color-tertiary-400);
    --sf-color-tertiary-darker:     var(--sf-color-tertiary-600);
    --sf-color-tertiary-xdark:      var(--sf-color-tertiary-800);
    --sf-color-tertiary-superdark:  var(--sf-color-tertiary-950);
    --sf-color-tertiary--hover:     var(--sf-color-tertiary-darker);
    --sf-color-tertiary--active:    var(--sf-color-tertiary-xdark);
    --sf-color-tertiary-subtle:     var(--sf-color-tertiary-a10);
    --sf-color-tertiary-muted:      var(--sf-color-tertiary-a30);
    --sf-color-tertiary-tint:      var(--sf-color-tertiary-a5);



    /* ----------------------------------------------------------
       action
       ---------------------------------------------------------- */
    --sf-color-action-50: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h);
    --sf-color-action-100: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h);
    --sf-color-action-200: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h);
    --sf-color-action-300: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h);
    --sf-color-action-400: oklch(from var(--sf-color-action) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h);
    --sf-color-action-500: var(--sf-color-action);
    --sf-color-action-600: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h);
    --sf-color-action-700: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h);
    --sf-color-action-800: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h);
    --sf-color-action-900: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h);
    --sf-color-action-950: oklch(from var(--sf-color-action) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h);

    --sf-color-action-a5:  oklch(from var(--sf-color-action) l c h / 0.05);
    --sf-color-action-a10: oklch(from var(--sf-color-action) l c h / 0.10);
    --sf-color-action-a30: oklch(from var(--sf-color-action) l c h / 0.30);
    --sf-color-action-a50: oklch(from var(--sf-color-action) l c h / 0.50);
    --sf-color-action-a80: oklch(from var(--sf-color-action) l c h / 0.80);

    --sf-color-action-superlight: var(--sf-color-action-50);
    --sf-color-action-xlight:     var(--sf-color-action-200);
    --sf-color-action-lighter:    var(--sf-color-action-400);
    --sf-color-action-darker:     var(--sf-color-action-600);
    --sf-color-action-xdark:      var(--sf-color-action-800);
    --sf-color-action-superdark:  var(--sf-color-action-950);
    --sf-color-action--hover:     var(--sf-color-action-darker);
    --sf-color-action--active:    var(--sf-color-action-xdark);
    --sf-color-action-subtle:     var(--sf-color-action-a10);
    --sf-color-action-muted:      var(--sf-color-action-a30);
    --sf-color-action-tint:      var(--sf-color-action-a5);



    /* ----------------------------------------------------------
       neutral
       ---------------------------------------------------------- */
    --sf-color-neutral-50: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.95)) calc(c * 0.2) h);
    --sf-color-neutral-100: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.88)) calc(c * 0.3) h);
    --sf-color-neutral-200: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.72)) calc(c * 0.5) h);
    --sf-color-neutral-300: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.52)) calc(c * 0.72) h);
    --sf-color-neutral-400: oklch(from var(--sf-color-neutral) max(l, calc(l + (var(--sf-palette-tint-l) - l) * 0.3)) calc(c * 0.88) h);
    --sf-color-neutral-500: var(--sf-color-neutral);
    --sf-color-neutral-600: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.16)) calc(c * 0.96) h);
    --sf-color-neutral-700: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.36)) calc(c * 0.88) h);
    --sf-color-neutral-800: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.58)) calc(c * 0.72) h);
    --sf-color-neutral-900: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.78)) calc(c * 0.52) h);
    --sf-color-neutral-950: oklch(from var(--sf-color-neutral) min(l, calc(l + (var(--sf-palette-shade-l) - l) * 0.9)) calc(c * 0.38) h);

    --sf-color-neutral-a5:  oklch(from var(--sf-color-neutral) l c h / 0.05);
    --sf-color-neutral-a10: oklch(from var(--sf-color-neutral) l c h / 0.10);
    --sf-color-neutral-a30: oklch(from var(--sf-color-neutral) l c h / 0.30);
    --sf-color-neutral-a50: oklch(from var(--sf-color-neutral) l c h / 0.50);
    --sf-color-neutral-a80: oklch(from var(--sf-color-neutral) l c h / 0.80);

    --sf-color-neutral-superlight: var(--sf-color-neutral-50);
    --sf-color-neutral-xlight:     var(--sf-color-neutral-200);
    --sf-color-neutral-lighter:    var(--sf-color-neutral-400);
    --sf-color-neutral-darker:     var(--sf-color-neutral-600);
    --sf-color-neutral-xdark:      var(--sf-color-neutral-800);
    --sf-color-neutral-superdark:  var(--sf-color-neutral-950);
    --sf-color-neutral--hover:     var(--sf-color-neutral-darker);
    --sf-color-neutral--active:    var(--sf-color-neutral-xdark);
    --sf-color-neutral-subtle:     var(--sf-color-neutral-a10);
    --sf-color-neutral-muted:      var(--sf-color-neutral-a30);
    --sf-color-neutral-tint:      var(--sf-color-neutral-a5);



    /* ----------------------------------------------------------
       base — fixed-lightness ramp (mode-independent, monotonic)
       ────────────────────────────────────────────────────────
       base is a surface-elevation family, not a mid-lightness brand
       colour. The ramp uses oklch() relative syntax with fixed L steps
       spanning 0.97 → 0.06, preserving the base source's hue and chroma.
       50 is always near-white; 950 is always near-black regardless of
       light/dark mode or the source colour's position.

       OKLCH L values (fixed, mode-independent):
         base-50  = 0.97   near-white
         base-100 = 0.94   very light gray
         base-200 = 0.88   light gray
         base-300 = 0.78   medium-light gray
         base-400 = 0.65   medium gray
         base-500 = 0.50   mid gray
         base-600 = 0.37   medium-dark gray
         base-700 = 0.27   dark gray
         base-800 = 0.17   very dark gray
         base-900 = 0.11   near-black
         base-950 = 0.06   near-black

       For mode-adaptive surface differentiation use the surface tokens
       (--sf-color-inset / --sf-color-raised / --sf-color-bg) which derive
       from --sf-color-base via relative oklch and adapt to light/dark mode.
       For overlays use alpha variants (-a10…-a80).
       ---------------------------------------------------------- */
    --sf-color-base-50:  oklch(from var(--sf-color-base) 0.97 c h);
    --sf-color-base-100: oklch(from var(--sf-color-base) 0.94 c h);
    --sf-color-base-200: oklch(from var(--sf-color-base) 0.88 c h);
    --sf-color-base-300: oklch(from var(--sf-color-base) 0.78 c h);
    --sf-color-base-400: oklch(from var(--sf-color-base) 0.65 c h);
    --sf-color-base-500: oklch(from var(--sf-color-base) 0.50 c h);
    --sf-color-base-600: oklch(from var(--sf-color-base) 0.37 c h);
    --sf-color-base-700: oklch(from var(--sf-color-base) 0.27 c h);
    --sf-color-base-800: oklch(from var(--sf-color-base) 0.17 c h);
    --sf-color-base-900: oklch(from var(--sf-color-base) 0.11 c h);
    --sf-color-base-950: oklch(from var(--sf-color-base) 0.06 c h);

    --sf-color-base-a5:  oklch(from var(--sf-color-base) l c h / 0.05);
    --sf-color-base-a10: oklch(from var(--sf-color-base) l c h / 0.10);
    --sf-color-base-a30: oklch(from var(--sf-color-base) l c h / 0.30);
    --sf-color-base-a50: oklch(from var(--sf-color-base) l c h / 0.50);
    --sf-color-base-a80: oklch(from var(--sf-color-base) l c h / 0.80);

    /* No relative aliases (lighter/darker/xlight/…) on base: it is an
       absolute scale, so a step's name would lie depending on where the
       source sits (e.g. "lighter" would be darker than a near-white base
       in light mode). For relative, mode-adaptive surface elevation use
       --sf-color-bg / --sf-color-inset / --sf-color-raised instead. */
    --sf-color-base--hover:     oklch(from var(--sf-color-base) clamp(0.01, calc(l - 0.04 + var(--sf-is-dark) * 0.08), 0.99) c h);
    --sf-color-base--active:    oklch(from var(--sf-color-base) clamp(0.01, calc(l - 0.08 + var(--sf-is-dark) * 0.16), 0.99) c h);
    --sf-color-base-subtle:     var(--sf-color-base-a10);
    --sf-color-base-muted:      var(--sf-color-base-a30);
    --sf-color-base-tint:      var(--sf-color-base-a5);


  }
  }

  /* ============================================================
     NON-COLOR DESIGN TOKENS
     ============================================================ */

  :root {

    /* ----------------------------------------------------------
       Scale multipliers
       ---------------------------------------------------------- */
    --sf-space-scale:        1;
    --sf-text-scale:         1;
    --sf-text-display-scale: 1;
    --sf-radius-scale:       1;
    --sf-motion-scale:       1;
    --sf-section-scale:      1;

    /* ----------------------------------------------------------
       Font families
       ---------------------------------------------------------- */
    --sf-font-body:    system-ui, -apple-system, sans-serif;
    --sf-font-heading: var(--sf-font-body);
    --sf-font-display: var(--sf-font-heading);
    --sf-font-mono:    ui-monospace, monospace;

    /* Optional system-font stacks (zero-cost, no @import) */
    --sf-font-humanist:  "Seravek", "Gill Sans Nova", "Ubuntu", "Calibri", "DejaVu Sans", source-sans-pro, sans-serif;
    --sf-font-geometric: "Avenir", "Montserrat", "Corbel", "URW Gothic", source-sans-pro, sans-serif;
    --sf-font-slab:      "Rockwell", "Rockwell Nova", "Roboto Slab", "DejaVu Serif", "Sitka Small", serif;

    /* Opt-in OpenType / variable-font controls (token-only, not applied by the framework) */
    --sf-font-features:  normal;  /* e.g. "cv11", "ss01" */
    --sf-font-variation: normal;  /* e.g. "wght" 450, "opsz" 32 */
    --sf-optical-sizing: auto;

    /* ----------------------------------------------------------
       Font weights
       ---------------------------------------------------------- */
    /* Base weights — trimmed, recognizable names. For an off-scale weight
       (e.g. 100/900 display work) write font-weight: 100 directly, or re-tune
       a role token below globally — every weight here is overridable. */
    --sf-font-weight-light:    300;
    --sf-font-weight-normal:   400;
    --sf-font-weight-medium:   500;
    --sf-font-weight-semibold: 600;
    --sf-font-weight-bold:     700;

    /* Semantic role aliases — set intent, not a number. Override these to
       reweight the whole site (e.g. --sf-font-weight-body: 300). */
    --sf-font-weight-body:        var(--sf-font-weight-normal);    /* body copy            */
    --sf-font-weight-heading:     var(--sf-font-weight-semibold);  /* h1–h6                */
    --sf-font-weight-display:     var(--sf-font-weight-bold);      /* hero / display       */
    --sf-font-weight-interactive: var(--sf-font-weight-semibold);  /* buttons, badges, nav.
       Note: "interactive" here names a TYPOGRAPHY WEIGHT TIER; .sf-card--interactive
       names a card BEHAVIOUR modifier. Deliberate coexistence (different property
       spaces) — do not introduce a third meaning of "interactive". */
    --sf-font-weight-strong:      var(--sf-font-weight-bold);      /* <strong> / emphasis  */

    /* ----------------------------------------------------------
       Font sizes — fluid
       ---------------------------------------------------------- */
    /* ----------------------------------------------------------
       Font sizes — fluid (generative)
       Computed from --sf-text-ratio-{min,max} + --sf-text-base-{min,max}
       over the --sf-fluid-{min,max}-vw range. Step exponent N is relative
       to --sf-text-m (N=0): 2xs=-3 … 4xl=5. Override the inputs above to
       reshape the whole scale; override an individual --sf-text-* to pin one.
       ---------------------------------------------------------- */
    --sf-text-2xs: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -3) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -3) * 1rem)) * var(--sf-text-scale));
    --sf-text-xs:  calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -2) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -2) * 1rem)) * var(--sf-text-scale));
    --sf-text-s:   calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -1) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -1) * 1rem)) * var(--sf-text-scale));
    --sf-text-m:   calc(clamp(calc(var(--sf-text-base-min) * 1rem), calc((var(--sf-text-base-max) - var(--sf-text-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * 1rem), calc(var(--sf-text-base-max) * 1rem)) * var(--sf-text-scale));
    --sf-text-l:   calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 1) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 1) * 1rem)) * var(--sf-text-scale));
    --sf-text-xl:  calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 2) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 2) * 1rem)) * var(--sf-text-scale));
    --sf-text-2xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 3) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 3) * 1rem)) * var(--sf-text-scale));
    --sf-text-3xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 4) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 4) * 1rem)) * var(--sf-text-scale));
    --sf-text-4xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 5) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 5) * 1rem)) * var(--sf-text-scale));

    /* Display — reuses the type ratios with its own larger base (s=0, m=1, l=2). */
    --sf-text-display-s: calc(clamp(calc(var(--sf-text-display-base-min) * 1rem), calc((var(--sf-text-display-base-max) - var(--sf-text-display-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * 1rem), calc(var(--sf-text-display-base-max) * 1rem)) * var(--sf-text-display-scale));
    --sf-text-display-m: calc(clamp(calc(var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc((var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 1) - var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc(var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 1) * 1rem)) * var(--sf-text-display-scale));
    --sf-text-display-l: calc(clamp(calc(var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc((var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 2) - var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc(var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 2) * 1rem)) * var(--sf-text-display-scale));

    /* ----------------------------------------------------------
       Line heights & letter spacing
       ---------------------------------------------------------- */
    --sf-leading-tight:   1.1;
    --sf-leading-snug:    1.3;
    --sf-leading-normal:  1.5;
    --sf-leading-relaxed: 1.625;

    /* Leading taper — progressive tightener for the per-size line-height
       tokens below. Each step up the type scale subtracts
       `step-index × taper` from that step's default leading.
       0 (default) keeps the curated stepped defaults; try 0.02 for a smooth
       metric taper across the scale. */
    --sf-leading-taper: 0;

    /* Display line-heights — display sizes need tighter leading than the
       --sf-leading-* scale provides. Not auto-applied (display sizes have no
       dedicated element); wire alongside font-size:
         h1.hero { font-size: var(--sf-text-display-l);
                   line-height: var(--sf-display-l-line-height); } */
    --sf-display-s-line-height: var(--sf-leading-tight);
    --sf-display-m-line-height: 1.05;
    --sf-display-l-line-height: 1;

    --sf-tracking-tight:   -0.025em;
    --sf-tracking-normal:   0;
    --sf-tracking-wide:     0.025em;
    --sf-tracking-wider:    0.05em;
    --sf-tracking-widest:   0.1em;

    /* Numeric figure style — tabular-nums gives every digit a fixed
       advance width so numbers line up in vertical columns (price
       lists, totals, invoices, dashboards). Consumed by number inputs
       in optional/forms.css and available to BEM components, e.g.
       `.price { font-variant-numeric: var(--sf-font-numeric); }`.
       Universal browser support. */
    --sf-font-numeric: tabular-nums;

    /* ----------------------------------------------------------
       Per-size typography sub-properties
       Not auto-applied — opt-in composable overrides. Wire alongside
       font-size in your own rules:
         .element { line-height: var(--sf-text-xl-line-height); }
       Small text: relaxed leading. Body: normal. Large: progressively
       tighter. --sf-leading-taper (default 0) tightens the whole
       scale at once.
       ---------------------------------------------------------- */

    --sf-text-2xs-line-height:            var(--sf-leading-relaxed);
    --sf-text-2xs-font-weight:            var(--sf-font-weight-body);
    --sf-text-2xs-letter-spacing:         var(--sf-tracking-normal);
    --sf-text-2xs-max-width:              55ch;

    --sf-text-xs-line-height:             calc(var(--sf-leading-relaxed) - 1 * var(--sf-leading-taper));
    --sf-text-xs-font-weight:             var(--sf-font-weight-body);
    --sf-text-xs-letter-spacing:          var(--sf-tracking-normal);
    --sf-text-xs-max-width:               60ch;

    --sf-text-s-line-height:              calc(var(--sf-leading-relaxed) - 2 * var(--sf-leading-taper));
    --sf-text-s-font-weight:              var(--sf-font-weight-body);
    --sf-text-s-letter-spacing:           var(--sf-tracking-normal);
    --sf-text-s-max-width:                65ch;

    --sf-text-m-line-height:              calc(var(--sf-leading-normal) - 3 * var(--sf-leading-taper));
    --sf-text-m-font-weight:              var(--sf-font-weight-body);
    --sf-text-m-letter-spacing:           var(--sf-tracking-normal);
    --sf-text-m-max-width:                65ch;

    --sf-text-l-line-height:              calc(var(--sf-leading-normal) - 4 * var(--sf-leading-taper));
    --sf-text-l-font-weight:              var(--sf-font-weight-body);
    --sf-text-l-letter-spacing:           var(--sf-tracking-normal);
    --sf-text-l-max-width:                none;

    --sf-text-xl-line-height:             calc(var(--sf-leading-snug) - 5 * var(--sf-leading-taper));
    --sf-text-xl-font-weight:             var(--sf-font-weight-body);
    --sf-text-xl-letter-spacing:          var(--sf-tracking-normal);
    --sf-text-xl-max-width:               none;

    --sf-text-2xl-line-height:            calc(var(--sf-leading-snug) - 6 * var(--sf-leading-taper));
    --sf-text-2xl-font-weight:            var(--sf-font-weight-heading);
    --sf-text-2xl-letter-spacing:         var(--sf-tracking-normal);
    --sf-text-2xl-max-width:              none;

    --sf-text-3xl-line-height:            calc(var(--sf-leading-tight) - 7 * var(--sf-leading-taper));
    --sf-text-3xl-font-weight:            var(--sf-font-weight-heading);
    --sf-text-3xl-letter-spacing:         var(--sf-tracking-tight);
    --sf-text-3xl-max-width:              none;

    --sf-text-4xl-line-height:            calc(var(--sf-leading-tight) - 8 * var(--sf-leading-taper));
    --sf-text-4xl-font-weight:            var(--sf-font-weight-heading);
    --sf-text-4xl-letter-spacing:         var(--sf-tracking-tight);
    --sf-text-4xl-max-width:              none;

    /* ----------------------------------------------------------
       Icon sizes — em-based by design.
       Icons are sized in em so they scale with the surrounding
       text: an icon in a button at --sf-text-m renders at 1rem;
       moved into a heading at --sf-text-2xl, the same icon scales
       up automatically.
       Global scaling flows transitively through --sf-text-scale
       (parent text grows → em-icons grow) — there is no separate
       --sf-icon-scale knob by design. clamp() is intentionally
       absent here: making icons fluid INDEPENDENTLY of context
       would break the relationship to surrounding text.
       Capped at --2xl (4em ≈ 64px on default text); above that the
       element ceases to be an icon and becomes an illustration.
       ---------------------------------------------------------- */
    --sf-icon-xs:  0.875em;
    --sf-icon-s:   1em;
    --sf-icon-m:   1.5em;
    --sf-icon-l:   2em;
    --sf-icon-xl:  3em;
    --sf-icon-2xl: 4em;

    /* ----------------------------------------------------------
       Spacing — fixed
       ---------------------------------------------------------- */
    --sf-space-none:   0;
    --sf-space-px:     1px;

    /* Spacing — fluid (generative). Same engine as type; space uses base_max=2
       (more dramatic growth than type's 1.25). Step exponent N relative to
       --sf-space-m (N=0): 2xs=-3 … 4xl=5. */
    --sf-space-2xs: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -3) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -3) * 1rem)) * var(--sf-space-scale));
    --sf-space-xs:  calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -2) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -2) * 1rem)) * var(--sf-space-scale));
    --sf-space-s:   calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -1) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -1) * 1rem)) * var(--sf-space-scale));
    --sf-space-m:   calc(clamp(calc(var(--sf-space-base-min) * 1rem), calc((var(--sf-space-base-max) - var(--sf-space-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * 1rem), calc(var(--sf-space-base-max) * 1rem)) * var(--sf-space-scale));
    --sf-space-l:   calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 1) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 1) * 1rem)) * var(--sf-space-scale));
    --sf-space-xl:  calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 2) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 2) * 1rem)) * var(--sf-space-scale));
    --sf-space-2xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 3) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 3) * 1rem)) * var(--sf-space-scale));
    --sf-space-3xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 4) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 4) * 1rem)) * var(--sf-space-scale));
    --sf-space-4xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 5) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 5) * 1rem)) * var(--sf-space-scale));

    /* ----------------------------------------------------------
       Density — the compact ↔ comfortable dial for interactive
       control GEOMETRY. 1 = default; <1 packs controls tighter
       (dashboards, data tables, power-user tools), >1 loosens them.
       It is a discrete design/product choice (or a user preference),
       NOT a viewport response — control height must never shrink on
       small screens where touch targets need to be larger, so unlike
       the fluid text and space scales the size ladder stays non-fluid
       and is scaled only by this deliberate knob. Orthogonal to
       --sf-space-scale (overall whitespace) and --sf-section-scale
       (macro section rhythm); combine them for a fully compact UI.
       Accessibility is unaffected: the coarse-pointer floor lives on
       --sf-touch-target (core/accessibility.css), never on a rung, so
       a small --sf-density can't shrink native controls below the
       WCAG target. Like the other global multipliers it is a :root
       dial — the size ladder is computed at :root and inherits, so a
       nested override does not retroactively rescale it (same
       computed-value rule as --sf-space-scale et al.). */
    --sf-density: 1;

    /* ----------------------------------------------------------
       UI sizes — a purely geometric rung ladder (+0.5rem / 8px per
       step: 24 · 32 · 40 · 48 · 56 px at density 1). These are free
       design knobs, scaled by --sf-density; overriding a rung just
       rescales that component height. Accessibility floors live on
       their own tokens (--sf-touch-target), never on a rung.
       ---------------------------------------------------------- */
    --sf-size-xs: calc(1.5rem * var(--sf-density));
    --sf-size-s:  calc(2rem   * var(--sf-density));
    --sf-size-m:  calc(2.5rem * var(--sf-density));
    --sf-size-l:  calc(3rem   * var(--sf-density));
    --sf-size-xl: calc(3.5rem * var(--sf-density));

    /* ----------------------------------------------------------
       Containers
       ---------------------------------------------------------- */
    --sf-container-narrow:  38rem;
    --sf-container-prose:   65ch;
    --sf-container-default: 75rem;
    --sf-container-wide:    90rem;
    --sf-container-full:    100%;

    /* ----------------------------------------------------------
       Aspect ratios
       ---------------------------------------------------------- */
    --sf-ratio-square:   1;
    --sf-ratio-video:    16 / 9;
    --sf-ratio-cinema:   21 / 9;
    --sf-ratio-4-3:      4 / 3;
    --sf-ratio-3-2:      3 / 2;
    --sf-ratio-portrait: 3 / 4;
    --sf-ratio-golden:   1.618 / 1;

    /* ----------------------------------------------------------
       Border widths
       --sf-border-width-hairline: device-pixel-dependent. On 1x DPR
       displays (Windows non-Retina) the browser will round 0.5px up
       to 1px, so it visually matches --sf-border-width-1. On 2x+
       DPR (macOS/iOS Retina, most modern phones) it renders as a
       true half-pixel hairline. Use it for subtle separators where
       1px on low-DPR is acceptable.
       ---------------------------------------------------------- */
    /* --sf-border-scale — global multiplier for border widths. Set to 0 for
       borderless, 2 for heavy borders. Hairline is intentionally excluded
       (it's a device-pixel constant, not a design variable). */
    --sf-border-scale:           1;
    --sf-border-width-hairline: 0.5px;
    --sf-border-width-1:        calc(1px * var(--sf-border-scale, 1));
    --sf-border-width-2:        calc(2px * var(--sf-border-scale, 1));
    --sf-border-width-3:        calc(3px * var(--sf-border-scale, 1));
    --sf-border-width-4:        calc(4px * var(--sf-border-scale, 1));

    /* ----------------------------------------------------------
       Border style — global knob paired with --sf-border-width-* and
       --sf-color-border*. Consumer BEM:
         .my-card { border: var(--sf-border-width-1) var(--sf-border-style) var(--sf-color-border); }
       Set once on :root to restyle every framework border, or override
       per element. For one-off decorative styles use the CSS keyword
       directly (e.g. `border-style: dashed`).
       ---------------------------------------------------------- */
    --sf-border-style: solid;     /* default */

    /* ----------------------------------------------------------
       Border shorthands — convenience tokens composing width, style,
       and color into a single value for the common cases.
       subtle / strong vary COLOR CONTRAST only — all three use
       --sf-border-width-1 (1px). This matches the IBM Carbon and
       GitHub Primer convention where subtle/strong name a color axis,
       not a weight axis. For a thicker border compose manually:
         border: var(--sf-border-width-2) var(--sf-border-style) var(--sf-color-border--strong)
       Usage: border: var(--sf-border);
              border-bottom: var(--sf-border-subtle);
       ---------------------------------------------------------- */
    --sf-border:        var(--sf-border-width-1) var(--sf-border-style) var(--sf-color-border);
    --sf-border-subtle: var(--sf-border-width-1) var(--sf-border-style) var(--sf-color-border--subtle);
    --sf-border-strong: var(--sf-border-width-1) var(--sf-border-style) var(--sf-color-border--strong);

    /* ----------------------------------------------------------
       Divider — global separator system. Drives `hr` (base) and
       the `.sf-divider` layout primitive.
       ---------------------------------------------------------- */
    --sf-divider-width: var(--sf-border-width-1);
    --sf-divider-style: solid;
    --sf-divider-color: var(--sf-color-border);
    --sf-divider-gap:   var(--sf-space-m);

    /* ----------------------------------------------------------
       Border radius — scale ramp, all multiplied by --sf-radius-scale.
       ---------------------------------------------------------- */
    --sf-radius-none: 0;
    --sf-radius-2xs:  calc(1px  * var(--sf-radius-scale));
    --sf-radius-xs:   calc(2px  * var(--sf-radius-scale));
    --sf-radius-s:    calc(4px  * var(--sf-radius-scale));
    --sf-radius-m:    calc(8px  * var(--sf-radius-scale));
    --sf-radius-l:    calc(12px * var(--sf-radius-scale));
    --sf-radius-xl:   calc(16px * var(--sf-radius-scale));
    --sf-radius-2xl:  calc(24px * var(--sf-radius-scale));
    --sf-radius-3xl:  calc(32px * var(--sf-radius-scale));
    --sf-radius-4xl:  calc(48px * var(--sf-radius-scale));
    /* ----------------------------------------------------------
       Full/pill — topological constants, not scaled by --sf-radius-scale.
       A pill/circle is a topological constant, not a relative size:
       any --sf-radius-scale: 0 ("sharp" design system) should still
       render pill buttons as pills. 9999px is a magic-number convention
       large enough to clip to half the shorter edge for any realistic UI.
       ---------------------------------------------------------- */
    --sf-radius-full: 9999px;
    /* Pill — semantic alias of --sf-radius-full. Reach for this name
       on rectangles you want capsule-shaped (badges, tags, chips); use
       --sf-radius-full when you mean "as round as topologically possible". */
    --sf-radius-pill: var(--sf-radius-full);
    /* Concentric helper — outer radius for a container that wraps
       content padded by --sf-component-pad with inner radius m.
       Keeps inner elements visually proportional inside a padded box.
       Override per use:
         .my-card { border-radius: var(--sf-radius-outer); }
       Maths: outer = inner + padding ⇒ aligned curves at corners. */
    --sf-radius-outer: calc(var(--sf-radius-m) + var(--sf-component-pad));

    /* Opt-in global media radius — 0 by default (off). Set to a
       --sf-radius-* value to round <img>/<figure> globally:
         :root { --sf-media-radius: var(--sf-radius-m); }
       Applied via :where() in core/base.css so it never fights
       .sf-bg-layer or a component's own radius. */
    --sf-media-radius: 0;

    /* ----------------------------------------------------------
       Shadows — BEM consumer API
       Use in your own classes: .card { box-shadow: var(--sf-shadow-m); }
       ---------------------------------------------------------- */


    /* ----------------------------------------------------------
       Blur & opacity
       One frosted-surface default (nav/overlay glass) and one general
       de-emphasis opacity. For other amounts write the value directly:
       backdrop-filter: blur(24px); opacity: .3;
       (--sf-opacity-disabled is defined with the interaction tokens.)
       ---------------------------------------------------------- */
    --sf-blur:          12px;
    --sf-opacity-muted: 0.5;

    /* ----------------------------------------------------------
       Motion & easing
       ---------------------------------------------------------- */
    --sf-duration-none:    0ms;
    --sf-duration-instant: calc(100ms * var(--sf-motion-scale));
    --sf-duration-fast:    calc(150ms * var(--sf-motion-scale));
    --sf-duration-normal:  calc(250ms * var(--sf-motion-scale));
    --sf-duration-slow:    calc(400ms * var(--sf-motion-scale));
    --sf-duration-slower:  calc(600ms * var(--sf-motion-scale));

    /* Opt-in light/dark cross-fade duration — the knob for .sf-theme-transition
       (core/themes.css). Registered <color> tokens make the fade possible;
       this controls how long it takes. */
    --sf-theme-transition-duration: calc(300ms * var(--sf-motion-scale));

    --sf-ease-linear:  linear;
    --sf-ease-out:     cubic-bezier(0.25, 0, 0.15, 1);
    --sf-ease-in:      cubic-bezier(0.5, 0, 0.75, 0.25);
    --sf-ease-in-out:  cubic-bezier(0.4, 0, 0.2, 1);
    --sf-ease-spring:    linear(0, 0.5, 1.1, 0.95, 1.02, 1);
    --sf-ease-elastic:   linear(0, 0.3, 1.2, 0.9, 1.05, 1);
    --sf-ease-bounce:    linear(0, 0.35 18%, 1 32%, 0.86 42%, 1.02 56%, 0.98 72%, 1);
    --sf-ease-overshoot: linear(0, 0.6 30%, 1.08 55%, 0.98 75%, 1);

    /* ----------------------------------------------------------
       Animation presets — pair keyframes (core/motion.css) with
       duration + easing. Use directly: animation: var(--sf-animation-fade-in);
       ---------------------------------------------------------- */
    --sf-animation-fade-in:        sf-fade-in        var(--sf-duration-normal) var(--sf-ease-out)       both;
    --sf-animation-fade-out:       sf-fade-out       var(--sf-duration-normal) var(--sf-ease-in)        both;
    --sf-animation-slide-in-up:    sf-slide-in-up    var(--sf-duration-normal) var(--sf-ease-out)       both;
    --sf-animation-slide-in-down:  sf-slide-in-down  var(--sf-duration-normal) var(--sf-ease-out)       both;
    --sf-animation-slide-in-left:  sf-slide-in-left  var(--sf-duration-normal) var(--sf-ease-out)       both;
    --sf-animation-slide-in-right: sf-slide-in-right var(--sf-duration-normal) var(--sf-ease-out)       both;
    --sf-animation-scale-up:       sf-scale-up       var(--sf-duration-normal) var(--sf-ease-overshoot) both;
    --sf-animation-scale-down:     sf-scale-down     var(--sf-duration-normal) var(--sf-ease-in)        both;
    --sf-animation-slide-out-up:    sf-slide-out-up    var(--sf-duration-normal) var(--sf-ease-in) both;
    --sf-animation-slide-out-down:  sf-slide-out-down  var(--sf-duration-normal) var(--sf-ease-in) both;
    --sf-animation-slide-out-left:  sf-slide-out-left  var(--sf-duration-normal) var(--sf-ease-in) both;
    --sf-animation-slide-out-right: sf-slide-out-right var(--sf-duration-normal) var(--sf-ease-in) both;
    --sf-animation-color-pulse:    sf-color-pulse    var(--sf-duration-slow)   var(--sf-ease-in-out)    infinite;
    --sf-animation-ping:           sf-ping           var(--sf-duration-slow)   var(--sf-ease-out)       infinite;
    --sf-animation-blink:          sf-blink          calc(1s * var(--sf-motion-scale)) steps(1, end) infinite;
    --sf-animation-float:          sf-float          calc(3s * var(--sf-motion-scale)) var(--sf-ease-in-out) infinite;
    --sf-animation-spin:    sf-spin var(--sf-duration-slower) linear infinite;
    --sf-animation-shimmer: sf-shimmer calc(1.5s * var(--sf-motion-scale)) var(--sf-ease-in-out) infinite;

    /* Stagger step — the per-item delay increment consumed by the .sf-stagger
       utility (core/motion.css). One knob retunes the whole choreography; the
       class multiplies it by the child's index and by --sf-motion-scale, so the
       rhythm follows the motion knob without baking the scale in here. */
    --sf-stagger-step: 75ms;

    /* Hover-transform magnitudes — the .sf-hover-* utilities (optional/
       utilities.css) read these so the effect strength is one global knob per
       axis rather than hard-coded per class. --grow/--shrink are scale factors;
       --lift is the float/sink translate distance; --slide is the slide
       distance. */
    --sf-hover-grow-scale:   1.05;
    --sf-hover-shrink-scale: 0.95;
    --sf-hover-lift:         0.25em;
    --sf-hover-slide:        0.5em;

    /* ----------------------------------------------------------
       Scroll-driven animation range — consumer API. Attach these
       to your own scroll-timeline via animation-range. Not consumed
       by the framework itself; intended for BEM component authors.
       ---------------------------------------------------------- */
    --sf-scroll-timeline-range-start: entry 0%;
    --sf-scroll-timeline-range-end:   cover 30%;

    /* Exit counterpart — element is well into view before starting to
       leave, finishing exactly as it scrolls fully out. */
    --sf-scroll-timeline-range-exit-start: cover 70%;
    --sf-scroll-timeline-range-exit-end:   exit 100%;

    /* ----------------------------------------------------------
       Mask scrim — edge-fade stops for scroll reels / overflow.
       Use in a mask-image gradient to fade content near an edge:
         mask-image: linear-gradient(to right,
           transparent 0, #000 var(--sf-mask-scrim-start),
           #000 calc(100% - var(--sf-mask-scrim-end)), transparent 100%);
       ---------------------------------------------------------- */
    --sf-mask-scrim-start: var(--sf-space-l);
    --sf-mask-scrim-end:   var(--sf-space-l);

    /* ----------------------------------------------------------
       Z-index
       ---------------------------------------------------------- */
    /* Semantic z-index ladder — UI roles, not magic integers. Follows the
       Bootstrap/Chakra convention (1000-base, ordered by stacking role) so
       the names are familiar and the gaps leave room to insert custom layers.
       Low-level rungs (below/base/raised) handle local stacking; the named
       roles handle page chrome and overlays.

       Modal / popover / tooltip components render in the browser TOP LAYER
       (native <dialog> / [popover]), ordered above the page independently of
       z-index. The --sf-z-modal / --sf-z-overlay / --sf-z-tooltip rungs are
       the fallback for non-top-layer implementations that must beat the page. */
    --sf-z-below:  -1;
    --sf-z-base:    0;
    --sf-z-raised:  1;
    --sf-z-sticky:   1000;  /* sticky headers / sidebars            */
    --sf-z-fixed:    1010;  /* fixed app chrome (navbar, FAB)       */
    --sf-z-dropdown: 1020;  /* menus — clear sticky + fixed         */
    --sf-z-overlay:  1030;  /* scrims / non-top-layer backdrops     */
    --sf-z-modal:    1040;  /* dialogs (non-top-layer fallback)     */
    --sf-z-toast:    1050;  /* transient notifications              */
    --sf-z-tooltip:  1060;  /* tooltips — above everything          */

    /* ----------------------------------------------------------
       Layout & a11y
       ---------------------------------------------------------- */
    /* Header height fluidly interpolates between the mobile and desktop
       tokens across the framework viewport range (--sf-fluid-{min,max}-vw),
       the same range used by the fluid type/space scales. Override either
       endpoint to retune; set both equal for a fixed height. clamp() keeps the
       result bounded to the endpoints even when they are overridden. */
    --sf-header-height-mobile:  3.5rem;
    --sf-header-height-desktop: 5rem;
    --sf-header-height: clamp(
      var(--sf-header-height-mobile),
      calc((var(--sf-header-height-desktop) - var(--sf-header-height-mobile)) / ((var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * 1rem) * (100vw - var(--sf-fluid-min-vw) * 1rem) + var(--sf-header-height-mobile)),
      var(--sf-header-height-desktop));
    --sf-sticky-offset-mobile:  var(--sf-header-height-mobile);
    --sf-sticky-offset-desktop: var(--sf-header-height-desktop);
    --sf-sticky-offset: clamp(
      var(--sf-sticky-offset-mobile),
      calc((var(--sf-sticky-offset-desktop) - var(--sf-sticky-offset-mobile)) / ((var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * 1rem) * (100vw - var(--sf-fluid-min-vw) * 1rem) + var(--sf-sticky-offset-mobile)),
      var(--sf-sticky-offset-desktop));
    /* Focus ring dimensions and minimum touch-target size. Governs keyboard
       navigation affordance and WCAG 2.5.5 pointer-target requirements.
       --sf-touch-target owns the 44px WCAG floor as a literal — it is NOT an
       alias of a --sf-size-* rung, so retuning the size scale can never drag
       the accessibility minimum below spec. Override it deliberately if you
       have your own target policy. */
    --sf-focus-ring-width:  2px;
    --sf-focus-ring-offset: 2px;
    --sf-focus-ring-style:  solid;
    --sf-touch-target:      2.75rem;  /* 44px — WCAG 2.5.5 minimum, independent of the size scale */
    /* Global text-contrast knob. Nudges derived reading-text colours
       toward the extremes (darker in light mode, lighter in dark mode).
       Positive = more contrast; 0 = no change. Consumed by
       --sf-color-text, --sf-color-text--subtle, --sf-color-heading. */
    --sf-contrast-bias:     0;
    /* Lightness crossover for text-on-color auto-contrast. Colours with
       L above this value get dark text; below get light text.
       Default 0.6 guarantees ≥ 3:1 for most colours.
       The binary choice (near-black or near-white) cannot guarantee 4.5:1 when
       the background sits in the L ≈ 0.52–0.67 band — both extremes land near
       the crossover. Two escape hatches:
         1. Shift the threshold per surface — lower (e.g. 0.55) if your brand
            lands near 0.6 and you prefer white text on it:
              @layer slashed.overrides {
                .sf-surface--primary { --sf-contrast-threshold: 0.55; }
              }
         2. Override the resolved token directly when an exact colour is needed:
              @layer slashed.overrides {
                .sf-surface--primary { --sf-color-text--on-primary: oklch(0.15 0 0); }
              }
       CSS `contrast-color()` (currently only in the spec, no browser support)
       will replace this formula once it ships. */
    --sf-contrast-threshold: 0.6;

    /* Device safe-area insets (notches, rounded corners, home indicators).
       0px on devices without intrusions. Read these in your own padding/
       margin; the framework consumes them in layout edge spacing. */
    --sf-safe-top:    env(safe-area-inset-top,    0px);
    --sf-safe-bottom: env(safe-area-inset-bottom, 0px);
    --sf-safe-left:   env(safe-area-inset-left,   0px);
    --sf-safe-right:  env(safe-area-inset-right,  0px);

    /* ----------------------------------------------------------
       Print
       ---------------------------------------------------------- */
    --sf-print-page-margin: 2cm;
    --sf-print-page-size:   a4;
    --sf-print-base-size:   11pt;

    /* ----------------------------------------------------------
       Object fit / position — global defaults for replaced elements.
       Applied in core/base.css on img and video. Override per element
       via inline style="--sf-object-position: top" or in BEM CSS.
       ---------------------------------------------------------- */
    --sf-object-fit:      cover;
    --sf-object-position: 50% 50%;

  }

  /* @supports — Shadow ramp (box-shadow, text-shadow, drop-shadow) */
  @supports (color: oklch(from red l c h)) {
    :root {

      /* Shadow tint — near-black derived from the neutral; the tint simply
         inherits the neutral's own chroma/hue, so a colourless neutral yields
         colourless shadows. Forced dark in both modes; --sf-shadow-strength
         handles dark-mode intensity. Override to a brand colour for explicitly
         tinted shadows — keep it dark or you get bright slabs:
         oklch(from var(--sf-color-primary) 0.15 c h). */
      --sf-shadow-color: oklch(from var(--sf-color-neutral) var(--sf-shadow-lightness) c h);

      /* Elevation shadow ramp — box-shadow presets from xs to 2xl.
         Opacity scales with --sf-shadow-strength so dark-mode boost is automatic. */
      --sf-shadow-none:  none;
      --sf-shadow-xs:    0 1px 2px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.5), 0.7));
      --sf-shadow-s:     0 1px 2px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.5), 0.7)),
                         0 2px 6px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, var(--sf-shadow-strength), 0.7));
      --sf-shadow-m:     0 1px 3px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.5), 0.7)),
                         0 4px 12px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2), 0.7));
      --sf-shadow-l:     0 2px 4px 0   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.5), 0.7)),
                         0 8px 24px 0  oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 3), 0.7)),
                         0 16px 48px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2), 0.7));
      --sf-shadow-xl:    0 2px 8px 0   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.5), 0.7)),
                         0 12px 36px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 3.5), 0.7)),
                         0 24px 72px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2.5), 0.7));
      --sf-shadow-2xl:   0 4px 12px 0       oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 0.6), 0.7)),
                         0 20px 60px 0       oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 4), 0.7)),
                         0 40px 100px -8px   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 5), 0.7));
      --sf-shadow-inner: inset 0 2px 4px 0 oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2), 0.7));
  
      /* ----------------------------------------------------------
         Text shadows — share --sf-shadow-color / --sf-shadow-strength
         ---------------------------------------------------------- */
      --sf-text-shadow-none: none;
      --sf-text-shadow-xs: 0 0.5px 1px oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 1),   0.7));
      --sf-text-shadow-s:  0 1px 2px   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 1.5), 0.7));
      --sf-text-shadow-m:  0 2px 4px   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2),   0.7));
      --sf-text-shadow-l:  0 4px 8px   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2.5), 0.7));
      --sf-text-shadow-xl: 0 8px 16px  oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 3),   0.7));

      /* Drop shadows — for filter: drop-shadow() (respects alpha edges) */
      --sf-drop-shadow-xs: drop-shadow(0 0.5px 1px  oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 1),   0.7)));
      --sf-drop-shadow-s:  drop-shadow(0 1px 2px    oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 1.5), 0.7)));
      --sf-drop-shadow-m:  drop-shadow(0 4px 6px    oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2),   0.7)));
      --sf-drop-shadow-l:  drop-shadow(0 8px 16px   oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 2.5), 0.7)));
      --sf-drop-shadow-xl: drop-shadow(0 16px 32px  oklch(from var(--sf-shadow-color) l c h / clamp(0, calc(var(--sf-shadow-strength) * 3),   0.7)));

    }
  }

  /* ============================================================
     TYPOGRAPHY ALIASES — part of the per-style typography bundle
     for a named text role (body, code, heading, h1–h6, display).
     The full bundle spans font-family, size, weight, line-height,
     and letter-spacing across related tokens.
     ============================================================ */

  :root {
    --sf-body-font-size:     var(--sf-text-m);
    --sf-body-line-height:   var(--sf-leading-normal);
    --sf-body-font-weight:   var(--sf-font-weight-body);
    --sf-body-font-family:   var(--sf-font-body);
    --sf-body-color:         var(--sf-color-text);
    --sf-body-text-wrap:     pretty;
    --sf-body-strong-weight: var(--sf-font-weight-strong);
    --sf-body-em-style:      italic;

    --sf-code-font-size:     0.875em;

    --sf-heading-font-family: var(--sf-font-heading);
    --sf-heading-color:       var(--sf-color-heading);
    --sf-heading-text-wrap:   balance;

    --sf-h1-size:           var(--sf-text-4xl);
    --sf-h1-line-height:    var(--sf-leading-tight);
    --sf-h1-font-weight:    var(--sf-font-weight-heading);
    --sf-h1-letter-spacing: var(--sf-tracking-tight);

    --sf-h2-size:           var(--sf-text-3xl);
    --sf-h2-line-height:    var(--sf-leading-tight);
    --sf-h2-font-weight:    var(--sf-font-weight-heading);
    --sf-h2-letter-spacing: var(--sf-tracking-tight);

    --sf-h3-size:           var(--sf-text-2xl);
    --sf-h3-line-height:    var(--sf-leading-snug);
    --sf-h3-font-weight:    var(--sf-font-weight-heading);
    --sf-h3-letter-spacing: var(--sf-tracking-normal);

    --sf-h4-size:           var(--sf-text-xl);
    --sf-h4-line-height:    var(--sf-leading-snug);
    --sf-h4-font-weight:    var(--sf-font-weight-heading);
    --sf-h4-letter-spacing: var(--sf-tracking-normal);

    --sf-h5-size:           var(--sf-text-l);
    --sf-h5-line-height:    var(--sf-leading-normal);
    --sf-h5-font-weight:    var(--sf-font-weight-heading);
    --sf-h5-letter-spacing: var(--sf-tracking-normal);

    --sf-h6-size:           var(--sf-text-m);
    --sf-h6-line-height:    var(--sf-leading-normal);
    --sf-h6-font-weight:    var(--sf-font-weight-heading);
    --sf-h6-letter-spacing: var(--sf-tracking-wide);

    /* ----------------------------------------------------------
       Heading line-length constraints — public control hooks.
       Default `none` = no constraint. Set to a ch value to cap
       heading width independently of the prose container:
         :root { --sf-h1-max-width: 20ch; --sf-h2-max-width: 28ch; }
       Consumed by h1–h6 in core/base.css.
       ---------------------------------------------------------- */
    --sf-h1-max-width: none;
    --sf-h2-max-width: none;
    --sf-h3-max-width: none;
    --sf-h4-max-width: none;
    --sf-h5-max-width: none;
    --sf-h6-max-width: none;

    /* ----------------------------------------------------------
       Semantic gap tokens — the three rhythms every layout primitive
       defaults to. Also the BEM consumer API: .nav { gap: var(--sf-gap); }
       Override globally to retune all primitives of that rhythm at once.
       ---------------------------------------------------------- */
    --sf-gap:           var(--sf-space-m);  /* loose: between components   */
    --sf-content-gap:   var(--sf-space-s);  /* tight: within content       */
    --sf-gutter:        var(--sf-space-l);  /* wide: page/section gutters  */
    --sf-component-pad: var(--sf-space-m);  /* standard component padding  */
    --sf-field-block:   var(--sf-space-xs); /* form-field block padding — matches the shipped field default (see optional/forms.css) */
    --sf-field-required-marker: " *";
    /* Leading space is baked into the default so consumers can fully
       disable the indicator with `--sf-link-external-marker: ""` —
       without the space a bare "" still left a stray space after the
       link text. Override with your own glyph (include leading space
       if you want one): `:root { --sf-link-external-marker: " →" }`. */
    --sf-link-external-marker: " \2197";  /* " ↗" — consumed by .sf-link-external */
    /* Accessible name for the marker glyph, via the CSS alt-text syntax
       (`content: <value> / <string>`) — read by screen readers in place
       of the glyph, appended after the link's own text. Localise or
       disable (together with the marker) per-site. */
    --sf-link-external-label: "opens in a new window or external site";

    /* ----------------------------------------------------------
       Section padding
       ---------------------------------------------------------- */
    /* All sizes multiply by --sf-section-scale — one dial re-rhythms
       every section on the page (default 1 = no change). */
    --sf-section-pad:     var(--sf-section-pad--m);
    --sf-section-pad--xs: calc(var(--sf-space-xl)  * var(--sf-section-scale));
    --sf-section-pad--s:  calc(var(--sf-space-2xl) * var(--sf-section-scale));
    --sf-section-pad--m:  calc(var(--sf-space-3xl) * var(--sf-section-scale));
    --sf-section-pad--l:  calc(var(--sf-space-4xl) * var(--sf-section-scale));
    --sf-section-pad--xl: calc(var(--sf-space-4xl) * 1.5 * var(--sf-section-scale));
    --sf-section-pad--2xl: calc(var(--sf-space-4xl) * 2 * var(--sf-section-scale));

    /* ----------------------------------------------------------
       Transition shorthands

       All tokens name an explicit property set (no `transition: all`).
       The tempo presets (fast / slow / enter / exit) cover the curated
       "common interactive + entrance" set — color, background-color,
       border-color, box-shadow, opacity, transform, filter.
       ---------------------------------------------------------- */
    --sf-transition-colors:
      color var(--sf-duration-normal) var(--sf-ease-out),
      background-color var(--sf-duration-normal) var(--sf-ease-out),
      border-color var(--sf-duration-normal) var(--sf-ease-out),
      text-decoration-color var(--sf-duration-normal) var(--sf-ease-out),
      fill var(--sf-duration-normal) var(--sf-ease-out),
      stroke var(--sf-duration-normal) var(--sf-ease-out);
    /* Form fields: color/bg at normal pace, border/shadow/opacity at fast
       so focus rings and validation states react immediately. */
    --sf-transition-form-field:
      color              var(--sf-duration-normal) var(--sf-ease-out),
      background-color   var(--sf-duration-normal) var(--sf-ease-out),
      text-decoration-color var(--sf-duration-normal) var(--sf-ease-out),
      fill               var(--sf-duration-normal) var(--sf-ease-out),
      stroke             var(--sf-duration-normal) var(--sf-ease-out),
      border-color       var(--sf-duration-fast)   var(--sf-ease-out),
      box-shadow         var(--sf-duration-fast)   var(--sf-ease-out),
      opacity            var(--sf-duration-fast)   var(--sf-ease-out);
    /* Single-property transition: transform only. */
    --sf-transition-transform: transform var(--sf-duration-normal) var(--sf-ease-out);
    /* Single-property transition: opacity only. */
    --sf-transition-opacity:   opacity var(--sf-duration-normal) var(--sf-ease-out);
    /* Single-property transition: box-shadow only. */
    --sf-transition-shadow:    box-shadow var(--sf-duration-normal) var(--sf-ease-out);

    /* All interactive properties at fast duration — for hover/active states that need to feel snappy. */
    --sf-transition-fast:
      color var(--sf-duration-fast) var(--sf-ease-out),
      background-color var(--sf-duration-fast) var(--sf-ease-out),
      border-color var(--sf-duration-fast) var(--sf-ease-out),
      box-shadow var(--sf-duration-fast) var(--sf-ease-out),
      opacity var(--sf-duration-fast) var(--sf-ease-out),
      transform var(--sf-duration-fast) var(--sf-ease-out),
      filter var(--sf-duration-fast) var(--sf-ease-out);
    /* All interactive properties at slow duration — for deliberate, attention-drawing animations. */
    --sf-transition-slow:
      color var(--sf-duration-slow) var(--sf-ease-in-out),
      background-color var(--sf-duration-slow) var(--sf-ease-in-out),
      border-color var(--sf-duration-slow) var(--sf-ease-in-out),
      box-shadow var(--sf-duration-slow) var(--sf-ease-in-out),
      opacity var(--sf-duration-slow) var(--sf-ease-in-out),
      transform var(--sf-duration-slow) var(--sf-ease-in-out),
      filter var(--sf-duration-slow) var(--sf-ease-in-out);
    /* Entrance transition: normal duration + ease-out for elements entering the view. */
    --sf-transition-enter:
      color var(--sf-duration-normal) var(--sf-ease-out),
      background-color var(--sf-duration-normal) var(--sf-ease-out),
      border-color var(--sf-duration-normal) var(--sf-ease-out),
      box-shadow var(--sf-duration-normal) var(--sf-ease-out),
      opacity var(--sf-duration-normal) var(--sf-ease-out),
      transform var(--sf-duration-normal) var(--sf-ease-out),
      filter var(--sf-duration-normal) var(--sf-ease-out);
    /* Exit transition: fast duration + ease-in so exits feel crisp and don't linger. */
    --sf-transition-exit:
      color var(--sf-duration-fast) var(--sf-ease-in),
      background-color var(--sf-duration-fast) var(--sf-ease-in),
      border-color var(--sf-duration-fast) var(--sf-ease-in),
      box-shadow var(--sf-duration-fast) var(--sf-ease-in),
      opacity var(--sf-duration-fast) var(--sf-ease-in),
      transform var(--sf-duration-fast) var(--sf-ease-in),
      filter var(--sf-duration-fast) var(--sf-ease-in);

    /* Top-layer transition building block (dialog, [popover]).
       transition-behavior: allow-discrete keeps the discrete `display`
       and `overlay` properties in the transition so entry animations can
       fire and exit animations finish before the element leaves the top
       layer. Compose it into a component transition alongside the visual
       properties.
       NOTE: Requires @starting-style to be defined on the element for
       the entrance transition to trigger.
       Progressive enhancement — unsupporting engines simply show/hide instantly.
       Chrome/Edge/Safari and Firefox (2025+) support allow-discrete. */
    --sf-transition-overlay:
      overlay var(--sf-duration-normal) allow-discrete,
      display var(--sf-duration-normal) allow-discrete;
  }

}
