/* ==========================================================================
   SLASHED Full Bundle — v0.6.22.0
   Concatenation of: tokens-default + slashed-core + slashed-utilities +
                     slashed-components + slashed-utilities-visual +
                     slashed-animations + slashed-utilities-viewport
   Complete single-link option — includes all components, decorative
   utilities, animation helpers, and viewport breakpoint utilities.
   Does NOT include slashed-experimental.css (opt-in separately; see INSTALLATION.md).
   Does NOT include tokens-legacy.css (opt-in for sub-baseline browsers; loads BEFORE this bundle).
   Generated by bin/build-bundle.sh — do not edit by hand.
   ========================================================================== */

/* ==========================================================================
   SLASHED Tokens — Default — v0.6.22.0
   ========================================================================== */

/* ==========================================================================
   Tokens are scheme-aware via light-dark() and derive from --neutral and
   --neutral-dark. Single source of truth — no separate dark-mode block.
   Browser baseline: Chrome 123+, Firefox 120+, Safari 17.5+, Edge 123+.
   For sub-baseline browsers opt in to tokens-legacy.css (load before this
   file) — it ships static hex values that win when light-dark() is invalid.
   See docs/TOKENS.md for the full token hierarchy and authoring guide.
   ========================================================================== */

/* ===== Typed color tokens via @property — enables CSS transitions on brand colors.
   Chrome 85+, Firefox 128+, Safari 16.4+. initial-value = light-mode default. ===== */

@property --sf-primary   { syntax: '<color>'; inherits: true; initial-value: #2563eb; }
@property --sf-secondary { syntax: '<color>'; inherits: true; initial-value: #0d9488; }
@property --sf-tertiary  { syntax: '<color>'; inherits: true; initial-value: #7c3aed; }
@property --sf-accent    { syntax: '<color>'; inherits: true; initial-value: #f59e0b; }
@property --sf-action    { syntax: '<color>'; inherits: true; initial-value: #0369a1; }
@property --sf-base      { syntax: '<color>'; inherits: true; initial-value: #475569; }
@property --sf-neutral   { syntax: '<color>'; inherits: true; initial-value: #6b7280; }
@property --sf-neutral-dark          { syntax: '<color>'; inherits: true; initial-value: #111827; }
@property --sf-surface-dark-tint-low  { syntax: '<color>'; inherits: true; initial-value: #111827; }
@property --sf-surface-dark-tint-mid  { syntax: '<color>'; inherits: true; initial-value: #1f2937; }
@property --sf-surface-dark-tint-high { syntax: '<color>'; inherits: true; initial-value: #374151; }

/* ⚠️ BRICKS / WORDPRESS REM PROTECTION — (0,2,0) specificity defeats 62.5% root resets;
   max(16px, 1em) preserves user font-size preferences. Keep separate from :root. */
:root:root { font-size: max(16px, 1em); }

:root {
  /* Intentional duplicate of slashed-core.css html { color-scheme }.
     Both files must be self-contained — each works without the other. */
  color-scheme: light dark;

  /* ===== Colors — override on :root in a consumer stylesheet.
     See docs/TOKENS.md and css/tokens-user.example.css. ===== */

  --sf-primary:   light-dark(#2563eb, #5b8def);
  --sf-secondary: light-dark(#0d9488, #2dd4bf);
  --sf-tertiary:  light-dark(#7c3aed, #a78bfa);
  --sf-accent:    light-dark(#f59e0b, #fbbf24);
  --sf-action:    light-dark(#0369a1, #38bdf8);
  --sf-base:      light-dark(#475569, #94a3b8);
  --sf-neutral:   light-dark(#6b7280, #9ca3af);

  /* Dark-mode anchor for the neutral scale. The dark args of --neutral-50 …
     --neutral-400 mix var(--sf-neutral) against this anchor (steps 600–950 mix
     against white). Override --neutral AND --neutral-dark to fully retheme
     the dark palette from one place. Dark anchor must be a static color
     (not light-dark()) — light-dark() inside the dark arg of another
     light-dark() resolves circularly. */
  --sf-neutral-dark: #111827;

  /* Brand-tint dark surface anchors.
     Brand -50/-100/-200 dark args mix against these three steps instead of
     hardcoded hexes. Override all three together to retune all brand-tinted
     backgrounds in dark mode in one step. These are intentionally separate
     from --neutral-dark; the neutral scale uses --neutral-dark directly
     (darker anchor), while brand tints use a graduated surface range. */
  --sf-surface-dark-tint-low:  #111827;   /* darkest — brand -50 dark arg  */
  --sf-surface-dark-tint-mid:  #1f2937;   /* middle  — brand -100 dark arg */
  --sf-surface-dark-tint-high: #374151;   /* lightest — brand -200 dark arg */

  /* ===== Action interaction tokens =====
     Hover/active directions flip in dark mode (toward white instead of black).
     Override --action per project without touching --primary.
     Paired text token: update --color-text-on-action if --action becomes a light hue.
     TODO: replace with CSS if() auto-pair when baseline (csswg #10064). ===== */

  --sf-action-hover:       light-dark(color-mix(in oklch, var(--sf-action) 85%, black),
                                   color-mix(in oklch, var(--sf-action) 85%, white));
  --sf-action-active:      light-dark(color-mix(in oklch, var(--sf-action) 75%, black),
                                   color-mix(in oklch, var(--sf-action) 75%, white));
  --sf-action-destructive: light-dark(color-mix(in oklch, var(--sf-error)  80%, black),
                                   color-mix(in oklch, var(--sf-error)  85%, white));

  /* ===== Native form control accent =====
     Hue used by checkbox/radio/range/progress when the UA renders them.
     Defaults to --action; override per project to flip every native
     control with one token. Consumed globally by `accent-color` in slashed-core.css. */
  --sf-accent-color: var(--sf-action);

  /* ===== Required-field indicator =====
     Content rendered after a label that precedes a [required] field.
     Override to localize (e.g. " (required)") or set to empty to hide. */
  --sf-required-mark: " *";
  --sf-caret-color:   var(--sf-action);  /* text-insertion cursor in form inputs */

  --sf-success: light-dark(#16a34a, #4ade80);
  /* ⚠️ --warning on white: ~2.8:1 — fails WCAG for text. Use --warning-600 for text,
     --warning-100 background with --warning-600 text for accessible warning messages. */
  --sf-warning: light-dark(#eab308, #facc15);
  --sf-error:   light-dark(#dc2626, #f87171);
  --sf-info:    light-dark(#0ea5e9, #38bdf8);

  /* ===== Primary shades (auto-update from --primary) =====
     -100/-200 flip in dark mode; -300/-400 are light tints; -600 through -950 are dark shades.
     ===== */

  --sf-primary-50:  light-dark(color-mix(in oklch, var(--sf-primary) 5%,  white),
                            color-mix(in oklch, var(--sf-primary) 10%, var(--sf-surface-dark-tint-low)));
  --sf-primary-100: light-dark(color-mix(in oklch, var(--sf-primary) 10%, white),
                            color-mix(in oklch, var(--sf-primary) 20%, var(--sf-surface-dark-tint-mid)));
  --sf-primary-200: light-dark(color-mix(in oklch, var(--sf-primary) 25%, white),
                            color-mix(in oklch, var(--sf-primary) 35%, var(--sf-surface-dark-tint-high)));
  --sf-primary-300: color-mix(in oklch, var(--sf-primary) 45%, white);
  --sf-primary-400: color-mix(in oklch, var(--sf-primary) 70%, white);
  --sf-primary-600: color-mix(in oklch, var(--sf-primary) 80%, black);
  --sf-primary-700: color-mix(in oklch, var(--sf-primary) 60%, black);
  --sf-primary-800: color-mix(in oklch, var(--sf-primary) 40%, black);
  --sf-primary-900: color-mix(in oklch, var(--sf-primary) 25%, black);
  --sf-primary-950: color-mix(in oklch, var(--sf-primary) 15%, black);
  --sf-primary-hover: light-dark(color-mix(in oklch, var(--sf-primary) 85%, black),
                              color-mix(in oklch, var(--sf-primary) 85%, white));
  /* Alpha variants use srgb intentionally — matches browser/Figma opacity convention
     and avoids oklch hue-shift artefacts on semi-transparent overlays. */
  --sf-primary-a25: color-mix(in srgb, var(--sf-primary) 25%, transparent);
  --sf-primary-a50: color-mix(in srgb, var(--sf-primary) 50%, transparent);

  /* ===== Secondary shades ===== */

  --sf-secondary-50:  light-dark(color-mix(in oklch, var(--sf-secondary) 5%,  white),
                              color-mix(in oklch, var(--sf-secondary) 10%, var(--sf-surface-dark-tint-low)));
  --sf-secondary-100: light-dark(color-mix(in oklch, var(--sf-secondary) 10%, white),
                              color-mix(in oklch, var(--sf-secondary) 20%, var(--sf-surface-dark-tint-mid)));
  --sf-secondary-200: light-dark(color-mix(in oklch, var(--sf-secondary) 25%, white),
                              color-mix(in oklch, var(--sf-secondary) 35%, var(--sf-surface-dark-tint-high)));
  --sf-secondary-300: color-mix(in oklch, var(--sf-secondary) 45%, white);
  --sf-secondary-400: color-mix(in oklch, var(--sf-secondary) 70%, white);
  --sf-secondary-600: color-mix(in oklch, var(--sf-secondary) 80%, black);
  --sf-secondary-700: color-mix(in oklch, var(--sf-secondary) 60%, black);
  --sf-secondary-800: color-mix(in oklch, var(--sf-secondary) 40%, black);
  --sf-secondary-900: color-mix(in oklch, var(--sf-secondary) 25%, black);
  --sf-secondary-950: color-mix(in oklch, var(--sf-secondary) 15%, black);
  --sf-secondary-hover: light-dark(color-mix(in oklch, var(--sf-secondary) 85%, black),
                                color-mix(in oklch, var(--sf-secondary) 85%, white));
  /* Alpha variants — srgb intentionally, matches browser/Figma opacity convention */
  --sf-secondary-a25: color-mix(in srgb, var(--sf-secondary) 25%, transparent);
  --sf-secondary-a50: color-mix(in srgb, var(--sf-secondary) 50%, transparent);

  /* ===== Accent shades ===== */

  --sf-accent-50:  light-dark(color-mix(in oklch, var(--sf-accent) 5%,  white),
                           color-mix(in oklch, var(--sf-accent) 10%, var(--sf-surface-dark-tint-low)));
  --sf-accent-100: light-dark(color-mix(in oklch, var(--sf-accent) 10%, white),
                           color-mix(in oklch, var(--sf-accent) 20%, var(--sf-surface-dark-tint-mid)));
  --sf-accent-200: light-dark(color-mix(in oklch, var(--sf-accent) 25%, white),
                           color-mix(in oklch, var(--sf-accent) 35%, var(--sf-surface-dark-tint-high)));
  --sf-accent-300: color-mix(in oklch, var(--sf-accent) 45%, white);
  --sf-accent-400: color-mix(in oklch, var(--sf-accent) 70%, white);
  --sf-accent-600: color-mix(in oklch, var(--sf-accent) 80%, black);
  --sf-accent-700: color-mix(in oklch, var(--sf-accent) 60%, black);
  --sf-accent-800: color-mix(in oklch, var(--sf-accent) 40%, black);
  --sf-accent-900: color-mix(in oklch, var(--sf-accent) 25%, black);
  --sf-accent-950: color-mix(in oklch, var(--sf-accent) 15%, black);
  --sf-accent-hover: light-dark(color-mix(in oklch, var(--sf-accent) 85%, black),
                             color-mix(in oklch, var(--sf-accent) 85%, white));
  /* Alpha variants — srgb intentionally, matches browser/Figma opacity convention */
  --sf-accent-a25: color-mix(in srgb, var(--sf-accent) 25%, transparent);
  --sf-accent-a50: color-mix(in srgb, var(--sf-accent) 50%, transparent);

  /* ===== Tertiary shades ===== */

  --sf-tertiary-50:  light-dark(color-mix(in oklch, var(--sf-tertiary) 5%,  white),
                             color-mix(in oklch, var(--sf-tertiary) 10%, var(--sf-surface-dark-tint-low)));
  --sf-tertiary-100: light-dark(color-mix(in oklch, var(--sf-tertiary) 10%, white),
                             color-mix(in oklch, var(--sf-tertiary) 20%, var(--sf-surface-dark-tint-mid)));
  --sf-tertiary-200: light-dark(color-mix(in oklch, var(--sf-tertiary) 25%, white),
                             color-mix(in oklch, var(--sf-tertiary) 35%, var(--sf-surface-dark-tint-high)));
  --sf-tertiary-300: color-mix(in oklch, var(--sf-tertiary) 45%, white);
  --sf-tertiary-400: color-mix(in oklch, var(--sf-tertiary) 70%, white);
  --sf-tertiary-600: color-mix(in oklch, var(--sf-tertiary) 80%, black);
  --sf-tertiary-700: color-mix(in oklch, var(--sf-tertiary) 60%, black);
  --sf-tertiary-800: color-mix(in oklch, var(--sf-tertiary) 40%, black);
  --sf-tertiary-900: color-mix(in oklch, var(--sf-tertiary) 25%, black);
  --sf-tertiary-950: color-mix(in oklch, var(--sf-tertiary) 15%, black);
  --sf-tertiary-hover: light-dark(color-mix(in oklch, var(--sf-tertiary) 85%, black),
                               color-mix(in oklch, var(--sf-tertiary) 85%, white));
  /* Alpha variants — srgb intentionally, matches browser/Figma opacity convention */
  --sf-tertiary-a25: color-mix(in srgb, var(--sf-tertiary) 25%, transparent);
  --sf-tertiary-a50: color-mix(in srgb, var(--sf-tertiary) 50%, transparent);

  /* ===== Action shades ===== */

  --sf-action-50:  light-dark(color-mix(in oklch, var(--sf-action) 5%,  white),
                           color-mix(in oklch, var(--sf-action) 10%, var(--sf-surface-dark-tint-low)));
  --sf-action-100: light-dark(color-mix(in oklch, var(--sf-action) 10%, white),
                           color-mix(in oklch, var(--sf-action) 20%, var(--sf-surface-dark-tint-mid)));
  --sf-action-200: light-dark(color-mix(in oklch, var(--sf-action) 25%, white),
                           color-mix(in oklch, var(--sf-action) 35%, var(--sf-surface-dark-tint-high)));
  --sf-action-300: color-mix(in oklch, var(--sf-action) 45%, white);
  --sf-action-400: color-mix(in oklch, var(--sf-action) 70%, white);
  --sf-action-600: color-mix(in oklch, var(--sf-action) 80%, black);
  --sf-action-700: color-mix(in oklch, var(--sf-action) 60%, black);
  --sf-action-800: color-mix(in oklch, var(--sf-action) 40%, black);
  --sf-action-900: color-mix(in oklch, var(--sf-action) 25%, black);
  --sf-action-950: color-mix(in oklch, var(--sf-action) 15%, black);
  /* Alpha variants — srgb intentionally */
  --sf-action-a25: color-mix(in srgb, var(--sf-action) 25%, transparent);
  --sf-action-a50: color-mix(in srgb, var(--sf-action) 50%, transparent);

  /* ===== Base shades ===== */

  --sf-base-50:  light-dark(color-mix(in oklch, var(--sf-base) 5%,  white),
                         color-mix(in oklch, var(--sf-base) 10%, var(--sf-surface-dark-tint-low)));
  --sf-base-100: light-dark(color-mix(in oklch, var(--sf-base) 10%, white),
                         color-mix(in oklch, var(--sf-base) 20%, var(--sf-surface-dark-tint-mid)));
  --sf-base-200: light-dark(color-mix(in oklch, var(--sf-base) 25%, white),
                         color-mix(in oklch, var(--sf-base) 35%, var(--sf-surface-dark-tint-high)));
  --sf-base-300: color-mix(in oklch, var(--sf-base) 45%, white);
  --sf-base-400: color-mix(in oklch, var(--sf-base) 70%, white);
  --sf-base-600: color-mix(in oklch, var(--sf-base) 80%, black);
  --sf-base-700: color-mix(in oklch, var(--sf-base) 60%, black);
  --sf-base-800: color-mix(in oklch, var(--sf-base) 40%, black);
  --sf-base-900: color-mix(in oklch, var(--sf-base) 25%, black);
  --sf-base-950: color-mix(in oklch, var(--sf-base) 15%, black);
  --sf-base-hover: light-dark(color-mix(in oklch, var(--sf-base) 85%, black),
                           color-mix(in oklch, var(--sf-base) 85%, white));
  /* Alpha variants — srgb intentionally */
  --sf-base-a25: color-mix(in srgb, var(--sf-base) 25%, transparent);
  --sf-base-a50: color-mix(in srgb, var(--sf-base) 50%, transparent);

  /* ===== Status shades — functional 4-step ramp (-100, -200, -600, -700).
     Status colors are FUNCTIONAL not decorative; they don't ship the full
     -50…-950 brand-color ramp. Use:
       -100 : subtle background (alert/badge fill)
       -200 : border (alert/filled badge edge)
       -600 : accessible text on light bg
       -700 : hover / active text on light bg (deeper emphasis)
     Each shade uses light-dark() so it flips to a contrast-correct value
     in dark mode. ===== */

  --sf-success-100: light-dark(color-mix(in oklch, var(--sf-success) 10%, white),
                            color-mix(in oklch, var(--sf-success) 20%, var(--sf-surface-dark-tint-mid)));
  --sf-success-200: light-dark(color-mix(in oklch, var(--sf-success) 25%, white),
                            color-mix(in oklch, var(--sf-success) 35%, var(--sf-surface-dark-tint-high)));
  --sf-success-600: light-dark(color-mix(in oklch, var(--sf-success) 80%, black),
                            color-mix(in oklch, var(--sf-success) 40%, white));
  --sf-success-700: light-dark(color-mix(in oklch, var(--sf-success) 90%, black),
                            color-mix(in oklch, var(--sf-success) 30%, white));

  --sf-warning-100: light-dark(color-mix(in oklch, var(--sf-warning) 10%, white),
                            color-mix(in oklch, var(--sf-warning) 20%, var(--sf-surface-dark-tint-mid)));
  --sf-warning-200: light-dark(color-mix(in oklch, var(--sf-warning) 25%, white),
                            color-mix(in oklch, var(--sf-warning) 35%, var(--sf-surface-dark-tint-high)));
  --sf-warning-600: light-dark(color-mix(in oklch, var(--sf-warning) 80%, black),
                            color-mix(in oklch, var(--sf-warning) 40%, white));
  --sf-warning-700: light-dark(color-mix(in oklch, var(--sf-warning) 90%, black),
                            color-mix(in oklch, var(--sf-warning) 30%, white));

  --sf-error-100: light-dark(color-mix(in oklch, var(--sf-error) 10%, white),
                          color-mix(in oklch, var(--sf-error) 20%, var(--sf-surface-dark-tint-mid)));
  --sf-error-200: light-dark(color-mix(in oklch, var(--sf-error) 25%, white),
                          color-mix(in oklch, var(--sf-error) 35%, var(--sf-surface-dark-tint-high)));
  --sf-error-600: light-dark(color-mix(in oklch, var(--sf-error) 80%, black),
                          color-mix(in oklch, var(--sf-error) 40%, white));
  --sf-error-700: light-dark(color-mix(in oklch, var(--sf-error) 90%, black),
                          color-mix(in oklch, var(--sf-error) 30%, white));

  --sf-info-100: light-dark(color-mix(in oklch, var(--sf-info) 10%, white),
                         color-mix(in oklch, var(--sf-info) 20%, var(--sf-surface-dark-tint-mid)));
  --sf-info-200: light-dark(color-mix(in oklch, var(--sf-info) 25%, white),
                         color-mix(in oklch, var(--sf-info) 35%, var(--sf-surface-dark-tint-high)));
  --sf-info-600: light-dark(color-mix(in oklch, var(--sf-info) 80%, black),
                         color-mix(in oklch, var(--sf-info) 40%, white));
  --sf-info-700: light-dark(color-mix(in oklch, var(--sf-info) 90%, black),
                         color-mix(in oklch, var(--sf-info) 30%, white));

  /* ===== Neutral shades — override --neutral and --neutral-dark on :root to retune the scale. */

  --sf-neutral-50:  light-dark(color-mix(in oklch, var(--sf-neutral) 5%,  white),
                            var(--sf-neutral-dark));
  --sf-neutral-100: light-dark(color-mix(in oklch, var(--sf-neutral) 10%, white),
                            color-mix(in oklch, var(--sf-neutral) 15%, var(--sf-neutral-dark)));
  --sf-neutral-200: light-dark(color-mix(in oklch, var(--sf-neutral) 25%, white),
                            color-mix(in oklch, var(--sf-neutral) 30%, var(--sf-neutral-dark)));
  --sf-neutral-300: light-dark(color-mix(in oklch, var(--sf-neutral) 45%, white),
                            color-mix(in oklch, var(--sf-neutral) 50%, var(--sf-neutral-dark)));
  --sf-neutral-400: light-dark(color-mix(in oklch, var(--sf-neutral) 70%, white),
                            color-mix(in oklch, var(--sf-neutral) 70%, var(--sf-neutral-dark)));
  --sf-neutral-500: var(--sf-neutral);
  --sf-neutral-600: light-dark(color-mix(in oklch, var(--sf-neutral) 80%, black),
                            color-mix(in oklch, var(--sf-neutral) 80%, white));
  --sf-neutral-700: light-dark(color-mix(in oklch, var(--sf-neutral) 60%, black),
                            color-mix(in oklch, var(--sf-neutral) 60%, white));
  --sf-neutral-800: light-dark(color-mix(in oklch, var(--sf-neutral) 40%, black),
                            color-mix(in oklch, var(--sf-neutral) 40%, white));
  --sf-neutral-900: light-dark(color-mix(in oklch, var(--sf-neutral) 25%, black),
                            color-mix(in oklch, var(--sf-neutral) 25%, white));
  --sf-neutral-950: light-dark(color-mix(in oklch, var(--sf-neutral) 15%, black),
                            color-mix(in oklch, var(--sf-neutral) 10%, white));
  --sf-neutral-hover: light-dark(color-mix(in oklch, var(--sf-neutral) 85%, black),
                              color-mix(in oklch, var(--sf-neutral) 85%, white));
  /* Alpha variants — srgb intentionally */
  --sf-neutral-a25: color-mix(in srgb, var(--sf-neutral) 25%, transparent);
  --sf-neutral-a50: color-mix(in srgb, var(--sf-neutral) 50%, transparent);

  /* ===== Semantic aliases — role-based names over neutral primitives. See docs/TOKENS.md. ===== */

  --sf-color-bg:                   var(--sf-neutral-50);
  --sf-color-surface:              light-dark(#ffffff, var(--sf-neutral-100));
  --sf-color-surface-2:            light-dark(var(--sf-neutral-100), var(--sf-neutral-200));
  --sf-color-surface-3:            light-dark(var(--sf-neutral-200), var(--sf-neutral-300));
  --sf-color-surface-4:            light-dark(var(--sf-neutral-300), var(--sf-neutral-400));
  --sf-color-surface-elevated:     light-dark(#ffffff, var(--sf-neutral-200));
  --sf-color-surface-overlay:      light-dark(color-mix(in srgb, white                  90%, transparent),
                                           color-mix(in srgb, var(--sf-neutral-dark)    90%, transparent));
  --sf-color-border:               var(--sf-neutral-200);
  --sf-color-border-subtle:        var(--sf-neutral-100);
  --sf-color-border-strong:        var(--sf-neutral-400);
  --sf-color-text:                 light-dark(var(--sf-neutral-900), var(--sf-neutral-800));
  --sf-color-text-secondary:       light-dark(var(--sf-neutral-700), var(--sf-neutral-600));
  --sf-color-text-muted:           light-dark(var(--sf-neutral-600), var(--sf-neutral-500));
  --sf-color-text-decorative:      var(--sf-neutral-400);
  --sf-color-text-disabled:        var(--sf-neutral-300); /* intentionally below WCAG AA — disabled elements are exempt */
  /* ⚠️ --sf-color-text-decorative: ~3.4:1 — intentionally below WCAG AA. For decorative/idle states only; use --color-text-muted for body text. */
  --sf-color-text-on-primary:      light-dark(#ffffff, var(--sf-neutral-dark));
  --sf-color-text-on-secondary:    light-dark(#ffffff, var(--sf-neutral-dark));
  --sf-color-text-on-tertiary:     light-dark(#ffffff, var(--sf-neutral-dark));
  --sf-color-text-on-accent:       var(--sf-neutral-dark); /* same in both modes — accent stays dark text */
  --sf-color-text-on-action:       light-dark(#ffffff, var(--sf-neutral-dark)); /* update if --action becomes a light hue */
  --sf-color-text-on-destructive:  light-dark(#ffffff, var(--sf-neutral-dark));
  --sf-color-text-on-base:         light-dark(#ffffff, var(--sf-neutral-dark));
  --sf-color-text-on-neutral:      light-dark(#ffffff, var(--sf-neutral-dark));
  --sf-color-text-on-dark:         #f3f4f6; /* always near-white — semantic is "text on a dark surface" regardless of theme */
  --sf-color-text-on-light:        var(--sf-neutral-dark); /* always near-black — symmetric partner to -on-dark; for text on a light surface regardless of theme */
  --sf-overlay-opacity:            0.5;  /* override per project or per instance */
  --sf-color-backdrop:             oklch(0 0 0 / var(--sf-overlay-opacity));
  --sf-color-selection:            light-dark(var(--sf-primary-a25), var(--sf-primary-a50));
  --sf-color-selection-text:       inherit;
  --sf-color-link:                 var(--sf-primary);
  --sf-color-link-visited:         light-dark(var(--sf-primary-800), var(--sf-primary-200));
  --sf-color-link-hover:           light-dark(var(--sf-primary-700), var(--sf-primary-300));
  --sf-color-link-active:          light-dark(var(--sf-primary-800), var(--sf-primary-200));
  --sf-color-text-body:            var(--sf-color-text);
  --sf-color-placeholder:          var(--sf-color-text-decorative);
  --sf-color-text-on-success:      light-dark(white, var(--sf-neutral-dark));
  --sf-color-text-on-warning:      var(--sf-neutral-dark); /* same in both modes — warning stays dark text */
  --sf-color-text-on-error:        light-dark(white, var(--sf-neutral-dark));
  --sf-color-text-on-info:         var(--sf-neutral-dark); /* same in both modes — info stays dark text */

  /* ===== Status semantic aliases — safe-default pairs ===========================
     Reach for these instead of raw --sf-warning / --sf-error / etc., which fail
     WCAG AA on light backgrounds (~2.8:1 for warning). These point at the
     accessible -100 / -600 functional shades and inherit dark-mode flip
     transparently via the underlying light-dark() definitions. ============== */

  --sf-color-success-bg:   var(--sf-success-100);
  --sf-color-warning-bg:   var(--sf-warning-100);
  --sf-color-error-bg:     var(--sf-error-100);
  --sf-color-info-bg:      var(--sf-info-100);
  --sf-color-success-text: var(--sf-success-600);
  --sf-color-warning-text: var(--sf-warning-600);
  --sf-color-error-text:   var(--sf-error-600);
  --sf-color-info-text:    var(--sf-info-600);

  /* ===== Scrollbar ===== */

  --sf-color-scrollbar-thumb:  var(--sf-neutral-400);
  --sf-color-scrollbar-track:  transparent;
  --sf-scrollbar-size:         6px;
  --sf-scrollbar-radius:       var(--sf-radius-full);

  /* ===== Spacing (fluid, base 16→24px, 320→1440px) ===== */

  --sf-space-px:   1px;
  --sf-space-micro: 0.125rem; /* 2px — micro-adjustments, icon alignment */
  --sf-space-scale: 1; /* unitless multiplier — scales the entire fluid space system */
  --sf-space-2xs: clamp(calc(0.25rem  * var(--sf-space-scale)), calc((0.21rem  + 0.18vw) * var(--sf-space-scale)), calc(0.375rem * var(--sf-space-scale)));
  --sf-space-xs:  clamp(calc(0.5rem   * var(--sf-space-scale)), calc((0.43rem  + 0.36vw) * var(--sf-space-scale)), calc(0.75rem  * var(--sf-space-scale)));
  --sf-space-s:   clamp(calc(0.75rem  * var(--sf-space-scale)), calc((0.64rem  + 0.54vw) * var(--sf-space-scale)), calc(1.125rem * var(--sf-space-scale)));
  --sf-space-m:   clamp(calc(1rem     * var(--sf-space-scale)), calc((0.86rem  + 0.71vw) * var(--sf-space-scale)), calc(1.5rem   * var(--sf-space-scale)));
  --sf-space-l:   clamp(calc(1.5rem   * var(--sf-space-scale)), calc((1.29rem  + 1.07vw) * var(--sf-space-scale)), calc(2.25rem  * var(--sf-space-scale)));
  --sf-space-xl:  clamp(calc(2rem     * var(--sf-space-scale)), calc((1.71rem  + 1.43vw) * var(--sf-space-scale)), calc(3rem     * var(--sf-space-scale)));
  --sf-space-2xl: clamp(calc(3rem     * var(--sf-space-scale)), calc((2.57rem  + 2.14vw) * var(--sf-space-scale)), calc(4.5rem   * var(--sf-space-scale)));
  --sf-space-3xl: clamp(calc(4rem     * var(--sf-space-scale)), calc((3.43rem  + 2.86vw) * var(--sf-space-scale)), calc(6rem     * var(--sf-space-scale)));
  --sf-space-4xl: clamp(calc(6rem     * var(--sf-space-scale)), calc((5.14rem  + 4.29vw) * var(--sf-space-scale)), calc(9rem     * var(--sf-space-scale)));

  /* Semantic spacing aliases — intentional API surface, not redundant.
     Retune the whole system by editing these (e.g. --space-gap once
     to make every layout primitive's gap tighter). See docs/TOKENS.md. */
  --sf-space-section: var(--sf-space-3xl); /* `.sf-section` padding-block */
  --sf-space-content: var(--sf-space-l);   /* `.sf-flow`/`.sf-stack`/`.sf-prose` rhythm */
  --sf-space-gap:     var(--sf-space-m);   /* default gap in layout primitives */
  --sf-space-gutter:  clamp(calc(1rem * var(--sf-space-scale)), calc((0.5rem + 2vw) * var(--sf-space-scale)), calc(2rem * var(--sf-space-scale))); /* page-edge gutter (own clamp, not alias) */
  --sf-space-section-gap:   var(--sf-space-3xl); /* gap between top-level page sections */
  --sf-space-component-gap: var(--sf-space-l);   /* internal padding of cards, modals, panels */

  /* ===== Typography (fluid, 375→1600px, body 17→20px, ratio ~1.25) =====
     Calibrated for viewport range 375px (modern phone) → 1600px (desktop).
     Formula: clamp(minRem, bRem + cVw, maxRem)
       c = 100 × (maxPx − minPx) / (1600 − 375) = (maxPx − minPx) / 12.25
       b = (minPx − c × 3.75) / 16
     Headings now grow continuously up to 1600px (old scale froze at ~1150px).
     Minimums raised: text-2xs was 10px, text-xs 11px — both now at least 11/12px.
     Body minimum raised 16→17px for better mobile readability. ===== */

  --sf-text-scale: 1; /* unitless multiplier — scales the entire fluid type system */
  --sf-text-2xs: clamp(calc(0.6875rem * var(--sf-text-scale)), calc((0.668rem  + 0.082vw) * var(--sf-text-scale)), calc(0.75rem   * var(--sf-text-scale)));  /* 11→12px */
  --sf-text-xs:  clamp(calc(0.75rem   * var(--sf-text-scale)), calc((0.712rem  + 0.163vw) * var(--sf-text-scale)), calc(0.875rem  * var(--sf-text-scale)));  /* 12→14px */
  --sf-text-s:   clamp(calc(0.875rem  * var(--sf-text-scale)), calc((0.837rem  + 0.163vw) * var(--sf-text-scale)), calc(1rem      * var(--sf-text-scale)));   /* 14→16px */
  --sf-text-m:   clamp(calc(1.0625rem * var(--sf-text-scale)), calc((1rem      + 0.25vw)  * var(--sf-text-scale)), calc(1.25rem   * var(--sf-text-scale)));   /* 17→20px */
  --sf-text-l:   clamp(calc(1.3125rem * var(--sf-text-scale)), calc((1.236rem  + 0.327vw) * var(--sf-text-scale)), calc(1.5625rem * var(--sf-text-scale)));  /* 21→25px */
  --sf-text-xl:  clamp(calc(1.5625rem * var(--sf-text-scale)), calc((1.429rem  + 0.571vw) * var(--sf-text-scale)), calc(2rem      * var(--sf-text-scale)));   /* 25→32px */
  --sf-text-2xl: clamp(calc(2rem      * var(--sf-text-scale)), calc((1.847rem  + 0.653vw) * var(--sf-text-scale)), calc(2.5rem    * var(--sf-text-scale)));   /* 32→40px */
  --sf-text-3xl: clamp(calc(2.5rem    * var(--sf-text-scale)), calc((2.232rem  + 1.143vw) * var(--sf-text-scale)), calc(3.375rem  * var(--sf-text-scale)));  /* 40→54px */
  --sf-text-4xl: clamp(calc(3.125rem  * var(--sf-text-scale)), calc((2.704rem  + 1.796vw) * var(--sf-text-scale)), calc(4.5rem    * var(--sf-text-scale)));  /* 50→72px */
  --sf-text-5xl: clamp(calc(4rem      * var(--sf-text-scale)), calc((3.388rem  + 2.612vw) * var(--sf-text-scale)), calc(6rem      * var(--sf-text-scale)));   /* 64→96px */
  /* text-fluid-hero: viewport-relative heading for full-bleed hero sections.
     3rem = minimum, 10vw = preferred (viewport-relative), 12rem = maximum.
     Use only on single-line display text — body text would be inaccessible at this scale. */
  --sf-text-fluid-hero: clamp(calc(3rem * var(--sf-text-scale)), calc(10vw * var(--sf-text-scale)), calc(12rem * var(--sf-text-scale)));

  /* Heading size aliases — semantic shorthand for the type scale.
     var(--sf-h2) reads as intent in BEM rules; var(--sf-text-3xl) reads as
     position on a scale. Both work, but the alias layer is the
     framework's contract — rebind --hN to a different scale step to
     retune heading sizes globally without touching component rules.
     See docs/TOKENS.md "Why aliases exist". */
  --sf-h1: var(--sf-text-4xl);
  --sf-h2: var(--sf-text-3xl);
  --sf-h3: var(--sf-text-2xl);
  --sf-h4: var(--sf-text-xl);
  --sf-h5: var(--sf-text-l);
  --sf-h6: var(--sf-text-m);

  /* Semantic text-size aliases — intent-named shortcuts below the heading scale */
  --sf-text-body:    var(--sf-text-m);    /* default body copy */
  --sf-text-small:   var(--sf-text-s);    /* helper text, table cells, secondary labels */
  --sf-text-caption: var(--sf-text-xs);   /* captions, timestamps, metadata */
  --sf-text-micro:   var(--sf-text-2xs);  /* legal, footnotes — use sparingly */

  --sf-font-body:    ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
  --sf-font-heading: var(--sf-font-body);
  --sf-font-mono:    ui-monospace, 'Cascadia Code', 'Source Code Pro', Menlo, Consolas, 'DejaVu Sans Mono', monospace;

  /* font-weight named tokens */
  --sf-font-weight-light:     300;
  --sf-font-weight-heading:   700;
  --sf-font-weight-body:      400;
  --sf-font-weight-medium:    500;
  --sf-font-weight-semi:      600;
  --sf-font-weight-bold:      700;  /* inline strong/.sf-font-bold — decoupled from heading weight */
  --sf-font-weight-extrabold: 800;
  --sf-font-weight-black:     900;

  --sf-leading-tight:  1.2;
  --sf-leading-snug:   1.35;
  --sf-leading-normal: 1.5;
  --sf-leading-loose:  1.75;

  /* Semantic leading aliases — intent-named shortcuts over the abstract scale */
  --sf-leading-display: var(--sf-leading-tight);   /* headlines, display text */
  --sf-leading-ui:      var(--sf-leading-snug);    /* buttons, labels, navigation */
  --sf-leading-prose:   var(--sf-leading-normal);  /* body copy, long-form text */

  --sf-tracking-tighter: -0.05em;
  --sf-tracking-tight:   -0.02em;
  --sf-tracking-normal:   0em;     /* center anchor — default browser tracking */
  --sf-tracking-wide:     0.025em;
  --sf-tracking-wider:    0.05em;
  --sf-tracking-widest:   0.1em;

  /* Semantic tracking aliases — intent-named shortcuts over the abstract scale */
  --sf-tracking-heading: var(--sf-tracking-tight);    /* large display headings — tighter for visual density */
  --sf-tracking-eyebrow: var(--sf-tracking-widest);   /* all-caps labels, eyebrows, section tags */
  --sf-tracking-ui:      var(--sf-tracking-normal);   /* UI text — no tracking; improves readability at small sizes */

  /* ===== Icon sizes (em — scales with surrounding font-size) =====
     --icon-l is the default used by [data-icon] (via --sf-icon-size fallback).
     Use --icon-s for inline text icons, --icon-l for standalone UI icons. */

  --sf-icon-xs: 0.75em;
  --sf-icon-s:  1em;
  --sf-icon-m:  1.25em;
  --sf-icon-l:  1.5em;
  --sf-icon-xl: 2em;

  /* ===== Radius ===== */

  --sf-radius-xs:   0.125rem;
  --sf-radius-s:    0.25rem;
  --sf-radius-m:    0.5rem;
  --sf-radius-l:    0.75rem;
  --sf-radius-xl:   1rem;
  --sf-radius-2xl:  1.5rem;
  --sf-radius-full: 9999px;

  /* ===== Border ===== */

  --sf-border-width-thin: 0.5px; /* hairline — retina/HiDPI only; renders as 1px on 1x screens */
  --sf-border-width-1:    1px;
  --sf-border-width-2:    2px;
  --sf-border-width-4:    4px;
  --sf-border-style:      solid;

  /* ===== Shadows — calc()-based, dark mode overrides only --shadow-strength ===== */

  --sf-shadow-strength:   0.04;  /* light mode base opacity multiplier */
  --sf-shadow-strength-2: 0.08;  /* stronger layers */

  --sf-shadow-2xs:   0 1px 2px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength) * 0.375));
  --sf-shadow-xs:    0 1px 2px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength) * 0.75));
  --sf-shadow-s:     0 1px 2px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength) * 0.5)),
                  0 2px 6px 0 rgb(0 0 0 / var(--sf-shadow-strength));
  --sf-shadow-m:     0 1px 3px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength) * 0.5)),
                  0 4px 12px 0 rgb(0 0 0 / var(--sf-shadow-strength-2));
  --sf-shadow-l:     0 2px 4px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength) * 0.4)),
                  0 8px 24px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength-2) * 1.5)),
                  0 16px 48px 0 rgb(0 0 0 / var(--sf-shadow-strength-2));
  --sf-shadow-xl:    0 2px 8px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength) * 0.4)),
                  0 12px 36px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength-2) * 1.75)),
                  0 24px 72px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength-2) * 1.25));
  --sf-shadow-float: 0 4px 12px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength) * 0.5)),
                  0 16px 48px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength-2) * 1.75)),
                  0 32px 80px -8px rgb(0 0 0 / calc(var(--sf-shadow-strength-2) * 2));
  /* inner: inset shadow for pressed states and inset UI elements */
  --sf-shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / calc(var(--sf-shadow-strength) * 1.5));
  /* glow: colored ambient glow — set --glow-color per component for brand-colored glow */
  --sf-shadow-glow:  0 0 0 3px var(--sf-glow-color, var(--sf-primary-a25)),
                  0 0 20px 0 var(--sf-glow-color, var(--sf-primary-a25));
  /* colored: brand-colored drop shadow. Set --shadow-color per component:
     style="--shadow-color: var(--sf-primary-a50)" */
  --sf-shadow-colored: 0 4px 12px 0 var(--sf-shadow-color, var(--sf-primary-a25)),
                    0 8px 24px 0 var(--sf-shadow-color, var(--sf-primary-a25));

  /* ===== Drop shadows (filter: drop-shadow) =====
     For SVGs, PNGs with transparency, cutout shapes — box-shadow does not apply to
     element silhouettes, drop-shadow() does. Uses --shadow-strength for dark-mode adaptation.
     Usage: filter: var(--sf-drop-shadow-m); */
  --sf-drop-shadow-xs: drop-shadow(0 1px 1px rgb(0 0 0 / calc(var(--sf-shadow-strength) * 2)));
  --sf-drop-shadow-s:  drop-shadow(0 1px 2px rgb(0 0 0 / calc(var(--sf-shadow-strength) * 3)));
  --sf-drop-shadow-m:  drop-shadow(0 2px 4px rgb(0 0 0 / calc(var(--sf-shadow-strength) * 4)));
  --sf-drop-shadow-l:  drop-shadow(0 4px 8px rgb(0 0 0 / calc(var(--sf-shadow-strength) * 5)));

  /* ===== Text shadows =====
     For display headings and decorative text effects.
     Usage: text-shadow: var(--sf-text-shadow-m); */
  --sf-text-shadow-xs: 0 0.5px 1px rgb(0 0 0 / calc(var(--sf-shadow-strength) * 1.5));
  --sf-text-shadow-s:  0 1px 2px rgb(0 0 0 / calc(var(--sf-shadow-strength) * 3));
  --sf-text-shadow-m:  0 2px 4px rgb(0 0 0 / calc(var(--sf-shadow-strength) * 5));
  --sf-text-shadow-l:  0 4px 8px rgb(0 0 0 / calc(var(--sf-shadow-strength) * 7));

  /* ===== Z-index ===== */
  /* Scale designed to survive WordPress admin bar (z-index: 99999) and common plugins.
     --sf-z-max: 999999 ensures framework UI (toasts, modals) always wins. */

  --sf-z-below:    -1;
  --sf-z-base:      0;
  --sf-z-raised:    1;
  --sf-z-docked:   10;
  --sf-z-above:    100;   /* elements that must clear docked but not compete with sticky UI (e.g. inline popovers) */
  --sf-z-sticky:   1100;  /* intentionally below WP admin bar (99999) — only --z-max beats the admin bar */
  --sf-z-dropdown: 1150; /* above sticky so menus opened from sticky headers overlay adjacent sticky sections */
  --sf-z-banner:   1200;
  --sf-z-overlay:  1300;
  --sf-z-modal:    1400;
  --sf-z-popover:  1500;
  --sf-z-toast:    1700;
  --sf-z-tooltip:  1800;
  --sf-z-max:      999999;
  --sf-z-step:     10; /* relative stacking buffer — z-index: calc(var(--sf-z-modal) + var(--sf-z-step)) */

  /* ===== Aspect-ratio reference values =====
     For use in consumer BEM blocks: `aspect-ratio: var(--sf-ratio-video)`.
     Same purpose as the .aspect-* utilities, but available where a utility
     class is overkill (e.g. inside a component declaration). */
  --sf-ratio-video:     16 / 9;
  --sf-ratio-square:    1;
  --sf-ratio-golden:    1.618 / 1;
  --sf-ratio-photo:     3 / 2;
  --sf-ratio-portrait:  3 / 4;
  --sf-ratio-landscape: 4 / 3;

  /* ===== Transitions & easings ===== */

  /* Duration tokens */
  --sf-duration-fast:    150ms;
  --sf-duration-normal:  250ms;
  --sf-duration-slow:    400ms;

  --sf-duration-enter:   var(--sf-duration-normal);
  --sf-duration-exit:    var(--sf-duration-fast);
  --sf-duration-stagger: 80ms; /* for sequential stagger animations */

  --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:  cubic-bezier(0.34, 1.56, 0.64, 1);

  /* Semantic easing aliases — intent-named shortcuts over the technical scale.
     Mirrors the --leading-display/ui/prose pattern for easings.
     --sf-ease-smooth: balanced in-out — menus, modals, page transitions
     --sf-ease-snappy: quick deceleration — UI feedback, button hovers
     --sf-ease-bouncy: cubic-bezier overshoot — playful pop-in effects
     --sf-ease-elastic: true spring via linear() — Baseline 2024, more accurate than cubic-bezier */
  --sf-ease-smooth:  var(--sf-ease-in-out);
  --sf-ease-snappy:  var(--sf-ease-out);
  --sf-ease-bouncy:  var(--sf-ease-spring);
  --sf-ease-elastic: linear(
    0, 0.006, 0.025 2.8%, 0.101 6.1%, 0.539 18.9%, 0.721 25.3%,
    0.849 31.5%, 0.937 38.1%, 0.968 41.8%, 1.003 51.8%, 1.014 59.3%,
    1.011 63.3%, 1 72.3%, 0.998 80%, 1
  );

  /* Spring easing scale via linear() — Baseline 2024.
     Replaces cubic-bezier approximations with true spring-physics curves.
     spring-1: subtle — one gentle overshoot, settles quickly
     spring-2: standard — balanced bounce, good for most UI elements
     spring-3: expressive — pronounced bounce for playful, attention-grabbing motion */
  --sf-ease-spring-1: linear(
    0, 0.009, 0.035 2.1%, 0.141 4.4%, 0.723 12.5%, 0.938 16.2%,
    1.017 19%, 1.035, 1.031 23.5%, 1.007 27.2%, 1
  );
  --sf-ease-spring-2: linear(
    0, 0.007, 0.029 2.2%, 0.118 4.7%, 0.625 12.5%, 0.826 16.4%,
    0.902 18.9%, 0.962 22.4%, 0.991 25.7%, 1.007 29.7%, 1.011 32.9%,
    1.007 36%, 0.998 43%, 1
  );
  --sf-ease-spring-3: linear(
    0, 0.004, 0.016 1.8%, 0.065 3.9%, 0.34 9.4%, 0.609 13.9%,
    0.706 16%, 0.801 18.7%, 0.863 21.5%, 0.898 24.3%, 0.934 30.1%,
    0.951 34.1%, 0.961 38.5%, 0.97 48.3%, 1.001 63.3%,
    1.005 70.7%, 1.005 79.4%, 1
  );

  /* Transition shorthand tokens — single-var convenience for transition: declarations.
     Usage: transition: color var(--sf-transition), transform var(--sf-transition);
     --sf-transition: default for most UI interactions
     --sf-transition-enter: element entering — uses normal duration (feels deliberate)
     --sf-transition-exit: element leaving — uses fast duration (feels responsive) */
  --sf-transition:       var(--sf-duration-normal) var(--sf-ease-out);
  --sf-transition-enter: var(--sf-duration-enter)  var(--sf-ease-out);
  --sf-transition-exit:  var(--sf-duration-exit)   var(--sf-ease-in);

  /* Transition property list tokens — reusable transition-property values.
     Matches the property set used by .motion-safe\:sf-transition in slashed-core.css. */
  --sf-transition-props-colors:   color, background-color, border-color, outline-color, box-shadow, opacity;
  --sf-transition-props-transform: transform, translate, scale, rotate;
  --sf-transition-props-all:      color, background-color, border-color, outline-color, box-shadow, opacity, transform, translate, scale, rotate;

  /* ===== Interactive states ===== */

  --sf-opacity-disabled: 0.5;   /* disabled controls, skeleton placeholders */
  --sf-opacity-hover:    0.85;  /* hover tint on icon buttons, overlays */
  --sf-opacity-pressed:  0.7;   /* active/mousedown feedback */
  --sf-scale-pressed:    0.97;  /* subtle push-down on click */
  --sf-hover-lift-y:          -2px;              /* vertical translate on .sf-hover-lift */
  --sf-hover-lift-shadow:     var(--sf-shadow-m);   /* shadow on .sf-hover-lift */

  /* ===== Containers — semantic, intent-named ===== */

  --sf-container-dialog:  20rem;  /*  320px — dialogs, popovers, narrow sidebars */
  --sf-container-form:    24rem;  /*  384px — single-column forms */
  --sf-container-narrow:  45ch;   /*  ≈28rem — tight editorial, pull-quotes, side columns */
  --sf-container-prose:   65ch;   /*  ≈40rem — readable line length for body text */
  --sf-container-default: 75rem;  /* 1200px — main content */
  --sf-content-width:     var(--sf-container-default); /* semantic alias — width of the
                                                     readable content column. Used by
                                                     `.sf-section` content track and
                                                     `.w-content-*` utilities. */
  --sf-container-wide:    90rem;  /* 1440px */
  --sf-container-full:    100%;

  /* ===== Focus ring ===== */

  --sf-focus-ring-width:  2px;
  --sf-focus-ring-color:  var(--sf-primary);
  --sf-focus-ring-offset: 2px;

  /* ===== Scroll ===== */

  --sf-header-height:     5rem;   /* override per project */

  /* Sticky offset accumulator — prevents stacked sticky headers from overlapping.
     Override --sticky-offset-1 to match your actual header height.
     --sticky-offset-2 adds a sub-nav or announcement bar on top. */
  --sf-sticky-offset-1:   var(--sf-header-height);
  --sf-sticky-offset-2:   calc(var(--sf-sticky-offset-1) + 3rem);

  /* ===== Blur scale ===== */

  --sf-blur-2xs: 2px;
  --sf-blur-xs:  4px;
  --sf-blur-s:   8px;
  --sf-blur-m:   16px;
  --sf-blur-l:   32px;
  --sf-blur-xl:  64px;

  /* ===== Safe-area insets (mobile notch / gesture bar) ===== */

  --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);

  /* ===== Skeleton loading ===== */

  --sf-skeleton-bg:        var(--sf-neutral-100);
  --sf-skeleton-highlight: var(--sf-neutral-200);
  --sf-skeleton-speed:     1.5s;

  /* ===== A11y scaling ===== */

  /* Default: 1 / 0 = no boost. The a11y layer raises these under prefers-contrast: more.
     Consumer BEM blocks can multiply border/focus widths:
       border-width: calc(var(--sf-border-width-1) * var(--sf-a11y-stroke-scale)); */
  --sf-a11y-stroke-scale:    1;
  --sf-a11y-contrast-boost:  0;
}

/* ===== Dark mode toggle =====
   Applied to :root for global switching, or to any element for section-level theming.
   <section data-theme="dark"> inherits dark color-scheme, causing light-dark() tokens
   to resolve to their dark values. background-color and color must be explicit here —
   they are not inherited automatically from :root when color-scheme changes. ===== */

[data-theme="dark"] {
  color-scheme: dark;
  background-color: var(--sf-color-bg);
  color: var(--sf-color-text);
}
[data-theme="light"] {
  color-scheme: light;
  background-color: var(--sf-color-bg);
  color: var(--sf-color-text);
}


/* ==========================================================================
   SCALAR DARK-MODE OVERRIDES — only the shadow-strength multipliers.

   --shadow-strength / --shadow-strength-2 are scalar numbers, not colors,
   so light-dark() cannot wrap them. They retain a dual-block form: one
   block for system dark preference (deferred when [data-theme="light"] is
   forced), one for explicit [data-theme="dark"]. Every other dark-mode
   value lives inside a light-dark() declaration in :root above.
   ========================================================================== */

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --sf-shadow-strength:   0.12;
    --sf-shadow-strength-2: 0.24;
  }
}

[data-theme="dark"] {
  --sf-shadow-strength:   0.12;
  --sf-shadow-strength-2: 0.24;
}

/* ==========================================================================
   SLASHED Core — v0.6.22.0
   Reset, base element defaults, layout primitives, a11y, print.
   Baseline: Chrome 123+, Firefox 120+, Safari 17.5+, Edge 123+.
   Sub-baseline: opt in to css/tokens-legacy.css (load BEFORE this file).
   ========================================================================== */

@layer slashed.reset, slashed.base, slashed.layout, slashed.components, slashed.utilities, slashed.visual, slashed.animations, slashed.a11y, slashed.overrides;

/* slashed.overrides: empty — reserved for user styles that must win over all framework layers. */

@layer slashed.reset {

/* ==========================================================================
   RESET
   ========================================================================== */


  *, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
  }

  html {
    text-size-adjust: 100%;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    /* Set --sf-header-height to the actual rendered height of your sticky header
       so in-page anchor jumps clear it. */
    scroll-padding-top: var(--sf-header-height);
    /* scrollbar-gutter: stable — always reserve space for scrollbar, even when content
       doesn't overflow. Prevents layout shift when scroll appears/disappears (e.g. opening
       modals, mobile menus, or dynamically loaded content). Chrome 94+, Firefox 97+, Safari 16+. */
    scrollbar-gutter: stable;
    /* Intentional duplicate of tokens-default.css :root { color-scheme }.
       Both files must be self-contained — each works without the other. */
    color-scheme: light dark;
    /* hanging-punctuation: opening/closing quotes and dashes optically hang outside
       the text margin at block start/end. Safari-supported for years; Chrome 2025+.
       Set globally so it benefits all text, not just .sf-prose. Zero risk — ignored by
       non-supporting browsers. */
    hanging-punctuation: first last;
  }

  @supports (interpolate-size: allow-keywords) {
    html { interpolate-size: allow-keywords; }
  }

  @media (prefers-reduced-motion: no-preference) {
    html { scroll-behavior: smooth; }
  }

  body {
    min-height: 100vh;
    min-height: 100dvh;
    min-inline-size: 320px;
  }

  img, picture, video, svg {
    display: block;
    max-width: 100%;
    height: auto;
  }

  button, input, select, textarea { font: inherit; }

  summary { list-style: none; }
  summary::-webkit-details-marker { display: none; }

  dialog, [popover], fieldset {
    border: 0;
    padding: 0;
  }

  @media (prefers-reduced-motion: reduce) {
    :root {
      --sf-duration-fast:   0.01ms;
      --sf-duration-normal: 0.01ms;
      --sf-duration-slow:   0.01ms;
      --sf-duration-enter:  0.01ms;
      --sf-duration-exit:   0.01ms;
    }
    *, *::before, *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
    }
  }
}

/* ==========================================================================
   BASE
   ========================================================================== */

@layer slashed.base {

  body {
    font-family: var(--sf-font-body);
    font-size: var(--sf-text-m);
    line-height: var(--sf-leading-normal);
    color: var(--sf-color-text);
    background: var(--sf-color-bg);
    scrollbar-width: thin;
    scrollbar-color: var(--sf-color-scrollbar-thumb) var(--sf-color-scrollbar-track);
    /* Native form-control accent (checkbox, radio, range, progress).
       Inherits to descendants; per-control overrides still win. */
    accent-color: var(--sf-accent-color);
  }

  h1, h2, h3, h4, h5, h6 {
    font-family: var(--sf-font-heading);
    font-weight: var(--sf-font-weight-heading);
    line-height: var(--sf-leading-tight);
    text-wrap: balance;
    overflow-wrap: break-word;
  }
  h1 { font-size: var(--sf-h1); }
  h2 { font-size: var(--sf-h2); }
  h3 { font-size: var(--sf-h3); }
  h4 { font-size: var(--sf-h4); }
  h5 { font-size: var(--sf-h5); }
  h6 { font-size: var(--sf-h6); }

  p { text-wrap: pretty; }

  /* ----- Lists (minimal indent, .sf-list-none resets) ----- */

  ul, ol { padding-inline-start: 1.25em; }

  a {
    color: var(--sf-color-link);
    text-decoration-color: color-mix(in srgb, currentcolor 30%, transparent);
    text-underline-offset: 0.15em;
    transition: color var(--sf-duration-fast) var(--sf-ease-out),
                text-decoration-color var(--sf-duration-fast) var(--sf-ease-out);
  }
  a:hover { color: var(--sf-color-link-hover); text-decoration-color: currentcolor; }
  a:visited { color: var(--sf-color-link-visited); }
  /* text-decoration-skip-ink: auto draws underlines around descenders (g, p, y etc.)
     giving a cleaner, more typographically accurate underline on unclassed links. */
  a:not([class]) { text-decoration-skip-ink: auto; }

  code {
    font-family: var(--sf-font-mono);
    font-size: 0.875em;
    background: var(--sf-color-surface-2);
    padding: 0.125em 0.3em;
    border-radius: var(--sf-radius-xs);
  }

  pre {
    font-family: var(--sf-font-mono);
    font-size: var(--sf-text-s);
    background: var(--sf-color-surface-2);
    padding: var(--sf-space-m);
    border-radius: var(--sf-radius-m);
    overflow-x: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--sf-color-scrollbar-thumb) var(--sf-color-scrollbar-track);
    tab-size: 2;
  }
  pre code { background: none; padding: 0; font-size: inherit; border-radius: 0; white-space: inherit; }

  blockquote {
    border-inline-start: var(--sf-blockquote-border-width, 3px) solid var(--sf-primary);
    padding-inline-start: var(--sf-space-m);
    color: var(--sf-color-text-muted);
  }

  /* ----- Inline semantics ----- */

  abbr[title] {
    text-decoration: underline dotted;
    cursor: help;
  }

  sub, sup {
    font-size: 0.75em;
    line-height: 0;
    position: relative;
    vertical-align: baseline;
  }
  sub { bottom: -0.25em; }
  sup { top: -0.5em; }

  kbd {
    font-family: var(--sf-font-mono);
    font-size: 0.875em;
    padding: 0.125em 0.375em;
    background: var(--sf-color-surface-2);
    border: var(--sf-border-width-1) solid var(--sf-color-border-strong);
    border-radius: var(--sf-radius-s);
    box-shadow: 0 1px 0 var(--sf-color-border-strong);
  }

  /* ----- Button base ----- */

  button, [role="button"] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5em;
    cursor: pointer;
    padding: var(--sf-space-xs) var(--sf-space-m);
    /* min 44×44px touch target (WCAG 2.5.5 / Apple HIG / Material).
       min-width ensures icon-only buttons stay square — add aspect-ratio: 1
       and remove padding for a circular icon button. */
    min-height: 2.75rem;
    min-width: 2.75rem;
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-s);
    background: var(--sf-color-surface);
    color: inherit;
    transition: border-color var(--sf-duration-fast) var(--sf-ease-out),
                background-color var(--sf-duration-fast) var(--sf-ease-out),
                color var(--sf-duration-fast) var(--sf-ease-out);
  }

  /* ----- Mobile UX: eliminate 300ms tap delay and iOS grey flash ----- */
  /* touch-action: manipulation disables double-tap-to-zoom on interactive elements,
     removing the 300ms delay browsers add to wait for a potential second tap.
     -webkit-tap-highlight-color: transparent eliminates the grey/blue overlay iOS
     draws on tap — without this, custom hover/bg effects flash with the system color.
     Applied to all interactive elements; safe to set globally on these selectors. */

  a, button, input, select, textarea, label, summary, [role="button"], [tabindex] {
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
  }

  /* ----- Form input base ----- */

  input:not([type="checkbox"], [type="radio"], [type="hidden"], [type="range"], [type="file"], [type="image"], [type="button"], [type="submit"], [type="reset"]),
  select,
  textarea {
    padding: var(--sf-space-xs) var(--sf-space-s);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-s);
    background: var(--sf-color-surface);
    color: inherit;
    caret-color: var(--sf-caret-color);
    transition: border-color var(--sf-duration-fast) var(--sf-ease-out);

    &:focus {
      border-color: var(--sf-primary);
      outline: var(--sf-focus-ring-width) solid color-mix(in srgb, var(--sf-primary) 25%, transparent);
      outline-offset: 0;
    }
    
    @media (hover: hover) {
      &:hover { border-color: var(--sf-color-border-strong); }
    }
  }

  textarea {
    resize: vertical;
    /* field-sizing: content auto-grows the textarea to its content; min/max-block-size
       set the floor and ceiling. Override --textarea-max-height to widen the cap. */
    field-sizing: content;
    min-block-size: 3lh;
    max-block-size: var(--sf-textarea-max-height, 20rem);
  }

  /* ----- Disabled & read-only states ----- */

  input:not([type="checkbox"], [type="radio"], [type="hidden"], [type="range"], [type="file"], [type="image"], [type="button"], [type="submit"], [type="reset"]):disabled,
  select:disabled,
  textarea:disabled {
    background: var(--sf-color-surface-2);
    color: var(--sf-color-text-muted);
    cursor: not-allowed;
    opacity: 1; /* Override global [disabled] opacity — color change is sufficient signal */
  }

  input:not([type="checkbox"], [type="radio"], [type="hidden"], [type="range"], [type="file"], [type="image"], [type="button"], [type="submit"], [type="reset"]):read-only,
  textarea:read-only {
    background: var(--sf-color-surface-2);
    cursor: default;
  }

  /* ----- Form validation ----- */

  input:user-invalid,
  select:user-invalid,
  textarea:user-invalid {
    border-color: var(--sf-error);
  }
  input:user-invalid:focus-visible,
  select:user-invalid:focus-visible,
  textarea:user-invalid:focus-visible {
    outline: var(--sf-focus-ring-width) solid color-mix(in srgb, var(--sf-error) 40%, transparent);
  }

  /* ----- Checkbox / radio accent -----
     Base accent inherits from `body { accent-color }` above (resolves to --sf-accent-color).
     Indeterminate state — used in "select all" patterns and tree views.
     --sf-primary-400 (lighter primary) signals partial selection without
     the warning semantics that yellow would incorrectly imply. */
  input[type="checkbox"]:indeterminate { accent-color: var(--sf-primary-400); }

  /* ----- Select (custom chevron) ----- */
  /* appearance: none removes the native OS arrow. A custom SVG chevron replaces it.
     Excludes select[multiple] and select[size>1] which render as listboxes, not dropdowns.
     Includes select[size="1"] explicitly as it is semantically a dropdown.
     Chevron stroke maps to hardcoded hex equivalents of --sf-neutral-600 (light) /
     --sf-neutral-400 (dark) — currentColor is not available in background-image SVGs.
     ⚠️ <option> elements are always rendered by the OS and cannot be fully styled. */

  select:not([multiple]):not([size]),
  select:not([multiple])[size="1"] {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%234b5563' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: calc(100% - var(--sf-space-s)) center; /* LTR */
    background-size: 1em 1em;
    padding-inline-end: calc(var(--sf-space-s) * 2 + 1em);
  }

  /* RTL: flip chevron to inline-end (left). background-position percentages are
     physical, not logical — the calc() above does not flip automatically in RTL. */
  :is([dir="rtl"], [dir="rtl"] *) select:not([multiple]):not([size]),
  :is([dir="rtl"], [dir="rtl"] *) select:not([multiple])[size="1"] {
    background-position: var(--sf-space-s) center;
  }

  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) select:not([multiple]):not([size]),
    :root:not([data-theme="light"]) select:not([multiple])[size="1"] {
      background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
    }
  }

  [data-theme="dark"] select:not([multiple]):not([size]),
  [data-theme="dark"] select:not([multiple])[size="1"] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  }

  /* ----- Range slider ----- */
  /* Fully cross-browser styled. Fill gradient painted by JS via --_fill (set by slashed-ui.js).
     Use --sf-range-thumb-color / --sf-range-fill-color to customise colors per instance. */

  input[type="range"] {
    appearance: none;
    -webkit-appearance: none;
    inline-size: 100%;
    height: 0.25rem;
    background: linear-gradient(
      to right,
      var(--sf-range-fill-color, var(--sf-primary)) var(--_fill, 0%),
      var(--sf-color-border) var(--_fill, 0%)
    );
    border-radius: var(--sf-radius-full);
    cursor: pointer;
    transition: background var(--sf-duration-fast) var(--sf-ease-out);
  }
  input[type="range"]::-moz-range-progress {
    background: var(--sf-range-fill-color, var(--sf-primary));
    height: 0.25rem;
    border-radius: var(--sf-radius-full);
  }
  input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 1.25rem;
    height: 1.25rem;
    border-radius: var(--sf-radius-full);
    background: var(--sf-range-thumb-color, var(--sf-primary));
    cursor: pointer;
    border: var(--sf-border-width-2) solid var(--sf-color-surface);
    box-shadow: var(--sf-shadow-s);
    transition: scale var(--sf-duration-fast) var(--sf-ease-out);
  }
  
  @media (hover: hover) {
    input[type="range"]::-webkit-slider-thumb:hover { scale: 1.15; }
  }
  
  input[type="range"]::-moz-range-thumb {
    width: 1.25rem;
    height: 1.25rem;
    border-radius: var(--sf-radius-full);
    background: var(--sf-range-thumb-color, var(--sf-primary));
    cursor: pointer;
    border: var(--sf-border-width-2) solid var(--sf-color-surface);
    box-shadow: var(--sf-shadow-s);
    transition: scale var(--sf-duration-fast) var(--sf-ease-out);
  }
  
  @media (hover: hover) {
    input[type="range"]::-moz-range-thumb:hover { scale: 1.15; }
  }
  
  input[type="range"]::-moz-range-track {
    height: 0.25rem;
    background: var(--sf-color-border);
    border-radius: var(--sf-radius-full);
  }
  /* Focus ring on the thumb, not the track */
  input[type="range"]:focus-visible { outline: none; }
  input[type="range"]:focus-visible::-webkit-slider-thumb {
    outline: var(--sf-focus-ring-width) solid var(--sf-primary);
    outline-offset: 2px;
  }
  input[type="range"]:focus-visible::-moz-range-thumb {
    outline: var(--sf-focus-ring-width) solid var(--sf-primary);
    outline-offset: 2px;
  }

  /* ----- File input ----- */
  /* ::file-selector-button is the "Choose File" button rendered inside the input.
     The text after it ("No file chosen") is not styleable — OS-rendered. */

  input[type="file"] {
    padding: 0;
    cursor: pointer;
  }
  input[type="file"]::file-selector-button {
    font: inherit;
    background: var(--sf-color-surface-2);
    border: 0;
    border-inline-end: var(--sf-border-width-1) solid var(--sf-color-border);
    padding: var(--sf-space-xs) var(--sf-space-m);
    margin-inline-end: var(--sf-space-m);
    cursor: pointer;
    transition: background-color var(--sf-duration-fast) var(--sf-ease-out);
  }
  
  @media (hover: hover) {
    input[type="file"]::file-selector-button:hover {
      background: color-mix(in srgb, var(--sf-color-surface-2) 60%, var(--sf-neutral-300));
    }
  }
  

  /* ----- Color input ----- */
  /* height and width set explicit touch-target size; padding: 0 removes default inset.
     ::-webkit-color-swatch-wrapper / ::-webkit-color-swatch remove the double-border
     Chrome renders around the color preview — Firefox exposes no pseudo-elements here. */

  input[type="color"] {
    padding: 0;
    height: 2.75rem;
    width: 4rem;
    cursor: pointer;
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-s);
    background: var(--sf-color-surface);
  }
  input[type="color"]::-webkit-color-swatch-wrapper { padding: 0.25rem; }
  input[type="color"]::-webkit-color-swatch {
    border: none;
    border-radius: calc(var(--sf-radius-s) - 2px);
  }

  /* ----- Search input ----- */
  /* ::-webkit-search-cancel-button removes the × button that appears when the field has
     content. Set to revert to restore it — display: none hides it entirely. */

  input[type="search"]::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
    width: 1em;
    height: 1em;
    cursor: pointer;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%239ca3af' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M4 4l8 8M12 4l-8 8'/%3E%3C/svg%3E") center / contain no-repeat;
  }

  /* ----- Placeholder normalization (Firefox opacity fix) ----- */

  ::placeholder { color: var(--sf-color-placeholder); opacity: 1; }

  /* ----- Required field indicator -----
     Adds a red asterisk after the label of any sibling [required] field.
     Pure CSS — no markup change. Override --sf-required-mark in tokens to
     localize (e.g. " (required)") or set to empty to hide. */

  label:has(+ :is(input, select, textarea)[required])::after {
    content: var(--sf-required-mark);
    color: var(--sf-error);
  }

  /* ----- Fieldset / Legend ----- */

  fieldset {
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-m);
    padding: var(--sf-space-m);
  }
  legend {
    padding-inline: var(--sf-space-xs);
    font-weight: 600;
    font-size: var(--sf-text-s);
    color: var(--sf-color-text-muted);
  }

  /* ----- Table ----- */

  table { border-collapse: collapse; text-align: start; }
  th, td {
    padding: var(--sf-space-xs) var(--sf-space-s);
    border-block-end: var(--sf-border-width-1) solid var(--sf-color-border);
  }
  th { font-weight: 600; text-align: inherit; }

  mark {
    background: var(--sf-warning-100);
    color: inherit;
    padding: 0.1em 0.2em;
    border-radius: var(--sf-radius-xs);
  }

  small { font-size: smaller; } /* HTML semantic — relative to parent, so nested small contexts stay sized correctly */

  hr {
    border: none;
    border-block-start: var(--sf-border-width-1) solid var(--sf-color-border);
    margin-block: var(--sf-space-l);
  }

  /* ----- Dialog ----- */
  /* Default width tracks --sf-container-dialog (20rem) — narrow confirmation
     pattern. Override per-instance with the --sf-dialog-max-width custom property
     for substantive dialogs:
       <dialog style="--sf-dialog-max-width: var(--sf-container-prose)">…</dialog>
     or globally on consumer :root. */

  dialog {
    --sf-dialog-max-width: var(--sf-container-dialog);
    margin: auto;
    width: min(calc(100% - 2 * var(--sf-space-gutter)), var(--sf-dialog-max-width));
    max-width: min(90vw, var(--sf-dialog-max-width));
    padding: var(--sf-space-l);
    border-radius: var(--sf-radius-l);
    box-shadow: var(--sf-shadow-float);
    background: var(--sf-color-surface);
    color: var(--sf-color-text);
    overscroll-behavior: contain;
  }
  dialog::backdrop { background: oklch(0 0 0 / 0.5); }

  /* ----- Dialog scroll lock ----- */
  /* scrollbar-gutter: stable reserves scrollbar space before overflow: hidden removes it,
     preventing the ~17px layout shift that occurs on Windows when the scrollbar disappears.
     :modal matches only dialogs opened via showModal() — not open attribute or show(). */

  body:has(dialog[open]:modal) {
    overflow: hidden;
    scrollbar-gutter: stable;
  }

  /* ----- Popover ----- */

  [popover] {
    padding: var(--sf-space-m);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-m);
    box-shadow: var(--sf-shadow-l);
    background: var(--sf-color-surface);
    color: var(--sf-color-text);
    opacity: 0;
    translate: 0 -0.5rem;
    transition: opacity var(--sf-duration-fast) var(--sf-ease-out),
                translate var(--sf-duration-fast) var(--sf-ease-out),
                overlay var(--sf-duration-fast) var(--sf-ease-out) allow-discrete,
                display var(--sf-duration-fast) var(--sf-ease-out) allow-discrete;
  }
  [popover]:popover-open { opacity: 1; translate: 0 0; }
  @starting-style {
    [popover]:popover-open { opacity: 0; translate: 0 -0.5rem; }
  }
  [popover]::backdrop { background: transparent; }

  /* ----- Details / Summary ----- */

  summary { cursor: pointer; font-weight: 600; }

  /* ----- States ----- */

  [aria-busy="true"]                    { cursor: wait; opacity: 0.7; }
  [disabled], [aria-disabled="true"]    { cursor: not-allowed; opacity: 0.6; }
  [inert], [inert] *                    { opacity: 0.4; pointer-events: none; user-select: none; }

  /* ----- ARIA state styles ----- */
  /* CSS-driven state styling via ARIA attributes — no JS class toggling needed.
     These selectors mirror the semantic states that assistive technology reads,
     keeping visual and accessibility state in sync automatically. */

  [aria-expanded="false"] > .sf-expand-icon { rotate: 0deg; }
  [aria-expanded="true"]  > .sf-expand-icon { rotate: 180deg; transition: rotate var(--sf-duration-fast) var(--sf-ease-out); }

  [aria-invalid="true"],
  [aria-invalid="spelling"],
  [aria-invalid="grammar"] {
    border-color: var(--sf-error);
  }

  [aria-current="page"],
  [aria-current="step"] {
    font-weight: 600;
    color: var(--sf-primary);
  }

  [aria-current="page"]::before {
    content: '';
    display: inline-block;
    width: 0.25em;
    height: 1em;
    background: var(--sf-primary);
    border-radius: var(--sf-radius-full);
    margin-inline-end: 0.5em;
    vertical-align: middle;
  }

  [aria-selected="true"] {
    background: var(--sf-primary-100);
    color: var(--sf-primary-700);
  }

  [aria-pressed="true"] {
    background: var(--sf-primary);
    color: var(--sf-color-text-on-primary);
    border-color: var(--sf-primary);
  }
  [aria-pressed="mixed"] {
    background: var(--sf-primary-100);
    border-color: var(--sf-primary);
  }

  /* ----- CSS-only dark mode toggle ----- */
  /* Optional progressive enhancement for sites that want a CSS-only toggle.
     Add a hidden checkbox and label to your HTML, then override the selector
     in your own stylesheet to match whatever ID or class you use:

       body:has([data-theme-toggle]:checked) { color-scheme: dark; }

     The [data-theme-toggle] attribute is the recommended pattern — apply it
     to a <input type="checkbox"> element. Bricks 2.2+ users: use the built-in
     Toggle–Mode element instead — it handles localStorage persistence too.

     For JS-driven toggle: document.documentElement.setAttribute('data-theme', 'dark')
     Both approaches use the [data-theme="dark"] rule already in tokens-default.css. */

  ::selection {
    background: var(--sf-color-selection);
    color: var(--sf-color-selection-text);
  }

  :focus-visible {
    outline: var(--sf-focus-ring-width) solid var(--sf-focus-ring-color);
    outline-offset: var(--sf-focus-ring-offset);
  }


  /* ----- Switch toggle (CSS-only) ----- */
  /* Use <input type="checkbox" role="switch"> in HTML.
     role="switch" overrides the implicit checkbox role, correctly conveying
     on/off semantics to screen readers per the ARIA spec. */

  input[role="switch"] {
    --sf-switch-size: 1.5em; /* override to scale the entire switch: --sf-switch-size: 2em */

    appearance: none;
    position: relative;
    width: calc(var(--sf-switch-size) * 11 / 6);
    height: var(--sf-switch-size);
    border-radius: var(--sf-radius-full);
    background: var(--sf-switch-bg, var(--sf-neutral-300));
    cursor: pointer;
    transition: background-color var(--sf-duration-fast) var(--sf-ease-out);
  }
  input[role="switch"]::after {
    content: '';
    position: absolute;
    inset-block-start: calc(var(--sf-switch-size) * 0.125);
    inset-inline-start: calc(var(--sf-switch-size) * 0.125);
    width: calc(var(--sf-switch-size) * 0.75);
    height: calc(var(--sf-switch-size) * 0.75);
    border-radius: var(--sf-radius-full);
    background: var(--sf-switch-thumb, var(--sf-color-text-on-dark));
    box-shadow: var(--sf-shadow-xs);
    transition: translate var(--sf-duration-fast) var(--sf-ease-out);
  }
  input[role="switch"]:checked {
    background: var(--sf-switch-active, var(--sf-primary));
  }
  input[role="switch"]:checked::after {
    translate: calc(var(--sf-switch-size) * 5 / 6) 0;
  }
  input[role="switch"]:focus-visible {
    outline: var(--sf-focus-ring-width) solid var(--sf-focus-ring-color);
    outline-offset: var(--sf-focus-ring-offset);
  }

  /* ----- Icon base (data-icon) ----- */

  [data-icon] {
    display: inline-flex;
    width: var(--sf-icon-size, var(--sf-icon-l));
    height: var(--sf-icon-size, var(--sf-icon-l));
    color: var(--sf-icon-color, currentcolor);
    flex-shrink: 0;
  }

  /* ----- Progress bar ----- */

  progress {
    appearance: none;
    inline-size: 100%;
    height: var(--sf-progress-height, 0.5rem);
    border: none;
    border-radius: var(--sf-radius-full);
    background: var(--sf-color-surface-2);
    overflow: hidden;
  }
  progress::-webkit-progress-bar {
    background: var(--sf-color-surface-2);
    border-radius: var(--sf-radius-full);
  }
  progress::-webkit-progress-value {
    background: var(--sf-progress-color, var(--sf-primary));
    border-radius: var(--sf-radius-full);
  }
  progress::-moz-progress-bar {
    background: var(--sf-progress-color, var(--sf-primary));
    border-radius: var(--sf-radius-full);
  }

  /* ----- View Transitions ----- */
  /* Sets default fade animation for full-page View Transitions.
     Chrome 111+, Safari 18+. Progressive enhancement.
     Override per-element with view-transition-name + custom keyframes. */

  @supports (view-transition-name: none) {
    ::view-transition-old(root),
    ::view-transition-new(root) {
      animation-duration: var(--sf-duration-normal);
      animation-timing-function: var(--sf-ease-out);
    }
    ::view-transition-old(root) { animation-name: fade-out; }
    ::view-transition-new(root) { animation-name: fade-in; }
  }

  /* ----- Keyframes ----- */

  @keyframes fade-in       { from { opacity: 0; } }
  @keyframes fade-out      { from { opacity: 1; } to { opacity: 0; } }
  @keyframes slide-up      { from { opacity: 0; translate: 0 1rem; } }
  @keyframes scale-in      { from { opacity: 0; scale: 0.95; } }
  @keyframes spin          { to { rotate: 360deg; } }
  @keyframes skeleton-pulse {
    0%   { background-position: 200% 0; }
    100% { background-position: -200% 0; }
  }

}

/* ==========================================================================
   LAYOUT PRIMITIVES
   ========================================================================== */

@layer slashed.layout {

  /* ================================================================
     BREAKPOINTS used in this layer.

     Fixed and ratio grids (.grid-N, .sf-grid-sidebar, .sf-grid-1-1, .sf-grid-1-2,
     .sf-grid-1-3, .sf-grid-2-1) use @container queries and respond to their
     own width — correct behaviour in sidebars, Bricks columns, and
     nested layouts. .sf-cq-inline on a grid is redundant.

     Other rules in this layer (.sf-alternate, etc.) still use @media.
     If you change breakpoints, keep them in sync with slashed-utilities.css.

     md: 48em (768px)  →  find: (min-width: 48em)
     sm: 30em (480px)  →  find: (min-width: 30em)
     ================================================================ */

  .sf-section     { padding-block: var(--sf-space-section); }
  .sf-section--xs { padding-block: var(--sf-space-l); }
  .sf-section--s  { padding-block: var(--sf-space-xl); }
  .sf-section--m  { padding-block: var(--sf-space-2xl); }
  .sf-section--l  { padding-block: var(--sf-space-4xl); }
  .sf-section--xl { padding-block: clamp(8rem, 12vw, 12rem); }
  .sf-section--alt  { background: var(--sf-color-surface-2); }
  .sf-section--soft { background: var(--sf-primary-50);  color: var(--sf-color-text); }
  .sf-section--bold {
    background:           var(--sf-primary);
    color:                var(--sf-color-text-on-primary);
    --sf-color-text:         var(--sf-color-text-on-primary);
    --sf-color-text-body:    var(--sf-color-text-on-primary);
    --sf-color-text-muted:   var(--sf-color-text-on-primary);
    --sf-color-link:         var(--sf-color-text-on-primary);
    --sf-color-link-hover:   var(--sf-color-text-on-primary);
    --sf-color-link-visited: var(--sf-color-text-on-primary);
    --sf-color-link-active:  var(--sf-color-text-on-primary);
    --sf-color-border:       color-mix(in srgb, var(--sf-primary) 70%, white);
  }
  .sf-section-group > .sf-section + .sf-section { padding-block-start: 0; }

  /* ----- Container ----- */

  .sf-container {
    width: 100%;
    max-width: var(--sf-container-default);
    margin-inline: auto;
    padding-inline: var(--sf-space-gutter);
  }
  .sf-container--dialog { max-width: var(--sf-container-dialog); }
  .sf-container--form   { max-width: var(--sf-container-form); }
  .sf-container--prose  { max-width: var(--sf-container-prose); }
  .sf-container--wide   { max-width: var(--sf-container-wide); }
  .sf-container--full   { max-width: var(--sf-container-full); }

  /* ----- Content grid (breakout pattern) ----- */
  /* ⚠️ --sf-breakout-width must be >= --sf-content-width.
     If --sf-content-width > --sf-breakout-width, the calc() yields a negative value
     and the breakout columns collapse to 0. */

  .sf-content-grid {
    --sf-content-width: var(--sf-container-default);
    --sf-breakout-width: var(--sf-container-wide);

    display: grid;
    grid-template-columns:
      [full-start] minmax(var(--sf-space-gutter), 1fr)
      [breakout-start] minmax(0, calc((var(--sf-breakout-width) - var(--sf-content-width)) / 2))
      [content-start] min(var(--sf-content-width), 100% - var(--sf-space-gutter) * 2) [content-end]
      minmax(0, calc((var(--sf-breakout-width) - var(--sf-content-width)) / 2)) [breakout-end]
      minmax(var(--sf-space-gutter), 1fr) [full-end];
  }
  .sf-content-grid > *           { grid-column: content; }
  .sf-content-grid > .sf-breakout   { grid-column: breakout; }
  .sf-content-grid > .sf-full-bleed { grid-column: full; }

  /* ----- Auto-grid ----- */

  .sf-auto-grid {
    --sf-grid-min: 16rem;

    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(var(--sf-grid-min), 100%), 1fr));
    gap: var(--sf-space-gap);
  }
  .sf-auto-grid--s    { --sf-grid-min: 12rem; }
  .sf-auto-grid--m    { --sf-grid-min: 18rem; }
  .sf-auto-grid--l    { --sf-grid-min: 24rem; }
  /* auto-fill keeps empty grid tracks visible (useful for UI with "add item" placeholders).
     auto-fit (default) collapses empty tracks so items stretch to fill the row. */
  .sf-auto-grid--fill { grid-template-columns: repeat(auto-fill,  minmax(min(var(--sf-grid-min), 100%), 1fr)); }

  /* ----- Variable column grid ----- */
  /* Set --cols via inline style: <div class="grid-cols" style="--cols: 3">
     Spacing tokens use clamp() and are fluid — responsive override classes are
     intentionally limited to zero-resets to keep file size in check. */

  .sf-grid-cols {
    display: grid;
    grid-template-columns: repeat(var(--sf-cols, 1), 1fr);
    gap: var(--sf-grid-gap, var(--sf-space-gap));
  }

  /* ----- Variable flex / grid primitives ----- */
  /* Set properties via inline style or parent rule:
     <div class="sf-grid" style="--sf-grid-cols: 3; --sf-grid-gap: var(--sf-space-l)">
     <div class="sf-flex" style="--sf-flex-dir: column; --sf-flex-gap: var(--sf-space-s)">
     Namespaced tokens (--sf-grid-*, --sf-flex-*) prevent inheritance leaking into
     nested primitives when the same generic name is set on an ancestor. */

  .sf-grid {
    display: grid;
    grid-template-columns: repeat(var(--sf-grid-cols, 1), 1fr);
    gap: var(--sf-grid-gap, var(--sf-space-gap));
    align-items: var(--sf-grid-align, stretch);
  }
  .sf-flex {
    display: flex;
    flex-direction: var(--sf-flex-dir, row);
    gap: var(--sf-flex-gap, var(--sf-space-gap));
    justify-content: var(--sf-flex-justify, flex-start);
    align-items: var(--sf-flex-align, stretch);
    flex-wrap: var(--sf-flex-wrap, wrap);
  }

  /* ----- Admin layout (nav | content, 3-row: header / main / footer) ----- */
  /* Uses --admin-nav to avoid collision with --sidebar-width on .sf-grid-sidebar.
     Set --sf-admin-nav: 0 to collapse the nav column on mobile. */

  .sf-layout-admin {
    display: grid;
    grid-template-columns: var(--sf-admin-nav, 16rem) 1fr;
    grid-template-rows: auto 1fr auto;
    min-block-size: 100dvh;
  }

  /* ----- Fixed grids (mobile-first, 1–4 columns) ----- */
  /* For 5–12 columns use: <div class="grid-cols" style="--cols: 6"> */

  .sf-grid-1, .sf-grid-2, .sf-grid-3, .sf-grid-4 {
    container-type: inline-size;
    display: grid;
    gap: var(--sf-space-gap);
  }
  @container (min-width: 30em) {
    .sf-grid-4 { grid-template-columns: repeat(2, 1fr); }
  }
  @container (min-width: 48em) {
    .sf-grid-2 { grid-template-columns: repeat(2, 1fr); }
    .sf-grid-3 { grid-template-columns: repeat(3, 1fr); }
    .sf-grid-4 { grid-template-columns: repeat(4, 1fr); }
  }

  /* ----- Grid sidebar ----- */

  .sf-grid-sidebar {
    container-type: inline-size;
    display: grid;
    gap: var(--sf-space-gap);
  }
  @container (min-width: 48em) {
    .sf-grid-sidebar { grid-template-columns: var(--sf-sidebar-width, 18rem) 1fr; }
  }

  /* ----- Ratio grids (narrow: stacked, ≥48em container width: ratio) ----- */

  .sf-grid-1-1, .sf-grid-1-3, .sf-grid-1-2, .sf-grid-2-1 {
    container-type: inline-size;
    display: grid;
    gap: var(--sf-space-gap);
  }
  @container (min-width: 48em) {
    .sf-grid-1-1 { grid-template-columns: 1fr 1fr; }
    .sf-grid-1-3 { grid-template-columns: 1fr 3fr; }
    .sf-grid-1-2 { grid-template-columns: 1fr 2fr; }
    .sf-grid-2-1 { grid-template-columns: 2fr 1fr; }
  }

  /* ----- Sidebar layout ----- */

  .sf-sidebar-layout { display: flex; flex-wrap: wrap; gap: var(--sf-space-gap); }
  .sf-sidebar-layout > :first-child { flex-basis: var(--sf-sidebar-width, 18rem); flex-grow: 1; }
  .sf-sidebar-layout > :last-child  { flex-basis: 0; flex-grow: 999; min-inline-size: 60%; }
  /* .sf-sidebar-layout--right: sidebar is the second child (right side) */
  .sf-sidebar-layout--right > :first-child { flex-basis: 0; flex-grow: 999; min-inline-size: 60%; }
  .sf-sidebar-layout--right > :last-child  { flex-basis: var(--sf-sidebar-width, 18rem); flex-grow: 1; }
  .sf-sidebar-layout--narrow { --sf-sidebar-width: 12rem; }
  .sf-sidebar-layout--wide   { --sf-sidebar-width: 26rem; }

  /* ----- Switcher (intrinsic horizontal↔vertical) ----- */

  .sf-switcher {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sf-space-gap);
  }
  .sf-switcher > * {
    flex-grow: 1;
    flex-basis: calc((var(--sf-switcher-threshold, 30rem) - 100%) * 999);
  }
  /* .sf-switcher--no-wrap: always horizontal with overflow scroll on mobile.
     Use for tab bars, step indicators, or horizontal lists that must not stack. */
  .sf-switcher--no-wrap { flex-wrap: nowrap; overflow-x: auto; }
  /* .sf-switcher--vertical: always stacked regardless of available width. */
  .sf-switcher--vertical { flex-direction: column; }

  /* ----- Subgrid ----- */

  .sf-subgrid      { display: grid; grid-template-columns: subgrid; }
  .sf-subgrid-rows { display: grid; grid-template-rows: subgrid; }

  /* ----- Flow ----- */

  .sf-flow > * + *    { margin-block-start: var(--sf-space-content); }
  .sf-flow--s > * + * { margin-block-start: var(--sf-space-s); }
  .sf-flow--l > * + * { margin-block-start: var(--sf-space-l); }

  /* ----- Stack ----- */

  .sf-stack      { display: flex; flex-direction: column; gap: var(--sf-space-content); }
  .sf-stack--2xs { gap: var(--sf-space-2xs); }
  .sf-stack--xs  { gap: var(--sf-space-xs); }
  .sf-stack--s   { gap: var(--sf-space-s); }
  .sf-stack--m   { gap: var(--sf-space-m); }
  .sf-stack--l   { gap: var(--sf-space-l); }
  .sf-stack--xl  { gap: var(--sf-space-xl); }
  .sf-stack--2xl { gap: var(--sf-space-2xl); }
  .sf-stack--3xl { gap: var(--sf-space-3xl); }
  /* .sf-stack--recursive: applies gap to all descendant stacked elements, not just direct children.
     Useful for deeply nested flow content (MDX, CMS-rendered blocks). */
  .sf-stack--recursive * + * { margin-block-start: var(--sf-space-content); }

  /* ----- Cluster ----- */

  .sf-cluster      { display: flex; flex-wrap: wrap; gap: var(--sf-space-gap); }
  .sf-cluster--2xs { gap: var(--sf-space-2xs); }
  .sf-cluster--xs  { gap: var(--sf-space-xs); }
  .sf-cluster--s   { gap: var(--sf-space-s); }
  .sf-cluster--l   { gap: var(--sf-space-l); }
  .sf-cluster--xl  { gap: var(--sf-space-xl); }
  .sf-cluster--no-wrap { flex-wrap: nowrap; }

  /* ----- Alternate (zigzag, mobile-first) ----- */

  .sf-alternate { display: grid; gap: var(--sf-space-content); container-type: inline-size; }
  .sf-alternate > * { display: grid; gap: var(--sf-space-gap); align-items: center; }
  @container (min-width: 48em) {
    .sf-alternate > * { grid-template-columns: 1fr 1fr; }
    .sf-alternate > :nth-child(even) > :first-child { order: 2; }
    .sf-alternate > :nth-child(even) > :last-child  { order: 1; }
  }

  /* ----- Cover (hero) ----- */

  .sf-cover {
    display: flex; flex-direction: column;
    min-height: var(--sf-cover-height, 100dvh);
    padding-block: var(--sf-space-section);
    padding-inline: var(--sf-space-gutter);
  }
  .sf-cover > .sf-cover__center { margin-block: auto; }
  .sf-cover--min { min-height: var(--sf-cover-min, 50dvh); }
  .sf-cover--max { min-height: 0; max-height: var(--sf-cover-max, 100dvh); }
  .sf-cover--padding-s { padding-block: var(--sf-space-xl); }
  .sf-cover--padding-l { padding-block: var(--sf-space-4xl); }

  /* ----- Reel (horizontal scroll) ----- */

  .sf-reel {
    display: flex;
    gap: var(--sf-reel-gap, var(--sf-space-gap));
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--sf-reel-padding, var(--sf-space-gap));
    /* overscroll-behavior: contain prevents scroll from propagating to the document
       when the reel reaches its end — without this, horizontal swipe on mobile
       can trigger browser back/forward navigation or pull-to-refresh. */
    overscroll-behavior: contain;
    scrollbar-width: thin;
    scrollbar-color: var(--sf-color-scrollbar-thumb) var(--sf-color-scrollbar-track);
  }
  .sf-reel > * { flex-shrink: 0; scroll-snap-align: start; }

  /* ----- Clickable parent ----- */

  .sf-clickable-parent { position: relative; }
  .sf-clickable-parent a:first-of-type::after {
    content: ''; position: absolute; inset: 0;
    z-index: var(--sf-z-raised);
  }
  .sf-clickable-parent:has(a):hover { cursor: pointer; }

  /* ----- Focus parent ----- */
  /* Uses :has(:focus-visible) so the outline only appears during keyboard navigation,
     not on mouse click. This matches the intent of the focus-visible pattern. */

  .sf-focus-parent:has(:focus-visible) {
    outline: var(--sf-focus-ring-width) solid var(--sf-focus-ring-color);
    outline-offset: var(--sf-focus-ring-offset);
  }

  /* ----- Group hover/show ----- */
  /* visibility + opacity combo is intentional: visibility: hidden removes the element
     from the accessibility tree when invisible; opacity alone would not. The visibility
     transition snaps (it doesn't interpolate) — this is expected CSS behavior. */

  .sf-group-show {
    opacity: 0; visibility: hidden;
    transition: opacity var(--sf-duration-fast) var(--sf-ease-out),
                visibility var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-group:hover > .sf-group-show { opacity: 1; visibility: visible; }
  }
  .sf-group:has(:focus-visible) > .sf-group-show { opacity: 1; visibility: visible; }

  /* ----- Overlay ----- */
  /* isolation: isolate creates a new stacking context. z-index: -1 on ::after places it
     between the element's own background and its children — exactly the intended layering:
     background-image → ::after overlay → content.
     ⚠️ Do NOT add background to .sf-overlay itself — the overlay ::after sits above it,
     creating a combined tint rather than a pure overlay effect. */

  .sf-overlay { position: relative; isolation: isolate; }
  .sf-overlay::after {
    content: ''; position: absolute; inset: 0;
    background: var(--sf-overlay, rgb(0 0 0 / 0.5));
    border-radius: inherit; pointer-events: none;
    z-index: -1;
  }

  /* ----- Bleed ----- */
  /* ⚠️ Requires the parent to have padding-inline: var(--sf-space-gutter) (e.g. .sf-container).
     If the parent uses a different padding value, .sf-bleed will overshoot. */

  .sf-bleed {
    margin-inline: calc(-1 * var(--sf-space-gutter));
    padding-inline: var(--sf-space-gutter);
  }

  /* ----- Center ----- */
  /* Horizontally centers content with max-width and optional gutters.
     .sf-center--intrinsic additionally centers children along the inline axis (flex column). */

  .sf-center {
    box-sizing: content-box;
    margin-inline: auto;
    max-inline-size: var(--sf-center-max, var(--sf-container-default));
    padding-inline: var(--sf-center-gutter, var(--sf-space-gutter));
  }
  .sf-center--intrinsic {
    display: flex;
    flex-direction: column;
    align-items: center;
  }

  /* ----- Frame (aspect-ratio media wrapper) ----- */
  /* Constrains img/video children to a fixed aspect ratio regardless of intrinsic dimensions.
     Use --sf-frame-ratio to set arbitrary ratios: style="--sf-frame-ratio: 4/3" */

  .sf-frame {
    aspect-ratio: var(--sf-frame-ratio, 16 / 9);
    overflow: hidden;
    display: flex;
    justify-content: center;
    align-items: center;
  }
  .sf-frame > img,
  .sf-frame > video {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }
  .sf-frame--square   { --sf-frame-ratio: 1; }
  .sf-frame--video    { --sf-frame-ratio: 16 / 9; }
  .sf-frame--portrait { --sf-frame-ratio: 3 / 4; }
  .sf-frame--cinema   { --sf-frame-ratio: 21 / 9; }
  .sf-frame--4-3      { --sf-frame-ratio: 4 / 3; }

  /* ----- Imposter (centered absolute/fixed overlay) ----- */
  /* Positions an element at the center of its nearest positioned ancestor.
     .sf-imposter--fixed: stays centered in the viewport regardless of scroll.
     .sf-imposter--contain: clamps to avoid overflow beyond the positioned parent. */

  .sf-imposter {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    translate: -50% -50%;
  }
  .sf-imposter--fixed { position: fixed; }
  .sf-imposter--contain {
    --sf-imposter-margin: var(--sf-space-m);

    max-inline-size: calc(100% - var(--sf-imposter-margin) * 2);
    max-block-size:  calc(100% - var(--sf-imposter-margin) * 2);
    overflow: auto;
  }

  /* ----- Bento grid ----- */
  /* CSS Grid layout for asymmetric "bento box" patterns.
     Uses container queries (not viewport queries) — bento collapses correctly
     whether it's full-width or inside a sidebar.

     Span children with existing utilities: .sf-col-span-2/3/4/full, .sf-row-span-2
     Customizable: --sf-bento-cols (default: 3), --sf-bento-row (default: 14rem), --sf-bento-gap

     Usage:
       <div class="sf-bento sf-cq-inline">
         <div class="sf-col-span-2 sf-row-span-2">Featured</div>
         <div>Item</div>
         <div class="sf-col-span-2">Wide item</div>
       </div> */

  .sf-bento {
    container-type: inline-size;
    display: grid;
    grid-template-columns: repeat(var(--sf-bento-cols, 3), 1fr);
    /* minmax(min, auto): row has a minimum height for visual rhythm but extends when
       content is taller. Featured cards (row-span-2) get minimum 2× bento-row while
       still preventing overflow-hidden content clipping for long copy. */
    grid-auto-rows: minmax(var(--sf-bento-row, 14rem), auto);
    grid-auto-flow: dense;
    gap: var(--sf-bento-gap, var(--sf-space-gap));
  }

  /* 2-column layout between 30em and 48em */
  @container (min-width: 30em) and (max-width: 47.99em) {
    .sf-bento {
      grid-template-columns: repeat(2, 1fr);
      /* Same minmax pattern — keeps row-span-2 dominance while accommodating content */
      grid-auto-rows: minmax(var(--sf-bento-row, 14rem), auto);
    }
  }

  /* Preset column variants */
  .sf-bento--2 { --sf-bento-cols: 2; }
  .sf-bento--4 { --sf-bento-cols: 4; }

  /* Row height presets */
  .sf-bento--compact { --sf-bento-row: 10rem; }
  .sf-bento--tall    { --sf-bento-row: 20rem; }

  /* Masonry moved to slashed-experimental.css in 0.3.7.0. */

  /* ----- Prose ----- */

  .sf-prose {
    max-width: var(--sf-container-prose);
    overflow-wrap: break-word;
    /* hanging-punctuation is set globally on html — .sf-prose inherits it automatically. */
  }
  .sf-prose > * + *                 { margin-block-start: var(--sf-space-content); }
  .sf-prose :is(h2, h3, h4) + *    { margin-block-start: var(--sf-space-s); }
  .sf-prose li + li                 { margin-block-start: var(--sf-space-xs); }
  .sf-prose :is(blockquote, pre)    { margin-block: var(--sf-space-m); }
  .sf-prose img                     { margin-block: var(--sf-space-m); border-radius: var(--sf-radius-m); }
  .sf-prose :is(ul, ol)             { padding-inline-start: 1.25em; }
  .sf-prose ul                      { list-style: disc; }
  .sf-prose ol                      { list-style: decimal; }
  .sf-prose ::marker                { color: var(--sf-primary); }
  .sf-prose figure                  { margin-block: var(--sf-space-l); }
  .sf-prose figcaption              { font-size: var(--sf-text-s); color: var(--sf-color-text-muted); margin-block-start: var(--sf-space-xs); }
  /* display: block + overflow-x: auto required for reliable table scroll on mobile.
     overflow-x alone on a table element does not create a scroll container across browsers. */
  .sf-prose table                   { margin-block: var(--sf-space-m); display: block; overflow-x: auto; max-width: 100%; }
  .sf-prose video                   { margin-block: var(--sf-space-m); border-radius: var(--sf-radius-m); }

  /* ----- Not-prose (resets prose descendant styles for embedded components) ----- */
  /* Prevents .sf-prose flow spacing and element styles from leaking into cards,
     widgets, or other components embedded inside prose content.
     Only resets what .sf-prose actually sets — not a destructive all: revert. */

  .sf-prose .sf-not-prose > * + *           { margin-block-start: 0; }
  .sf-prose .sf-not-prose :is(ul, ol)       { list-style: revert; padding-inline-start: revert; }
  .sf-prose .sf-not-prose ::marker          { color: inherit; }
  .sf-prose .sf-not-prose img               { margin-block: 0; border-radius: 0; }
  .sf-prose .sf-not-prose figure            { margin-block: 0; }
  .sf-prose .sf-not-prose figcaption        { font-size: inherit; color: inherit; margin-block-start: 0; }
  .sf-prose .sf-not-prose table             { margin-block: 0; display: revert; }
  .sf-prose .sf-not-prose video             { margin-block: 0; border-radius: 0; }

  /* ==========================================================================
     BEHAVIORAL PATTERNS
     Hover effects, scroll-driven animations, stagger — behavioral classes that
     add interaction and motion without defining spatial structure.
     Sit in layout layer (not utilities) because they are multi-property behavioral
     patterns, not single-property escape hatches.
     ========================================================================== */

  /* ----- Hover patterns ----- */
  /* Transition declarations sit outside @media (hover: hover) so deactivation
     is smooth. Hover state rules are guarded to prevent stuck states on touch. */

  .sf-hover-lift {
    transition: box-shadow var(--sf-duration-fast) var(--sf-ease-out),
                translate var(--sf-duration-fast) var(--sf-ease-out);
  }

  .sf-hover-fade {
    transition: opacity var(--sf-duration-fast) var(--sf-ease-out);
  }

  .sf-hover-bg {
    transition: background-color var(--sf-duration-fast) var(--sf-ease-out);
  }

  .sf-hover-scale {
    transition: scale var(--sf-duration-fast) var(--sf-ease-out);
  }

  .sf-hover-border {
    transition: border-color var(--sf-duration-fast) var(--sf-ease-out);
  }

  .sf-hover-text {
    --sf-hover-text: var(--sf-primary-700);

    transition: color var(--sf-duration-fast) var(--sf-ease-out);
  }

  .sf-hover-shadow {
    --sf-hover-shadow: var(--sf-shadow-l);

    transition: box-shadow var(--sf-duration-fast) var(--sf-ease-out);
  }

  @media (hover: hover) {
    .sf-hover-lift:hover   { box-shadow: var(--sf-hover-lift-shadow); translate: 0 var(--sf-hover-lift-y); }
    .sf-hover-fade:hover   { opacity: 0.7; }
    .sf-hover-bg:hover     { background-color: var(--sf-hover-bg, var(--sf-color-surface-2)); }
    .sf-hover-scale:hover  { scale: 1.05; }
    .sf-hover-border:hover { border-color: var(--sf-hover-border, var(--sf-primary)); }
    .sf-hover-text:hover   { color: var(--sf-hover-text); }
    .sf-hover-shadow:hover { box-shadow: var(--sf-hover-shadow); }
  }


  /* Keyboard focus mirrors hover — outside @media (hover: hover) so keyboard users
     on touch devices also receive feedback. Additive: focus-visible outline still applies. */
  .sf-hover-lift:focus-visible   { box-shadow: var(--sf-hover-lift-shadow); translate: 0 var(--sf-hover-lift-y); }
  .sf-hover-fade:focus-visible   { opacity: 0.7; }
  .sf-hover-bg:focus-visible     { background-color: var(--sf-hover-bg, var(--sf-color-surface-2)); }
  .sf-hover-scale:focus-visible  { scale: 1.05; }
  .sf-hover-border:focus-visible { border-color: var(--sf-hover-border, var(--sf-primary)); }
  .sf-hover-text:focus-visible   { color: var(--sf-hover-text); }
  .sf-hover-shadow:focus-visible { box-shadow: var(--sf-hover-shadow); }

  /* ----- Scroll reveal (scroll-driven) ----- */
  /* Wrapped in prefers-reduced-motion: no-preference — elements are fully visible
     without animation in unsupporting browsers or when reduced motion is active. */

  @media (prefers-reduced-motion: no-preference) {
    .sf-scroll-reveal {
      animation-name: fade-in;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: view();
      animation-range: entry 10% entry 90%;
    }
    .sf-scroll-reveal-up {
      animation-name: slide-up;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: view();
      animation-range: entry 10% entry 90%;
    }
  }

  /* ----- Parallax (scroll-driven) ----- */
  /* ⚠️ Apply only to decorative elements — animated transforms on CPU compositing
     layers can cause repaint when combined with opacity. Add will-change: transform if needed. */

  @media (prefers-reduced-motion: no-preference) {
    .sf-parallax {
      animation: parallax-move linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
    @keyframes parallax-move {
      from { translate: 0 calc(var(--sf-parallax-speed, -3rem)); }
      to   { translate: 0 calc(var(--sf-parallax-speed, -3rem) * -1); }
    }
  }

  /* ----- Stagger ----- */
  /* Polyfill path: set --_i as an inline style on each child via initStagger().
     Native CSS path: sibling-index() (Baseline Newly Available: Chrome 130+,
     Firefox 131+, Safari 18+) — used automatically when supported. */

  @media (prefers-reduced-motion: no-preference) {
    .sf-stagger > * {
      animation: fade-in var(--sf-duration-normal) var(--sf-ease-out) both;
      animation-delay: calc(var(--_i, 0) * var(--sf-stagger-delay, var(--sf-duration-stagger)));
    }
  }

  @supports (animation-delay: calc(sibling-index() * 1ms)) {
    @media (prefers-reduced-motion: no-preference) {
      .sf-stagger > * {
        animation-delay: calc(
          (sibling-index() - 1) * var(--sf-stagger-delay, var(--sf-duration-stagger))
        );
      }
    }
  }

}

/* ==========================================================================
   ACCESSIBILITY
   ========================================================================== */

@layer slashed.a11y {
  /* ----- Screen reader only ----- */

  .sf-sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
  }

  /* ----- Skip to content ----- */

  .sf-skip-to-content {
    position: fixed; inset-block-start: -100%; inset-inline-start: 50%; translate: -50% 0;
    padding: var(--sf-space-s) var(--sf-space-m);
    background: var(--sf-primary); color: var(--sf-color-text-on-primary);
    border-radius: var(--sf-radius-m); z-index: var(--sf-z-max);
    transition: inset-block-start var(--sf-duration-fast) var(--sf-ease-out);
  }
  .sf-skip-to-content:focus { inset-block-start: var(--sf-space-s); }

  @media (prefers-contrast: more) {
    :root {
      --sf-color-border:        var(--sf-neutral-400);
      --sf-color-border-strong: var(--sf-neutral-600);
      --sf-color-text-muted:    var(--sf-neutral-700);
      --sf-focus-ring-width:    3px;
      --sf-a11y-stroke-scale:   2;
      --sf-a11y-contrast-boost: 1;
    }
  }

  @media (prefers-reduced-transparency: reduce) {
    :root {
      --sf-primary-a10: var(--sf-primary-100);
      --sf-primary-a25: var(--sf-primary-200);
      --sf-primary-a50: var(--sf-primary-300);
    }
  }

  @media (forced-colors: active) {
    button, input, select, textarea, [role="button"], summary {
      border: 1px solid ButtonText;
    }
    /* dialog and [popover] need a visible border in HCM — their default UA
       chrome (shadow + background) goes flat in forced-colors mode. */
    dialog, [popover] {
      border: 1px solid CanvasText;
    }
    /* Ensure focus-visible stays visible — UA outline can resolve to
       `Highlight` already, but explicit value guarantees it across vendors. */
    :focus-visible {
      outline: 2px solid Highlight;
      outline-offset: 2px;
    }
  }

  /* ----- prefers-reduced-data ----- */
  /* Activated by "Data Saver" mode on Android Chrome and iOS Low Data Mode.
     Disables decorative background images and heavy gradients to reduce bandwidth.
     Zero functional impact — layout and all interactive states are preserved.

     Note: .sf-bg-gradient / .sf-text-gradient fallbacks live in slashed-utilities-visual.css
     (opt-in layer) alongside their base rules — they are no-ops without that file. */

  @media (prefers-reduced-data: reduce) {
    /* Scope to SLASHED-owned decorative elements to avoid stripping author-owned backgrounds.
       Whole-token matching (^="sf-" / *=" sf-" instead of *="sf-") so unrelated classes
       like "btn-sf-primary" or "shop-sf-card" are not caught by substring overlap. */
    :is(
      [class^="sf-"], [class*=" sf-"],
      [class^="bg-"], [class*=" bg-"],
      [data-slashed-bg]
    )[style*="background-image"] {
      background-image: none !important;
    }
    .sf-mask-fade { mask-image: none; }
  }

  /* ----- Motion preference utilities -----
     Relocated from slashed.utilities → slashed.a11y in 0.4.2.0.
     Class names unchanged. Sits in the a11y layer alongside other
     prefers-* overrides so motion preference always beats decoration. */

  @media (prefers-reduced-motion: no-preference) {
    .motion-safe\:sf-transition        { transition-property: var(--sf-transition-props-all); transition-duration: var(--sf-duration-normal); transition-timing-function: var(--sf-ease-out); }
    .motion-safe\:sf-animate-fade-in   { animation: fade-in var(--sf-duration-normal) var(--sf-ease-out) both; }
    .motion-safe\:sf-animate-slide-up  { animation: slide-up var(--sf-duration-normal) var(--sf-ease-out) both; }
    .motion-safe\:sf-animate-scale-in  { animation: scale-in var(--sf-duration-normal) var(--sf-ease-out) both; }
    .motion-safe\:sf-animate-spin      { animation: spin var(--sf-spin-duration, 1s) linear infinite; }
  }
  @media (prefers-reduced-motion: no-preference) and (hover: hover) {
    .motion-safe\:sf-hover-lift:hover  { box-shadow: var(--sf-hover-lift-shadow); translate: 0 var(--sf-hover-lift-y); }
  }

  @media (prefers-reduced-motion: reduce) {
    .motion-reduce\:sf-animate-none    { animation: none !important; }
    .motion-reduce\:sf-transition-none { transition: none !important; }
    .motion-reduce\:sf-animate-fade-in { animation: fade-in 0.01ms both !important; }

    /* Stop marquee scroll; wrap items so content is still accessible */
    .sf-marquee__track {
      animation: none;
      flex-wrap: wrap;
      justify-content: center;
    }
  }
}

/* ==========================================================================
   PRINT (unlayered — beats all layers by default)
   ========================================================================== */

.sf-print-only { display: none; }

/* Default page margins for invoices, reports, receipts, articles. Consumer
   can override with their own @page rule (size, margin, marks). No `size`
   declaration here — locales differ (A4 vs Letter); user agent decides.
   Override in consumer CSS: @page { size: A4 portrait; margin: 1.5cm }

   Static fallback first — var() inside @page margin descriptors is not
   reliably supported in current browsers (CSSWG #4761). Engines that ignore
   the second declaration use the static 2cm default; engines that resolve
   it pick up the consumer's --sf-print-page-margin override. */
@page {
  margin: 2cm;
  margin: var(--sf-print-page-margin, 2cm);
}

@media print {
  *, *::before, *::after {
    background: transparent !important;
    color: black !important;
    box-shadow: none !important;
    text-shadow: none !important;
  }
  body { orphans: 3; widows: 3; }
  .sf-no-print   { display: none; }
  .sf-print-only { display: block; }
  .sf-page-break-before { break-before: page; }
  .sf-page-break-after  { break-after: page; }

  /* Keep block-level content together across page boundaries. Cards, notices,
     callouts, banners, stats, empty states, error summaries, figures, code
     blocks, and quotes should not split mid-element. Tables: rows + thead
     stay intact so a row never splits across a page. */
  .sf-card,
  .sf-callout,
  .sf-banner,
  .sf-notice,
  .sf-stat,
  .sf-empty,
  .sf-error-summary,
  figure,
  pre,
  blockquote { break-inside: avoid; }

  thead, tr { break-inside: avoid; }

  /* Headings should not be orphaned at the bottom of a page. */
  h1, h2, h3, h4, h5, h6 { break-after: avoid; }

  /* Show link destinations — standard in professional print stylesheets */
  a[href]:not([href^="#"]):not([href^="javascript:"]):not([href^="tel:"]):not([href^="mailto:"])::after {
    content: " (" attr(href) ")";
    font-size: 0.8em;
    color: #000 !important;
    opacity: 0.6;
    word-break: break-all;
  }

  /* Prevent code blocks from overflowing the page margin */
  pre {
    white-space: pre-wrap;
    word-break: normal;
    overflow-wrap: anywhere;
    border: 1px solid #000 !important;
    opacity: 1;
  }
}

/* ==========================================================================
   OVERRIDES (empty — user layer)
   Sits above all slashed layers. Use for project-specific overrides that
   need to beat framework defaults without !important.

   Usage:
     @layer slashed.overrides {
       .hero { padding-block: 10rem; }
       .sf-card { --sf-card-padding: var(--sf-space-xl); }
     }
   ========================================================================== */

@layer slashed.overrides {}

/* ==========================================================================
   SLASHED Utilities — v0.6.19.1
   Layout, functional, and inline typographic composition utilities.
   See docs/UTILITIES.md for authoring guidance and the full class inventory.
   Requires: tokens-default.css + slashed-core.css (or slashed-essential.css /
   slashed-full.css).
   ========================================================================== */

/* ================================================================
   VIEWPORT BREAKPOINT UTILITIES (sm: md: lg: xl:) live in
   slashed-utilities-viewport.css. They are included in slashed-full.css.
   When using slashed-essential.css, link slashed-utilities-viewport.css
   separately to get the sm:/md:/lg:/xl: prefix classes.
   Container query utilities (cq-sm: cq-md: cq-lg: cq-xl:) are
   included here and are the preferred path for component layout.
   ================================================================ */

@layer slashed.reset, slashed.base, slashed.layout, slashed.components, slashed.utilities, slashed.visual, slashed.animations, slashed.a11y, slashed.overrides;

/* ==========================================================================
   UTILITIES
   ========================================================================== */

@layer slashed.utilities {

  /* ----- Spacing: padding ----- */

  .sf-p-0   { padding: 0; }
  .sf-py-0  { padding-block: 0; }
  .sf-px-0  { padding-inline: 0; }
  .sf-p-px  { padding: var(--sf-space-px); }
  .sf-p-micro { padding: var(--sf-space-micro); }
  .sf-p-2xs { padding: var(--sf-space-2xs); }
  .sf-p-xs  { padding: var(--sf-space-xs); }
  .sf-p-s   { padding: var(--sf-space-s); }
  .sf-p-m   { padding: var(--sf-space-m); }
  .sf-p-l   { padding: var(--sf-space-l); }
  .sf-p-xl  { padding: var(--sf-space-xl); }
  .sf-p-2xl { padding: var(--sf-space-2xl); }
  .sf-p-3xl { padding: var(--sf-space-3xl); }
  .sf-p-4xl { padding: var(--sf-space-4xl); }

  .sf-px-px  { padding-inline: var(--sf-space-px); }
  .sf-px-2xs { padding-inline: var(--sf-space-2xs); }
  .sf-px-xs  { padding-inline: var(--sf-space-xs); }
  .sf-px-s   { padding-inline: var(--sf-space-s); }
  .sf-px-m   { padding-inline: var(--sf-space-m); }
  .sf-px-l   { padding-inline: var(--sf-space-l); }
  .sf-px-xl  { padding-inline: var(--sf-space-xl); }
  .sf-px-2xl { padding-inline: var(--sf-space-2xl); }
  .sf-px-3xl { padding-inline: var(--sf-space-3xl); }
  .sf-px-4xl { padding-inline: var(--sf-space-4xl); }
  .sf-px-gutter { padding-inline: var(--sf-space-gutter); }

  .sf-py-px  { padding-block: var(--sf-space-px); }
  .sf-py-2xs { padding-block: var(--sf-space-2xs); }
  .sf-py-xs  { padding-block: var(--sf-space-xs); }
  .sf-py-s   { padding-block: var(--sf-space-s); }
  .sf-py-m   { padding-block: var(--sf-space-m); }
  .sf-py-l   { padding-block: var(--sf-space-l); }
  .sf-py-xl  { padding-block: var(--sf-space-xl); }
  .sf-py-2xl { padding-block: var(--sf-space-2xl); }
  .sf-py-3xl { padding-block: var(--sf-space-3xl); }
  .sf-py-4xl { padding-block: var(--sf-space-4xl); }

  .sf-pt-0   { padding-block-start: 0; }
  .sf-pt-2xs { padding-block-start: var(--sf-space-2xs); }
  .sf-pt-xs  { padding-block-start: var(--sf-space-xs); }
  .sf-pt-s   { padding-block-start: var(--sf-space-s); }
  .sf-pt-m   { padding-block-start: var(--sf-space-m); }
  .sf-pt-l   { padding-block-start: var(--sf-space-l); }
  .sf-pt-xl  { padding-block-start: var(--sf-space-xl); }
  .sf-pt-2xl { padding-block-start: var(--sf-space-2xl); }
  .sf-pt-3xl { padding-block-start: var(--sf-space-3xl); }
  .sf-pt-4xl { padding-block-start: var(--sf-space-4xl); }

  .sf-pb-0   { padding-block-end: 0; }
  .sf-pb-2xs { padding-block-end: var(--sf-space-2xs); }
  .sf-pb-xs  { padding-block-end: var(--sf-space-xs); }
  .sf-pb-s   { padding-block-end: var(--sf-space-s); }
  .sf-pb-m   { padding-block-end: var(--sf-space-m); }
  .sf-pb-l   { padding-block-end: var(--sf-space-l); }
  .sf-pb-xl  { padding-block-end: var(--sf-space-xl); }
  .sf-pb-2xl { padding-block-end: var(--sf-space-2xl); }
  .sf-pb-3xl { padding-block-end: var(--sf-space-3xl); }
  .sf-pb-4xl { padding-block-end: var(--sf-space-4xl); }

  .sf-ps-0   { padding-inline-start: 0; }
  .sf-ps-2xs { padding-inline-start: var(--sf-space-2xs); }
  .sf-ps-xs  { padding-inline-start: var(--sf-space-xs); }
  .sf-ps-s   { padding-inline-start: var(--sf-space-s); }
  .sf-ps-m   { padding-inline-start: var(--sf-space-m); }
  .sf-ps-l   { padding-inline-start: var(--sf-space-l); }
  .sf-ps-xl  { padding-inline-start: var(--sf-space-xl); }
  .sf-ps-2xl { padding-inline-start: var(--sf-space-2xl); }
  .sf-ps-3xl { padding-inline-start: var(--sf-space-3xl); }
  .sf-ps-4xl { padding-inline-start: var(--sf-space-4xl); }

  .sf-pe-0   { padding-inline-end: 0; }
  .sf-pe-2xs { padding-inline-end: var(--sf-space-2xs); }
  .sf-pe-xs  { padding-inline-end: var(--sf-space-xs); }
  .sf-pe-s   { padding-inline-end: var(--sf-space-s); }
  .sf-pe-m   { padding-inline-end: var(--sf-space-m); }
  .sf-pe-l   { padding-inline-end: var(--sf-space-l); }
  .sf-pe-xl  { padding-inline-end: var(--sf-space-xl); }
  .sf-pe-2xl { padding-inline-end: var(--sf-space-2xl); }
  .sf-pe-3xl { padding-inline-end: var(--sf-space-3xl); }
  .sf-pe-4xl { padding-inline-end: var(--sf-space-4xl); }

  /* ----- Spacing: margin ----- */

  .sf-m-0     { margin: 0; }
  .sf-m-2xs   { margin: var(--sf-space-2xs); }
  .sf-m-xs    { margin: var(--sf-space-xs); }
  .sf-m-s     { margin: var(--sf-space-s); }
  .sf-m-m     { margin: var(--sf-space-m); }
  .sf-m-l     { margin: var(--sf-space-l); }
  .sf-m-xl    { margin: var(--sf-space-xl); }
  .sf-m-2xl   { margin: var(--sf-space-2xl); }
  .sf-m-3xl   { margin: var(--sf-space-3xl); }
  .sf-m-4xl   { margin: var(--sf-space-4xl); }

  .sf-m-auto  { margin: auto; }
  .sf-mx-auto { margin-inline: auto; }
  .sf-mx-0    { margin-inline: 0; }
  .sf-mx-2xs  { margin-inline: var(--sf-space-2xs); }
  .sf-mx-xs   { margin-inline: var(--sf-space-xs); }
  .sf-mx-s    { margin-inline: var(--sf-space-s); }
  .sf-mx-m    { margin-inline: var(--sf-space-m); }
  .sf-mx-l    { margin-inline: var(--sf-space-l); }
  .sf-mx-xl   { margin-inline: var(--sf-space-xl); }
  .sf-mx-2xl  { margin-inline: var(--sf-space-2xl); }
  .sf-mx-3xl  { margin-inline: var(--sf-space-3xl); }
  .sf-mx-4xl  { margin-inline: var(--sf-space-4xl); }

  .sf-my-0    { margin-block: 0; }
  .sf-my-2xs  { margin-block: var(--sf-space-2xs); }
  .sf-my-xs   { margin-block: var(--sf-space-xs); }
  .sf-my-s    { margin-block: var(--sf-space-s); }
  .sf-my-m    { margin-block: var(--sf-space-m); }
  .sf-my-l    { margin-block: var(--sf-space-l); }
  .sf-my-xl   { margin-block: var(--sf-space-xl); }
  .sf-my-2xl  { margin-block: var(--sf-space-2xl); }
  .sf-my-3xl  { margin-block: var(--sf-space-3xl); }
  .sf-my-4xl  { margin-block: var(--sf-space-4xl); }

  .sf-mt-auto { margin-block-start: auto; }
  .sf-mb-auto { margin-block-end: auto; }
  .sf-ms-auto { margin-inline-start: auto; }
  .sf-me-auto { margin-inline-end: auto; }

  .sf-mt-0   { margin-block-start: 0; }
  .sf-mt-2xs { margin-block-start: var(--sf-space-2xs); }
  .sf-mt-xs  { margin-block-start: var(--sf-space-xs); }
  .sf-mt-s   { margin-block-start: var(--sf-space-s); }
  .sf-mt-m   { margin-block-start: var(--sf-space-m); }
  .sf-mt-l   { margin-block-start: var(--sf-space-l); }
  .sf-mt-xl  { margin-block-start: var(--sf-space-xl); }
  .sf-mt-2xl { margin-block-start: var(--sf-space-2xl); }
  .sf-mt-3xl { margin-block-start: var(--sf-space-3xl); }
  .sf-mt-4xl { margin-block-start: var(--sf-space-4xl); }

  .sf-mb-0   { margin-block-end: 0; }
  .sf-mb-2xs { margin-block-end: var(--sf-space-2xs); }
  .sf-mb-xs  { margin-block-end: var(--sf-space-xs); }
  .sf-mb-s   { margin-block-end: var(--sf-space-s); }
  .sf-mb-m   { margin-block-end: var(--sf-space-m); }
  .sf-mb-l   { margin-block-end: var(--sf-space-l); }
  .sf-mb-xl  { margin-block-end: var(--sf-space-xl); }
  .sf-mb-2xl { margin-block-end: var(--sf-space-2xl); }
  .sf-mb-3xl { margin-block-end: var(--sf-space-3xl); }
  .sf-mb-4xl { margin-block-end: var(--sf-space-4xl); }

  .sf-ms-0   { margin-inline-start: 0; }
  .sf-ms-2xs { margin-inline-start: var(--sf-space-2xs); }
  .sf-ms-xs  { margin-inline-start: var(--sf-space-xs); }
  .sf-ms-s   { margin-inline-start: var(--sf-space-s); }
  .sf-ms-m   { margin-inline-start: var(--sf-space-m); }
  .sf-ms-l   { margin-inline-start: var(--sf-space-l); }
  .sf-ms-xl  { margin-inline-start: var(--sf-space-xl); }
  .sf-ms-2xl { margin-inline-start: var(--sf-space-2xl); }
  .sf-ms-3xl { margin-inline-start: var(--sf-space-3xl); }
  .sf-ms-4xl { margin-inline-start: var(--sf-space-4xl); }

  .sf-me-0   { margin-inline-end: 0; }
  .sf-me-2xs { margin-inline-end: var(--sf-space-2xs); }
  .sf-me-xs  { margin-inline-end: var(--sf-space-xs); }
  .sf-me-s   { margin-inline-end: var(--sf-space-s); }
  .sf-me-m   { margin-inline-end: var(--sf-space-m); }
  .sf-me-l   { margin-inline-end: var(--sf-space-l); }
  .sf-me-xl  { margin-inline-end: var(--sf-space-xl); }
  .sf-me-2xl { margin-inline-end: var(--sf-space-2xl); }
  .sf-me-3xl { margin-inline-end: var(--sf-space-3xl); }
  .sf-me-4xl { margin-inline-end: var(--sf-space-4xl); }

  /* ----- Spacing: gap ----- */

  .sf-gap-0   { gap: 0; }
  .sf-gap-2xs { gap: var(--sf-space-2xs); }
  .sf-gap-xs  { gap: var(--sf-space-xs); }
  .sf-gap-s   { gap: var(--sf-space-s); }
  .sf-gap-m   { gap: var(--sf-space-m); }
  .sf-gap-l   { gap: var(--sf-space-l); }
  .sf-gap-xl  { gap: var(--sf-space-xl); }
  .sf-gap-2xl { gap: var(--sf-space-2xl); }
  .sf-gap-3xl { gap: var(--sf-space-3xl); }
  .sf-gap-4xl { gap: var(--sf-space-4xl); }

  .sf-gap-x-0   { column-gap: 0; }
  .sf-gap-x-2xs { column-gap: var(--sf-space-2xs); }
  .sf-gap-x-xs  { column-gap: var(--sf-space-xs); }
  .sf-gap-x-s   { column-gap: var(--sf-space-s); }
  .sf-gap-x-m   { column-gap: var(--sf-space-m); }
  .sf-gap-x-l   { column-gap: var(--sf-space-l); }
  .sf-gap-x-xl  { column-gap: var(--sf-space-xl); }
  .sf-gap-x-2xl { column-gap: var(--sf-space-2xl); }
  .sf-gap-x-3xl { column-gap: var(--sf-space-3xl); }
  .sf-gap-x-4xl { column-gap: var(--sf-space-4xl); }

  .sf-gap-y-0   { row-gap: 0; }
  .sf-gap-y-2xs { row-gap: var(--sf-space-2xs); }
  .sf-gap-y-xs  { row-gap: var(--sf-space-xs); }
  .sf-gap-y-s   { row-gap: var(--sf-space-s); }
  .sf-gap-y-m   { row-gap: var(--sf-space-m); }
  .sf-gap-y-l   { row-gap: var(--sf-space-l); }
  .sf-gap-y-xl  { row-gap: var(--sf-space-xl); }
  .sf-gap-y-2xl { row-gap: var(--sf-space-2xl); }
  .sf-gap-y-3xl { row-gap: var(--sf-space-3xl); }
  .sf-gap-y-4xl { row-gap: var(--sf-space-4xl); }

  /* ----- Typography: font size scale ----- */

  .sf-text-2xs { font-size: var(--sf-text-2xs); }
  .sf-text-xs  { font-size: var(--sf-text-xs); }
  .sf-text-s   { font-size: var(--sf-text-s); }
  .sf-text-m   { font-size: var(--sf-text-m); }
  .sf-text-l   { font-size: var(--sf-text-l); }
  .sf-text-xl  { font-size: var(--sf-text-xl); }
  .sf-text-2xl { font-size: var(--sf-text-2xl); }
  .sf-text-3xl { font-size: var(--sf-text-3xl); }
  .sf-text-4xl { font-size: var(--sf-text-4xl); }
  .sf-text-5xl { font-size: var(--sf-text-5xl); }

  /* ----- Typography: semantic size aliases ----- */
  /* Pair with token aliases (see tokens-default.css "Semantic text-size aliases").
     Override the alias once to retune every consumer of an intent. */
  .sf-text-small   { font-size: var(--sf-text-small); }
  .sf-text-caption { font-size: var(--sf-text-caption); }
  .sf-text-micro   { font-size: var(--sf-text-micro); }

  .sf-text-fluid-hero { font-size: var(--sf-text-fluid-hero); }

  /* ----- Typography: semantic heading scale ----- */
  /* Use when semantic heading level and visual size must differ.
     e.g. <p class="h2">Large display text that is not an h2</p> */

  .sf-h1 { font-family: var(--sf-font-heading); font-size: var(--sf-h1); line-height: var(--sf-leading-tight); font-weight: var(--sf-font-weight-heading); text-wrap: balance; }
  .sf-h2 { font-family: var(--sf-font-heading); font-size: var(--sf-h2); line-height: var(--sf-leading-tight); font-weight: var(--sf-font-weight-heading); text-wrap: balance; }
  .sf-h3 { font-family: var(--sf-font-heading); font-size: var(--sf-h3); line-height: var(--sf-leading-tight); font-weight: var(--sf-font-weight-heading); text-wrap: balance; }
  .sf-h4 { font-family: var(--sf-font-heading); font-size: var(--sf-h4); line-height: var(--sf-leading-snug);  font-weight: var(--sf-font-weight-heading); text-wrap: balance; }
  .sf-h5 { font-family: var(--sf-font-heading); font-size: var(--sf-h5); line-height: var(--sf-leading-snug);  font-weight: var(--sf-font-weight-heading); }
  .sf-h6 { font-family: var(--sf-font-heading); font-size: var(--sf-h6); line-height: var(--sf-leading-normal); font-weight: var(--sf-font-weight-heading); }

  /* ----- Typography: weight ----- */

  .sf-font-light     { font-weight: var(--sf-font-weight-light); }
  .sf-font-normal    { font-weight: var(--sf-font-weight-body); }
  .sf-font-medium    { font-weight: var(--sf-font-weight-medium); }
  .sf-font-semi      { font-weight: var(--sf-font-weight-semi); }
  .sf-font-bold      { font-weight: var(--sf-font-weight-bold); }
  .sf-font-extrabold { font-weight: var(--sf-font-weight-extrabold); }
  .sf-font-black     { font-weight: var(--sf-font-weight-black); }

  /* ----- Typography: style, transform, decoration ----- */

  .sf-italic       { font-style: italic; }
  .sf-uppercase    { text-transform: uppercase; }
  .sf-lowercase    { text-transform: lowercase; }
  .sf-capitalize   { text-transform: capitalize; }
  .sf-underline    { text-decoration: underline; }
  .sf-line-through { text-decoration: line-through; }
  .sf-no-underline { text-decoration: none; }
  .sf-link-reset   { color: var(--sf-color-text); text-decoration: none; }
  .sf-text-eyebrow { font-weight: 700; letter-spacing: var(--sf-tracking-widest); text-transform: uppercase; }

  /* Animated arrow — translates 0.2em inline-end on parent hover.
     Apply to the icon child inside any link or button:
       <a href="#">Learn more <svg class="sf-link-arrow-icon">…</svg></a>
       <button>Submit <svg class="sf-link-arrow-icon">…</svg></button> */
  .sf-link-arrow-icon {
    display: inline-block;
    transition: translate var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    :is(a, button):hover .sf-link-arrow-icon { translate: 0.2em 0; }
  }
  @media (prefers-reduced-motion: reduce) {
    .sf-link-arrow-icon { transition: none; }
  }

  /* ----- Typography: line-height & letter-spacing ----- */

  .sf-leading-none   { line-height: 1; }
  .sf-leading-tight  { line-height: var(--sf-leading-tight); }
  .sf-leading-snug   { line-height: var(--sf-leading-snug); }
  .sf-leading-normal { line-height: var(--sf-leading-normal); }
  .sf-leading-loose  { line-height: var(--sf-leading-loose); }

  .sf-tracking-tighter { letter-spacing: var(--sf-tracking-tighter); }
  .sf-tracking-tight   { letter-spacing: var(--sf-tracking-tight); }
  .sf-tracking-wide    { letter-spacing: var(--sf-tracking-wide); }
  .sf-tracking-wider   { letter-spacing: var(--sf-tracking-wider); }
  .sf-tracking-widest  { letter-spacing: var(--sf-tracking-widest); }

  /* ----- Typography: alignment & wrapping ----- */

  .sf-text-left    { text-align: start; }
  .sf-text-center  { text-align: center; }
  .sf-text-right   { text-align: end; }
  .sf-text-balance { text-wrap: balance; }
  .sf-text-pretty  { text-wrap: pretty; }

  /* ----- Typography: font families ----- */

  .sf-font-body    { font-family: var(--sf-font-body); }
  .sf-font-heading { font-family: var(--sf-font-heading); }
  .sf-font-mono    { font-family: var(--sf-font-mono); }

  /* ----- Typography: overflow & wrapping ----- */

  .sf-truncate          { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .sf-line-clamp-1,
  .sf-line-clamp-2,
  .sf-line-clamp-3,
  .sf-line-clamp-4,
  .sf-line-clamp-5  { display: -webkit-box; -webkit-box-orient: vertical; overflow: hidden; }
  .sf-line-clamp-1  { -webkit-line-clamp: 1; }
  .sf-line-clamp-2  { -webkit-line-clamp: 2; }
  .sf-line-clamp-3  { -webkit-line-clamp: 3; }
  .sf-line-clamp-4  { -webkit-line-clamp: 4; }
  .sf-line-clamp-5  { -webkit-line-clamp: 5; }
  .sf-break-words       { overflow-wrap: break-word; }
  .sf-wrap-anywhere     { overflow-wrap: anywhere; }
  .sf-whitespace-nowrap { white-space: nowrap; }

  /* ----- Text colors ----- */

  .sf-text-primary    { color: var(--sf-primary); }
  .sf-text-secondary  { color: var(--sf-secondary); }
  .sf-text-tertiary   { color: var(--sf-tertiary); }
  .sf-text-accent     { color: var(--sf-accent); }
  .sf-text-action     { color: var(--sf-action); }
  .sf-text-base       { color: var(--sf-base); }
  .sf-text-neutral    { color: var(--sf-neutral); }
  .sf-text-muted      { color: var(--sf-color-text-muted); }
  .sf-text-subdued    { color: var(--sf-color-text-secondary); }
  .sf-text-decorative      { color: var(--sf-color-text-decorative); }
  .sf-text-disabled   { color: var(--sf-color-text-disabled); }
  /* Status text utilities route through the WCAG-AA-safe semantic aliases
     (which resolve to *-600 in light mode and flip in dark mode). Avoids the
     ~2.8:1 hazard of putting raw --sf-warning on white. */
  .sf-text-success    { color: var(--sf-color-success-text); }
  .sf-text-warning    { color: var(--sf-color-warning-text); }
  .sf-text-error      { color: var(--sf-color-error-text); }
  .sf-text-info       { color: var(--sf-color-info-text); }
  .sf-text-white      { color: var(--sf-color-text-on-dark); }
  .sf-text-inherit    { color: inherit; }
  .sf-text-on-primary     { color: var(--sf-color-text-on-primary); }
  .sf-text-on-secondary   { color: var(--sf-color-text-on-secondary); }
  .sf-text-on-tertiary    { color: var(--sf-color-text-on-tertiary); }
  .sf-text-on-accent      { color: var(--sf-color-text-on-accent); }
  .sf-text-on-action      { color: var(--sf-color-text-on-action); }
  .sf-text-on-base        { color: var(--sf-color-text-on-base); }
  .sf-text-on-neutral     { color: var(--sf-color-text-on-neutral); }
  .sf-text-on-dark        { color: var(--sf-color-text-on-dark); }
  .sf-text-on-light       { color: var(--sf-color-text-on-light); }
  .sf-text-on-destructive { color: var(--sf-color-text-on-destructive); }
  .sf-text-on-success     { color: var(--sf-color-text-on-success); }
  .sf-text-on-warning     { color: var(--sf-color-text-on-warning); }
  .sf-text-on-error       { color: var(--sf-color-text-on-error); }
  .sf-text-on-info        { color: var(--sf-color-text-on-info); }

  /* Background color utilities → see slashed-utilities-visual.css */

  /* ----- Scheme / Theme ----- */

  /* UA color-scheme helpers only.
     They do not replace [data-theme] because semantic --color-* tokens
     are switched by the theme selectors in tokens-default.css. */
  .sf-scheme-dark  { color-scheme: dark; }
  .sf-scheme-light { color-scheme: light; }

  /* ----- Border ----- */

  .sf-divide-y > * + * { border-block-start: var(--sf-border-width-1) solid var(--sf-color-border); }
  .sf-divide-x > * + * { border-inline-start: var(--sf-border-width-1) solid var(--sf-color-border); }

  /* ----- Display ----- */

  .sf-block        { display: block; }
  .sf-inline-block { display: inline-block; }
  .sf-inline       { display: inline; }
  .sf-flex         { display: flex; }
  .sf-inline-flex  { display: inline-flex; }
  .sf-grid         { display: grid; }
  .sf-inline-grid  { display: inline-grid; }
  .sf-contents     { display: contents; }
  .sf-hidden       { display: none; }

  /* ----- Flex ----- */

  .sf-flex-row         { flex-direction: row; }
  .sf-flex-col         { flex-direction: column; }
  .sf-flex-row-reverse { flex-direction: row-reverse; }
  .sf-flex-wrap        { flex-wrap: wrap; }
  .sf-flex-nowrap      { flex-wrap: nowrap; }
  .sf-flex-1           { flex: 1 1 0%; }
  .sf-flex-auto        { flex: 1 1 auto; }
  .sf-flex-none        { flex: none; }
  .sf-grow             { flex-grow: 1; }
  .sf-grow-0           { flex-grow: 0; }
  .sf-shrink           { flex-shrink: 1; }
  .sf-shrink-0         { flex-shrink: 0; }

  /* ----- Alignment ----- */

  .sf-items-start    { align-items: flex-start; }
  .sf-items-center   { align-items: center; }
  .sf-items-end      { align-items: flex-end; }
  .sf-items-stretch  { align-items: stretch; }
  .sf-items-baseline { align-items: baseline; }

  .sf-justify-start   { justify-content: flex-start; }
  .sf-justify-center  { justify-content: center; }
  .sf-justify-end     { justify-content: flex-end; }
  .sf-justify-between { justify-content: space-between; }
  .sf-justify-around  { justify-content: space-around; }
  .sf-justify-evenly  { justify-content: space-evenly; }

  .sf-self-start   { align-self: flex-start; }
  .sf-self-center  { align-self: center; }
  .sf-self-end     { align-self: flex-end; }
  .sf-self-stretch { align-self: stretch; }
  .sf-self-auto    { align-self: auto; }

  .sf-place-center { display: grid; place-items: center; }

  /* ----- Grid spans ----- */

  .sf-col-span-2    { grid-column: span 2; }
  .sf-col-span-3    { grid-column: span 3; }
  .sf-col-span-4    { grid-column: span 4; }
  .sf-col-span-5    { grid-column: span 5; }
  .sf-col-span-6    { grid-column: span 6; }
  .sf-col-span-full { grid-column: 1 / -1; }
  .sf-row-span-2    { grid-row: span 2; }
  .sf-row-span-3    { grid-row: span 3; }
  .sf-row-span-4    { grid-row: span 4; }

  /* ----- Grid placement — explicit start/end position ----- */
  /* Use when span is insufficient — e.g. pinning an item to column 3 regardless of its width. */

  .sf-col-start-1  { grid-column-start: 1; }
  .sf-col-start-2  { grid-column-start: 2; }
  .sf-col-start-3  { grid-column-start: 3; }
  .sf-col-start-4  { grid-column-start: 4; }
  .sf-col-start-5  { grid-column-start: 5; }
  .sf-col-start-6  { grid-column-start: 6; }
  .sf-col-start-7  { grid-column-start: 7; }
  .sf-col-start-8  { grid-column-start: 8; }
  .sf-col-start-9  { grid-column-start: 9; }
  .sf-col-start-10 { grid-column-start: 10; }
  .sf-col-start-11 { grid-column-start: 11; }
  .sf-col-start-12 { grid-column-start: 12; }
  .sf-col-start-auto { grid-column-start: auto; }

  .sf-col-end-last { grid-column-end: -1; } /* pin to final column edge, any grid width */
  .sf-col-end-auto { grid-column-end: auto; }

  .sf-row-start-1  { grid-row-start: 1; }
  .sf-row-start-2  { grid-row-start: 2; }
  .sf-row-start-3  { grid-row-start: 3; }
  .sf-row-start-4  { grid-row-start: 4; }
  .sf-row-start-auto { grid-row-start: auto; }

  .sf-row-end-last { grid-row-end: -1; }
  .sf-row-end-auto { grid-row-end: auto; }

  /* Bento responsive collapse — placed here so .sf-bento > .col-span-* (specificity 0,2,0)
     beats plain .col-span-* (0,1,0) within the same layer without !important. */
  @container (min-width: 30em) and (max-width: 47.99em) {
    .sf-bento > .sf-col-span-3,
    .sf-bento > .sf-col-span-4,
    .sf-bento > .sf-col-span-5,
    .sf-bento > .sf-col-span-6,
    .sf-bento > .sf-col-span-full { grid-column: 1 / -1; }
  }
  @container (max-width: 29.9999em) {
    .sf-bento                   { grid-auto-rows: auto; }
    .sf-bento > *               { grid-column: 1 / -1; grid-row: auto; }
  }

  /* ----- Sizing — three axes with explicit prefix -----
     Parent-relative fractions  →  .w-1/2, .w-1/3, .w-2/3, .w-1/4, .w-3/4
     Viewport-relative          →  .sf-w-vw-10 … .sf-w-vw-100 (steps of 10)
     Content-width-relative     →  .w-content-1/4 … .w-content-3/4, .sf-w-content-full
     Intrinsic                  →  .sf-w-full, .sf-w-auto, .sf-w-fit, .sf-w-min, .sf-w-max
     The slash is escaped in CSS (\/) and used unescaped in HTML (class="w-1/2"). */

  .sf-w-full  { width: 100%; }
  .sf-w-auto  { width: auto; }
  .sf-w-fit   { width: fit-content; }
  .sf-w-min   { width: min-content; }
  .sf-w-max   { width: max-content; }
  .sf-h-fit   { height: fit-content; }
  .sf-min-w-0    { min-width: 0; }
  .sf-min-w-full { min-width: 100%; }
  .sf-max-w-full    { max-width: 100%; }
  .sf-max-w-none    { max-width: none; }
  .sf-max-w-dialog  { max-width: var(--sf-container-dialog); }
  .sf-max-w-form    { max-width: var(--sf-container-form); }
  .sf-max-w-narrow  { max-width: var(--sf-container-narrow); }
  .sf-max-w-prose   { max-width: var(--sf-container-prose); }
  .sf-max-w-wide    { max-width: var(--sf-container-wide); }
  .sf-max-h-full    { max-height: 100%; }

  /* ----- Measure (centred reading widths) -----
     Pair `margin-inline: auto` with `max-inline-size` for centred reading
     columns. Sourced from blueprints audit pass #2 (PR #5): each width
     recurred in ≥3 unrelated wireframe categories. Distinct from
     `.sf-max-w-prose` (which uses the `--container-prose` token at 65ch). */

  .sf-measure-xs  { margin-inline: auto; max-inline-size: 40rem; }
  .sf-measure-s   { margin-inline: auto; max-inline-size: 42rem; }
  .sf-measure-m   { margin-inline: auto; max-inline-size: 44rem; }
  .sf-measure-l   { margin-inline: auto; max-inline-size: 48rem; }
  .sf-measure-xl  { margin-inline: auto; max-inline-size: 56rem; }
  .sf-measure-2xl { margin-inline: auto; max-inline-size: 64rem; }

  /* Parent-relative fractions */
  .sf-w-1\/2  { width: 50%; }
  .sf-w-1\/3  { width: 33.3333%; }
  .sf-w-2\/3  { width: 66.6667%; }
  .sf-w-1\/4  { width: 25%; }
  .sf-w-3\/4  { width: 75%; }

  /* Viewport-relative — for hero sections, full-bleed elements, breakouts.
     Use sparingly: vw ignores ancestor padding/scrollbars. */
  .sf-w-vw-10  { width: 10vw; }
  .sf-w-vw-20  { width: 20vw; }
  .sf-w-vw-30  { width: 30vw; }
  .sf-w-vw-40  { width: 40vw; }
  .sf-w-vw-50  { width: 50vw; }
  .sf-w-vw-60  { width: 60vw; }
  .sf-w-vw-70  { width: 70vw; }
  .sf-w-vw-80  { width: 80vw; }
  .sf-w-vw-90  { width: 90vw; }
  .sf-w-vw-100 { width: 100vw; }

  /* Content-width-relative — centers with max-inline-size as fraction of --content-width */
  .sf-w-content-1\/4  { width: 100%; max-inline-size: calc(var(--sf-content-width) * 0.25);   margin-inline: auto; }
  .sf-w-content-1\/3  { width: 100%; max-inline-size: calc(var(--sf-content-width) * 0.3333); margin-inline: auto; }
  .sf-w-content-1\/2  { width: 100%; max-inline-size: calc(var(--sf-content-width) * 0.5);    margin-inline: auto; }
  .sf-w-content-2\/3  { width: 100%; max-inline-size: calc(var(--sf-content-width) * 0.6667); margin-inline: auto; }
  .sf-w-content-3\/4  { width: 100%; max-inline-size: calc(var(--sf-content-width) * 0.75);   margin-inline: auto; }
  .sf-w-content-full  { width: 100%; max-inline-size: var(--sf-content-width);                margin-inline: auto; }

  .sf-w-screen { width: 100vw; }
  .sf-h-full   { height: 100%; }
  .sf-h-auto   { height: auto; }
  .sf-h-screen { height: 100vh; height: 100dvh; }
  .sf-h-svh    { height: 100svh; }
  .sf-h-min    { height: min-content; }
  .sf-h-max    { height: max-content; }

  .sf-min-h-screen { min-height: 100vh; min-height: 100dvh; }
  .sf-min-h-0      { min-height: 0; }
  .sf-max-h-screen { max-height: 100vh; max-height: 100dvh; }

  .sf-aspect-video  { aspect-ratio: 16 / 9; }
  .sf-aspect-square { aspect-ratio: 1; }
  .sf-aspect-3-2    { aspect-ratio: 3 / 2; }
  .sf-aspect-4-3    { aspect-ratio: 4 / 3; }
  .sf-aspect-16-10  { aspect-ratio: 16 / 10; }
  .sf-aspect-3-1    { aspect-ratio: 3 / 1; }
  .sf-aspect-2-3    { aspect-ratio: 2 / 3; }
  .sf-aspect-5-4    { aspect-ratio: 5 / 4; }
  .sf-aspect-4-5    { aspect-ratio: 4 / 5; }
  /* Escape hatch — set the ratio per instance: style="--ratio: 21/9". */
  .sf-aspect-var    { aspect-ratio: var(--sf-ratio, 16 / 9); }

  /* ----- Position ----- */

  .sf-static   { position: static; }
  .sf-relative { position: relative; }
  .sf-absolute { position: absolute; }
  .sf-fixed    { position: fixed; }
  .sf-sticky   { position: sticky; inset-block-start: var(--sf-sticky-top, 0); }

  .sf-inset-0   { inset: 0; }
  .sf-inset-x-0 { inset-inline: 0; }
  .sf-inset-y-0 { inset-block: 0; }
  .sf-top-0     { inset-block-start: 0; }
  .sf-right-0   { inset-inline-end: 0; }
  .sf-bottom-0  { inset-block-end: 0; }
  .sf-left-0    { inset-inline-start: 0; }
  .sf-start-0   { inset-inline-start: 0; }
  .sf-end-0     { inset-inline-end: 0; }

  /* ----- Z-index ----- */

  .sf-z-below     { z-index: var(--sf-z-below); }
  .sf-z-base      { z-index: var(--sf-z-base); }
  .sf-z-raised    { z-index: var(--sf-z-raised); }
  .sf-z-docked    { z-index: var(--sf-z-docked); }
  .sf-z-above     { z-index: var(--sf-z-above); }
  .sf-z-dropdown  { z-index: var(--sf-z-dropdown); }
  .sf-z-sticky    { z-index: var(--sf-z-sticky); }
  .sf-z-banner    { z-index: var(--sf-z-banner); }
  .sf-z-overlay   { z-index: var(--sf-z-overlay); }
  .sf-z-modal     { z-index: var(--sf-z-modal); }
  .sf-z-popover   { z-index: var(--sf-z-popover); }
  .sf-z-toast     { z-index: var(--sf-z-toast); }
  .sf-z-tooltip   { z-index: var(--sf-z-tooltip); }
  .sf-z-max       { z-index: var(--sf-z-max); }

  /* ----- View Transition name utilities ----- */
  /* Assign unique view-transition-name values for per-element cross-page animations.
     Chrome 111+, Safari 18+. Use unique names per page — duplicates are silently ignored. */

  .sf-vt-hero  { view-transition-name: hero; }
  .sf-vt-image { view-transition-name: image; }
  .sf-vt-title { view-transition-name: title; }
  /* .sf-vt-card: uses CSS variable to avoid collisions — set unique --vt-name per instance:
     style="--vt-name: product-42" */
  .sf-vt-card  { view-transition-name: var(--sf-vt-name, card); }

  /* ----- Object fit & overflow ----- */

  .sf-object-cover      { object-fit: cover; }
  .sf-object-contain    { object-fit: contain; }
  .sf-object-fill       { object-fit: fill; }
  .sf-object-scale-down { object-fit: scale-down; }
  .sf-object-top        { object-position: top; }
  .sf-object-bottom     { object-position: bottom; }
  .sf-object-center     { object-position: center; }
  .sf-object-left       { object-position: left; }
  .sf-object-right      { object-position: right; }

  .sf-overflow-hidden  { overflow: hidden; }
  .sf-overflow-auto    { overflow: auto; }
  .sf-overflow-scroll  { overflow: scroll; }
  .sf-overflow-visible { overflow: visible; }
  .sf-overflow-x-auto  { overflow-x: auto; }
  .sf-overflow-y-auto  { overflow-y: auto; }
  .sf-scrollbar-thin   { scrollbar-width: thin; }

  .sf-overscroll-contain { overscroll-behavior: contain; }
  .sf-overscroll-none    { overscroll-behavior: none; }

  .sf-scroll-smooth    { scroll-behavior: smooth; }
  .sf-scroll-auto      { scroll-behavior: auto; }
  .sf-scroll-mt-header { scroll-margin-top: var(--sf-header-height); }
  .sf-scroll-pt-header { scroll-padding-top: var(--sf-header-height); }

  .sf-touch-none  { touch-action: none; }
  .sf-touch-pan-x { touch-action: pan-x; }
  .sf-touch-pan-y { touch-action: pan-y; }

  /* ----- Interaction ----- */

  .sf-cursor-pointer      { cursor: pointer; }
  .sf-cursor-default      { cursor: default; }
  .sf-cursor-text         { cursor: text; }
  .sf-cursor-not-allowed  { cursor: not-allowed; }
  .sf-cursor-wait         { cursor: wait; }
  .sf-cursor-grab         { cursor: grab; }
  .sf-cursor-grabbing     { cursor: grabbing; }
  .sf-select-none         { user-select: none; }
  .sf-pointer-events-none { pointer-events: none; }
  .sf-appearance-none     { appearance: none; -webkit-appearance: none; }
  .sf-resize-none         { resize: none; }

  /* ----- Visibility & order ----- */

  .sf-invisible   { visibility: hidden; }
  .sf-visible     { visibility: visible; }
  /* order scale — `.sf-order-first` (-1) and `.sf-order-last` (13) bracket the 0–12 range
     so they compose predictably with explicit positions. */
  .sf-order-first { order: -1; }
  .sf-order-last  { order: 13; }
  .sf-order-none  { order: 0; }
  .sf-order-0     { order: 0; }
  .sf-order-1     { order: 1; }
  .sf-order-2     { order: 2; }
  .sf-order-3     { order: 3; }
  .sf-order-4     { order: 4; }
  .sf-order-5     { order: 5; }
  .sf-order-6     { order: 6; }
  .sf-order-7     { order: 7; }
  .sf-order-8     { order: 8; }
  .sf-order-9     { order: 9; }
  .sf-order-10    { order: 10; }
  .sf-order-11    { order: 11; }
  .sf-order-12    { order: 12; }

  /* ----- Conditional state utilities -----
     Single-property state escape hatches for the most common interactive cues.
     For multi-property hover/focus behaviour use the BEM hover-* patterns in
     slashed-core.css (slashed.layout layer). Hover variants are wrapped in
     `@media (hover: hover)` so touch devices do not get stuck states. */

  @media (hover: hover) {
    .hover\:sf-bg-surface:hover    { background-color: var(--sf-color-surface); }
    .hover\:sf-bg-action:hover     { background-color: var(--sf-action); }
    .hover\:sf-text-primary:hover  { color: var(--sf-primary); }
    .hover\:sf-text-muted:hover    { color: var(--sf-color-text-muted); }
  }

  .focus\:sf-ring:focus-visible {
    outline: var(--sf-focus-ring-width) solid var(--sf-focus-ring-color);
    outline-offset: var(--sf-focus-ring-offset);
  }
  .focus\:sf-border:focus-visible        { border-color: var(--sf-action); }
  .focus-within\:sf-ring:focus-within {
    outline: var(--sf-focus-ring-width) solid var(--sf-focus-ring-color);
    outline-offset: var(--sf-focus-ring-offset);
  }
  .focus-within\:sf-border:focus-within  { border-color: var(--sf-action); }

  /* ----- Misc ----- */

  .sf-list-none    { list-style: none; padding-inline-start: 0; }
  .sf-input-hidden { position: absolute; opacity: 0; width: 0; height: 0; }
  .sf-content-auto { content-visibility: auto; contain-intrinsic-size: auto 500px; }
  .sf-mask-fade {
    mask-image: linear-gradient(
      var(--sf-mask-dir, to bottom),
      black var(--sf-mask-from, 50%),
      transparent var(--sf-mask-to, 100%)
    );
  }

  /* ----- Scroll snap ----- */

  .sf-snap-x      { scroll-snap-type: x mandatory; }
  .sf-snap-y      { scroll-snap-type: y mandatory; }
  .sf-snap-x-prox { scroll-snap-type: x proximity; }
  .sf-snap-y-prox { scroll-snap-type: y proximity; }
  .sf-snap-start  { scroll-snap-align: start; }
  .sf-snap-center { scroll-snap-align: center; }
  .sf-snap-end    { scroll-snap-align: end; }

  /* ----- SVG ----- */

  .sf-fill-current { fill: currentcolor; }

  .sf-stroke-current { stroke: currentcolor; }

  /* ----- Accessibility ----- */

  .sf-not-sr-only {
    position: static; width: auto; height: auto;
    padding: 0; margin: 0; overflow: visible;
    clip-path: none; white-space: normal;
  }

  /* ----- :has() utilities ----- */
  /* No JS — browser applies :user-invalid after first interaction with an invalid field. */

  .sf-has-invalid:has(:user-invalid) {
    border-color: var(--sf-error);
  }
  .sf-has-checked:has(:checked) {
    border-color: var(--sf-primary);
    background-color: var(--sf-primary-50); /* not shorthand — preserves any existing background-image/position/size */
  }

  /* ----- Container query setup ----- */
  /* Establish a query context on the parent, then use cq-* classes on children. */

  .sf-cq-inline { container-type: inline-size; }
  .sf-cq-size   { container-type: size; }
  .sf-cq-normal { container-type: normal; }

  @container (min-width: 20em) {
    .cq-xs\:sf-flex     { display: flex; }
    .cq-xs\:sf-block    { display: block; }
    .cq-xs\:sf-grid     { display: grid; }
    .cq-xs\:sf-hidden   { display: none; }
    .cq-xs\:sf-flex-row { flex-direction: row; }
    .cq-xs\:sf-flex-col { flex-direction: column; }
    .cq-xs\:sf-grid-2   { grid-template-columns: repeat(2, 1fr); }
    .cq-xs\:sf-items-center { align-items: center; }
    .cq-xs\:sf-order-first  { order: -1; }
    .cq-xs\:sf-order-last   { order: 13; }
    .cq-xs\:sf-order-0      { order: 0; }
    .cq-xs\:sf-order-1      { order: 1; }
    .cq-xs\:sf-order-2      { order: 2; }
    .cq-xs\:sf-order-3      { order: 3; }
    .cq-xs\:sf-order-4      { order: 4; }
    .cq-xs\:sf-order-5      { order: 5; }
    .cq-xs\:sf-order-6      { order: 6; }
    .cq-xs\:sf-order-7      { order: 7; }
    .cq-xs\:sf-order-8      { order: 8; }
    .cq-xs\:sf-order-9      { order: 9; }
    .cq-xs\:sf-order-10     { order: 10; }
    .cq-xs\:sf-order-11     { order: 11; }
    .cq-xs\:sf-order-12     { order: 12; }
    .cq-xs\:sf-text-left    { text-align: start; }
    .cq-xs\:sf-text-center  { text-align: center; }
    .cq-xs\:sf-text-right   { text-align: end; }
  }

  @container (min-width: 30em) {
    .cq-sm\:sf-flex     { display: flex; }
    .cq-sm\:sf-block    { display: block; }
    .cq-sm\:sf-grid     { display: grid; }
    .cq-sm\:sf-hidden   { display: none; }
    .cq-sm\:sf-flex-row { flex-direction: row; }
    .cq-sm\:sf-flex-col { flex-direction: column; }
    .cq-sm\:sf-grid-2   { grid-template-columns: repeat(2, 1fr); }
    .cq-sm\:sf-grid-3   { grid-template-columns: repeat(3, 1fr); }
    .cq-sm\:sf-items-center  { align-items: center; }
    .cq-sm\:sf-justify-between { justify-content: space-between; }
    .cq-sm\:sf-order-first  { order: -1; }
    .cq-sm\:sf-order-last   { order: 13; }
    .cq-sm\:sf-order-0      { order: 0; }
    .cq-sm\:sf-order-1      { order: 1; }
    .cq-sm\:sf-order-2      { order: 2; }
    .cq-sm\:sf-order-3      { order: 3; }
    .cq-sm\:sf-order-4      { order: 4; }
    .cq-sm\:sf-order-5      { order: 5; }
    .cq-sm\:sf-order-6      { order: 6; }
    .cq-sm\:sf-order-7      { order: 7; }
    .cq-sm\:sf-order-8      { order: 8; }
    .cq-sm\:sf-order-9      { order: 9; }
    .cq-sm\:sf-order-10     { order: 10; }
    .cq-sm\:sf-order-11     { order: 11; }
    .cq-sm\:sf-order-12     { order: 12; }
    .cq-sm\:sf-text-left    { text-align: start; }
    .cq-sm\:sf-text-center  { text-align: center; }
    .cq-sm\:sf-text-right   { text-align: end; }
    .cq-sm\:sf-gap-xs  { gap: var(--sf-space-xs); }
    .cq-sm\:sf-gap-s   { gap: var(--sf-space-s); }
    .cq-sm\:sf-gap-m   { gap: var(--sf-space-m); }
    .cq-sm\:sf-gap-l   { gap: var(--sf-space-l); }
    .cq-sm\:sf-gap-xl  { gap: var(--sf-space-xl); }
    .cq-sm\:sf-gap-2xl { gap: var(--sf-space-2xl); }
    .cq-sm\:sf-p-xs  { padding: var(--sf-space-xs); }
    .cq-sm\:sf-p-s   { padding: var(--sf-space-s); }
    .cq-sm\:sf-p-m   { padding: var(--sf-space-m); }
    .cq-sm\:sf-p-l   { padding: var(--sf-space-l); }
    .cq-sm\:sf-p-xl  { padding: var(--sf-space-xl); }
    .cq-sm\:sf-px-xs { padding-inline: var(--sf-space-xs); }
    .cq-sm\:sf-px-s  { padding-inline: var(--sf-space-s); }
    .cq-sm\:sf-px-m  { padding-inline: var(--sf-space-m); }
    .cq-sm\:sf-px-l  { padding-inline: var(--sf-space-l); }
    .cq-sm\:sf-px-xl { padding-inline: var(--sf-space-xl); }
    .cq-sm\:sf-py-xs { padding-block: var(--sf-space-xs); }
    .cq-sm\:sf-py-s  { padding-block: var(--sf-space-s); }
    .cq-sm\:sf-py-m  { padding-block: var(--sf-space-m); }
    .cq-sm\:sf-py-l  { padding-block: var(--sf-space-l); }
    .cq-sm\:sf-py-xl { padding-block: var(--sf-space-xl); }
    .cq-sm\:sf-pt-s  { padding-block-start: var(--sf-space-s); }
    .cq-sm\:sf-pt-m  { padding-block-start: var(--sf-space-m); }
    .cq-sm\:sf-pt-l  { padding-block-start: var(--sf-space-l); }
    .cq-sm\:sf-pb-s  { padding-block-end: var(--sf-space-s); }
    .cq-sm\:sf-pb-m  { padding-block-end: var(--sf-space-m); }
    .cq-sm\:sf-pb-l  { padding-block-end: var(--sf-space-l); }
    .cq-sm\:sf-mt-s  { margin-block-start: var(--sf-space-s); }
    .cq-sm\:sf-mt-m  { margin-block-start: var(--sf-space-m); }
    .cq-sm\:sf-mt-l  { margin-block-start: var(--sf-space-l); }
    .cq-sm\:sf-mb-s  { margin-block-end: var(--sf-space-s); }
    .cq-sm\:sf-mb-m  { margin-block-end: var(--sf-space-m); }
    .cq-sm\:sf-mb-l  { margin-block-end: var(--sf-space-l); }
    .cq-sm\:sf-ps-s  { padding-inline-start: var(--sf-space-s); }
    .cq-sm\:sf-ps-m  { padding-inline-start: var(--sf-space-m); }
    .cq-sm\:sf-ps-l  { padding-inline-start: var(--sf-space-l); }
    .cq-sm\:sf-pe-s  { padding-inline-end: var(--sf-space-s); }
    .cq-sm\:sf-pe-m  { padding-inline-end: var(--sf-space-m); }
    .cq-sm\:sf-pe-l  { padding-inline-end: var(--sf-space-l); }
    .cq-sm\:sf-ms-s  { margin-inline-start: var(--sf-space-s); }
    .cq-sm\:sf-ms-m  { margin-inline-start: var(--sf-space-m); }
    .cq-sm\:sf-ms-l  { margin-inline-start: var(--sf-space-l); }
    .cq-sm\:sf-me-s  { margin-inline-end: var(--sf-space-s); }
    .cq-sm\:sf-me-m  { margin-inline-end: var(--sf-space-m); }
    .cq-sm\:sf-me-l  { margin-inline-end: var(--sf-space-l); }
  }

  @container (min-width: 48em) {
    .cq-md\:sf-flex     { display: flex; }
    .cq-md\:sf-block    { display: block; }
    .cq-md\:sf-grid     { display: grid; }
    .cq-md\:sf-hidden   { display: none; }
    .cq-md\:sf-flex-row { flex-direction: row; }
    .cq-md\:sf-flex-col { flex-direction: column; }
    .cq-md\:sf-grid-2   { grid-template-columns: repeat(2, 1fr); }
    .cq-md\:sf-grid-3   { grid-template-columns: repeat(3, 1fr); }
    .cq-md\:sf-grid-4   { grid-template-columns: repeat(4, 1fr); }
    .cq-md\:sf-col-span-2    { grid-column: span 2; }
    .cq-md\:sf-col-span-full { grid-column: 1 / -1; }
    .cq-md\:sf-items-start   { align-items: flex-start; }
    .cq-md\:sf-items-center  { align-items: center; }
    .cq-md\:sf-items-end     { align-items: flex-end; }
    .cq-md\:sf-justify-between { justify-content: space-between; }
    .cq-md\:sf-order-first   { order: -1; }
    .cq-md\:sf-order-last    { order: 13; }
    .cq-md\:sf-order-0       { order: 0; }
    .cq-md\:sf-order-1       { order: 1; }
    .cq-md\:sf-order-2       { order: 2; }
    .cq-md\:sf-order-3       { order: 3; }
    .cq-md\:sf-order-4       { order: 4; }
    .cq-md\:sf-order-5       { order: 5; }
    .cq-md\:sf-order-6       { order: 6; }
    .cq-md\:sf-order-7       { order: 7; }
    .cq-md\:sf-order-8       { order: 8; }
    .cq-md\:sf-order-9       { order: 9; }
    .cq-md\:sf-order-10      { order: 10; }
    .cq-md\:sf-order-11      { order: 11; }
    .cq-md\:sf-order-12      { order: 12; }
    .cq-md\:sf-text-left     { text-align: start; }
    .cq-md\:sf-text-center   { text-align: center; }
    .cq-md\:sf-text-right    { text-align: end; }
    .cq-md\:sf-gap-xs  { gap: var(--sf-space-xs); }
    .cq-md\:sf-gap-s   { gap: var(--sf-space-s); }
    .cq-md\:sf-gap-m   { gap: var(--sf-space-m); }
    .cq-md\:sf-gap-l   { gap: var(--sf-space-l); }
    .cq-md\:sf-gap-xl  { gap: var(--sf-space-xl); }
    .cq-md\:sf-gap-2xl { gap: var(--sf-space-2xl); }
    .cq-md\:sf-p-xs  { padding: var(--sf-space-xs); }
    .cq-md\:sf-p-s   { padding: var(--sf-space-s); }
    .cq-md\:sf-p-m   { padding: var(--sf-space-m); }
    .cq-md\:sf-p-l   { padding: var(--sf-space-l); }
    .cq-md\:sf-p-xl  { padding: var(--sf-space-xl); }
    .cq-md\:sf-px-xs { padding-inline: var(--sf-space-xs); }
    .cq-md\:sf-px-s  { padding-inline: var(--sf-space-s); }
    .cq-md\:sf-px-m  { padding-inline: var(--sf-space-m); }
    .cq-md\:sf-px-l  { padding-inline: var(--sf-space-l); }
    .cq-md\:sf-px-xl { padding-inline: var(--sf-space-xl); }
    .cq-md\:sf-py-xs { padding-block: var(--sf-space-xs); }
    .cq-md\:sf-py-s  { padding-block: var(--sf-space-s); }
    .cq-md\:sf-py-m  { padding-block: var(--sf-space-m); }
    .cq-md\:sf-py-l  { padding-block: var(--sf-space-l); }
    .cq-md\:sf-py-xl { padding-block: var(--sf-space-xl); }
    .cq-md\:sf-pt-s  { padding-block-start: var(--sf-space-s); }
    .cq-md\:sf-pt-m  { padding-block-start: var(--sf-space-m); }
    .cq-md\:sf-pt-l  { padding-block-start: var(--sf-space-l); }
    .cq-md\:sf-pb-s  { padding-block-end: var(--sf-space-s); }
    .cq-md\:sf-pb-m  { padding-block-end: var(--sf-space-m); }
    .cq-md\:sf-pb-l  { padding-block-end: var(--sf-space-l); }
    .cq-md\:sf-mt-s  { margin-block-start: var(--sf-space-s); }
    .cq-md\:sf-mt-m  { margin-block-start: var(--sf-space-m); }
    .cq-md\:sf-mt-l  { margin-block-start: var(--sf-space-l); }
    .cq-md\:sf-mb-s  { margin-block-end: var(--sf-space-s); }
    .cq-md\:sf-mb-m  { margin-block-end: var(--sf-space-m); }
    .cq-md\:sf-mb-l  { margin-block-end: var(--sf-space-l); }
    .cq-md\:sf-ps-s  { padding-inline-start: var(--sf-space-s); }
    .cq-md\:sf-ps-m  { padding-inline-start: var(--sf-space-m); }
    .cq-md\:sf-ps-l  { padding-inline-start: var(--sf-space-l); }
    .cq-md\:sf-pe-s  { padding-inline-end: var(--sf-space-s); }
    .cq-md\:sf-pe-m  { padding-inline-end: var(--sf-space-m); }
    .cq-md\:sf-pe-l  { padding-inline-end: var(--sf-space-l); }
    .cq-md\:sf-ms-s  { margin-inline-start: var(--sf-space-s); }
    .cq-md\:sf-ms-m  { margin-inline-start: var(--sf-space-m); }
    .cq-md\:sf-ms-l  { margin-inline-start: var(--sf-space-l); }
    .cq-md\:sf-me-s  { margin-inline-end: var(--sf-space-s); }
    .cq-md\:sf-me-m  { margin-inline-end: var(--sf-space-m); }
    .cq-md\:sf-me-l  { margin-inline-end: var(--sf-space-l); }
  }

  @container (min-width: 64em) {
    .cq-lg\:sf-flex     { display: flex; }
    .cq-lg\:sf-block    { display: block; }
    .cq-lg\:sf-grid     { display: grid; }
    .cq-lg\:sf-hidden   { display: none; }
    .cq-lg\:sf-flex-row { flex-direction: row; }
    .cq-lg\:sf-flex-col { flex-direction: column; }
    .cq-lg\:sf-grid-2   { grid-template-columns: repeat(2, 1fr); }
    .cq-lg\:sf-grid-3   { grid-template-columns: repeat(3, 1fr); }
    .cq-lg\:sf-grid-4   { grid-template-columns: repeat(4, 1fr); }
    .cq-lg\:sf-col-span-2    { grid-column: span 2; }
    .cq-lg\:sf-col-span-full { grid-column: 1 / -1; }
    .cq-lg\:sf-items-start   { align-items: flex-start; }
    .cq-lg\:sf-items-center  { align-items: center; }
    .cq-lg\:sf-items-end     { align-items: flex-end; }
    .cq-lg\:sf-justify-between { justify-content: space-between; }
    .cq-lg\:sf-order-first   { order: -1; }
    .cq-lg\:sf-order-last    { order: 13; }
    .cq-lg\:sf-order-0       { order: 0; }
    .cq-lg\:sf-order-1       { order: 1; }
    .cq-lg\:sf-order-2       { order: 2; }
    .cq-lg\:sf-order-3       { order: 3; }
    .cq-lg\:sf-order-4       { order: 4; }
    .cq-lg\:sf-order-5       { order: 5; }
    .cq-lg\:sf-order-6       { order: 6; }
    .cq-lg\:sf-order-7       { order: 7; }
    .cq-lg\:sf-order-8       { order: 8; }
    .cq-lg\:sf-order-9       { order: 9; }
    .cq-lg\:sf-order-10      { order: 10; }
    .cq-lg\:sf-order-11      { order: 11; }
    .cq-lg\:sf-order-12      { order: 12; }
    .cq-lg\:sf-text-left     { text-align: start; }
    .cq-lg\:sf-text-center   { text-align: center; }
    .cq-lg\:sf-text-right    { text-align: end; }
    .cq-lg\:sf-gap-xs  { gap: var(--sf-space-xs); }
    .cq-lg\:sf-gap-s   { gap: var(--sf-space-s); }
    .cq-lg\:sf-gap-m   { gap: var(--sf-space-m); }
    .cq-lg\:sf-gap-l   { gap: var(--sf-space-l); }
    .cq-lg\:sf-gap-xl  { gap: var(--sf-space-xl); }
    .cq-lg\:sf-gap-2xl { gap: var(--sf-space-2xl); }
    .cq-lg\:sf-p-xs  { padding: var(--sf-space-xs); }
    .cq-lg\:sf-p-s   { padding: var(--sf-space-s); }
    .cq-lg\:sf-p-m   { padding: var(--sf-space-m); }
    .cq-lg\:sf-p-l   { padding: var(--sf-space-l); }
    .cq-lg\:sf-p-xl  { padding: var(--sf-space-xl); }
    .cq-lg\:sf-px-xs { padding-inline: var(--sf-space-xs); }
    .cq-lg\:sf-px-s  { padding-inline: var(--sf-space-s); }
    .cq-lg\:sf-px-m  { padding-inline: var(--sf-space-m); }
    .cq-lg\:sf-px-l  { padding-inline: var(--sf-space-l); }
    .cq-lg\:sf-px-xl { padding-inline: var(--sf-space-xl); }
    .cq-lg\:sf-py-xs { padding-block: var(--sf-space-xs); }
    .cq-lg\:sf-py-s  { padding-block: var(--sf-space-s); }
    .cq-lg\:sf-py-m  { padding-block: var(--sf-space-m); }
    .cq-lg\:sf-py-l  { padding-block: var(--sf-space-l); }
    .cq-lg\:sf-py-xl { padding-block: var(--sf-space-xl); }
    .cq-lg\:sf-pt-s  { padding-block-start: var(--sf-space-s); }
    .cq-lg\:sf-pt-m  { padding-block-start: var(--sf-space-m); }
    .cq-lg\:sf-pt-l  { padding-block-start: var(--sf-space-l); }
    .cq-lg\:sf-pb-s  { padding-block-end: var(--sf-space-s); }
    .cq-lg\:sf-pb-m  { padding-block-end: var(--sf-space-m); }
    .cq-lg\:sf-pb-l  { padding-block-end: var(--sf-space-l); }
    .cq-lg\:sf-mt-s  { margin-block-start: var(--sf-space-s); }
    .cq-lg\:sf-mt-m  { margin-block-start: var(--sf-space-m); }
    .cq-lg\:sf-mt-l  { margin-block-start: var(--sf-space-l); }
    .cq-lg\:sf-mb-s  { margin-block-end: var(--sf-space-s); }
    .cq-lg\:sf-mb-m  { margin-block-end: var(--sf-space-m); }
    .cq-lg\:sf-mb-l  { margin-block-end: var(--sf-space-l); }
    .cq-lg\:sf-ps-s  { padding-inline-start: var(--sf-space-s); }
    .cq-lg\:sf-ps-m  { padding-inline-start: var(--sf-space-m); }
    .cq-lg\:sf-ps-l  { padding-inline-start: var(--sf-space-l); }
    .cq-lg\:sf-pe-s  { padding-inline-end: var(--sf-space-s); }
    .cq-lg\:sf-pe-m  { padding-inline-end: var(--sf-space-m); }
    .cq-lg\:sf-pe-l  { padding-inline-end: var(--sf-space-l); }
    .cq-lg\:sf-ms-s  { margin-inline-start: var(--sf-space-s); }
    .cq-lg\:sf-ms-m  { margin-inline-start: var(--sf-space-m); }
    .cq-lg\:sf-ms-l  { margin-inline-start: var(--sf-space-l); }
    .cq-lg\:sf-me-s  { margin-inline-end: var(--sf-space-s); }
    .cq-lg\:sf-me-m  { margin-inline-end: var(--sf-space-m); }
    .cq-lg\:sf-me-l  { margin-inline-end: var(--sf-space-l); }
  }

  /* ----- Viewport responsive variants (sm: md: lg: xl:) ----- */
  /* Live in slashed-utilities-viewport.css — included in slashed-full.css.
     When using slashed-essential.css, load slashed-utilities-viewport.css
     separately. For component and layout work prefer cq-* container query
     utilities above. */

  /* ----- Dark / Light mode variants ----- */

  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      .dark\:sf-hidden { display: none; }
      .dark\:sf-block  { display: block; }
      .dark\:sf-flex   { display: flex; }
      .dark\:sf-text-white { color: var(--sf-color-text-on-dark); }
      .dark\:sf-text-muted { color: var(--sf-color-text-muted); }
    }
  }
  [data-theme="dark"] {
    .dark\:sf-hidden { display: none; }
    .dark\:sf-block  { display: block; }
    .dark\:sf-flex   { display: flex; }
    .dark\:sf-text-white { color: var(--sf-color-text-on-dark); }
    .dark\:sf-text-muted { color: var(--sf-color-text-muted); }
  }

  @media (prefers-color-scheme: light) {
    :root:not([data-theme="dark"]) {
      .light\:sf-hidden { display: none; }
      .light\:sf-block  { display: block; }
      .light\:sf-flex   { display: flex; }
    }
  }
  [data-theme="light"] {
    .light\:sf-hidden { display: none; }
    .light\:sf-block  { display: block; }
    .light\:sf-flex   { display: flex; }
  }

  /* ----- Print variants ----- */

  @media print {
    .print\:sf-hidden      { display: none; }
    .print\:sf-block       { display: block; }
    .print\:sf-text-black  { color: black !important; }
    .print\:sf-bg-white    { background: white !important; }
    .print\:sf-shadow-none { box-shadow: none !important; }
    .print\:sf-border-none { border: none !important; }
    .print\:sf-p-0         { padding: 0 !important; }
    .print\:sf-m-0         { margin: 0 !important; }

    /* ----- Print optimization — framework components ----- */
    /* No !important needed — slashed.utilities layer beats slashed.components. */
    .sf-navbar,
    .sf-toast-stack,
    [data-print="hide"] { display: none; }
    details > :not(summary) { display: block; } /* force-open all accordions */
    .sf-card { break-inside: avoid; }
    :is(.sf-btn--primary, .sf-btn--destructive, .sf-btn--outline, .sf-btn--ghost) { box-shadow: none; }
    a[href]:not([href^="#"]):not([href^="javascript:"]):not([href^="tel:"]):not([href^="mailto:"])::after {
      content: " (" attr(href) ")";
      font-size: var(--sf-text-xs);
      color: var(--sf-color-text-muted);
    }
  }

  /* ----- Typography: additional text color & word-break ----- */

  .sf-text-default { color: var(--sf-color-text); }
  .sf-text-body    { color: var(--sf-color-text-body); }

  .sf-break-all    { word-break: break-all; }
  .sf-break-keep   { word-break: keep-all; }
  .sf-hyphens-auto { hyphens: auto; }
  .sf-hyphens-none { hyphens: none; }
  .sf-tabular-nums { font-variant-numeric: tabular-nums; }

  /* ----- Lists ----- */

  .sf-list-disc    { list-style: disc;    padding-inline-start: 1.25em; }
  .sf-list-decimal { list-style: decimal; padding-inline-start: 1.25em; }

  /* ----- Sizing ----- */

  .sf-max-w-content { max-width: var(--sf-content-width); }
  .sf-size-full     { width: 100%; height: 100%; }
  .sf-size-fit      { width: fit-content; height: fit-content; }
  .sf-min-h-svh     { min-height: 100svh; }

  /* ----- Overflow: clip ----- */

  .sf-overflow-clip   { overflow: clip; }
  .sf-overflow-x-clip { overflow-x: clip; }
  .sf-overflow-y-clip { overflow-y: clip; }

  /* ----- Interaction ----- */

  .sf-pointer-events-auto { pointer-events: auto; }
  .sf-select-text         { user-select: text; }
  .sf-select-all          { user-select: all; }
  .sf-isolate             { isolation: isolate; }
  .sf-isolation-auto      { isolation: auto; }

  /* ----- CSS Columns ----- */

  .sf-cols-2       { columns: 2; }
  .sf-cols-3       { columns: 3; }
  .sf-cols-4       { columns: 4; }
  .sf-cols-auto-xs { columns: auto; column-width: 12rem; }
  .sf-cols-auto-s  { columns: auto; column-width: 16rem; }
  .sf-cols-auto-m  { columns: auto; column-width: 20rem; }
  .sf-col-gap-m    { column-gap: var(--sf-space-m); }
  .sf-col-gap-l    { column-gap: var(--sf-space-l); }
  .sf-col-span-all { column-span: all; }
  .sf-col-break-before { break-before: column; }
  .sf-col-break-after  { break-after:  column; }
  .sf-col-break-avoid  { break-inside: avoid; }

}

/* ==========================================================================
   SLASHED Components — v0.6.22.0
   Interactive UI components, form patterns, animation patterns.
   Requires: slashed-core.css (or slashed-full.css)
   ========================================================================== */

@layer slashed.reset, slashed.base, slashed.layout, slashed.components, slashed.utilities, slashed.visual, slashed.animations, slashed.a11y, slashed.overrides;

/* slashed.overrides: empty — reserved for user styles that must win over all framework layers. */

/* ==========================================================================
   COMPONENTS
   ========================================================================== */

@layer slashed.components {

  /* ----- Disclosure (bordered details/summary box) ----- */

  .sf-disclosure {
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-m);
    padding: var(--sf-space-s) var(--sf-space-m);
  }
  .sf-disclosure[open] > summary { margin-block-end: var(--sf-space-s); }

  /* Smooth open/close — matches .sf-accordion animation, same @supports guard. */
  @supports selector(details::details-content) {
    .sf-disclosure::details-content {
      height: 0;
      overflow: hidden;
      transition: height var(--sf-duration-exit) var(--sf-ease-out),
                  content-visibility var(--sf-duration-exit) var(--sf-ease-out) allow-discrete;
    }
    .sf-disclosure[open]::details-content {
      height: auto;
      transition: height var(--sf-duration-enter) var(--sf-ease-out),
                  content-visibility var(--sf-duration-enter) var(--sf-ease-out) allow-discrete;
    }
  }

  /* ----- Accordion (details/summary) ----- */
  /* Each .sf-accordion has only a bottom border. Wrap multiple accordions in .sf-accordion-group
     to get the top border on the first item and avoid double borders between items.
     BEM elements: __summary (clickable header), __body (content wrapper). */

  .sf-accordion-group {
    border-block-start: var(--sf-border-width-1) solid var(--sf-accordion-border, var(--sf-color-border));
  }
  .sf-accordion { border-block-end: var(--sf-border-width-1) solid var(--sf-accordion-border, var(--sf-color-border)); }

  .sf-accordion__summary,
  .sf-accordion > summary {
    padding: var(--sf-accordion-padding, var(--sf-space-m));
    cursor: pointer;
    list-style: none;
    font-weight: 600;
  }
  .sf-accordion__summary::-webkit-details-marker,
  .sf-accordion > summary::-webkit-details-marker { display: none; }
  .sf-accordion__summary::after,
  .sf-accordion > summary::after {
    content: "";
    display: inline-block;
    float: inline-end;
    width: 1em;
    height: 1em;
    border-inline-end: 2px solid currentcolor;
    border-block-end: 2px solid currentcolor;
    rotate: 45deg;
    translate: 0 -0.2em;
    transition: rotate var(--sf-duration-fast) var(--sf-ease-out);
  }
  .sf-accordion[open] > .sf-accordion__summary::after,
  .sf-accordion[open] > summary::after { rotate: -135deg; }

  .sf-accordion__body {
    padding: 0 var(--sf-accordion-padding, var(--sf-space-m)) var(--sf-accordion-padding, var(--sf-space-m));
    color: var(--sf-color-text-secondary);
  }

  /* Smooth accordion open/close via ::details-content (Chrome 131+, FF 133+, Safari 18.2+).
     Requires interpolate-size: allow-keywords on html (set in reset layer) to transition
     height to/from the `auto` keyword. Falls back to instant open/close in browsers below
     this — the accordion still functions everywhere <details> is supported. */

  @supports selector(details::details-content) {
    .sf-accordion::details-content {
      height: 0;
      overflow: hidden;
      transition: height var(--sf-duration-exit) var(--sf-ease-out),
                  content-visibility var(--sf-duration-exit) var(--sf-ease-out) allow-discrete;
    }
    .sf-accordion[open]::details-content {
      height: auto;
      transition: height var(--sf-duration-enter) var(--sf-ease-out),
                  content-visibility var(--sf-duration-enter) var(--sf-ease-out) allow-discrete;
    }
  }
  /* ----- Modal (dialog + animation) ----- */
  /* .sf-modal extends the base <dialog> styles with entrance animation and backdrop blur.
     The base dialog already handles sizing, padding, and colors.
     Use <dialog class="modal"> in HTML. */

  .sf-modal {
    opacity: 0;
    translate: 0 var(--sf-space-m);
    transition: opacity var(--sf-duration-exit) var(--sf-ease-out),
                translate var(--sf-duration-exit) var(--sf-ease-out),
                overlay var(--sf-duration-exit) var(--sf-ease-out) allow-discrete,
                display var(--sf-duration-exit) var(--sf-ease-out) allow-discrete;
  }
  .sf-modal[open] {
    opacity: 1;
    translate: 0 0;
    transition: opacity var(--sf-duration-enter) var(--sf-ease-out),
                translate var(--sf-duration-enter) var(--sf-ease-out),
                overlay var(--sf-duration-enter) var(--sf-ease-out) allow-discrete,
                display var(--sf-duration-enter) var(--sf-ease-out) allow-discrete;
  }
  @starting-style { .sf-modal[open] { opacity: 0; translate: 0 var(--sf-space-m); } }
  .sf-modal::backdrop {
    background: var(--sf-color-backdrop);
    backdrop-filter: blur(var(--sf-blur-xs));
    opacity: 0;
    transition: opacity var(--sf-duration-exit) var(--sf-ease-out),
                overlay var(--sf-duration-exit) var(--sf-ease-out) allow-discrete,
                display var(--sf-duration-exit) var(--sf-ease-out) allow-discrete;
  }
  .sf-modal[open]::backdrop {
    opacity: 1;
    transition: opacity var(--sf-duration-enter) var(--sf-ease-out),
                overlay var(--sf-duration-enter) var(--sf-ease-out) allow-discrete,
                display var(--sf-duration-enter) var(--sf-ease-out) allow-discrete;
  }
  @starting-style { .sf-modal[open]::backdrop { opacity: 0; } }

  /* ----- Modal: drawer offcanvas modifiers ----- */
  /* Slides in from inline-start or inline-end edge. No JS required for animation.
     Instance token: --drawer-width (default 20rem).
     Combine with initModalFocusRestore() for full a11y support. */

  .sf-modal--drawer-start,
  .sf-modal--drawer-end {
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;
    margin: 0;
    max-width: none;
    width: var(--sf-drawer-width, 20rem);
    height: 100%;
    max-height: none;
    border-radius: 0;
    translate: -100% 0;
    transition: opacity var(--sf-duration-exit) var(--sf-ease-out),
                translate var(--sf-duration-exit) var(--sf-ease-out),
                overlay var(--sf-duration-exit) var(--sf-ease-out) allow-discrete,
                display var(--sf-duration-exit) var(--sf-ease-out) allow-discrete;
  }
  .sf-modal--drawer-end {
    inset-inline-start: auto;
    inset-inline-end: 0;
    translate: 100% 0;
  }
  .sf-modal--drawer-start[open],
  .sf-modal--drawer-end[open] {
    translate: 0 0;
    transition: opacity var(--sf-duration-enter) var(--sf-ease-out),
                translate var(--sf-duration-enter) var(--sf-ease-out),
                overlay var(--sf-duration-enter) var(--sf-ease-out) allow-discrete,
                display var(--sf-duration-enter) var(--sf-ease-out) allow-discrete;
  }
  @starting-style {
    .sf-modal--drawer-start[open] { translate: -100% 0; }
    .sf-modal--drawer-end[open]   { translate:  100% 0; }
  }

  /* ----- Button patterns ----- */

  .sf-btn--primary,
  .sf-btn--destructive,
  .sf-btn--outline,
  .sf-btn--ghost {
    display: inline-flex;
    align-items: center;
    gap: var(--sf-space-xs);
    min-height: 2.75rem; /* also enforces touch target on <a> elements */
    padding: var(--sf-btn-py, var(--sf-space-xs)) var(--sf-btn-px, var(--sf-space-m));
    border-radius: var(--sf-btn-radius, var(--sf-radius-s));
    font-size: var(--sf-btn-font-size, var(--sf-text-m));
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--sf-duration-fast) var(--sf-ease-out),
                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),
                transform var(--sf-duration-fast) var(--sf-ease-out);
  }
  /* Optical vertical centering where glyph whitespace would otherwise be visible. Chrome 135+. */
  @supports (text-box: trim-both cap alphabetic) {
    .sf-btn--primary,
    .sf-btn--destructive,
    .sf-btn--outline,
    .sf-btn--ghost,
    .sf-badge,
    .sf-nav-link,
    .sf-chip,
    .sf-eyebrow {
      text-box: trim-both cap alphabetic;
    }
  }

  .sf-btn--primary {
    background: var(--sf-btn-bg, var(--sf-action));
    color: var(--sf-btn-text, var(--sf-color-text-on-action));
    border: var(--sf-border-width-1) solid var(--sf-btn-bg, var(--sf-action));
  }
  .sf-btn--destructive {
    background: var(--sf-btn-bg, var(--sf-action-destructive));
    color: var(--sf-btn-text, var(--sf-color-text-on-destructive));
    border: var(--sf-border-width-1) solid var(--sf-btn-bg, var(--sf-action-destructive));
  }
  .sf-btn--destructive:hover,
  .sf-btn--destructive:focus-visible,
  .sf-btn--destructive:active {
    background: light-dark(
      color-mix(in oklch, var(--sf-btn-bg, var(--sf-action-destructive)) 80%, black),
      color-mix(in oklch, var(--sf-btn-bg, var(--sf-action-destructive)) 80%, white)
    );
    border-color: light-dark(
      color-mix(in oklch, var(--sf-btn-bg, var(--sf-action-destructive)) 80%, black),
      color-mix(in oklch, var(--sf-btn-bg, var(--sf-action-destructive)) 80%, white)
    );
    transform: translateY(-1px);
    box-shadow: var(--sf-shadow-s);
  }
  .sf-btn--outline {
    background: transparent;
    color: var(--sf-btn-bg, var(--sf-action));
    border: var(--sf-border-width-1) solid var(--sf-btn-bg, var(--sf-action));
  }
  .sf-btn--ghost {
    background: transparent;
    color: var(--sf-btn-bg, var(--sf-action));
    border: var(--sf-border-width-1) solid transparent;
  }

  /* color-mix(in oklch) gives perceptually uniform dimming across all hues.
     filter: brightness() causes hue shift on yellow/orange/red — oklch avoids this.
     light-dark() flips direction: darkens in light mode, lightens in dark mode.
     80% mix + translateY(-1px) + shadow provides clear visual feedback on interaction.

     Applied to :hover, :focus-visible, and :active so feedback works on:
     - Desktop mouse (hover)
     - Keyboard navigation (focus-visible)
     - Touch devices (active while pressed) */

  .sf-btn--primary:hover,
  .sf-btn--primary:focus-visible,
  .sf-btn--primary:active {
    background: light-dark(
      color-mix(in oklch, var(--sf-btn-bg, var(--sf-action)) 80%, black),
      color-mix(in oklch, var(--sf-btn-bg, var(--sf-action)) 80%, white)
    );
    border-color: light-dark(
      color-mix(in oklch, var(--sf-btn-bg, var(--sf-action)) 80%, black),
      color-mix(in oklch, var(--sf-btn-bg, var(--sf-action)) 80%, white)
    );
    transform: translateY(-1px);
    box-shadow: var(--sf-shadow-s);
  }
  .sf-btn--outline:hover,
  .sf-btn--outline:focus-visible,
  .sf-btn--outline:active {
    background: var(--sf-btn-bg, var(--sf-action));
    color: var(--sf-btn-text, var(--sf-color-text-on-action));
    transform: translateY(-1px);
    box-shadow: var(--sf-shadow-s);
  }
  .sf-btn--ghost:hover,
  .sf-btn--ghost:focus-visible,
  .sf-btn--ghost:active {
    background: color-mix(in srgb, var(--sf-btn-bg, var(--sf-action)) 12%, transparent);
  }

  /* Outline button focus-visible needs outline-color since background fills solid */
  .sf-btn--outline:focus-visible {
    outline: 2px solid var(--sf-btn-bg, var(--sf-action));
    outline-offset: var(--sf-focus-ring-offset);
  }

  .sf-btn--s { padding: var(--sf-space-2xs) var(--sf-space-s); font-size: var(--sf-text-s); }
  .sf-btn--l { padding: var(--sf-space-s) var(--sf-space-l); font-size: var(--sf-text-l); }

  /* Icon-only button — equal x/y padding, square aspect ratio.
     Combines with existing variants: <button class="sf-btn--outline sf-btn--icon"> */
  .sf-btn--icon {
    padding: var(--sf-btn-icon-padding, var(--sf-space-xs));
    aspect-ratio: 1;
    justify-content: center;
    min-width: 2.75rem;
  }

  /* ----- Card ----- */

  .sf-card {
    container-type: inline-size;
    background: var(--sf-card-bg, var(--sf-color-surface));
    border-radius: var(--sf-card-radius, var(--sf-radius-l));
    padding: var(--sf-card-padding, var(--sf-space-l));
    box-shadow: var(--sf-card-shadow, var(--sf-shadow-s));
    overflow: var(--sf-card-overflow, hidden);
    display: flex;
    flex-direction: column;
    gap: var(--sf-card-gap, var(--sf-space-m));
  }

  .sf-card--bordered  { box-shadow: none; border: var(--sf-border-width-1) solid var(--sf-color-border); }
  .sf-card--flat      { box-shadow: none; background: transparent; }
  .sf-card--elevated  { box-shadow: var(--sf-shadow-m); }

  /* --sf-interactive: adds hover lift effect without requiring .sf-hover-lift utility.
     Use for clickable cards. Combine with .sf-clickable-parent for full-card link area. */
  .sf-card--interactive {
    cursor: pointer;
    transition: box-shadow var(--sf-duration-fast) var(--sf-ease-out),
                translate var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-card--interactive:hover {
      box-shadow: var(--sf-card-hover-shadow, var(--sf-shadow-l));
      translate: 0 var(--sf-card-hover-lift, -3px);
    }
  }
  .sf-card--interactive:focus-visible {
    box-shadow: var(--sf-card-hover-shadow, var(--sf-shadow-l));
    translate: 0 var(--sf-card-hover-lift, -3px);
  }

  /* --sf-horizontal: side-by-side layout (media + content).
     Stacks on narrow containers, goes horizontal when parent container ≥ 30rem.
     First child (image/icon) gets fixed width via --card-media-width (default: 10rem).
     Use with .sf-media or any two-child structure inside a container-type element. */
  .sf-card--horizontal {
    flex-direction: column;
    padding: 0;
  }
  /* @media rather than @container: a container cannot style itself,
     only its descendants. Use viewport width for the card's own flex-direction. */
  @media (min-width: 30rem) {
    .sf-card--horizontal {
      flex-direction: row;
      align-items: flex-start;
    }
    .sf-card--horizontal > :first-child {
      flex-shrink: 0;
      width: var(--sf-card-media-width, 10rem);
      align-self: stretch;
      object-fit: cover;
    }
    .sf-card--horizontal > :last-child {
      padding: var(--sf-card-padding, var(--sf-space-l));
      flex: 1;
      min-width: 0;
    }
  }

  /* ----- Badge ----- */

  .sf-badge {
    display: inline-flex;
    align-items: center;
    padding: var(--sf-badge-padding, var(--sf-space-2xs) var(--sf-space-xs));
    font-size: var(--sf-text-xs);
    font-weight: 600;
    line-height: 1;
    white-space: nowrap;
    border-radius: var(--sf-radius-full);
    background: var(--sf-badge-bg, var(--sf-primary-100));
    color: var(--sf-badge-text, var(--sf-primary));
  }

  .sf-badge--success { --sf-badge-bg: var(--sf-success-100); --sf-badge-text: var(--sf-success-600); }
  .sf-badge--warning { --sf-badge-bg: var(--sf-warning-100); --sf-badge-text: var(--sf-warning-600); }
  .sf-badge--error   { --sf-badge-bg: var(--sf-error-100);   --sf-badge-text: var(--sf-error-600);   }
  .sf-badge--info    { --sf-badge-bg: var(--sf-info-100);    --sf-badge-text: var(--sf-info-600);    }
  .sf-badge--neutral { --sf-badge-bg: var(--sf-neutral-100); --sf-badge-text: var(--sf-neutral-600); }

  /* --sf-outline: transparent background, colored border */
  .sf-badge--outline {
    background: transparent;
    border: var(--sf-border-width-1) solid var(--sf-badge-text, var(--sf-primary));
  }

  /* size variants */
  .sf-badge--s { --sf-badge-padding: 0.1em var(--sf-space-2xs); font-size: var(--sf-text-2xs); }
  .sf-badge--l { --sf-badge-padding: var(--sf-space-xs) var(--sf-space-s); font-size: var(--sf-text-s); }

  /* ----- Notice ----- */

  .sf-notice {
    padding: var(--sf-space-s) var(--sf-space-m);
    border-radius: var(--sf-radius-m);
    border-inline-start: var(--sf-notice-border-width, 3px) solid var(--sf-notice-color, var(--sf-primary));
    background: var(--sf-notice-bg, var(--sf-primary-100));
    color: var(--sf-notice-text, var(--sf-color-text));
  }

  .sf-notice--success { --sf-notice-color: var(--sf-success); --sf-notice-bg: var(--sf-success-100); }
  .sf-notice--warning { --sf-notice-color: var(--sf-warning); --sf-notice-bg: var(--sf-warning-100); }
  .sf-notice--error   { --sf-notice-color: var(--sf-error);   --sf-notice-bg: var(--sf-error-100);   }
  .sf-notice--info    { --sf-notice-color: var(--sf-info);    --sf-notice-bg: var(--sf-info-100);    }

  /* --sf-bordered: full border on all sides instead of left accent only */
  .sf-notice--bordered {
    border: var(--sf-border-width-1) solid var(--sf-notice-color, var(--sf-primary));
    border-inline-start-width: var(--sf-notice-border-width, 3px);
  }

  /* dismiss button — position the notice relative, then absolutely place the ×
     HTML: <div class="sf-notice sf-notice--dismissible"><button class="sf-notice__close" aria-label="Dismiss">×</button>…</div> */
  .sf-notice--dismissible {
    position: relative;
    padding-inline-end: var(--sf-space-xl);
  }
  .sf-notice__close {
    position: absolute;
    inset-block-start: var(--sf-space-xs);
    inset-inline-end: var(--sf-space-xs);
    width: 1.5rem;
    height: 1.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    min-width: 0;
    min-height: 0;
    min-inline-size: 0;
    line-height: 0;
    border: none;
    background: transparent;
    color: inherit;
    cursor: pointer;
    border-radius: var(--sf-radius-s);
    opacity: 0.6;
    transition: opacity var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-notice__close:hover { opacity: 1; }
  }

  /* ----- Banner (sticky full-width notification strip) ----- */
  /* Distinct from .sf-notice (inline content element with left accent).
     Use cases: cookie consent, site-wide announcements, promotional strips,
     maintenance warnings.
     --bottom modifier: sticky bottom requires the banner to be the last child
     of a tall scroll container — sticky bottom on a non-last child does nothing. */

  .sf-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sf-space-m);
    flex-wrap: wrap;
    width: 100%;
    padding-block: var(--sf-banner-padding-block, var(--sf-space-s));
    padding-inline: var(--sf-banner-padding-inline, var(--sf-space-gutter));
    background: var(--sf-banner-bg, var(--sf-primary-100));
    color: var(--sf-banner-color, var(--sf-color-text));
    border-block-end: 1px solid var(--sf-banner-border, var(--sf-color-border));
    position: sticky;
    inset-block-start: 0;
    z-index: var(--sf-z-banner); /* 1200 — above sticky header at 1100 */
  }

  .sf-banner--info    { --sf-banner-bg: var(--sf-color-info-bg);    --sf-banner-color: var(--sf-color-info-text);    --sf-banner-border: color-mix(in srgb, var(--sf-info) 25%, transparent); }
  .sf-banner--success { --sf-banner-bg: var(--sf-color-success-bg); --sf-banner-color: var(--sf-color-success-text); --sf-banner-border: color-mix(in srgb, var(--sf-success) 25%, transparent); }
  .sf-banner--warning { --sf-banner-bg: var(--sf-color-warning-bg); --sf-banner-color: var(--sf-color-warning-text); --sf-banner-border: color-mix(in srgb, var(--sf-warning) 25%, transparent); }
  .sf-banner--error   { --sf-banner-bg: var(--sf-color-error-bg);   --sf-banner-color: var(--sf-color-error-text);   --sf-banner-border: color-mix(in srgb, var(--sf-error) 25%, transparent); }

  /* Bottom-anchored: flip sticky edge and border to the correct side */
  .sf-banner--bottom {
    inset-block-start: unset;
    inset-block-end: 0;
    border-block-end: none;
    border-block-start: 1px solid var(--sf-banner-border, var(--sf-color-border));
  }

  .sf-banner__message { flex: 1; }
  .sf-banner__actions { display: flex; gap: var(--sf-space-s); align-items: center; flex-wrap: wrap; }

  .sf-banner__close {
    flex-shrink: 0;
    inline-size: 1.5rem;
    block-size: 1.5rem;
    display: grid;
    place-items: center;
    background: none;
    border: none;
    cursor: pointer;
    color: inherit;
    opacity: 0.6;
    padding: 0;
  }
  @media (hover: hover) {
    .sf-banner__close:hover { opacity: 1; }
  }

  /* ----- Marquee (horizontally scrolling strip) ----- */
  /* Use cases: logo bars, tag clouds, announcement tickers.
     HTML structure: .sf-marquee > .sf-marquee__track > [items × 2]
     Items must be duplicated in HTML — the animation translates by exactly
     calc(-50% - gap/2) so each set of items must be identical in width for
     a seamless loop. Without duplication the loop jumps.
     Instance tokens: --marquee-speed (default 40s, lower = faster), --marquee-gap. */

  .sf-marquee {
    --sf-marquee-speed: 40s;
    --sf-marquee-gap: var(--sf-space-l);
    overflow: hidden;
    display: flex;
    user-select: none;
  }

  .sf-marquee__track {
    display: flex;
    gap: var(--sf-marquee-gap);
    animation: sf-marquee-scroll var(--sf-marquee-speed) linear infinite;
  }

  @keyframes sf-marquee-scroll {
    from { transform: translateX(0); }
    to   { transform: translateX(calc(-50% - var(--sf-marquee-gap) / 2)); }
  }

  /* ----- Section header ----- */
  /* The most repeated pattern on marketing sites: eyebrow + heading + lead text.
     Centered by default. Use --left modifier for left-aligned sections.
     Customizable: --section-header-max (default: --container-prose) */

  .sf-section-header {
    text-align: center;
    max-width: var(--sf-section-header-max, var(--sf-container-prose));
    margin-inline: auto;
  }

  .sf-section-header__heading {
    font-size: var(--sf-h2);
    line-height: var(--sf-leading-tight);
    font-weight: var(--sf-font-weight-heading);
    text-wrap: balance;
    color: var(--sf-color-text);
    margin-block: var(--sf-space-xs) var(--sf-space-s);
  }

  .sf-section-header__lead {
    font-size: var(--sf-text-l);
    line-height: var(--sf-leading-normal);
    color: var(--sf-color-text-muted);
    text-wrap: pretty;
    max-width: var(--sf-section-header-lead-max, 55ch);
    margin-inline: auto;
  }

  .sf-section-header__cta {
    margin-block-start: var(--sf-space-l);
    display: flex;
    gap: var(--sf-space-s);
    justify-content: center;
    flex-wrap: wrap;
  }

  /* --sf-left: left-aligned variant */
  .sf-section-header--left {
    text-align: start;
    margin-inline: 0;
  }
  .sf-section-header--left .sf-section-header__lead { margin-inline: 0; }
  .sf-section-header--left .sf-section-header__cta  { justify-content: flex-start; }

  /* ----- Eyebrow ----- */

  .sf-eyebrow {
    display: inline-block;
    font-size: var(--sf-text-s);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: var(--sf-tracking-wide);
    color: var(--sf-eyebrow-color, var(--sf-primary));
    margin-block-end: var(--sf-space-xs);
  }

  /* Pill variant: surface-2 background + full radius. */
  .sf-eyebrow--pill {
    padding-block: var(--sf-space-2xs);
    padding-inline: var(--sf-space-s);
    background: var(--sf-eyebrow-pill-bg, var(--sf-primary-100));
    border-radius: var(--sf-radius-full);
  }

  /* ----- Media object ----- */

  .sf-media {
    display: flex;
    gap: var(--sf-space-m);
    align-items: flex-start;
  }
  .sf-media > :first-child { flex-shrink: 0; }
  .sf-media > :last-child  { flex: 1; min-width: 0; }

  /* ----- Input group ----- */

  /* Children retain full borders. Joining is done by the negative margin
     in the addons block below (margin-inline-start: -1px on > * + *), so
     overlapping borders collapse to a single 1px line and the last child
     keeps its trailing border intact. */
  .sf-input-group { display: flex; }
  .sf-input-group > input,
  .sf-input-group > select {
    flex: 1;
    min-width: 0;
  }

  /* Addon — non-input prefix/suffix child (label, icon, currency symbol).
     Pairs with the existing > * + * radius/border-collapse rules below to
     glue against neighbouring inputs and buttons without a doubled border. */
  .sf-input-group__addon {
    display: inline-flex;
    align-items: center;
    padding-inline: var(--sf-space-m);
    background: var(--sf-color-surface-2);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-input-radius, var(--sf-radius-m));
    color: var(--sf-color-text-decorative);
    white-space: nowrap;
    flex-shrink: 0;
  }

  /* ----- Divider (line-text-line) ----- */

  .sf-divider {
    display: flex;
    align-items: center;
    gap: var(--sf-space-m);
    color: var(--sf-color-text-decorative);
    font-size: var(--sf-text-s);
  }
  .sf-divider::before,
  .sf-divider::after {
    content: '';
    flex: 1;
    border-block-start: var(--sf-border-width-1) solid var(--sf-color-border);
  }

  /* Vertical rule — a 1px line in the inline direction.
     Use inside flex rows to separate items:
       <span class="sf-divider--vertical" aria-hidden="true"></span> */
  .sf-divider--vertical {
    display: inline-block;
    inline-size: var(--sf-border-width-1);
    block-size: var(--sf-divider-height, 1.25em);
    background: var(--sf-color-border);
    align-self: center;
    flex-shrink: 0;
  }

  /* ----- Skeleton loader ----- */
  /* .sf-skeleton__line must be a direct child of .sf-skeleton to correctly inherit
     the animation and background-size values. Deeper nesting desynchronizes the animation.
     Shimmer midpoint uses --color-surface-3 (subtle depth token, adapts in dark mode). */

  .sf-skeleton {
    background: linear-gradient(
      90deg,
      var(--sf-color-surface-2) 25%,
      var(--sf-color-surface-3) 50%,
      var(--sf-color-surface-2) 75%
    );
    background-size: 200% 100%;
    border-radius: var(--sf-radius-s);
    color: transparent;
    user-select: none;
    pointer-events: none;
  }
  @media (prefers-reduced-motion: no-preference) {
    .sf-skeleton { animation: skeleton-pulse var(--sf-skeleton-speed) ease-in-out infinite; }
  }
  .sf-skeleton > * { visibility: hidden; }
  .sf-skeleton > .sf-skeleton__line {
    display: block;
    height: 0.75em;
    border-radius: var(--sf-radius-xs);
    background: inherit;
    animation: inherit;
    background-size: inherit;
    visibility: visible;
  }
  /* Shape modifiers — standalone skeletons without .sf-skeleton__line children */
  .sf-skeleton--text   { block-size: 0.75em; border-radius: var(--sf-radius-full); }
  .sf-skeleton--rect   { border-radius: var(--sf-radius-m); }
  .sf-skeleton--circle { border-radius: var(--sf-radius-full); }

  /* ----- Empty / error state (no data, no results, load failed) ----- */
  /* Centered icon + title + description + action slot. Use unmodified for
     "blank slate" cases (no items yet, no search results); add --error for
     failure cases (load failed, network error). All children are optional —
     any subset composes correctly.

     Markup:
       <div class="sf-empty">
         <svg class="sf-icon sf-empty__icon" aria-hidden="true">…</svg>
         <h2 class="sf-empty__title">No results</h2>
         <p class="sf-empty__description">Try adjusting your filters.</p>
         <div class="sf-empty__action"><button class="sf-btn--primary">Reset</button></div>
       </div> */

  .sf-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sf-space-s);
    padding: var(--sf-empty-padding-block, var(--sf-space-xl)) var(--sf-empty-padding-inline, var(--sf-space-m));
    text-align: center;
    color: var(--sf-color-text-muted);
  }
  .sf-empty__icon {
    --sf-icon-size: var(--sf-empty-icon-size, 3rem);
    --sf-icon-color: var(--sf-empty-icon-color, var(--sf-color-text-muted));
    opacity: var(--sf-empty-icon-opacity, 0.5);
  }
  .sf-empty__title {
    margin: 0;
    font-size: var(--sf-text-l);
    font-weight: 600;
    color: var(--sf-color-text);
  }
  .sf-empty__description {
    margin: 0;
    max-inline-size: 40ch;
    color: var(--sf-color-text-muted);
  }
  .sf-empty__action {
    margin-block-start: var(--sf-space-2xs);
  }
  /* Error variant — error-tinted icon, full opacity. Title + description tone
     stays neutral so consumer copy can decide urgency. Uses --sf-icon-color
     (the property .sf-icon consumes), not `color`, so the cascade resolves
     correctly regardless of source order. */
  .sf-empty--error .sf-empty__icon {
    --sf-icon-color: var(--sf-empty-icon-color, var(--sf-error));
    opacity: 1;
  }

  /* ----- Separated list (breadcrumbs, footer links, tag lists) ----- */

  .sf-separated-list {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sf-space-2xs);
    list-style: none;
    padding: 0;
  }
  .sf-separated-list > * + *::before {
    content: var(--sf-separator, "/");
    margin-inline-end: var(--sf-space-2xs);
    opacity: 0.5;
  }

  /* ----- Form group (CSS-only validation cascade via :has()) ----- */
  /* No JS required — browser applies :user-invalid after the first blur on an invalid field.
     .sf-form-group__error is hidden by default and revealed when the group contains an invalid field.
     Full BEM: __label, __input, __hint, __error for consistency across the framework. */

  .sf-form-group { display: flex; flex-direction: column; gap: var(--sf-space-2xs); }
  .sf-form-group__label { font-size: var(--sf-text-s); font-weight: 500; color: var(--sf-color-text); }
  .sf-form-group__hint  { font-size: var(--sf-text-s); color: var(--sf-color-text-muted); }
  .sf-form-group__error { display: none; font-size: var(--sf-text-s); color: var(--sf-error); }

  /* Opinionated input styling — matches buttons (padding, border-radius, transitions).
     Use via <input class="sf-form-group__input"> for consistent sizing and focus states. */
  .sf-form-group__input,
  .sf-form-group__input[type="text"],
  .sf-form-group__input[type="email"],
  .sf-form-group__input[type="tel"],
  .sf-form-group__input[type="url"],
  .sf-form-group__input[type="search"],
  .sf-form-group__input[type="password"],
  .sf-form-group__input[type="number"],
  .sf-form-group__input:is(textarea, select) {
    padding: var(--sf-input-padding-y, var(--sf-space-xs)) var(--sf-input-padding-x, var(--sf-space-s));
    border: var(--sf-border-width-1) solid var(--sf-input-border, var(--sf-color-border));
    border-radius: var(--sf-input-radius, var(--sf-radius-m));
    background: var(--sf-input-bg, var(--sf-color-surface));
    color: var(--sf-input-text, var(--sf-color-text));
    font: inherit;
    transition: border-color var(--sf-duration-fast) var(--sf-ease-out),
                box-shadow var(--sf-duration-fast) var(--sf-ease-out);
  }
  .sf-form-group__input:focus-visible {
    border-color: var(--sf-input-border-focus, var(--sf-primary));
    outline: 0;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--sf-primary) 20%, transparent);
  }
  .sf-form-group__input:user-invalid {
    border-color: var(--sf-error);
  }

  .sf-form-group:has(:user-invalid) .sf-form-group__label  { color: var(--sf-error); }
  .sf-form-group:has(:user-invalid) .sf-form-group__error  { display: block; }
  .sf-form-group:has(:user-valid:not(:placeholder-shown)) .sf-form-group__label { color: var(--sf-success); }

  /* Server-rendered error modifier — mirrors the :user-invalid visuals so
     server-side validation can paint the error state without waiting for JS.
     Pair with aria-invalid="true" on the input for the matching a11y signal.
     Focus ring uses the same error-tinted outline as the :user-invalid:focus-visible
     rule in slashed-core.css for visual consistency between SSR and live validation. */
  .sf-form-group--error .sf-form-group__label { color: var(--sf-error); }
  .sf-form-group--error .sf-form-group__error { display: block; }
  .sf-form-group--error .sf-form-group__input { border-color: var(--sf-error); }
  .sf-form-group--error .sf-form-group__input:focus-visible {
    outline: var(--sf-focus-ring-width) solid color-mix(in srgb, var(--sf-error) 40%, transparent);
  }

  /* ----- Error summary (form-level error list with anchor links) ----- */
  /* WCAG 3.3.1 pattern — gather every field error at the top of the form so
     users with screen readers, magnifiers, or motor impairments can see and
     jump to each error in one place. Pure CSS; consumer wires anchor hrefs to
     field IDs.

     Markup:
       <div class="sf-error-summary" role="alert" tabindex="-1"
            aria-labelledby="error-summary-title">
         <h2 class="sf-error-summary__title" id="error-summary-title">There is a problem</h2>
         <ul class="sf-error-summary__list">
           <li><a href="#name">Enter your name</a></li>
           <li><a href="#email">Enter a valid email address</a></li>
         </ul>
       </div>

     A11y notes:
       - role="alert" announces the summary to AT when injected after submit.
       - tabindex="-1" lets the consumer focus() the summary post-submit.
       - Each link's href targets the field's id; clicking jumps focus to it. */

  .sf-error-summary {
    padding: var(--sf-space-m);
    border: var(--sf-border-width-1) solid var(--sf-error);
    border-inline-start: var(--sf-error-summary-bar-width, 4px) solid var(--sf-error);
    border-radius: var(--sf-radius-m);
    background: var(--sf-color-error-bg);
    color: var(--sf-color-error-text);
  }
  .sf-error-summary__title {
    margin: 0 0 var(--sf-space-xs) 0;
    font-size: var(--sf-text-l);
    font-weight: 600;
    color: var(--sf-error);
  }
  .sf-error-summary__list {
    margin: 0;
    padding-inline-start: var(--sf-space-l);
  }
  .sf-error-summary__list a {
    color: var(--sf-color-error-text);
    text-decoration: underline;
    font-weight: 500;
  }
  .sf-error-summary__list a:hover,
  .sf-error-summary__list a:focus-visible {
    text-decoration-thickness: 2px;
  }

  /* ----- Select wrapper (enhanced chevron via mask-image) ----- */
  /* Wrapping <select> in <div class="sf-select-wrap"> upgrades the
     chevron from a hardcoded-color SVG background-image to a
     token-driven mask-image that follows --color-text-muted and
     dark mode automatically.

     Usage:
       <div class="sf-select-wrap">
         <select>...</select>
       </div>

     Without wrapper: built-in chevron (hardcoded color, see core reset).
     With wrapper: token-driven chevron via ::after. */

  .sf-select-wrap {
    position: relative;
    display: grid;
  }
  .sf-select-wrap select {
    /* Remove the background-image chevron from the naked select */
    background-image: none;
    padding-inline-end: calc(var(--sf-space-s) * 2 + 1em);
  }
  .sf-select-wrap::after {
    content: "";
    position: absolute;
    inset-block-start: 50%;
    inset-inline-end: var(--sf-space-s);
    translate: 0 -50%;
    inline-size: 1em;
    block-size: 1em;
    pointer-events: none;
    background-color: var(--sf-color-text-muted);
    mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
    mask-repeat: no-repeat;
    mask-position: center;
    mask-size: contain;
  }

  /* ----- Spinner ----- */
  /* Use as: <span class="spinner" aria-label="Loading" role="status"></span>
     --spinner-size and --spinner-color customizable per instance. */

  .sf-spinner {
    display: inline-block;
    width: var(--sf-spinner-size, 1.5rem);
    height: var(--sf-spinner-size, 1.5rem);
    border-radius: var(--sf-radius-full);
    border: calc(var(--sf-spinner-size, 1.5rem) * 0.15) solid
      color-mix(in srgb, var(--sf-spinner-color, var(--sf-primary)) 25%, transparent);
    border-block-start-color: var(--sf-spinner-color, var(--sf-primary));
    animation: spin var(--sf-spinner-duration, 0.65s) linear infinite;
    flex-shrink: 0;
  }
  .sf-spinner--s { --sf-spinner-size: 1rem; }
  .sf-spinner--l { --sf-spinner-size: 2.5rem; }

  /* ----- Chip (clickable tag / removable badge) ----- */
  /* Semantically distinct from .sf-badge (read-only label): .sf-chip is interactive.
     Use <button class="chip"> or <a class="chip"> for a standalone chip.
     Add a <button class="chip__remove"> child for a removable chip. */

  .sf-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--sf-space-2xs);
    padding: var(--sf-space-2xs) var(--sf-space-s);
    font-size: var(--sf-text-s);
    font-weight: 500;
    line-height: 1;
    white-space: nowrap;
    border-radius: var(--sf-radius-full);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    background: var(--sf-color-surface-2);
    color: var(--sf-color-text);
    cursor: pointer;
    text-decoration: none;
    transition: background-color var(--sf-duration-fast) var(--sf-ease-out),
                border-color var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-chip:hover { background: var(--sf-color-border); border-color: var(--sf-color-border-strong); }
  }
  .sf-chip:focus-visible {
    outline: var(--sf-focus-ring-width) solid var(--sf-focus-ring-color);
    outline-offset: var(--sf-focus-ring-offset);
  }
  .sf-chip--active {
    background: var(--sf-primary-100);
    border-color: var(--sf-primary);
    color: var(--sf-primary);
  }
  .sf-chip__remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1em;
    height: 1em;
    border-radius: var(--sf-radius-full);
    border: 0;
    background: transparent;
    color: inherit;
    cursor: pointer;
    padding: 0;
    opacity: 0.6;
    min-height: revert;
    min-width: revert;
    transition: opacity var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-chip__remove:hover { opacity: 1; }
  }
  .sf-chip__remove:focus-visible {
    opacity: 1;
    outline: var(--sf-focus-ring-width) solid var(--sf-focus-ring-color);
    outline-offset: var(--sf-focus-ring-offset);
  }

  /* ----- Tooltip (CSS-only, progressive enhancement) ----- */
  /* Usage: <button data-tooltip="This is the tooltip">Hover me</button>
     Positioned above the element by default. Use CSS to override placement.
     Fallback: classic position: absolute. Progressive enhancement: CSS Anchor Positioning
     (Chrome 125+) when supported — enables smarter placement without scroll clipping. */

  [data-tooltip] {
    position: relative;
  }
  /* ⚠️ Fallback (non-anchor-positioning browsers): tooltip uses
     position: absolute and may clip inside overflow: hidden parents.
     Fix: add position: relative + overflow: visible on the parent,
     or wrap in a z-index container. */
  [data-tooltip]::after {
    content: attr(data-tooltip);
    position: absolute;
    inset-block-end: calc(100% + var(--sf-space-xs));
    inset-inline-start: 50%;
    translate: -50% 0;
    width: max-content;
    max-width: var(--sf-tooltip-max-width, 16rem);
    padding: var(--sf-space-2xs) var(--sf-space-s);
    font-size: var(--sf-text-xs);
    font-weight: 500;
    line-height: var(--sf-leading-snug);
    white-space: normal;
    background: var(--sf-tooltip-bg, var(--sf-neutral-dark));
    color: var(--sf-tooltip-color, var(--sf-color-text-on-dark));
    border-radius: var(--sf-radius-s);
    box-shadow: var(--sf-shadow-m);
    pointer-events: none;
    z-index: var(--sf-z-tooltip);
    /* Hidden by default — shown on focus/hover */
    opacity: 0;
    scale: 0.95;
    transition: opacity var(--sf-duration-fast) var(--sf-ease-out),
                scale var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    [data-tooltip]:hover::after { opacity: 1; scale: 1; }
  }
  [data-tooltip]:focus-visible::after { opacity: 1; scale: 1; }

  /* CSS Anchor Positioning — progressive enhancement for Chrome 125+.
     Replaces the position: absolute fallback with proper anchor-based placement
     that avoids clipping inside overflow: hidden parents. */
  @supports (anchor-name: --a) {
    [data-tooltip] { anchor-name: --_tooltip-anchor; }
    [data-tooltip]::after {
      position-anchor: --_tooltip-anchor;
      position: absolute;
      inset-block-end: anchor(top);
      inset-inline-start: anchor(center);
      translate: -50% calc(-1 * var(--sf-space-xs));
      /* Remove the position: relative dependency — anchor handles placement */
    }
  }

  /* ----- Popover (BEM wrapper around native [popover]) ----- */
  /* Native [popover] base lives in slashed-core.css (essential bundle): surface,
     padding, radius, shadow, and open/close transitions via @starting-style.
     This component layer adds:
       - max-inline-size token + intrinsic sizing
       - placement modifiers (top/bottom/start/end) via CSS Anchor Positioning
       - arrow indicator on placement variants
     Plain native popover usage works without these classes. Add .sf-popover when
     you want token-driven sizing; add .sf-popover--bottom (etc.) when you also
     wire CSS Anchor Positioning for placement.

     Markup (centred, no anchor wiring):
       <button popovertarget="my-pop" class="sf-btn--ghost">Open</button>
       <div id="my-pop" popover class="sf-popover">…</div>

     Markup (anchored placement, Chrome 125+):
       <button popovertarget="my-pop" class="sf-btn--ghost"
               style="anchor-name: --my-anchor">Open</button>
       <div id="my-pop" popover class="sf-popover sf-popover--bottom"
            style="position-anchor: --my-anchor">…</div> */

  .sf-popover {
    inline-size: max-content;
    max-inline-size: var(--sf-popover-max-width, 20rem);
    position: relative;
  }

  .sf-popover__title {
    display: block;
    margin-block-end: var(--sf-space-2xs);
    font-weight: 600;
    color: var(--sf-color-heading, var(--sf-color-text));
  }

  /* CSS Anchor Positioning enhancement — placement modifiers + arrow.
     Requires consumer-wired anchor-name on trigger and position-anchor
     on popover (see markup example above). Falls back to native default
     positioning (browser-centred) in non-supporting browsers. */
  @supports (anchor-name: --a) {
    .sf-popover--top,
    .sf-popover--bottom,
    .sf-popover--start,
    .sf-popover--end {
      margin: 0;
      position: absolute;
    }
    .sf-popover--top {
      inset-block-end: anchor(top);
      inset-inline-start: anchor(center);
      translate: -50% calc(-1 * var(--sf-popover-offset, var(--sf-space-2xs)));
    }
    .sf-popover--bottom {
      inset-block-start: anchor(bottom);
      inset-inline-start: anchor(center);
      translate: -50% var(--sf-popover-offset, var(--sf-space-2xs));
    }
    .sf-popover--start {
      inset-block-start: anchor(center);
      inset-inline-end: anchor(start);
      translate: calc(-1 * var(--sf-popover-offset, var(--sf-space-2xs))) -50%;
    }
    .sf-popover--end {
      inset-block-start: anchor(center);
      inset-inline-start: anchor(end);
      translate: var(--sf-popover-offset, var(--sf-space-2xs)) -50%;
    }
  }

  /* Arrow — only on placement variants (centred fallback has no anchor to
     point at). Rotated square inheriting parent border so the seam is
     invisible against the surface. */
  .sf-popover--top::after,
  .sf-popover--bottom::after,
  .sf-popover--start::after,
  .sf-popover--end::after {
    content: "";
    position: absolute;
    inline-size: 0.625rem;
    block-size: 0.625rem;
    background: var(--sf-color-surface);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    rotate: 45deg;
  }
  .sf-popover--top::after {
    inset-block-end: -0.375rem;
    inset-inline-start: 50%;
    translate: -50% 0;
    border-block-start-color: transparent;
    border-inline-start-color: transparent;
  }
  .sf-popover--bottom::after {
    inset-block-start: -0.375rem;
    inset-inline-start: 50%;
    translate: -50% 0;
    border-block-end-color: transparent;
    border-inline-end-color: transparent;
  }
  .sf-popover--start::after {
    inset-block-start: 50%;
    inset-inline-end: -0.375rem;
    translate: 0 -50%;
    border-block-end-color: transparent;
    border-inline-start-color: transparent;
  }
  .sf-popover--end::after {
    inset-block-start: 50%;
    inset-inline-start: -0.375rem;
    translate: 0 -50%;
    border-block-start-color: transparent;
    border-inline-end-color: transparent;
  }

  /* ----- Table modifiers ----- */

  .sf-table--striped tbody tr:nth-child(odd) { background: var(--sf-color-surface-2); }
  .sf-table--bordered,
  .sf-table--bordered th,
  .sf-table--bordered td {
    border: var(--sf-border-width-1) solid var(--sf-color-border);
  }
  .sf-table--bordered { border-radius: var(--sf-radius-m); overflow: hidden; }
  .sf-table--hoverable tbody tr {
    transition: background-color var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-table--hoverable tbody tr:hover { background: var(--sf-color-surface-2); }
  }

  /* display: block + overflow-x: auto required for reliable horizontal scroll on
     narrow viewports — overflow-x alone on a <table> element does not create a
     scroll container across browsers. Same pattern used by .sf-prose table. */
  .sf-table--responsive { display: block; overflow-x: auto; max-width: 100%; }


  /* ----- Feature list (checkmark-prefixed list) ----- */
  /* Tag-agnostic — works on <ul>, <ol>, or <div>. Marker uses ::before with unicode,
     no SVG needed. Override --feature-list-marker for custom icons (e.g., "→", "★"). */

  .sf-feature-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sf-feature-list-gap, var(--sf-space-xs));
  }
  .sf-feature-list__item {
    display: block;
    position: relative;
    padding-inline-start: calc(1.1em + var(--sf-space-xs));
  }
  .sf-feature-list__item::before {
    content: var(--sf-feature-list-marker, "✓");
    color: var(--sf-feature-list-marker-color, var(--sf-success));
    font-weight: 700;
    line-height: inherit;
    font-size: 1.1em;
    position: absolute;
    inset-inline-start: 0;
    inset-block-start: 0;
  }
  /* Variants — swap marker and color in one place */
  .sf-feature-list--arrow { --sf-feature-list-marker: "→"; --sf-feature-list-marker-color: var(--sf-primary); }
  .sf-feature-list--star  { --sf-feature-list-marker: "★"; --sf-feature-list-marker-color: var(--sf-accent); }
  .sf-feature-list--bullet { --sf-feature-list-marker: "•"; --sf-feature-list-marker-color: var(--sf-color-text-muted); }
  .sf-feature-list--cross { --sf-feature-list-marker: "✗"; --sf-feature-list-marker-color: var(--sf-error); }

  /* Item-level variants — for mixed lists (some features included, some excluded) */
  .sf-feature-list__item--cross { --sf-feature-list-marker: "✗"; --sf-feature-list-marker-color: var(--sf-color-text-decorative); color: var(--sf-color-text-decorative); }
  .sf-feature-list__item--muted { color: var(--sf-color-text-muted); }

  /* ----- Avatar (circular or square portrait) ----- */
  /* Use with <img> child or initials inside <span>/<div>. --avatar-size controls dimension,
     --avatar-radius controls shape (50% circle by default, var(--sf-radius-m) for rounded square). */

  .sf-avatar {
    display: inline-grid;
    place-items: center;
    inline-size: var(--sf-avatar-size, 3rem);
    block-size: var(--sf-avatar-size, 3rem);
    border-radius: var(--sf-avatar-radius, 50%);
    overflow: hidden;
    flex-shrink: 0;
    background: var(--sf-avatar-bg, var(--sf-color-surface-2));
    color: var(--sf-avatar-text, var(--sf-color-text));
    font-weight: 600;
    font-size: calc(var(--sf-avatar-size, 3rem) * 0.4);
    line-height: 1;
    user-select: none;
  }
  .sf-avatar > img,
  .sf-avatar > picture > img {
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
    display: block;
  }
  .sf-avatar--xs { --sf-avatar-size: 1.5rem; }
  .sf-avatar--s  { --sf-avatar-size: 2rem; }
  .sf-avatar--l  { --sf-avatar-size: 4rem; }
  .sf-avatar--xl { --sf-avatar-size: 6rem; }
  .sf-avatar--2xl { --sf-avatar-size: 8rem; }
  .sf-avatar--square { --sf-avatar-radius: var(--sf-radius-m); }
  .sf-avatar--bordered { box-shadow: 0 0 0 2px var(--sf-avatar-border-color, var(--sf-color-surface)); }

  /* Avatar stack — overlapping circular avatars (like GitHub contributors) */
  .sf-avatar-stack {
    display: inline-flex;
    flex-direction: row;
  }
  .sf-avatar-stack > .sf-avatar + .sf-avatar {
    margin-inline-start: calc(var(--sf-avatar-size, 3rem) * -1 * var(--sf-avatar-stack-overlap, 0.33));
    box-shadow: 0 0 0 2px var(--sf-avatar-stack-bg, var(--sf-color-bg));
  }

  /* ----- Rating (interactive star rating, fieldset + hidden radios) ----- */
  /* Pure-CSS fill via `:checked ~ .sf-rating__star` cascade. DOM order is
     5 → 1 (highest to lowest) so the general-sibling combinator matches the
     checked star plus all lower-value labels following it in the DOM. The
     fieldset uses flex-direction: row-reverse so visual order reads 1 → 5
     left-to-right while keeping the sibling-cascade math correct.

     Markup:
       <fieldset class="sf-rating">
         <legend class="sf-rating__label">Rating</legend>
         <input type="radio" name="r" value="5" id="r5" class="sf-rating__input">
         <label for="r5" class="sf-rating__star" aria-label="5 stars">★</label>
         …
         <input type="radio" name="r" value="1" id="r1" class="sf-rating__input">
         <label for="r1" class="sf-rating__star" aria-label="1 star">★</label>
       </fieldset>

     Read-only display: replace inputs+labels with bare <span class="sf-rating__star
     sf-rating__star--filled"> elements; the fieldset wrapper still styles the row.
     `--rating-color`, `--rating-hover-color`, and `--rating-size` configurable per
     instance. */

  .sf-rating {
    display: inline-flex;
    flex-direction: row-reverse;
    justify-content: flex-end;
    border: 0;
    padding: 0;
    margin: 0;
    font-size: var(--sf-rating-size, 1rem);
    line-height: 1;
  }
  .sf-rating__label {
    /* Visually-hidden legend — kept in the a11y tree so screen readers announce it. */
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  .sf-rating__input {
    /* Visually-hidden but focusable so keyboard users can navigate stars. */
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  .sf-rating__star {
    cursor: pointer;
    color: var(--sf-color-border);
    padding-inline: 0.05em;
    transition: color var(--sf-duration-fast) var(--sf-ease-out);
  }
  /* Fill on :checked — matches the checked input plus every following label
     in DOM order (which is values lower than the checked one). */
  .sf-rating__input:checked ~ .sf-rating__star {
    color: var(--sf-rating-color, var(--sf-warning));
  }
  /* Hover preview — temporarily reset all stars and re-fill from the
     hovered label leftwards (visually). The :hover guard scopes the reset
     to active hover so the :checked state snaps back when the mouse leaves. */
  .sf-rating:hover .sf-rating__star {
    color: var(--sf-color-border);
  }
  .sf-rating__star:hover,
  .sf-rating__star:hover ~ .sf-rating__star {
    color: var(--sf-rating-hover-color, var(--sf-rating-color, var(--sf-warning)));
  }
  /* Keyboard focus ring on the visually-hidden input projects to its label. */
  .sf-rating__input:focus-visible + .sf-rating__star {
    outline: var(--sf-focus-ring-width) solid var(--sf-primary);
    outline-offset: var(--sf-focus-ring-offset);
    border-radius: var(--sf-radius-xs);
  }
  .sf-rating:has(.sf-rating__input:disabled) .sf-rating__star {
    cursor: not-allowed;
    opacity: 0.6;
  }
  /* Read-only display variant: bare spans pre-filled by adding the modifier. */
  .sf-rating__star--filled {
    color: var(--sf-rating-color, var(--sf-warning));
  }
  .sf-rating--l { --sf-rating-size: 1.25rem; }
  .sf-rating--xl { --sf-rating-size: 1.5rem; }

  /* ----- Icon (SVG icon sizing wrapper) ----- */
  /* Framework does NOT bundle an icon library — pick one (Lucide, Tabler, Phosphor,
     Heroicons, Iconoir) and host it your way. See docs/ICONS.md for the three
     supported patterns: inline SVG, sprite via <use>, and mask-image.
     Reference stroke-width 1.75 works well for Lucide; use 1.5 for thinner feel.

     Inline SVG markup:
       <svg class="sf-icon" xmlns="..." viewBox="0 0 24 24" fill="none"
            stroke="currentcolor" stroke-width="1.75" stroke-linecap="round"
            stroke-linejoin="round">
         <path d="..."/>
       </svg>

     Mask-image markup (single-color, host-agnostic):
       <span class="sf-icon sf-icon--mask"
             style="--sf-icon-mask: url('icons/check.svg')"
             role="img" aria-label="Done"></span>

     Size scales with font-size via `em` units — icon in a text-l context scales up
     automatically. Override via --sf-icon-size token for explicit sizing. */

  .sf-icon {
    inline-size: var(--sf-icon-size, 1.5em);
    block-size: var(--sf-icon-size, 1.5em);
    color: var(--sf-icon-color, currentcolor);
    flex-shrink: 0;
    vertical-align: middle;
  }
  .sf-icon--xs { --sf-icon-size: 0.875em; }
  .sf-icon--s  { --sf-icon-size: 1em; }
  .sf-icon--m  { --sf-icon-size: 1.5em; }  /* explicit default */
  .sf-icon--l  { --sf-icon-size: 2em; }
  .sf-icon--xl { --sf-icon-size: 3em; }
  .sf-icon--2xl { --sf-icon-size: 4em; }

  /* stroke-width utility for line icons (Lucide-style) */
  .sf-icon--thin   { stroke-width: 1.25; }
  .sf-icon--regular { stroke-width: 1.75; }
  .sf-icon--bold   { stroke-width: 2.25; }

  /* Baseline-aligned variant — corrects the typical 0.125em descender mismatch
     when an icon sits inline with body text (replaces vertical-align: middle). */
  .sf-icon--inline { vertical-align: -0.125em; }

  /* Solid icon sets (Heroicons-solid, Phosphor-fill, Material) — fill the
     glyph with currentcolor and drop stroke handling entirely. */
  .sf-icon--solid {
    fill: currentcolor;
    stroke: none;
  }

  /* Mirror in RTL contexts — apply to chevrons, arrows, and other directional
     glyphs that should flip when the document direction is right-to-left.
     Logical-property safe: works with [dir="rtl"] anywhere up the tree. */
  .sf-icon--mirror-rtl:dir(rtl) { transform: scaleX(-1); }

  /* Mask-image rendering: single-color icon via mask, host-agnostic.
     Consumer sets --sf-icon-mask: url(...) on the element. Background is
     currentcolor, masked by the SVG; size + color inherit from .sf-icon.
     Accessibility: NOT exposed to AT — pair with role="img" + aria-label,
     or aria-hidden="true" if decorative. */
  .sf-icon--mask {
    display: inline-block;
    background: currentcolor;
    mask-image: var(--sf-icon-mask);
    mask-size: contain;
    mask-repeat: no-repeat;
    mask-position: center;
    -webkit-mask-image: var(--sf-icon-mask);
    -webkit-mask-size: contain;
    -webkit-mask-repeat: no-repeat;
    -webkit-mask-position: center;
  }
  /* Forced-colors fallback: mask-image + currentcolor produce a CanvasText
     silhouette (correct), but make the rule explicit so HCM users always get
     a visible glyph even if a UA optimises the mask path away. */
  @media (forced-colors: active) {
    .sf-icon--mask { background: CanvasText; }
  }

  /* ----- Logo (SVG logo styling for logo strips) ----- */
  /* Use on <svg> directly: <svg class="sf-logo">...</svg>
     Configurable: --logo-size (default 2rem), --logo-color (default text-muted) */

  .sf-logo {
    block-size: var(--sf-logo-size, 2rem);
    inline-size: auto;
    color: var(--sf-logo-color, var(--sf-color-text-muted));
    fill: currentcolor;
    flex-shrink: 0;
  }
  .sf-logo--s  { --sf-logo-size: 1.5rem; }
  .sf-logo--l  { --sf-logo-size: 2.5rem; }
  .sf-logo--xl { --sf-logo-size: 3rem; }

  /* ----- Nav link (plain navigation link, matches parent in dropdowns) ----- */
  /* Use on plain <a> in navigation alongside sf-nav-dropdown for visual consistency.
     Lives in @layer slashed.components, beats base `a` / `a:visited` by layer order. */
  .sf-nav-link {
    text-decoration: none;
    color: var(--sf-color-text-muted);
    padding-block: var(--sf-space-2xs);
    transition: color var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-nav-link:hover,
    .sf-nav-link:visited:hover { color: var(--sf-color-text); }
  }
  .sf-nav-link:visited { color: var(--sf-color-text-muted); }

  /* ----- Nav dropdown (submenu for primary navigation) ----- */
  /* Uses native <details>/<summary> — zero JS required for basic operation.
     Works on desktop (click to open) and mobile (tap to expand).
     Use name="some-name" on multiple <details> for exclusive accordion (only one open).
     Chrome 120+, Firefox 133+. Falls back to non-exclusive in older browsers.

     The parent item is clickable as a link. Click on the label text navigates to the href,
     click on the chevron area toggles the dropdown. Minimal JS (~8 lines) required to
     route clicks correctly.

     Markup with clickable parent:
       <details class="sf-nav-dropdown" name="primary-nav">
         <summary class="sf-nav-dropdown__trigger">
           <a href="/product" class="sf-nav-dropdown__parent">Product</a>
         </summary>
         <ul class="sf-nav-dropdown__menu">
           <li><a class="sf-nav-dropdown__link" href="#">Features</a></li>
         </ul>
       </details>

     Markup without clickable parent (dropdown-only):
       <details class="sf-nav-dropdown" name="primary-nav">
         <summary class="sf-nav-dropdown__trigger">Solutions</summary>
         <ul class="sf-nav-dropdown__menu">...</ul>
       </details>

     Required JS (handles both: click-outside to close, and link navigation vs toggle):
       document.addEventListener('click', function(e) {
         var parentLink = e.target.closest('.sf-nav-dropdown__parent');
         if (parentLink) { e.stopPropagation(); return; }
         document.querySelectorAll('details.sf-nav-dropdown[open]').forEach(function(d) {
           if (!d.contains(e.target)) d.removeAttribute('open');
         });
       }); */

  .sf-nav-dropdown {
    position: relative;
  }
  .sf-nav-dropdown > summary {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: var(--sf-space-xs);
    user-select: none;
    font-weight: inherit;
    transition: color var(--sf-duration-fast) var(--sf-ease-out);
  }
  .sf-nav-dropdown > summary::-webkit-details-marker { display: none; }
  .sf-nav-dropdown > summary::after {
    content: "";
    display: inline-block;
    inline-size: 0.5em;
    block-size: 0.5em;
    border-inline-end: 2px solid currentcolor;
    border-block-end: 2px solid currentcolor;
    rotate: 45deg;
    margin-block-end: 0.15em;
    transition: rotate var(--sf-duration-fast) var(--sf-ease-out);
    flex-shrink: 0;
  }
  .sf-nav-dropdown[open] > summary::after { rotate: -135deg; margin-block-end: -0.15em; }

  /* Parent link — matches .sf-nav-link styling.
     padding-block extends click target to full nav height.
     Lives in @layer slashed.components, beats base `a` / `a:visited` by layer order. */
  .sf-nav-dropdown__parent {
    text-decoration: none;
    color: var(--sf-color-text-muted);
    padding-block: var(--sf-space-2xs);
    transition: color var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-nav-dropdown__parent:hover,
    .sf-nav-dropdown__parent:visited:hover { color: var(--sf-color-text); }
  }
  .sf-nav-dropdown[open] > summary > .sf-nav-dropdown__parent {
    color: var(--sf-color-text);
  }
  .sf-nav-dropdown__parent:visited { color: var(--sf-color-text-muted); }

  .sf-nav-dropdown__menu {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
  }
  .sf-nav-dropdown__link,
  .sf-nav-dropdown__menu a {
    display: flex;
    flex-direction: column;
    padding: var(--sf-space-xs) var(--sf-space-s);
    border-radius: var(--sf-radius-s);
    text-decoration: none;
    color: var(--sf-color-text);
    transition: background var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-nav-dropdown__link:hover,
    .sf-nav-dropdown__menu a:hover {
      background: var(--sf-color-surface-2);
    }
  }
  .sf-nav-dropdown__link-label {
    font-weight: 600;
  }
  .sf-nav-dropdown__link-desc {
    font-size: var(--sf-text-xs);
    color: var(--sf-color-text-muted);
  }

  /* Desktop: menu opens as absolute dropdown */
  @media (min-width: 48em) {
    .sf-nav-dropdown[open] > .sf-nav-dropdown__menu {
      position: absolute;
      inset-block-start: calc(100% + var(--sf-space-xs));
      inset-inline-start: 0;
      min-inline-size: 16rem;
      padding: var(--sf-space-xs);
      background: var(--sf-color-surface);
      border: var(--sf-border-width-1) solid var(--sf-color-border);
      border-radius: var(--sf-radius-m);
      box-shadow: var(--sf-shadow-m);
      z-index: var(--sf-z-dropdown);
    }
    /* Wide dropdown for multi-column menus */
    .sf-nav-dropdown--wide[open] > .sf-nav-dropdown__menu {
      min-inline-size: 32rem;
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: var(--sf-space-2xs);
    }
  }

  /* Mobile: menu expands inline (natural flow) */
  @media (max-width: 47.99em) {
    .sf-nav-dropdown__menu {
      padding-inline-start: var(--sf-space-m);
      padding-block: var(--sf-space-xs);
      gap: var(--sf-space-2xs);
    }

    /* Animated expand on mobile only. Cannot apply globally because
       overflow: hidden on ::details-content would clip the desktop popover
       which uses position: absolute below — popover would be cut to height: 0
       of its details parent. Future: reimplement desktop using popover API +
       anchor positioning, then this rule can apply globally. */
    @supports selector(details::details-content) {
      .sf-nav-dropdown::details-content {
        height: 0;
        overflow: hidden;
        transition: height var(--sf-duration-normal) var(--sf-ease-out),
                    content-visibility var(--sf-duration-normal) var(--sf-ease-out) allow-discrete;
      }
      .sf-nav-dropdown[open]::details-content { height: auto; }
      @starting-style {
        .sf-nav-dropdown[open]::details-content { height: 0; }
      }
    }
  }

  /* ==========================================================================
     0.2.0 ADDITIONS — e-commerce & transactional patterns
     ==========================================================================
     Added after battle-testing the blueprint library against framework surface.
     All additions are additive: no existing class is modified. */

  /* ----- Brand tile (colored container for single-letter or SVG logomarks) ----- */
  /* Distinct from .sf-icon: .sf-icon is for inline SVG sizing in text contexts
     (em-based, currentcolor). .sf-brand-tile is a block with explicit background
     and foreground used in header/footer logos, integration cards, carrier logos.
     --tile-bg / --tile-color / --tile-radius are per-instance overrides. */

  .sf-brand-tile {
    display: inline-grid;
    place-items: center;
    inline-size: var(--sf-tile-size, 2.5rem);
    block-size: var(--sf-tile-size, 2.5rem);
    border-radius: var(--sf-tile-radius, var(--sf-radius-s));
    background: var(--sf-tile-bg, var(--sf-primary));
    color: var(--sf-tile-color, var(--sf-color-text-on-primary));
    font-weight: 700;
    line-height: 1;
    flex-shrink: 0;
    overflow: hidden;
  }
  .sf-brand-tile--s  { --sf-tile-size: 2rem;   }
  .sf-brand-tile--l  { --sf-tile-size: 3rem;   }
  .sf-brand-tile--xl { --sf-tile-size: 4rem;   }

  /* ----- Price (main number + row + original/save sub-elements) ----- */
  /* Tag-agnostic: use on <span>, <strong>, <p>. Default size is text-l.
     --price-size / --price-color for per-instance scaling and tier colors
     (e.g. featured pricing tier can set --sf-price-color: var(--sf-primary)). */

  .sf-price {
    font-weight: 700;
    font-size: var(--sf-price-size, var(--sf-text-l));
    line-height: 1;
    color: var(--sf-price-color, var(--sf-color-text));
  }
  .sf-price--s  { --sf-price-size: var(--sf-text-m); }
  .sf-price--l  { --sf-price-size: var(--sf-text-2xl); }
  .sf-price--xl { --sf-price-size: var(--sf-text-3xl); }

  /* Row wrapper aligning main price with period, original, and save pill */
  .sf-price__row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--sf-space-xs);
  }

  /* Strikethrough previous price */
  .sf-price__original {
    text-decoration: line-through;
    color: var(--sf-color-text-muted);
    font-size: var(--sf-text-s);
    font-weight: 500;
  }

  /* Small colored pill — percent off, savings amount, etc. */
  .sf-price__save {
    display: inline-flex;
    align-items: center;
    padding: var(--sf-space-2xs) var(--sf-space-xs);
    font-size: var(--sf-text-xs);
    font-weight: 600;
    line-height: 1;
    border-radius: var(--sf-radius-s);
    background: var(--sf-success-100);
    color: var(--sf-success-600);
  }

  /* ----- Summary card (order/cart/checkout totals aside) ----- */
  /* Use on top of .sf-card (or any container). Designed to be sticky in wide
     layouts: wrap in a parent that allows sticky positioning.
     --summary-total-size lets per-instance variants use a compact total
     (e.g. text-m for inline steppers, text-xl for full checkout).
     --summary-heading-size mirrors that for the title. */

  .sf-summary-card__heading {
    font-size: var(--sf-summary-heading-size, var(--sf-text-m));
    font-weight: 600;
    margin: 0;
  }

  .sf-summary-card__row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--sf-space-m);
    padding-block: var(--sf-space-2xs);
    font-size: var(--sf-text-s);
  }

  .sf-summary-card__row > :last-child {
    font-weight: 500;
    text-align: end;
  }

  .sf-summary-card__total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--sf-space-m);
    padding-block-start: var(--sf-space-s);
    margin-block-start: var(--sf-space-s);
    border-block-start: var(--sf-border-width-1) solid var(--sf-color-border);
    font-size: var(--sf-summary-total-size, var(--sf-text-xl));
    font-weight: 700;
  }

  /* ----- Line item (cart/checkout/order row: thumb + info + price) ----- */
  /* Canonical line-item pattern — three-column grid: thumbnail, info stack, price.
     Info stack holds name + variant + optional meta. Price aligns start by default
     (use .sf-items-center on the root to center price with thumb). */

  .sf-line-item {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: var(--sf-space-m);
    align-items: start;
    padding-block: var(--sf-line-item-padding, var(--sf-space-s));
  }

  .sf-line-item__thumb {
    inline-size: var(--sf-line-item-thumb-size, 4rem);
    block-size: var(--sf-line-item-thumb-size, 4rem);
    border-radius: var(--sf-radius-s);
    background: var(--sf-color-surface-2);
    object-fit: cover;
    flex-shrink: 0;
  }

  .sf-line-item__info {
    display: flex;
    flex-direction: column;
    gap: var(--sf-space-2xs);
    min-inline-size: 0;
  }

  .sf-line-item__name {
    font-weight: 600;
    font-size: var(--sf-text-s);
    line-height: var(--sf-leading-snug);
    margin: 0;
  }

  .sf-line-item__variant {
    font-size: var(--sf-text-xs);
    color: var(--sf-color-text-muted);
  }

  .sf-line-item__price {
    font-weight: 700;
    font-size: var(--sf-text-s);
    white-space: nowrap;
  }

  /* ----- Quantity input (inline ±/value control) ----- */
  /* Use with three <button> or mix of buttons + <input type="number">.
     Size modifier --s drops to 1.75rem buttons for compact contexts.
     Hidden native spinners on <input type="number"> for consistency. */

  .sf-quantity-input {
    display: inline-flex;
    align-items: stretch;
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-m);
    background: var(--sf-color-surface);
    overflow: hidden;
  }

  .sf-quantity-input__btn {
    inline-size: var(--sf-qty-btn-size, 2rem);
    block-size: var(--sf-qty-btn-size, 2rem);
    display: inline-grid;
    place-items: center;
    background: transparent;
    border: 0;
    padding: 0;
    cursor: pointer;
    color: var(--sf-color-text);
    transition: background var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-quantity-input__btn:hover { background: var(--sf-color-surface-2); }
  }
  .sf-quantity-input__btn:disabled { cursor: not-allowed; opacity: 0.4; }

  .sf-quantity-input__value {
    min-inline-size: 2.5rem;
    padding: 0;
    text-align: center;
    font-weight: 600;
    font-size: var(--sf-text-s);
    background: var(--sf-color-surface);
    color: var(--sf-color-text);
    border: 0;
    border-inline: var(--sf-border-width-1) solid var(--sf-color-border);
    line-height: var(--sf-qty-btn-size, 2rem);
    -moz-appearance: textfield;
  }
  .sf-quantity-input__value::-webkit-outer-spin-button,
  .sf-quantity-input__value::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
  }

  .sf-quantity-input--s { --sf-qty-btn-size: 1.75rem; }
  .sf-quantity-input--s .sf-quantity-input__value {
    font-size: var(--sf-text-xs);
    min-inline-size: 2rem;
  }

  /* ----- Radio card / check card (selectable card with hidden form input) ----- */
  /* Markup: <label class="sf-radio-card"><input type="radio" class="sf-radio-card__input">
              <span class="sf-radio-card__surface">…</span></label>
     Uses :has() to style the surface when the hidden input is checked.
     --radio-card-bg-selected / --radio-card-border-selected tokenize the selected state. */

  .sf-radio-card,
  .sf-check-card {
    display: block;
    position: relative;
    cursor: pointer;
  }

  .sf-radio-card__input,
  .sf-check-card__input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  .sf-radio-card__surface,
  .sf-check-card__surface {
    display: block;
    padding: var(--sf-radio-card-padding, var(--sf-space-m));
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-m);
    background: var(--sf-color-surface);
    transition: border-color var(--sf-duration-fast) var(--sf-ease-out),
                background var(--sf-duration-fast) var(--sf-ease-out),
                box-shadow var(--sf-duration-fast) var(--sf-ease-out);
  }

  .sf-radio-card:has(input:checked) .sf-radio-card__surface,
  .sf-check-card:has(input:checked) .sf-check-card__surface {
    border-color: var(--sf-radio-card-border-selected, var(--sf-primary));
    background: var(--sf-radio-card-bg-selected, var(--sf-primary-50));
    box-shadow: inset 0 0 0 1px var(--sf-radio-card-border-selected, var(--sf-primary));
  }

  .sf-radio-card:has(input:focus-visible) .sf-radio-card__surface,
  .sf-check-card:has(input:focus-visible) .sf-check-card__surface {
    outline: 2px solid var(--sf-primary);
    outline-offset: var(--sf-focus-ring-offset);
  }

  .sf-radio-card:has(input:disabled),
  .sf-check-card:has(input:disabled) {
    cursor: not-allowed;
    opacity: 0.6;
  }

  /* ----- Option group (pill/rectangle mutually-exclusive choices) ----- */
  /* Stateless list of options — click-to-select via JS, OR combine with a hidden
     radio group via the `:has(input:checked)` fallback clause below.
     For form-backed cards (bigger surface, richer content) use .sf-radio-card instead. */

  .sf-option-group {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sf-space-xs);
  }

  .sf-option-group__option {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: var(--sf-space-xs) var(--sf-space-m);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-option-radius, var(--sf-radius-m));
    background: var(--sf-color-surface);
    color: var(--sf-color-text);
    font-size: var(--sf-text-s);
    font-weight: 500;
    line-height: 1;
    cursor: pointer;
    transition: border-color var(--sf-duration-fast) var(--sf-ease-out),
                background var(--sf-duration-fast) var(--sf-ease-out),
                color var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-option-group__option:hover { border-color: var(--sf-color-border-strong); }
  }

  .sf-option-group__option--selected,
  .sf-option-group__option:has(input:checked) {
    border-color: var(--sf-primary);
    background: var(--sf-primary-50);
    color: var(--sf-primary);
  }

  /* ----- Segment (segmented control: connected radio toggles) ----- */
  /* Pure-CSS active state via :has(:checked) — no JS required. Pair with
     <fieldset>/<legend> or role="radiogroup" + aria-label for a11y context.
     Distinct from .sf-option-group: segment is a unified control with shared
     background where the active option appears raised; option-group is a
     row of independent pills.

     Markup:
       <div class="sf-segment" role="radiogroup" aria-label="View mode">
         <label class="sf-segment__option">
           <input type="radio" name="view" value="grid" checked>
           <span>Grid</span>
         </label>
         <label class="sf-segment__option">
           <input type="radio" name="view" value="list">
           <span>List</span>
         </label>
       </div> */

  .sf-segment {
    display: inline-flex;
    gap: var(--sf-segment-gap, 0.125rem);
    padding: var(--sf-segment-padding, 0.25rem);
    background: var(--sf-color-surface-2);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-m);
  }
  .sf-segment--full-width {
    display: flex;
    inline-size: 100%;
  }
  .sf-segment--full-width .sf-segment__option {
    flex: 1;
  }
  .sf-segment--s { --sf-segment-padding: 0.125rem; }
  .sf-segment--l { --sf-segment-padding: 0.375rem; }

  .sf-segment__option {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sf-space-2xs);
    padding-block: var(--sf-space-2xs);
    padding-inline: var(--sf-space-s);
    border-radius: calc(var(--sf-radius-m) - 0.125rem);
    color: var(--sf-color-text-muted);
    font-size: var(--sf-text-s);
    font-weight: 500;
    line-height: var(--sf-leading-snug);
    cursor: pointer;
    user-select: none;
    transition: background var(--sf-duration-fast) var(--sf-ease-out),
                color var(--sf-duration-fast) var(--sf-ease-out);
  }
  .sf-segment--s .sf-segment__option {
    padding-block: 0;
    padding-inline: var(--sf-space-xs);
    font-size: var(--sf-text-xs);
  }
  .sf-segment--l .sf-segment__option {
    padding-block: var(--sf-space-xs);
    padding-inline: var(--sf-space-m);
    font-size: var(--sf-text-m);
  }

  /* Visually hide the radio input — keep accessible to AT.
     Same clip pattern as .sf-sr-only; scoped so global utility need not be loaded. */
  .sf-segment__option > input[type="radio"] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    border: 0;
    white-space: nowrap;
  }

  /* Active state via :has(:checked) — pure CSS. */
  .sf-segment__option:has(:checked) {
    background: var(--sf-color-surface);
    color: var(--sf-color-text);
    box-shadow: var(--sf-shadow-s);
  }
  @media (hover: hover) {
    .sf-segment__option:hover:not(:has(:checked)) {
      color: var(--sf-color-text);
    }
  }
  /* Focus ring on the wrapper when the radio is keyboard-focused. */
  .sf-segment__option:has(:focus-visible) {
    outline: var(--sf-focus-ring-width) solid var(--sf-focus-ring-color);
    outline-offset: var(--sf-focus-ring-offset);
  }
  /* Disabled */
  .sf-segment__option:has(:disabled) {
    cursor: not-allowed;
    opacity: 0.5;
  }

  /* ----- Progress bar ----- */
  /* Primary: use native <progress value="65" max="100"> for
     semantic markup and built-in accessibility (screen readers
     announce the value automatically). Set value via HTML attribute.

     Modifiers: --progress-color (default var(--sf-primary)),
                --progress-size  (default 6px)

     Fallback div pattern (JS-driven or animation-only contexts):
       <div class="sf-progress" style="--progress: 65%">
         <div class="sf-progress__fill"></div>
       </div>
     See docs/COMPONENTS.md for fallback usage. */

  .sf-progress {
    appearance: none;
    display: block;
    inline-size: 100%;
    block-size: var(--sf-progress-size, 6px);
    border: 0;
    border-radius: var(--sf-radius-full);
    overflow: hidden;
    color: var(--sf-progress-color, var(--sf-primary));
    background: var(--sf-color-border);
  }
  .sf-progress--s { --sf-progress-size: 3px; }
  .sf-progress--l { --sf-progress-size: 10px; }

  /* WebKit: track + fill */
  .sf-progress::-webkit-progress-bar {
    background: var(--sf-color-border);
    border-radius: var(--sf-radius-full);
  }
  .sf-progress::-webkit-progress-value {
    background: var(--sf-progress-color, var(--sf-primary));
    border-radius: var(--sf-radius-full);
    transition: width var(--sf-duration-normal) var(--sf-ease-out);
  }

  /* Firefox: fill (track inherits from .sf-progress background) */
  .sf-progress::-moz-progress-bar {
    background: var(--sf-progress-color, var(--sf-primary));
    border-radius: var(--sf-radius-full);
  }

  /* Div fallback pattern (kept for JS-driven/animation contexts) */
  .sf-progress__fill {
    display: block;
    block-size: 100%;
    inline-size: var(--sf-progress, 0%);
    background: var(--sf-progress-color, var(--sf-primary));
    border-radius: inherit;
    transition: inline-size var(--sf-duration-normal) var(--sf-ease-out);
  }

  /* ----- Stepper (horizontal default + --vertical) ----- */
  /* Steps connected by a pseudo-line between dots. Modifier classes --active and
     --complete drive color state. Connector gets the active/complete color when
     the PRECEDING step has that state (sibling combinator on ::before). */

  .sf-stepper {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0;
    list-style: none;
    padding: 0;
    margin: 0;
  }

  .sf-stepper__step {
    flex: 1;
    min-inline-size: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sf-space-xs);
    position: relative;
    text-align: center;
  }

  .sf-stepper__step + .sf-stepper__step::before {
    content: "";
    position: absolute;
    inset-block-start: calc(var(--sf-stepper-dot-size, 2rem) / 2);
    inset-inline-start: -50%;
    inset-inline-end: 50%;
    block-size: var(--sf-stepper-line-width, 2px);
    background: var(--sf-color-border);
    z-index: 0;
    transform: translateY(-50%);
  }
  .sf-stepper__step--complete + .sf-stepper__step::before,
  .sf-stepper__step--active + .sf-stepper__step::before {
    background: var(--sf-stepper-line-active, var(--sf-primary));
  }

  .sf-stepper__dot {
    inline-size: var(--sf-stepper-dot-size, 2rem);
    block-size: var(--sf-stepper-dot-size, 2rem);
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--sf-color-surface);
    border: 2px solid var(--sf-color-border);
    color: var(--sf-color-text-muted);
    font-size: var(--sf-text-s);
    font-weight: 600;
    z-index: var(--sf-z-raised);
    position: relative;
    flex-shrink: 0;
  }
  .sf-stepper__step--complete .sf-stepper__dot {
    background: var(--sf-primary);
    border-color: var(--sf-primary);
    color: var(--sf-color-text-on-primary);
  }
  .sf-stepper__step--active .sf-stepper__dot {
    background: var(--sf-color-text);
    border-color: var(--sf-color-text);
    color: var(--sf-color-surface);
  }

  .sf-stepper__label {
    font-size: var(--sf-text-s);
    font-weight: 500;
    color: var(--sf-color-text-muted);
  }
  .sf-stepper__step--complete .sf-stepper__label,
  .sf-stepper__step--active   .sf-stepper__label {
    color: var(--sf-color-text);
  }

  /* Optional wrapper for step label + time + detail (vertical-stepper content column) */
  .sf-stepper__content {
    display: flex;
    flex-direction: column;
    gap: var(--sf-space-2xs);
    flex: 1;
    min-inline-size: 0;
  }

  /* Vertical orientation — dot in left gutter, content beside, connector running
     vertically down the dot column. */
  .sf-stepper--vertical {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
  }
  .sf-stepper--vertical .sf-stepper__step {
    flex: 0 0 auto;
    flex-direction: row;
    align-items: flex-start;
    text-align: start;
    padding-block-end: var(--sf-stepper-vertical-gap, var(--sf-space-l));
  }
  .sf-stepper--vertical .sf-stepper__step:last-child { padding-block-end: 0; }

  .sf-stepper--vertical .sf-stepper__step + .sf-stepper__step::before {
    inset-block-start: calc(-1 * var(--sf-stepper-vertical-gap, var(--sf-space-l)));
    inset-block-end: auto;
    inset-inline-start: calc(var(--sf-stepper-dot-size, 2rem) / 2 - var(--sf-stepper-line-width, 2px) / 2);
    inset-inline-end: auto;
    block-size: var(--sf-stepper-vertical-gap, var(--sf-space-l));
    inline-size: var(--sf-stepper-line-width, 2px);
    transform: none;
  }
  .sf-stepper--vertical .sf-stepper__step--active .sf-stepper__dot {
    background: var(--sf-primary);
    border-color: var(--sf-primary);
    color: var(--sf-color-text-on-primary);
    box-shadow: 0 0 0 4px var(--sf-primary-a25);
  }

  /* ----- Badge: --pill modifier + __dot element ----- */
  /* Pill variant: semi-transparent color-mixed background + pure semantic color
     text. Combines with existing --success/--warning/--error/--neutral to produce
     the standard "status pill" look (delivered/in-transit/processing/cancelled).
     __dot adds a small leading circle using currentcolor — no extra color setup. */

  .sf-badge--pill {
    --sf-badge-bg: color-mix(in oklab, var(--sf-badge-text, var(--sf-primary)) 15%, transparent);
    padding-inline: var(--sf-space-s);
    border-radius: var(--sf-radius-full);
    gap: var(--sf-space-2xs);
  }

  .sf-badge__dot {
    inline-size: 0.5em;
    block-size: 0.5em;
    border-radius: 50%;
    background: currentcolor;
    flex-shrink: 0;
    display: inline-block;
  }

  /* ----- Rating: __count element + --with-count modifier ----- */
  /* Extends .sf-rating. Pattern: stars + "(123)" review-count on the same
     baseline. The __count element must come BEFORE the input/label pairs in
     DOM (right after the legend) so flex-direction: row-reverse places it
     visually to the right of the stars. margin-inline-start gives it
     breathing room — `gap` would space adjacent stars apart and is avoided. */

  .sf-rating--with-count {
    align-items: center;
  }
  .sf-rating--with-count .sf-rating__count {
    margin-inline-start: var(--sf-space-xs);
  }
  .sf-rating__count {
    font-size: var(--sf-text-s);
    color: var(--sf-color-text-muted);
    font-weight: 500;
    letter-spacing: normal;
  }

  /* ----- Breadcrumb (hierarchical nav trail) ----- */
  /* Use on <nav aria-label="Breadcrumb"> wrapping an <ol>. Items are links except
     the current page which gets __current (non-link, bolder, text color). */

  .sf-breadcrumb {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sf-breadcrumb-gap, var(--sf-space-xs));
    font-size: var(--sf-text-s);
    color: var(--sf-color-text-muted);
  }
  .sf-breadcrumb > ol,
  .sf-breadcrumb > ul {
    display: contents;
    list-style: none;
    padding: 0;
    margin: 0;
  }
  .sf-breadcrumb__item {
    display: inline-flex;
    align-items: center;
    gap: var(--sf-space-xs);
  }
  .sf-breadcrumb__sep {
    opacity: 0.5;
    user-select: none;
  }
  .sf-breadcrumb__current {
    color: var(--sf-color-text);
    font-weight: 500;
  }

  /* ----- Divider: __text element + --s modifier ----- */
  /* Extends existing .sf-divider (line-text-line layout) with styled text slot
     and a smaller-gap variant. Typical usage:
       <div class="sf-divider"><span class="sf-divider__text">Or continue with email</span></div> */

  .sf-divider__text {
    font-size: var(--sf-text-xs);
    text-transform: uppercase;
    letter-spacing: var(--sf-tracking-widest);
    font-weight: 600;
    color: var(--sf-color-text-muted);
  }
  .sf-divider--s {
    gap: var(--sf-space-s);
  }
  .sf-divider--s .sf-divider__text {
    font-size: var(--sf-text-2xs);
  }

  /* ----- Data list (label/value pairs with separators) ----- */
  /* Semantic: use on <dl> with <div class="sf-data-list__row"><dt><dd> pattern, or
     on <div> with arbitrary children styled via the element classes. */

  .sf-data-list {
    display: flex;
    flex-direction: column;
    padding: 0;
    margin: 0;
  }
  .sf-data-list__row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--sf-space-m);
    padding-block: var(--sf-space-s);
    border-block-end: var(--sf-border-width-1) solid var(--sf-color-border);
    font-size: var(--sf-text-s);
  }
  .sf-data-list__row:last-child { border-block-end: 0; }
  .sf-data-list__label {
    color: var(--sf-color-text-muted);
    margin: 0;
    min-inline-size: var(--sf-data-list-label-width, auto);
  }
  .sf-data-list__value {
    color: var(--sf-color-text);
    font-weight: 500;
    margin: 0;
    text-align: end;
  }

  /* ----- Swatches (color-circle selector row) ----- */
  /* Container is a horizontal cluster; each swatch is a circle driven by
     --swatch-color. Selected state: 2px outline ring with offset. */

  .sf-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sf-space-xs);
  }
  .sf-swatch {
    inline-size: var(--sf-swatch-size, 1.25rem);
    block-size: var(--sf-swatch-size, 1.25rem);
    border-radius: 50%;
    background: var(--sf-swatch-color, var(--sf-primary));
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    cursor: pointer;
    flex-shrink: 0;
    padding: 0;
  }
  .sf-swatch--l  { --sf-swatch-size: 1.75rem; }
  .sf-swatch--xl { --sf-swatch-size: 2.25rem; }
  .sf-swatch--selected {
    outline: 2px solid var(--sf-primary);
    outline-offset: var(--sf-focus-ring-offset);
  }

  /* ==========================================================================
     0.3.3.0 ADDITIONS — missing core components (tabs / pagination / dropdown /
     message / footer)
     ==========================================================================
     All additions are additive; no existing class is modified. */

  /* ----- Tabs (CSS-only via radio inputs + :has) ----- */
  /* No JS required.

     Full WAI-ARIA Tabs pattern markup (ids + aria-controls + aria-labelledby
     + aria-selected + roving tabindex). CSS is role-agnostic, so a simpler
     radio-group markup without ARIA also works visually — but for screen-reader
     correctness follow the Tabs pattern as below:
       <div class="sf-tabs">
         <div class="sf-tabs__list" role="tablist" aria-label="Section tabs">
           <label class="sf-tabs__tab"
                  id="tab-one"
                  role="tab"
                  aria-selected="true"
                  aria-controls="panel-one"
                  tabindex="0">
             <input type="radio" name="t" checked>
             <span>One</span>
           </label>
           <label class="sf-tabs__tab"
                  id="tab-two"
                  role="tab"
                  aria-selected="false"
                  aria-controls="panel-two"
                  tabindex="-1">
             <input type="radio" name="t">
             <span>Two</span>
           </label>
         </div>
         <div class="sf-tabs__panels">
           <div class="sf-tabs__panel"
                id="panel-one"
                role="tabpanel"
                aria-labelledby="tab-one">Panel 1</div>
           <div class="sf-tabs__panel"
                id="panel-two"
                role="tabpanel"
                aria-labelledby="tab-two">Panel 2</div>
         </div>
       </div>

     A small JS handler can flip aria-selected + tabindex when the user changes
     the radio (see js/slashed-ui.js `initTabs` for an example). Without JS
     the visual state still works via :has(input:checked); the aria-selected
     and tabindex attributes will be stale but the roles remain correct and
     the inactive panel is hidden from everyone (CSS display: none removes it
     from the accessibility tree) rather than only sighted users.

     NOTE: do not add the `hidden` HTML attribute to inactive panels unless
     you also wire up JS to toggle it — the framework's base rule already sets
     display: none on non-active panels, and a stale `hidden` would trap the
     panel's content from assistive technologies even when CSS :has() reveals
     it visually.

     This is a styled radio/segmented control component. .sf-tabs wraps the entire
     component, .sf-tabs__list contains the radio buttons styled as tabs,
     .sf-tabs__tab wraps each radio input, .sf-tabs__panels contains the content,
     and .sf-tabs__panel holds each panel. Uses :has(input:checked) on .sf-tabs__tab
     to style active tab and nth-child() pairing to reveal matching panel.
     Requires :has() support (Chrome 105+, Firefox 121+, Safari 15.4+). */

  .sf-tabs {
    --sf-tabs-gap: var(--sf-space-xs);
    --sf-tab-padding: var(--sf-space-s) var(--sf-space-m);
    display: flex;
    flex-direction: column;
    gap: var(--sf-space-m);
  }
  .sf-tabs__list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sf-tabs-gap);
    border-block-end: var(--sf-border-width-1) solid var(--sf-color-border);
  }
  .sf-tabs__tab {
    padding: var(--sf-tab-padding);
    cursor: pointer;
    color: var(--sf-color-text-muted);
    font-weight: 500;
    border-block-end: 2px solid transparent;
    margin-block-end: -1px;
    transition: color var(--sf-duration-fast) var(--sf-ease-out),
                border-color var(--sf-duration-fast) var(--sf-ease-out);
  }
  .sf-tabs__tab > input { position: absolute; opacity: 0; pointer-events: none; }
  @media (hover: hover) {
    .sf-tabs__tab:hover { color: var(--sf-color-text); }
  }
  /* Active tab: CSS-only path via :has(input:checked), JS-enhanced path via aria-selected.
     Both selectors are kept so either mechanism can activate the tab independently.
     background: transparent overrides the global [aria-selected="true"] rule in slashed-core.css
     which sets background: var(--sf-primary-100) on all aria-selected elements. */
  .sf-tabs__tab:has(input:checked),
  .sf-tabs__tab[aria-selected="true"] {
    background: transparent;
    color: var(--sf-primary);
    border-block-end-color: var(--sf-primary);
  }
  .sf-tabs__tab:has(input:focus-visible) {
    outline: 2px solid var(--sf-primary);
    outline-offset: var(--sf-focus-ring-offset);
    border-radius: var(--sf-radius-s);
  }
  .sf-tabs__panel { display: none; }
  /* CSS-only panel reveal via :has(). Supports up to 10 tabs without JS.
     .sf-tabs__panel.sf-is-active and [aria-hidden="false"] kept for JS-enhanced/SSR. */
  .sf-tabs:has(.sf-tabs__tab:nth-child(1) input:checked) .sf-tabs__panel:nth-child(1),
  .sf-tabs:has(.sf-tabs__tab:nth-child(2) input:checked) .sf-tabs__panel:nth-child(2),
  .sf-tabs:has(.sf-tabs__tab:nth-child(3) input:checked) .sf-tabs__panel:nth-child(3),
  .sf-tabs:has(.sf-tabs__tab:nth-child(4) input:checked) .sf-tabs__panel:nth-child(4),
  .sf-tabs:has(.sf-tabs__tab:nth-child(5) input:checked) .sf-tabs__panel:nth-child(5),
  .sf-tabs:has(.sf-tabs__tab:nth-child(6) input:checked) .sf-tabs__panel:nth-child(6),
  .sf-tabs:has(.sf-tabs__tab:nth-child(7) input:checked) .sf-tabs__panel:nth-child(7),
  .sf-tabs:has(.sf-tabs__tab:nth-child(8) input:checked) .sf-tabs__panel:nth-child(8),
  .sf-tabs:has(.sf-tabs__tab:nth-child(9) input:checked) .sf-tabs__panel:nth-child(9),
  .sf-tabs:has(.sf-tabs__tab:nth-child(10) input:checked) .sf-tabs__panel:nth-child(10),
  .sf-tabs__panel.sf-is-active,
  .sf-tabs__panel[aria-hidden="false"] { display: block; }

  /* --sf-vertical: tab list on the inline-start, panels alongside */
  .sf-tabs--vertical {
    flex-direction: row;
    gap: var(--sf-space-l);
  }
  .sf-tabs--vertical > .sf-tabs__list {
    flex-direction: column;
    border-block-end: 0;
    border-inline-end: var(--sf-border-width-1) solid var(--sf-color-border);
    flex-shrink: 0;
  }
  .sf-tabs--vertical > .sf-tabs__list > .sf-tabs__tab {
    border-block-end: 0;
    border-inline-end: 2px solid transparent;
    margin-block-end: 0;
    margin-inline-end: -1px;
  }
  .sf-tabs--vertical > .sf-tabs__list > .sf-tabs__tab:has(input:checked),
  .sf-tabs--vertical > .sf-tabs__list > .sf-tabs__tab[aria-selected="true"] {
    border-inline-end-color: var(--sf-primary);
  }
  .sf-tabs--vertical > .sf-tabs__panels { flex: 1; }

  /* --sf-boxed: connected rectangular tabs (active is filled surface) */
  .sf-tabs--boxed > .sf-tabs__list { gap: 0; }
  .sf-tabs--boxed > .sf-tabs__list > .sf-tabs__tab {
    border: var(--sf-border-width-1) solid transparent;
    border-block-end: 0;
    border-start-start-radius: var(--sf-radius-m);
    border-start-end-radius: var(--sf-radius-m);
  }
  .sf-tabs--boxed > .sf-tabs__list > .sf-tabs__tab:has(input:checked),
  .sf-tabs--boxed > .sf-tabs__list > .sf-tabs__tab[aria-selected="true"] {
    border-color: var(--sf-color-border);
    background: var(--sf-color-surface);
    color: var(--sf-color-text);
  }

  /* --sf-pill: rounded capsule tabs, no bottom border */
  .sf-tabs--pill > .sf-tabs__list { border-block-end: 0; }
  .sf-tabs--pill > .sf-tabs__list > .sf-tabs__tab {
    border-radius: var(--sf-radius-full);
    border-block-end: 0;
    margin-block-end: 0;
  }
  .sf-tabs--pill > .sf-tabs__list > .sf-tabs__tab:has(input:checked),
  .sf-tabs--pill > .sf-tabs__list > .sf-tabs__tab[aria-selected="true"] {
    background: var(--sf-primary);
    color: var(--sf-color-text-on-primary);
    border-block-end-color: transparent;
  }

  /* ----- Pagination (numbered page navigation) ----- */
  /* Markup:
       <nav class="sf-pagination" aria-label="Pagination">
         <a class="sf-pagination__prev" href="?p=2" rel="prev">Previous</a>
         <ul>
           <li><a class="sf-pagination__link" href="?p=1">1</a></li>
           <li><a class="sf-pagination__link sf-pagination__link--current" aria-current="page">2</a></li>
           <li><span class="sf-pagination__ellipsis">…</span></li>
           <li><a class="sf-pagination__link" href="?p=10">10</a></li>
         </ul>
         <a class="sf-pagination__next" href="?p=3" rel="next">Next</a>
       </nav> */

  .sf-pagination {
    --sf-pagination-size: 2.25rem;
    --sf-pagination-gap: var(--sf-space-2xs);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sf-pagination-gap);
  }
  .sf-pagination > ul,
  .sf-pagination > ol {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sf-pagination-gap);
    list-style: none;
    padding: 0;
    margin: 0;
  }
  .sf-pagination__link,
  .sf-pagination__prev,
  .sf-pagination__next,
  .sf-pagination__ellipsis {
    min-inline-size: var(--sf-pagination-size);
    block-size: var(--sf-pagination-size);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 var(--sf-space-s);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-s);
    text-decoration: none;
    color: var(--sf-color-text);
    background: var(--sf-color-surface);
    font-weight: 500;
    transition: background var(--sf-duration-fast) var(--sf-ease-out),
                border-color var(--sf-duration-fast) var(--sf-ease-out),
                color var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-pagination__link:hover,
    .sf-pagination__prev:hover,
    .sf-pagination__next:hover {
      background: var(--sf-color-surface-2);
      border-color: var(--sf-primary);
    }
  }
  .sf-pagination__link--current,
  .sf-pagination__link[aria-current="page"] {
    background: var(--sf-primary);
    border-color: var(--sf-primary);
    color: var(--sf-color-text-on-primary);
    pointer-events: none;
  }
  .sf-pagination__ellipsis {
    border-color: transparent;
    background: transparent;
    color: var(--sf-color-text-muted);
    cursor: default;
  }
  .sf-pagination--s { --sf-pagination-size: 1.75rem; font-size: var(--sf-text-s); }
  .sf-pagination--l { --sf-pagination-size: 2.75rem; font-size: var(--sf-text-l); }

  /* ----- Dropdown (generic, distinct from .sf-nav-dropdown) ----- */
  /* General-purpose dropdown for action menus, filters, user menus.
     Uses <details>/<summary> for zero-JS toggle. Differs from .sf-nav-dropdown:
       - Trigger is a button-styled element, not a nav link
       - Menu aligns to inline-start and lifts above surrounding content
       - Supports dividers and right-aligned keyboard hints
       - --up variant opens upward for bottom-anchored triggers

     Markup:
       <details class="sf-dropdown">
         <summary class="sf-dropdown__trigger">Actions</summary>
         <div class="sf-dropdown__menu">
           <button class="sf-dropdown__item">Edit</button>
           <button class="sf-dropdown__item">Duplicate</button>
           <hr class="sf-dropdown__divider">
           <button class="sf-dropdown__item">Delete</button>
         </div>
       </details>

     Click-outside close via js/slashed-ui.js (same helper as .sf-nav-dropdown). */

  .sf-dropdown {
    position: relative;
    display: inline-block;
  }
  .sf-dropdown > summary {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: var(--sf-space-xs);
    padding: var(--sf-space-xs) var(--sf-space-m);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-s);
    background: var(--sf-color-surface);
    color: var(--sf-color-text);
    font-weight: 500;
    user-select: none;
    transition: background var(--sf-duration-fast) var(--sf-ease-out),
                border-color var(--sf-duration-fast) var(--sf-ease-out);
  }
  .sf-dropdown > summary::-webkit-details-marker { display: none; }
  .sf-dropdown > summary::after {
    content: "";
    display: inline-block;
    inline-size: 0.5em;
    block-size: 0.5em;
    border-inline-end: 2px solid currentcolor;
    border-block-end: 2px solid currentcolor;
    rotate: 45deg;
    margin-block-end: 0.15em;
    transition: rotate var(--sf-duration-fast) var(--sf-ease-out);
    flex-shrink: 0;
  }
  .sf-dropdown[open] > summary::after { rotate: -135deg; margin-block-end: -0.15em; }
  @media (hover: hover) {
    .sf-dropdown > summary:hover { background: var(--sf-color-surface-2); }
  }
  .sf-dropdown > summary:focus-visible {
    outline: 2px solid var(--sf-primary);
    outline-offset: var(--sf-focus-ring-offset);
  }
  .sf-dropdown__menu {
    position: absolute;
    inset-block-start: calc(100% + var(--sf-space-2xs));
    inset-inline-start: 0;
    min-inline-size: 12rem;
    padding: var(--sf-space-2xs);
    background: var(--sf-color-surface);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-m);
    box-shadow: var(--sf-shadow-m);
    z-index: var(--sf-z-dropdown);
    display: none;
    overscroll-behavior: contain;
  }
  .sf-dropdown[open] .sf-dropdown__menu {
    display: flex;
    flex-direction: column;
    gap: 2px;
  }
  .sf-dropdown__item {
    display: flex;
    align-items: center;
    gap: var(--sf-space-s);
    padding: var(--sf-space-xs) var(--sf-space-s);
    border: 0;
    border-radius: var(--sf-radius-s);
    background: transparent;
    color: var(--sf-color-text);
    text-align: start;
    text-decoration: none;
    cursor: pointer;
    font: inherit;
    transition: background var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-dropdown__item:hover {
      background: var(--sf-color-surface-2);
      outline: none;
    }
  }
  .sf-dropdown__item:focus-visible {
    background: var(--sf-color-surface-2);
    outline: none;
  }
  .sf-dropdown__divider {
    border: 0;
    border-block-start: var(--sf-border-width-1) solid var(--sf-color-border);
    margin: var(--sf-space-2xs) 0;
  }

  /* --sf-up: menu lifts upward from the trigger */
  .sf-dropdown--up > .sf-dropdown__menu {
    inset-block-start: auto;
    inset-block-end: calc(100% + var(--sf-space-2xs));
  }
  /* --sf-end: menu aligns to inline-end edge of trigger */
  .sf-dropdown--end > .sf-dropdown__menu {
    inset-inline-start: auto;
    inset-inline-end: 0;
  }

  /* ----- Message (advanced alert with header + body) ----- */
  /* Distinct from .sf-notice: .sf-notice is a single-surface banner (left accent).
     .sf-message is a two-section block with a tinted header strip and a body.
     Use for terms of service blocks, long error explanations, onboarding tips.

     Markup:
       <article class="sf-message sf-message--warning">
         <header class="sf-message__header">
           Heads up
           <button class="sf-message__close" aria-label="Dismiss">×</button>
         </header>
         <div class="sf-message__body">Body text…</div>
       </article> */

  .sf-message {
    --sf-message-color: var(--sf-primary);
    --sf-message-bg: var(--sf-primary-100);
    border: var(--sf-border-width-1) solid var(--sf-message-color);
    border-radius: var(--sf-radius-m);
    overflow: hidden;
    background: var(--sf-color-surface);
  }
  .sf-message__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sf-space-s);
    padding: var(--sf-space-s) var(--sf-space-m);
    background: var(--sf-message-bg);
    color: var(--sf-message-color);
    font-weight: 600;
  }
  .sf-message__body {
    padding: var(--sf-space-m);
    color: var(--sf-color-text);
  }
  .sf-message__close {
    inline-size: 1.5rem;
    block-size: 1.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    cursor: pointer;
    border-radius: var(--sf-radius-s);
    opacity: 0.7;
    transition: opacity var(--sf-duration-fast) var(--sf-ease-out);
    font-size: 1.25em;
    line-height: 1;
  }
  @media (hover: hover) {
    .sf-message__close:hover { opacity: 1; }
  }
  .sf-message--success { --sf-message-color: var(--sf-success);    --sf-message-bg: var(--sf-success-100); }
  /* --warning uses --warning-600 for the header text (not --warning)
     because --warning is ~2.8:1 on --warning-100 which fails WCAG AA.
     --warning-600 ships ~5.2:1 on --warning-100 (AA-compliant). */
  .sf-message--warning { --sf-message-color: var(--sf-warning-600); --sf-message-bg: var(--sf-warning-100); }
  .sf-message--error   { --sf-message-color: var(--sf-error);       --sf-message-bg: var(--sf-error-100);   }
  .sf-message--info    { --sf-message-color: var(--sf-info-600);    --sf-message-bg: var(--sf-info-100);    }

  /* ----- Footer (page-bottom block) ----- */
  /* Dedicated footer element with wider default paddings and surface-2
     background. Intentionally minimal — most content inside is authored via
     existing utilities (grid, stack, cluster, sf-nav-link, sf-divider). */

  .sf-footer {
    padding-block: var(--sf-footer-padding-block, var(--sf-space-2xl));
    padding-inline: var(--sf-footer-padding-inline, var(--sf-space-l));
    background: var(--sf-footer-bg, var(--sf-color-surface-2));
    color: var(--sf-footer-color, var(--sf-color-text));
    border-block-start: var(--sf-border-width-1) solid var(--sf-color-border);
  }
  .sf-footer a { color: inherit; }
  .sf-footer__bottom {
    margin-block-start: var(--sf-space-xl);
    padding-block-start: var(--sf-space-m);
    border-block-start: var(--sf-border-width-1) solid var(--sf-color-border);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sf-space-m);
    color: var(--sf-color-text-muted);
    font-size: var(--sf-text-s);
  }

  /* ==========================================================================
     0.3.4.0 ADDITIONS — form enhancements
     ==========================================================================
     Extends the form surface with full select, checkbox/radio, input icons,
     input size modifiers, file upload, horizontal alignment, and is-loading
     states. All additive; .sf-form-group and .sf-input-group unchanged. */

  /* ----- Input size modifiers (.sf-input--s / --l) ----- */
  /* Applied to the same elements as .sf-form-group__input. Parallels .sf-btn--s/l. */

  .sf-form-group__input.sf-input--s,
  .sf-form-group__input--s {
    --sf-input-padding-y: var(--sf-space-2xs);
    --sf-input-padding-x: var(--sf-space-xs);
    font-size: var(--sf-text-s);
  }
  .sf-form-group__input.sf-input--l,
  .sf-form-group__input--l {
    --sf-input-padding-y: var(--sf-space-s);
    --sf-input-padding-x: var(--sf-space-m);
    font-size: var(--sf-text-l);
  }

  /* ----- Input with icon (.sf-input-wrap + --has-icon-left/right) ----- */
  /* Wrap <input> in a <div class="sf-input-wrap sf-input-wrap--has-icon-left">
     alongside an <svg class="sf-input-wrap__icon">. Automatic padding keeps
     text from overrunning the icon. */

  .sf-input-wrap {
    position: relative;
    display: grid;
  }
  .sf-input-wrap__icon {
    position: absolute;
    inset-block-start: 50%;
    translate: 0 -50%;
    inline-size: 1em;
    block-size: 1em;
    pointer-events: none;
    color: var(--sf-color-text-muted);
    flex-shrink: 0;
  }
  .sf-input-wrap--has-icon-left > .sf-input-wrap__icon  { inset-inline-start: var(--sf-space-s); }
  .sf-input-wrap--has-icon-right > .sf-input-wrap__icon { inset-inline-end:   var(--sf-space-s); }
  .sf-input-wrap--has-icon-left  > input,
  .sf-input-wrap--has-icon-left  > select { padding-inline-start: calc(var(--sf-space-s) * 2 + 1em); }
  .sf-input-wrap--has-icon-right > input,
  .sf-input-wrap--has-icon-right > select { padding-inline-end:   calc(var(--sf-space-s) * 2 + 1em); }

  /* ----- Full .sf-select (size + state parity with .sf-form-group__input) ----- */
  /* Layered on top of .sf-select-wrap — add .sf-select-wrap--s / --l for sizes. */

  .sf-select-wrap--s > select { --sf-input-padding-y: var(--sf-space-2xs); --sf-input-padding-x: var(--sf-space-xs); font-size: var(--sf-text-s); }
  .sf-select-wrap--l > select { --sf-input-padding-y: var(--sf-space-s);   --sf-input-padding-x: var(--sf-space-m);  font-size: var(--sf-text-l); }

  /* ----- Checkbox / radio (styled classes on the native input) ----- */
  /* Apply .sf-checkbox to <input type="checkbox"> or .sf-radio to <input type="radio">.
     Replaces the native UA style with a token-driven square/circle that flips
     cleanly in dark mode. Uses accent-color as a baseline for older browsers. */

  .sf-checkbox,
  .sf-radio {
    --sf-control-size: 1.15em;
    appearance: none;
    inline-size: var(--sf-control-size);
    block-size: var(--sf-control-size);
    margin: 0;
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    background: var(--sf-color-surface);
    display: inline-grid;
    place-content: center;
    cursor: pointer;
    vertical-align: -0.15em;
    transition: background var(--sf-duration-fast) var(--sf-ease-out),
                border-color var(--sf-duration-fast) var(--sf-ease-out);
    flex-shrink: 0;
  }
  .sf-checkbox { border-radius: var(--sf-radius-s); }
  .sf-radio    { border-radius: 50%; }
  @media (hover: hover) {
    .sf-checkbox:hover,
    .sf-radio:hover { border-color: var(--sf-primary); }
  }
  .sf-checkbox:focus-visible,
  .sf-radio:focus-visible {
    outline: 2px solid var(--sf-primary);
    outline-offset: var(--sf-focus-ring-offset);
  }
  .sf-checkbox:checked,
  .sf-radio:checked {
    background: var(--sf-primary);
    border-color: var(--sf-primary);
  }
  /* Checkbox tick */
  .sf-checkbox:checked::before {
    content: "";
    inline-size: 0.65em;
    block-size: 0.35em;
    border-inline-start: 2px solid var(--sf-color-text-on-primary);
    border-block-end:   2px solid var(--sf-color-text-on-primary);
    rotate: -45deg;
    translate: 0 -0.05em;
  }
  /* Radio dot */
  .sf-radio:checked::before {
    content: "";
    inline-size: 0.45em;
    block-size: 0.45em;
    border-radius: 50%;
    background: var(--sf-color-text-on-primary);
  }
  .sf-checkbox:disabled,
  .sf-radio:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  /* ----- Input addons (button chains on .sf-input-group) ----- */
  /* Existing .sf-input-group handles input + button. Extend with middle and
     chained-button cases: siblings strip rounding on the joining edges so any
     permutation (input|btn|btn, btn|input|btn) visually joins. */

  .sf-input-group > * { min-width: 0; }
  .sf-input-group > * + * {
    border-start-start-radius: 0;
    border-end-start-radius: 0;
    margin-inline-start: calc(var(--sf-border-width-1) * -1);
  }
  .sf-input-group > *:not(:last-child) {
    border-start-end-radius: 0;
    border-end-end-radius: 0;
  }
  .sf-input-group > *:focus-visible {
    position: relative;
    z-index: var(--sf-z-raised);
  }

  /* ----- Custom file upload (.sf-file) ----- */
  /* Hides the native <input type="file"> and styles the surrounding label
     as a branded button + filename slot. Uses :has() for the filled state.

     Markup:
       <label class="sf-file">
         <input type="file">
         <span class="sf-file__cta">Choose file</span>
         <span class="sf-file__name">No file selected</span>
       </label> */

  .sf-file {
    display: inline-flex;
    align-items: stretch;
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-m);
    overflow: hidden;
    cursor: pointer;
    background: var(--sf-color-surface);
  }
  .sf-file > input[type="file"] {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    pointer-events: none;
  }
  .sf-file__cta {
    display: inline-flex;
    align-items: center;
    gap: var(--sf-space-xs);
    padding: var(--sf-space-xs) var(--sf-space-m);
    background: var(--sf-primary);
    color: var(--sf-color-text-on-primary);
    font-weight: 500;
    transition: background var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-file:hover .sf-file__cta { background: var(--sf-primary-hover); }
  }
  .sf-file:focus-within { outline: 2px solid var(--sf-primary); outline-offset: var(--sf-focus-ring-offset); }
  .sf-file__name {
    display: inline-flex;
    align-items: center;
    padding: var(--sf-space-xs) var(--sf-space-m);
    color: var(--sf-color-text-muted);
    font-size: var(--sf-text-s);
    max-inline-size: 16rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* --sf-boxed: drag-and-drop dropzone variant */
  .sf-file--boxed {
    flex-direction: column;
    align-items: stretch;
    padding: var(--sf-space-xl);
    border-style: dashed;
    border-width: 2px;
    text-align: center;
    gap: var(--sf-space-s);
  }
  .sf-file--boxed .sf-file__cta { border-radius: var(--sf-radius-s); }

  /* ----- Horizontal form group (.sf-form-group--horizontal) ----- */
  /* Label on the inline-start, input on the inline-end, stacked on small screens.
     Uses existing .sf-form-group surface untouched — modifier only affects layout. */

  .sf-form-group--horizontal {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--sf-space-xs) var(--sf-space-m);
    align-items: center;
  }
  @media (min-width: 40em) {
    .sf-form-group--horizontal {
      grid-template-columns: var(--sf-form-label-width, 12rem) 1fr;
    }
    .sf-form-group--horizontal > .sf-form-group__label {
      text-align: end;
      padding-block-start: var(--sf-space-2xs);
    }
    .sf-form-group--horizontal > .sf-form-group__hint,
    .sf-form-group--horizontal > .sf-form-group__error {
      grid-column: 2;
    }
  }

  /* ----- is-loading states (spinner inside btn/input) ----- */
  /* Adds .sf-btn--loading or .sf-input-wrap--loading. Replaces content with a
     trailing spinner. Preserves intrinsic width via visible text + color:
     transparent so the button does not resize when toggled. For inputs,
     the loading class must be on the wrapper (.sf-input-wrap) since native
     input elements are replaced elements and don't support ::after. */

  @keyframes sf-loading-spin { to { rotate: 360deg; } }

  .sf-btn--loading {
    position: relative;
    pointer-events: none;
  }
  .sf-btn--loading::after {
    content: "";
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    inline-size: 1em;
    block-size: 1em;
    margin: -0.5em 0 0 -0.5em;
    border: 2px solid currentcolor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: sf-loading-spin var(--sf-duration-slow) linear infinite;
    color: var(--sf-color-text);
    opacity: 0.6;
  }
  .sf-btn--primary.sf-btn--loading::after {
    color: var(--sf-color-text-on-action);
    opacity: 1;
  }
  .sf-btn--destructive.sf-btn--loading::after {
    color: var(--sf-color-text-on-destructive);
    opacity: 1;
  }
  .sf-input-wrap--loading {
    position: relative;
    pointer-events: none;
  }
  .sf-input-wrap--loading > input {
    caret-color: transparent;
  }
  .sf-input-wrap--loading::after {
    content: "";
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    inline-size: 1em;
    block-size: 1em;
    margin: -0.5em 0 0 -0.5em;
    border: 2px solid currentcolor;
    border-top-color: transparent;
    border-radius: 50%;
    animation: sf-loading-spin var(--sf-duration-slow) linear infinite;
    color: var(--sf-color-text);
    opacity: 0.6;
    pointer-events: none;
  }
  @media (prefers-reduced-motion: reduce) {
    .sf-btn--loading::after,
    .sf-input-wrap--loading::after {
      animation-duration: 3s;
    }
  }

  /* ----- [aria-busy] semantic spinner -----
     Attaches a trailing spinner to any element with aria-busy="true" — including
     buttons, forms, and custom interactive elements — without a JS class toggle.
     Pure-CSS, WCAG-semantically linked. No reduced-motion guard needed: the
     spinner is hidden entirely when reduced-motion is preferred (animation: none). */

  @media (prefers-reduced-motion: no-preference) {
    :is(.sf-btn--primary, .sf-btn--destructive, .sf-btn--outline, .sf-btn--ghost)[aria-busy="true"] {
      position: relative;
      pointer-events: none;
    }
    :is(.sf-btn--primary, .sf-btn--destructive, .sf-btn--outline, .sf-btn--ghost)[aria-busy="true"]::after {
      content: "";
      position: absolute;
      inset-block-start: 50%;
      inset-inline-start: 50%;
      inline-size: 1em;
      block-size: 1em;
      margin: -0.5em 0 0 -0.5em;
      border: 2px solid currentcolor;
      border-top-color: transparent;
      border-radius: 50%;
      animation: sf-loading-spin var(--sf-duration-slow) linear infinite;
      color: var(--sf-color-text);
      opacity: 0.6;
    }
    .sf-btn--primary[aria-busy="true"]::after {
      color: var(--sf-color-text-on-action);
      opacity: 1;
    }
    .sf-btn--destructive[aria-busy="true"]::after {
      color: var(--sf-color-text-on-destructive);
      opacity: 1;
    }
  }

  /* ==========================================================================
     0.3.5.0 ADDITIONS — layout + structural components
     ==========================================================================
     Navbar with hamburger, Level toolbar, segmented Card, segmented Modal,
     advanced Table modifiers, sidebar Menu. All additive. */

  /* ----- Navbar (full-width primary navigation bar with hamburger) ----- */
  /* Horizontal nav with brand + collapsible menu + end slot. CSS-only burger
     toggle via <input type="checkbox"> + :has(). At ≥48em the menu stays
     inline; below that, the burger reveals/hides the menu.

     Markup:
       <nav class="sf-navbar">
         <a class="sf-navbar__brand" href="/">Brand</a>
         <input class="sf-navbar__toggle" type="checkbox" id="nav-t" aria-label="Toggle menu">
         <label class="sf-navbar__burger" for="nav-t"><span></span><span></span><span></span></label>
         <ul class="sf-navbar__menu">
           <li><a class="sf-navbar__item" href="#">Features</a></li>
           <li><a class="sf-navbar__item" href="#">Pricing</a></li>
         </ul>
         <div class="sf-navbar__end">
           <a class="sf-btn--primary" href="#">Sign up</a>
         </div>
       </nav> */

  .sf-navbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sf-space-m);
    padding: var(--sf-navbar-padding, var(--sf-space-s) var(--sf-space-l));
    background: var(--sf-navbar-bg, var(--sf-color-surface));
    border-block-end: var(--sf-border-width-1) solid var(--sf-color-border);
    min-block-size: var(--sf-navbar-height, 3.5rem);
  }
  .sf-navbar__brand {
    font-weight: 700;
    font-size: var(--sf-text-l);
    color: var(--sf-color-text);
    text-decoration: none;
    margin-inline-end: auto;
  }
  .sf-navbar__toggle {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    pointer-events: none;
  }
  .sf-navbar__burger {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--sf-space-2xs);
    inline-size: 2.5rem;
    block-size: 2.5rem;
    cursor: pointer;
    padding: 0.5rem;
    border-radius: var(--sf-radius-s);
  }
  .sf-navbar__burger > span {
    display: block;
    inline-size: 100%;
    block-size: 2px;
    background: currentcolor;
    border-radius: 1px;
    transition: transform var(--sf-duration-fast) var(--sf-ease-out),
                opacity var(--sf-duration-fast) var(--sf-ease-out);
    transform-origin: center;
  }
  .sf-navbar__toggle:focus-visible + .sf-navbar__burger {
    outline: 2px solid var(--sf-primary);
    outline-offset: var(--sf-focus-ring-offset);
  }
  /* Animated X when checked */
  .sf-navbar:has(.sf-navbar__toggle:checked) .sf-navbar__burger > span:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
  }
  .sf-navbar:has(.sf-navbar__toggle:checked) .sf-navbar__burger > span:nth-child(2) {
    opacity: 0;
  }
  .sf-navbar:has(.sf-navbar__toggle:checked) .sf-navbar__burger > span:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
  }
  .sf-navbar__menu {
    display: flex;
    align-items: center;
    gap: var(--sf-space-l);
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .sf-navbar__item {
    color: var(--sf-color-text-muted);
    text-decoration: none;
    font-weight: 500;
    transition: color var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-navbar__item:hover { color: var(--sf-color-text); }
  }
  .sf-navbar__item[aria-current="page"] {
    color: var(--sf-color-text);
  }
  .sf-navbar__end {
    display: inline-flex;
    align-items: center;
    gap: var(--sf-space-s);
    margin-inline-start: auto;
  }
  @media (max-width: 47.99em) {
    .sf-navbar__menu,
    .sf-navbar__end {
      flex-basis: 100%;
      flex-direction: column;
      align-items: stretch;
      gap: var(--sf-space-s);
      display: none;
    }
    .sf-navbar:has(.sf-navbar__toggle:checked) .sf-navbar__menu,
    .sf-navbar:has(.sf-navbar__toggle:checked) .sf-navbar__end { display: flex; }
  }
  @media (min-width: 48em) {
    .sf-navbar__burger { display: none; }
  }
  .sf-navbar--fixed-top,
  .sf-navbar--fixed-bottom {
    position: fixed;
    inset-inline: 0;
    z-index: var(--sf-z-sticky);
  }
  .sf-navbar--fixed-top    { inset-block-start: 0; }
  .sf-navbar--fixed-bottom {
    inset-block-end: 0;
    border-block-start: var(--sf-border-width-1) solid var(--sf-color-border);
    border-block-end: 0;
    padding-block-end: env(safe-area-inset-bottom, 0);
  }

  /* ----- Header (page-top masthead block; sticky is opt-in) ----- */
  /* Distinct from .sf-navbar (which is the nav bar inside the header).
     .sf-header provides the masthead surface + bottom border + blur (when
     sticky). Content composition (logo, nav, CTAs) is user-authored — or use
     .sf-navbar inside .sf-header for the common combination.

     Sticky is deliberately opt-in: headers in multi-demo pages should not
     all try to stick at top: 0. Apply --sticky only when you actually want
     the masthead to pin on scroll.

     Markup:
       <header class="sf-header sf-header--sticky">
         <nav class="sf-navbar">...</nav>
       </header> */

  .sf-header {
    background: var(--sf-header-bg, var(--sf-color-surface));
    border-block-end: var(--sf-header-border-width, var(--sf-border-width-1)) solid var(--sf-header-border-color, var(--sf-color-border));
    color: var(--sf-header-color, var(--sf-color-text));
  }
  .sf-header__bar {
    padding-block: var(--sf-header-bar-padding-block, var(--sf-space-s));
    padding-inline: var(--sf-header-bar-padding-inline, var(--sf-space-l));
  }
  /* --sticky pins the header on scroll. Intentionally does NOT apply
     backdrop-filter by default — backdrop-filter creates a stacking context
     that traps child dropdowns inside the header (they can't overlay sibling
     sticky sections even with --z-dropdown above --z-sticky). For the
     glassmorphism effect pair with .sf-header--glass when you know your header
     doesn't contain dropdowns, or portal your dropdown markup outside the
     header element. */
  .sf-header--sticky {
    position: sticky;
    inset-block-start: var(--sf-header-top, 0);
    z-index: var(--sf-z-sticky);
    background: var(--sf-header-bg-sticky, var(--sf-color-surface));
  }
  /* scroll-state(stuck) — native CSS shadow on scroll without JS. Chrome 133+.
     @supports guard keeps this inert on other browsers until it's cross-browser.
     ::after carries the shadow because @container rules only match descendants,
     never the container element itself. */
  @supports (container-type: scroll-state) {
    .sf-header--sticky { container-type: scroll-state; }
    .sf-header--sticky::after {
      content: '';
      position: absolute;
      inset: 0;
      pointer-events: none;
      transition: box-shadow var(--sf-duration-fast) var(--sf-ease-out);
    }
    @container scroll-state(stuck: top) {
      .sf-header--sticky::after { box-shadow: var(--sf-shadow-s); }
    }
  }
  /* --sf-glass: frosted surface for sticky headers. Creates a stacking context;
     do not use if the header contains dropdown menus that need to overlay
     following sticky siblings. */
  .sf-header--glass {
    background: var(--sf-header-bg-sticky, color-mix(in srgb, var(--sf-color-surface) 88%, transparent));
    backdrop-filter: var(--sf-header-blur, blur(12px));
    -webkit-backdrop-filter: var(--sf-header-blur, blur(12px));
  }
  /* Auto-escape (two parts) for when a child dropdown is open:
     1. Raise the sticky header to --z-dropdown so its menu still outpaints
        following sticky sections.
     2. On --glass, drop backdrop-filter for the duration the dropdown is
        open. Raising z-index alone isn't enough on glass headers because
        backdrop-filter creates a stacking context that traps descendant
        z-index — the menu would still paint inside the filtered layer.
     Covers .sf-nav-dropdown and .sf-dropdown; custom dropdowns can opt
     in via [data-state="open"]. */
  .sf-header--sticky:has(.sf-nav-dropdown[open], .sf-dropdown[open], [data-state="open"]) {
    z-index: var(--sf-z-dropdown);
  }
  .sf-header--glass:has(.sf-nav-dropdown[open], .sf-dropdown[open], [data-state="open"]) {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  /* --sf-transparent: sits on top of a hero without surface / border.
     Pair with data-theme="dark" on the header when the hero is dark imagery. */
  .sf-header--transparent {
    background: transparent;
    border-block-end: 0;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  /* --sf-bordered: explicit bottom hairline even without sticky surface.
     Uses the same header-border-* tokens as the base so instance theming
     via --header-border-width / --header-border-color is respected. */
  .sf-header--bordered {
    border-block-end: var(--sf-header-border-width, var(--sf-border-width-1))
                      solid var(--sf-header-border-color, var(--sf-color-border));
  }

  /* ----- Level (toolbar layout — left edge / right edge with center alignment) ----- */

  .sf-level {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sf-space-m);
  }
  .sf-level__left,
  .sf-level__right {
    display: inline-flex;
    align-items: center;
    gap: var(--sf-space-s);
  }
  .sf-level__item { display: inline-flex; align-items: center; }
  .sf-level--mobile-stack {
    flex-direction: column;
    align-items: stretch;
  }
  @media (min-width: 40em) {
    .sf-level--mobile-stack { flex-direction: row; align-items: center; }
  }

  /* ----- Segmented Card (partitioned: header / image / content / footer) ----- */
  /* Extends .sf-card with hard partitioning. The segmented structure overrides
     the default padding: the card itself becomes an unpadded shell, children
     provide their own padding. Detection: a .sf-card that contains any
     segmented sub-element strips its own padding via :has(). */

  .sf-card:has(> .sf-card__header, > .sf-card__image, > .sf-card__content, > .sf-card__footer) {
    padding: 0;
    gap: 0;
  }
  .sf-card__header {
    display: flex;
    align-items: center;
    gap: var(--sf-space-s);
    padding: var(--sf-space-m) var(--sf-space-l);
    border-block-end: var(--sf-border-width-1) solid var(--sf-color-border);
    font-weight: 600;
  }
  .sf-card__image {
    display: block;
    inline-size: 100%;
    block-size: auto;
  }
  .sf-card__content {
    padding: var(--sf-card-padding, var(--sf-space-l));
    display: flex;
    flex-direction: column;
    gap: var(--sf-space-m);
  }
  .sf-card__footer {
    display: flex;
    border-block-start: var(--sf-border-width-1) solid var(--sf-color-border);
  }
  .sf-card__footer-item {
    flex: 1;
    padding: var(--sf-space-s) var(--sf-space-m);
    text-align: center;
    color: var(--sf-color-text-muted);
    text-decoration: none;
    transition: background var(--sf-duration-fast) var(--sf-ease-out),
                color var(--sf-duration-fast) var(--sf-ease-out);
  }
  .sf-card__footer-item + .sf-card__footer-item {
    border-inline-start: var(--sf-border-width-1) solid var(--sf-color-border);
  }
  @media (hover: hover) {
    .sf-card__footer-item:hover {
      background: var(--sf-color-surface-2);
      color: var(--sf-color-text);
    }
  }

  /* ----- Segmented Modal (.sf-modal--card with __head / __body / __foot) ----- */
  /* Head pinned to top, body scrolls, foot pinned to bottom. Use on a
     <dialog class="sf-modal sf-modal--card"> element — inherits the base
     transition/backdrop styling from .sf-modal. */

  .sf-modal--card {
    padding: 0;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    max-block-size: min(90vh, 50rem);
  }
  .sf-modal__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sf-space-s);
    padding: var(--sf-space-m) var(--sf-space-l);
    border-block-end: var(--sf-border-width-1) solid var(--sf-color-border);
    font-weight: 600;
    flex-shrink: 0;
  }
  .sf-modal__body {
    padding: var(--sf-space-l);
    overflow-y: auto;
    overscroll-behavior: contain;
    flex: 1;
  }
  .sf-modal__foot {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--sf-space-s);
    padding: var(--sf-space-m) var(--sf-space-l);
    border-block-start: var(--sf-border-width-1) solid var(--sf-color-border);
    background: var(--sf-color-surface-2);
    flex-shrink: 0;
  }

  /* ----- Table modifiers (advanced: --narrow + cell-level status colors) ----- */
  /* Extends the existing .sf-table pattern. Cell/row classes are scoped under
     .sf-table to avoid leaking into other contexts. */

  .sf-table--narrow th,
  .sf-table--narrow td {
    padding: var(--sf-space-2xs) var(--sf-space-s);
  }
  .sf-table tr.is-success,
  .sf-table td.is-success {
    background: color-mix(in srgb, var(--sf-success) 12%, transparent);
  }
  .sf-table tr.is-warning,
  .sf-table td.is-warning {
    background: color-mix(in srgb, var(--sf-warning) 12%, transparent);
  }
  .sf-table tr.is-error,
  .sf-table td.is-error {
    background: color-mix(in srgb, var(--sf-error) 12%, transparent);
  }
  .sf-table tr.is-primary,
  .sf-table td.is-primary {
    background: color-mix(in srgb, var(--sf-primary) 12%, transparent);
  }

  /* ----- Sidebar Menu (.sf-menu — tree-style for admin panels) ----- */

  .sf-menu {
    --sf-menu-indent: var(--sf-space-m);
    display: flex;
    flex-direction: column;
    gap: var(--sf-space-s);
    font-size: var(--sf-text-s);
    overscroll-behavior: contain;
  }
  .sf-menu__label {
    font-size: var(--sf-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--sf-color-text-muted);
    padding: 0 var(--sf-space-s);
  }
  .sf-menu__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
  }
  .sf-menu__list .sf-menu__list {
    padding-inline-start: var(--sf-menu-indent);
  }
  .sf-menu__link {
    display: flex;
    align-items: center;
    gap: var(--sf-space-s);
    padding: var(--sf-space-xs) var(--sf-space-s);
    border-radius: var(--sf-radius-s);
    color: var(--sf-color-text);
    text-decoration: none;
    transition: background var(--sf-duration-fast) var(--sf-ease-out),
                color var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-menu__link:hover {
      background: var(--sf-color-surface-2);
    }
  }
  .sf-menu__link--active,
  .sf-menu__link[aria-current="page"] {
    background: var(--sf-primary);
    color: var(--sf-color-text-on-primary);
  }

  /* ==========================================================================
     0.3.6.0 ADDITIONS — micro-components + toast system
     ==========================================================================
     Toast notifications, universal close button, joined tags, progress
     variants, breadcrumb separators, icon-text wrapper. All additive. */

  /* ----- Toast stack + toast (notification system) ----- */
  /* Container is position: fixed in a corner via --toast-inset-*. Toasts
     slide in with opacity + translate. Use JS to append <aside class="sf-toast">
     into <div class="sf-toast-stack"> (helper provided in js/slashed-ui.js). */

  @keyframes sf-toast-in {
    from { opacity: 0; translate: 0 -0.5rem; }
    to   { opacity: 1; translate: 0 0; }
  }

  .sf-toast-stack {
    position: fixed;
    z-index: var(--sf-z-toast);
    inset-block-start: var(--sf-toast-inset-top, var(--sf-space-l));
    inset-inline-end:  var(--sf-toast-inset-end, var(--sf-space-l));
    display: flex;
    flex-direction: column;
    gap: var(--sf-space-s);
    pointer-events: none;
    max-inline-size: min(24rem, calc(100vw - var(--sf-space-l) * 2));
  }
  .sf-toast-stack--top-start    { inset-inline-end: auto; inset-inline-start: var(--sf-toast-inset-start, var(--sf-space-l)); }
  .sf-toast-stack--bottom-end   { inset-block-start: auto; inset-block-end: var(--sf-toast-inset-bottom, var(--sf-space-l)); flex-direction: column-reverse; }
  .sf-toast-stack--bottom-start {
    inset-block-start: auto;
    inset-block-end: var(--sf-toast-inset-bottom, var(--sf-space-l));
    inset-inline-end: auto;
    inset-inline-start: var(--sf-toast-inset-start, var(--sf-space-l));
    flex-direction: column-reverse;
  }

  .sf-toast {
    --sf-toast-color: var(--sf-primary);
    --sf-toast-bg: var(--sf-color-surface);
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: var(--sf-space-s);
    padding: var(--sf-space-s) var(--sf-space-m);
    background: var(--sf-toast-bg);
    color: var(--sf-color-text);
    border: var(--sf-border-width-1) solid var(--sf-toast-color);
    border-inline-start: 3px solid var(--sf-toast-color);
    border-radius: var(--sf-radius-m);
    box-shadow: var(--sf-shadow-m);
    pointer-events: auto;
    animation: sf-toast-in var(--sf-duration-normal) var(--sf-ease-out);
  }
  .sf-toast__icon {
    color: var(--sf-toast-color);
    inline-size: 1.25em;
    block-size: 1.25em;
    flex-shrink: 0;
  }
  .sf-toast__body {
    font-size: var(--sf-text-s);
    min-inline-size: 0;
  }
  .sf-toast__title {
    font-weight: 600;
    color: var(--sf-color-text);
  }
  .sf-toast__close {
    inline-size: 1.25rem;
    block-size: 1.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 0;
    border-radius: var(--sf-radius-s);
    background: transparent;
    color: inherit;
    cursor: pointer;
    opacity: 0.6;
    transition: opacity var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-toast__close:hover { opacity: 1; }
  }
  .sf-toast--success { --sf-toast-color: var(--sf-success); }
  .sf-toast--warning { --sf-toast-color: var(--sf-warning); }
  .sf-toast--error   { --sf-toast-color: var(--sf-error);   }
  .sf-toast--info    { --sf-toast-color: var(--sf-info);    }
  /* Exit state — JS adds this class on dismiss() instead of writing inline styles.
     Override transition-duration via unlayered .sf-toast--dismissing { … } from
     the consumer side to retune timing without !important. */
  .sf-toast--dismissing {
    opacity: 0;
    translate: 0 -0.5rem;
    transition: opacity var(--sf-transition-exit), translate var(--sf-transition-exit);
  }
  @media (prefers-reduced-motion: reduce) {
    .sf-toast { animation: none; }
    .sf-toast--dismissing { transition: none; }
  }

  /* ----- Delete (universal round close button) ----- */
  /* Standalone circular × button for notifications, modals, tags, chips.
     Distinct from .sf-notice__close / .sf-message__close / .sf-toast__close
     which are positioned within their parents — .sf-delete is freestanding.

     HTML: <button class="sf-delete" aria-label="Dismiss"></button>
     The × glyph is drawn with two rotated pseudo-elements (no font dependency). */

  .sf-delete {
    --sf-delete-size: 1.25rem;
    inline-size: var(--sf-delete-size);
    block-size: var(--sf-delete-size);
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: color-mix(in srgb, currentcolor 20%, transparent);
    color: inherit;
    cursor: pointer;
    display: inline-grid;
    place-content: center;
    position: relative;
    flex-shrink: 0;
    transition: background var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-delete:hover { background: color-mix(in srgb, currentcolor 35%, transparent); }
  }
  .sf-delete:focus-visible { outline: 2px solid currentcolor; outline-offset: var(--sf-focus-ring-offset); }
  .sf-delete::before,
  .sf-delete::after {
    content: "";
    position: absolute;
    inline-size: 50%;
    block-size: 2px;
    background: currentcolor;
    border-radius: 1px;
  }
  .sf-delete::before { rotate: 45deg; }
  .sf-delete::after  { rotate: -45deg; }
  .sf-delete--s { --sf-delete-size: 1rem; }
  .sf-delete--l { --sf-delete-size: 1.75rem; }

  /* ----- Tags (joined badge pairs via .sf-tags + .sf-tags--addons) ----- */
  /* Existing .sf-badge is a standalone pill. .sf-tags is a wrapper that
     groups adjacent badges; --addons joins them seamlessly (GitHub/NPM
     build:passing style). */

  .sf-tags {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--sf-space-2xs);
    align-items: center;
  }
  .sf-tags--addons { gap: 0; }
  .sf-tags--addons > .sf-badge {
    border-radius: 0;
  }
  .sf-tags--addons > .sf-badge:first-child {
    border-start-start-radius: var(--sf-radius-s);
    border-end-start-radius: var(--sf-radius-s);
  }
  .sf-tags--addons > .sf-badge:last-child {
    border-start-end-radius: var(--sf-radius-s);
    border-end-end-radius: var(--sf-radius-s);
  }

  /* ----- Progress color modifiers + indeterminate animation ----- */

  .sf-progress--success { --sf-progress-color: var(--sf-success); }
  .sf-progress--warning { --sf-progress-color: var(--sf-warning); }
  .sf-progress--error   { --sf-progress-color: var(--sf-error);   }

  @keyframes sf-progress-indeterminate {
    0%   { transform: translateX(-100%); }
    100% { transform: translateX(400%); }
  }
  /* Native <progress> without a value attribute is :indeterminate by default.
     WebKit lets us animate ::-webkit-progress-value; Firefox needs the
     fallback div pattern. */
  .sf-progress:indeterminate::-webkit-progress-value {
    inline-size: 25%;
    animation: sf-progress-indeterminate 1.5s ease-in-out infinite;
  }
  .sf-progress--indeterminate > .sf-progress__fill {
    inline-size: 25%;
    animation: sf-progress-indeterminate 1.5s ease-in-out infinite;
  }
  @media (prefers-reduced-motion: reduce) {
    .sf-progress:indeterminate::-webkit-progress-value,
    .sf-progress--indeterminate > .sf-progress__fill {
      animation-duration: 4s;
    }
  }

  /* ----- Breadcrumb separator modifiers ----- */
  /* Extends existing .sf-breadcrumb with auto-generated separators between
     items. When any --arrow/--dot/--slash/--chevron modifier is active, any
     explicit .sf-breadcrumb__sep element is hidden (CSS provides the separator
     so you can omit the markup, but existing markup keeps working). */

  .sf-breadcrumb--arrow   { --sf-breadcrumb-sep: "\2192"; } /* → */
  .sf-breadcrumb--dot     { --sf-breadcrumb-sep: "\2022"; } /* • */
  .sf-breadcrumb--slash   { --sf-breadcrumb-sep: "/"; }
  .sf-breadcrumb--chevron { --sf-breadcrumb-sep: "\203A"; } /* › */

  .sf-breadcrumb--arrow,
  .sf-breadcrumb--dot,
  .sf-breadcrumb--slash,
  .sf-breadcrumb--chevron {
    --sf-breadcrumb-gap: var(--sf-space-s);
  }
  .sf-breadcrumb--arrow   .sf-breadcrumb__sep,
  .sf-breadcrumb--dot     .sf-breadcrumb__sep,
  .sf-breadcrumb--slash   .sf-breadcrumb__sep,
  .sf-breadcrumb--chevron .sf-breadcrumb__sep { display: none; }

  .sf-breadcrumb--arrow   .sf-breadcrumb__item + .sf-breadcrumb__item::before,
  .sf-breadcrumb--dot     .sf-breadcrumb__item + .sf-breadcrumb__item::before,
  .sf-breadcrumb--slash   .sf-breadcrumb__item + .sf-breadcrumb__item::before,
  .sf-breadcrumb--chevron .sf-breadcrumb__item + .sf-breadcrumb__item::before {
    content: var(--sf-breadcrumb-sep);
    opacity: 0.5;
    margin-inline-end: var(--sf-space-s);
    user-select: none;
  }

  /* ----- Icon-text (guaranteed-vertical-center icon + text wrapper) ----- */
  /* Solves the common "SVG and text on one baseline" problem without having
     to fiddle with line-height or vertical-align per-use. The text side is
     flex: 1 so it can wrap to multiple lines while the icon stays top-aligned
     with the first line of text via inline-flex + align-items: baseline
     (with first-baseline fallback). */

  .sf-icon-text {
    display: inline-flex;
    align-items: center;
    gap: var(--sf-space-xs);
    min-inline-size: 0;
  }
  .sf-icon-text--top    { align-items: flex-start; }
  .sf-icon-text--bottom { align-items: flex-end; }
  .sf-icon-text > svg,
  .sf-icon-text > .sf-icon-text__icon {
    flex-shrink: 0;
    inline-size: 1em;
    block-size: 1em;
  }
  .sf-icon-text > span,
  .sf-icon-text > .sf-icon-text__text {
    min-inline-size: 0;
  }

  /* ==========================================================================
     0.6.0.0 ADDITIONS — new components
     ========================================================================== */

  /* ----- Floating label ----- */
  /* Animated placeholder-as-label. Label floats above the input on focus or fill.
     Requires placeholder=" " (one space) on the <input> for :placeholder-shown to work.

     Markup:
       <div class="sf-floating-label">
         <input type="text" id="f" placeholder=" ">
         <label for="f">Email address</label>
       </div> */

  .sf-floating-label { position: relative; }
  .sf-floating-label label {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: var(--sf-space-s);
    translate: 0 -50%;
    transform-origin: left top; /* logical 'inline-start' not valid for transform-origin */
    transition: transform var(--sf-duration-fast) var(--sf-ease-out),
                color     var(--sf-duration-fast) var(--sf-ease-out);
    pointer-events: none;
    color: var(--sf-color-text-decorative);
    font-size: var(--sf-text-m);
  }
  [dir="rtl"] .sf-floating-label label {
    transform-origin: right top;
  }
  .sf-floating-label input:placeholder-shown + label {
    transform: translateY(0) scale(1);
  }
  .sf-floating-label input:focus + label,
  .sf-floating-label input:not(:placeholder-shown) + label {
    transform: translateY(-1.5rem) scale(0.82);
    color: var(--sf-action);
    font-size: var(--sf-text-s);
  }
  @media (prefers-reduced-motion: reduce) {
    .sf-floating-label label { transition: none; }
  }

  /* ----- Carousel ----- */
  /* Horizontal scroll snap. Set --slide-width per-slide via inline style.
     scroll-behavior: smooth gated behind prefers-reduced-motion for vestibular safety.

     Markup:
       <div class="sf-carousel">
         <div class="sf-carousel__item" style="--slide-width: 80%">...</div>
       </div> */

  .sf-carousel {
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: auto;
    gap: var(--sf-carousel-gap, var(--sf-space-m));
    overscroll-behavior-x: contain;
    scrollbar-width: none;
  }
  .sf-carousel::-webkit-scrollbar { display: none; }
  @media (prefers-reduced-motion: no-preference) {
    .sf-carousel { scroll-behavior: smooth; }
  }
  .sf-carousel__item {
    flex: 0 0 var(--sf-slide-width, 100%);
    scroll-snap-align: start;
    min-inline-size: 0;
  }

  /* ----- Avatar group ----- */
  /* Stacked overlapping avatar row. Set --avatar-overlap to adjust overlap.

     Markup:
       <div class="sf-avatar-group">
         <img class="sf-avatar" src="..." alt="...">
         <img class="sf-avatar" src="..." alt="...">
       </div> */

  .sf-avatar-group {
    display: flex;
    align-items: center;
  }
  .sf-avatar-group > * + * {
    margin-inline-start: var(--sf-avatar-overlap, -0.75rem);
  }
  .sf-avatar-group > * {
    outline: 2px solid var(--sf-color-surface);
    flex-shrink: 0;
  }

  /* ----- Stat / KPI grid ----- */
  /* Markup:
       <dl class="sf-stats sf-stats--cols-4">
         <div class="sf-stat">
           <dt class="sf-stat__value">85<span class="sf-stat__suffix">+</span></dt>
           <dd class="sf-stat__label">Projects delivered</dd>
         </div>
         …
       </dl>
     --divided: vertical rule between adjacent items in the grid.
     --top-ruled: border-block-start accent above the grid. */

  .sf-stats {
    container-type: inline-size;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
    gap: var(--sf-stats-gap, var(--sf-space-l));
  }

  @container (min-width: 28rem) {
    .sf-stats--cols-2 { grid-template-columns: repeat(2, 1fr); }
  }
  @container (min-width: 36rem) {
    .sf-stats--cols-3 { grid-template-columns: repeat(3, 1fr); }
  }
  @container (min-width: 48rem) {
    .sf-stats--cols-4 { grid-template-columns: repeat(4, 1fr); }
  }

  .sf-stats--top-ruled {
    border-block-start: var(--sf-border-width-1) solid var(--sf-color-border);
    padding-block-start: var(--sf-space-l);
  }

  /* Collapse column-gap so the rule + padding becomes the sole separator —
     avoids gap+padding double-spacing. Block-gap is preserved so wrapped rows
     still stack with breathing room. The leading rule on a wrapped-row first
     item is acceptable (matches the visual cadence of the row above). */
  .sf-stats--divided { column-gap: 0; }
  .sf-stats--divided > .sf-stat + .sf-stat {
    border-inline-start: var(--sf-border-width-1) solid var(--sf-color-border);
    padding-inline-start: var(--sf-stats-gap, var(--sf-space-l));
  }

  .sf-stat {
    display: flex;
    flex-direction: column;
    gap: var(--sf-space-2xs);
  }

  .sf-stat__value {
    font-family: var(--sf-font-heading);
    font-size: var(--sf-stat-value-size, var(--sf-text-2xl));
    font-weight: 700;
    letter-spacing: var(--sf-tracking-tight);
    line-height: 1;
    color: var(--sf-stat-value-color, var(--sf-color-text));
  }

  .sf-stat__suffix,
  .sf-stat__prefix {
    color: var(--sf-stat-accent-color, var(--sf-primary));
  }

  .sf-stat__label {
    font-size: var(--sf-text-s);
    color: var(--sf-color-text-muted);
  }

  /* ----- Callout (pull-quote / footnote / aside with accent border) ----- */
  /* Distinct from .sf-banner (full-width ephemeral status alert) and .sf-card
     (generic surface). Use for pull-quotes, footnotes, info boxes, and asides.
     Markup:
       <aside class="sf-callout sf-callout--quote">
         <svg class="sf-callout__icon" …></svg>
         <p class="sf-callout__body">
           Text here…
           <cite class="sf-callout__cite">— Name, Role</cite>
         </p>
       </aside> */

  .sf-callout {
    --sf-callout-accent:  var(--sf-primary);
    --sf-callout-bg:      var(--sf-primary-100);
    --sf-callout-color:   var(--sf-color-text);
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--sf-callout-gap, var(--sf-space-m));
    padding: var(--sf-callout-pad, var(--sf-space-m));
    background: var(--sf-callout-bg);
    border-radius: var(--sf-callout-radius, var(--sf-radius-m));
    border-inline-start: var(--sf-border-width-4) solid var(--sf-callout-accent);
    color: var(--sf-callout-color);
  }

  .sf-callout:not(:has(.sf-callout__icon)) { grid-template-columns: 1fr; }

  .sf-callout__icon {
    inline-size: 1.25em;
    block-size: 1.25em;
    color: var(--sf-callout-accent);
    margin-block-start: 0.1em;
  }

  .sf-callout__body {
    margin: 0;
    line-height: var(--sf-leading-relaxed, 1.625);
  }

  .sf-callout__cite {
    display: block;
    margin-block-start: var(--sf-space-xs);
    font-size: var(--sf-text-s);
    font-style: normal;
    color: var(--sf-color-text-muted);
  }

  /* Variants */
  .sf-callout--info    { --sf-callout-accent: var(--sf-primary);       --sf-callout-bg: var(--sf-primary-100); }
  .sf-callout--success { --sf-callout-accent: var(--sf-success);       --sf-callout-bg: var(--sf-success-100); }
  .sf-callout--warning { --sf-callout-accent: var(--sf-warning-600);   --sf-callout-bg: var(--sf-warning-100); --sf-callout-color: var(--sf-color-text); }
  .sf-callout--error   { --sf-callout-accent: var(--sf-error);         --sf-callout-bg: var(--sf-error-100); }
  .sf-callout--note    { --sf-callout-accent: var(--sf-color-border-strong); --sf-callout-bg: var(--sf-color-surface-2); }
  .sf-callout--quote   {
    --sf-callout-accent: var(--sf-primary);
    --sf-callout-bg: var(--sf-primary-100);
    font-style: italic;
  }

  /* ----- Announcement bar (compact pill-shaped status ribbon) ----- */
  /* Distinct from .sf-banner (full-width severity alert).
     .sf-announcement is a quiet centred ribbon — "Currently booking Q2 2026",
     "Beta release", "New: dark mode". Works as <a> or <div>.
     Markup:
       <a class="sf-announcement" href="…">
         <span class="sf-announcement__dot sf-pulse" aria-hidden="true"></span>
         Currently booking for <strong>Q2 2026</strong>
         <svg class="sf-announcement__arrow" …></svg>
       </a> */

  .sf-announcement {
    --sf-announcement-bg:     var(--sf-color-surface-2);
    --sf-announcement-color:  var(--sf-color-text);
    --sf-announcement-border: var(--sf-color-border);
    display: inline-flex;
    align-items: center;
    gap: var(--sf-space-xs);
    padding-block: var(--sf-space-2xs);
    padding-inline: var(--sf-space-s);
    background: var(--sf-announcement-bg);
    color: var(--sf-announcement-color);
    border: var(--sf-border-width-1) solid var(--sf-announcement-border);
    border-radius: var(--sf-radius-full);
    font-size: var(--sf-text-s);
    font-weight: 500;
    text-decoration: none;
    transition: translate var(--sf-duration-fast) var(--sf-ease-out);
    cursor: default;
  }

  a.sf-announcement,
  .sf-announcement[href] {
    cursor: pointer;
  }

  @media (hover: hover) {
    a.sf-announcement:hover,
    .sf-announcement[href]:hover { translate: 0 -1px; }
  }

  .sf-announcement__dot {
    display: inline-block;
    inline-size: 0.5em;
    block-size: 0.5em;
    border-radius: 50%;
    background: currentColor;
    color: var(--sf-primary);
    flex-shrink: 0;
  }

  .sf-announcement__arrow {
    inline-size: 1em;
    block-size: 1em;
    flex-shrink: 0;
    opacity: 0.6;
  }

  .sf-announcement--solid {
    --sf-announcement-bg:     var(--sf-primary);
    --sf-announcement-color:  var(--sf-color-text-on-primary);
    --sf-announcement-border: transparent;
  }

  .sf-announcement--ghost {
    --sf-announcement-bg:     transparent;
    --sf-announcement-border: var(--sf-color-border-strong);
  }

  /* ----- Round icon button modifier ----- */
  /* Extends .sf-btn--icon. Use for social links, close buttons, theme toggles.
     <button class="sf-btn sf-btn--ghost sf-btn--icon sf-btn--icon-round" aria-label="…">
       <svg …></svg>
     </button> */

  .sf-btn--icon-round {
    border-radius: 50%;
    min-width: 0;
    min-inline-size: 0;
    min-block-size: 0;
    inline-size: var(--sf-icon-btn-size, 2.75rem);
    block-size: var(--sf-icon-btn-size, 2.75rem);
  }
  .sf-btn--icon-round.sf-btn--s { --sf-icon-btn-size: 2.25rem; }
  .sf-btn--icon-round.sf-btn--l { --sf-icon-btn-size: 3.25rem; }

  /* ----- Theme toggle (CSS-only color-scheme switcher) ----- */
  /* Flips the entire palette via :root:has() — no JS required for the visual flip.
     Add slashedUI.initThemeToggle() from slashed-ui.js for localStorage persistence.
     Markup:
       <label class="sf-theme-toggle" for="theme-chk" aria-label="Toggle dark mode">
         <input id="theme-chk" type="checkbox" class="sf-theme-toggle__input">
         <svg class="sf-theme-toggle__icon sf-theme-toggle__icon--sun" …></svg>
         <svg class="sf-theme-toggle__icon sf-theme-toggle__icon--moon" …></svg>
       </label>
     The :root:has() rule below drives the full token palette flip. */

  :root:has(.sf-theme-toggle__input:checked) { color-scheme: dark; }

  .sf-theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: var(--sf-theme-toggle-size, 2.75rem);
    block-size: var(--sf-theme-toggle-size, 2.75rem);
    border-radius: 50%;
    background: var(--sf-theme-toggle-bg, var(--sf-color-surface-2));
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    cursor: pointer;
    transition: background var(--sf-duration-fast) var(--sf-ease-out),
                border-color var(--sf-duration-fast) var(--sf-ease-out);
  }

  @media (hover: hover) {
    .sf-theme-toggle:hover { background: var(--sf-color-surface-3); }
  }

  .sf-theme-toggle__input { position: absolute; opacity: 0; inline-size: 0; block-size: 0; }

  /* Visible focus on the wrapper when the visually-hidden input has focus. */
  .sf-theme-toggle:has(.sf-theme-toggle__input:focus-visible) {
    outline: var(--sf-focus-ring-width) solid var(--sf-focus-ring-color);
    outline-offset: var(--sf-focus-ring-offset);
  }

  .sf-theme-toggle__icon {
    inline-size: 1.25em;
    block-size: 1.25em;
    pointer-events: none;
    transition: opacity var(--sf-duration-fast) var(--sf-ease-out),
                scale   var(--sf-duration-fast) var(--sf-ease-out);
  }

  /* Light mode: show sun, hide moon */
  .sf-theme-toggle__icon--sun  { opacity: 1; scale: 1; }
  .sf-theme-toggle__icon--moon { opacity: 0; scale: 0.6; position: absolute; }

  /* Dark mode (checkbox checked): show moon, hide sun */
  .sf-theme-toggle:has(.sf-theme-toggle__input:checked) .sf-theme-toggle__icon--sun  { opacity: 0; scale: 0.6; }
  .sf-theme-toggle:has(.sf-theme-toggle__input:checked) .sf-theme-toggle__icon--moon { opacity: 1; scale: 1; position: static; }

  @media (prefers-reduced-motion: reduce) {
    .sf-theme-toggle__icon { transition: none; }
  }

  /* ----- Segment (segmented control / pricing toggle) ----- */
  /* Radio-driven. Pure-CSS baseline; no JS required.
     Markup:
       <div class="sf-segment" role="group" aria-label="Billing period">
         <label class="sf-segment__option">
           <input type="radio" name="billing" class="sf-segment__input" checked>
           <span class="sf-segment__label">Monthly</span>
         </label>
         <label class="sf-segment__option">
           <input type="radio" name="billing" class="sf-segment__input">
           <span class="sf-segment__label">Annual <em class="sf-segment__badge">Save 20%</em></span>
         </label>
       </div> */

  .sf-segment {
    display: inline-flex;
    background: var(--sf-color-surface-2);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    border-radius: var(--sf-radius-full);
    padding: var(--sf-space-2xs);
    gap: var(--sf-space-2xs);
  }

  .sf-segment__input {
    position: absolute;
    opacity: 0;
    inline-size: 0;
    block-size: 0;
  }

  .sf-segment__option {
    display: inline-flex;
    align-items: center;
    cursor: pointer;
  }

  .sf-segment__label {
    display: inline-flex;
    align-items: center;
    gap: var(--sf-space-xs);
    padding-block: var(--sf-space-xs);
    padding-inline: var(--sf-space-m);
    border-radius: var(--sf-radius-full);
    font-size: var(--sf-text-s);
    font-weight: 500;
    color: var(--sf-color-text-muted);
    white-space: nowrap;
    transition: background var(--sf-duration-fast) var(--sf-ease-out),
                color     var(--sf-duration-fast) var(--sf-ease-out),
                box-shadow var(--sf-duration-fast) var(--sf-ease-out);
  }

  .sf-segment__option:has(.sf-segment__input:checked) .sf-segment__label {
    background: var(--sf-color-surface);
    color: var(--sf-color-text);
    box-shadow: var(--sf-shadow-s);
  }

  .sf-segment__option:has(.sf-segment__input:focus-visible) .sf-segment__label {
    outline: 2px solid var(--sf-action);
    outline-offset: 1px;
  }

  @media (hover: hover) {
    .sf-segment__option:not(:has(.sf-segment__input:checked)):hover .sf-segment__label {
      color: var(--sf-color-text);
    }
  }

  .sf-segment__badge {
    font-style: normal;
    font-size: var(--sf-text-xs);
    font-weight: 600;
    color: var(--sf-primary);
  }

  /* Variants */
  .sf-segment--s .sf-segment__label {
    padding-block: var(--sf-space-2xs);
    padding-inline: var(--sf-space-s);
    font-size: var(--sf-text-xs);
  }
  .sf-segment--l .sf-segment__label {
    padding-block: var(--sf-space-s);
    padding-inline: var(--sf-space-l);
    font-size: var(--sf-text-m);
  }

  /* ----- Accordion group — single-open (radio-driven) ----- */
  /* Unlike .sf-accordion-group (multi-open, wraps <details>), this variant
     uses hidden radio inputs so only one panel is open at a time. Works
     standalone or paired with .sf-stepper--linked (see below).
     Markup:
       <div class="sf-accordion-group sf-accordion-group--single">
         <input type="radio" name="faq" id="faq1" class="sf-accordion-group__input" hidden checked>
         <div class="sf-accordion-group__item">
           <label class="sf-accordion-group__summary" for="faq1">Question text</label>
           <div class="sf-accordion-group__body">
             <div class="sf-accordion-group__body-inner">Answer text</div>
           </div>
         </div>
         … more input+item pairs …
       </div>
     Each input must precede its matching .sf-accordion-group__item as a sibling. */

  .sf-accordion-group--single {
    display: flex;
    flex-direction: column;
  }

  .sf-accordion-group__input { position: absolute; opacity: 0; inline-size: 0; block-size: 0; }

  .sf-accordion-group__item {
    border-block-end: var(--sf-border-width-1) solid var(--sf-color-border);
  }
  /* Use :first-of-type on the visible item so the leading hidden radio inputs
     don't absorb the top border. */
  .sf-accordion-group--single > .sf-accordion-group__item:first-of-type {
    border-block-start: var(--sf-border-width-1) solid var(--sf-color-border);
  }

  .sf-accordion-group__summary {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--sf-space-m);
    padding-block: var(--sf-space-m);
    font-weight: 600;
    cursor: pointer;
    user-select: none;
  }

  .sf-accordion-group__summary::after {
    content: '';
    display: inline-block;
    inline-size: 0.6em;
    block-size: 0.6em;
    border-inline-end: 2px solid currentColor;
    border-block-end: 2px solid currentColor;
    rotate: 45deg;
    flex-shrink: 0;
    transition: rotate var(--sf-duration-normal) var(--sf-ease-out);
  }

  .sf-accordion-group__body {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--sf-duration-normal) var(--sf-ease-out);
  }

  .sf-accordion-group__body-inner { overflow: hidden; }

  .sf-accordion-group__body-inner > :last-child { padding-block-end: var(--sf-space-m); }

  /* Open state: when the radio input is checked, the immediately following item opens */
  .sf-accordion-group__input:checked + .sf-accordion-group__item .sf-accordion-group__body {
    grid-template-rows: 1fr;
  }

  .sf-accordion-group__input:checked + .sf-accordion-group__item .sf-accordion-group__summary::after {
    rotate: -135deg;
  }

  @media (prefers-reduced-motion: reduce) {
    .sf-accordion-group__body     { transition: none; }
    .sf-accordion-group__summary::after { transition: none; }
  }

  /* ----- Stepper — linked (radio-driven state sync) ----- */
  /* Extends .sf-stepper. When placed inside an .sf-accordion-group--single,
     step dots and labels automatically reflect which radio is checked.
     No JS or manual --active / --complete classes required.
     Markup: see .sf-accordion-group--single docs above.
     The stepper and accordion panels must share the same radio inputs. */

  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(1):checked) .sf-stepper--linked .sf-stepper__step:nth-child(1) .sf-stepper__dot { background: var(--sf-primary); color: var(--sf-color-text-on-primary); }
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(2):checked) .sf-stepper--linked .sf-stepper__step:nth-child(2) .sf-stepper__dot { background: var(--sf-primary); color: var(--sf-color-text-on-primary); }
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(3):checked) .sf-stepper--linked .sf-stepper__step:nth-child(3) .sf-stepper__dot { background: var(--sf-primary); color: var(--sf-color-text-on-primary); }
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(4):checked) .sf-stepper--linked .sf-stepper__step:nth-child(4) .sf-stepper__dot { background: var(--sf-primary); color: var(--sf-color-text-on-primary); }
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(5):checked) .sf-stepper--linked .sf-stepper__step:nth-child(5) .sf-stepper__dot { background: var(--sf-primary); color: var(--sf-color-text-on-primary); }
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(6):checked) .sf-stepper--linked .sf-stepper__step:nth-child(6) .sf-stepper__dot { background: var(--sf-primary); color: var(--sf-color-text-on-primary); }

  /* Mark steps before the active one as complete */
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(2):checked) .sf-stepper--linked .sf-stepper__step:nth-child(1) .sf-stepper__dot,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(3):checked) .sf-stepper--linked .sf-stepper__step:nth-child(-n+2) .sf-stepper__dot,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(4):checked) .sf-stepper--linked .sf-stepper__step:nth-child(-n+3) .sf-stepper__dot,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(5):checked) .sf-stepper--linked .sf-stepper__step:nth-child(-n+4) .sf-stepper__dot,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(6):checked) .sf-stepper--linked .sf-stepper__step:nth-child(-n+5) .sf-stepper__dot {
    background: var(--sf-stepper-complete-bg, var(--sf-success));
    color: var(--sf-color-text-on-primary);
  }

  /* Active step label bold */
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(1):checked) .sf-stepper--linked .sf-stepper__step:nth-child(1) .sf-stepper__label,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(2):checked) .sf-stepper--linked .sf-stepper__step:nth-child(2) .sf-stepper__label,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(3):checked) .sf-stepper--linked .sf-stepper__step:nth-child(3) .sf-stepper__label,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(4):checked) .sf-stepper--linked .sf-stepper__step:nth-child(4) .sf-stepper__label,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(5):checked) .sf-stepper--linked .sf-stepper__step:nth-child(5) .sf-stepper__label,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(6):checked) .sf-stepper--linked .sf-stepper__step:nth-child(6) .sf-stepper__label {
    color: var(--sf-color-text);
    font-weight: 600;
  }

  /* Connector lines complete colour (before active step) */
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(2):checked) .sf-stepper--linked .sf-stepper__step:nth-child(2)::before,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(3):checked) .sf-stepper--linked .sf-stepper__step:nth-child(-n+3):not(:nth-child(1))::before,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(4):checked) .sf-stepper--linked .sf-stepper__step:nth-child(-n+4):not(:nth-child(1))::before,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(5):checked) .sf-stepper--linked .sf-stepper__step:nth-child(-n+5):not(:nth-child(1))::before,
  .sf-accordion-group--single:has(.sf-accordion-group__input:nth-of-type(6):checked) .sf-stepper--linked .sf-stepper__step:nth-child(-n+6):not(:nth-child(1))::before {
    background: var(--sf-stepper-line-active, var(--sf-success));
  }

  /* ----- Comparison table modifier + mark ----- */
  /* .sf-table--comparison: extends .sf-table for yes/no feature matrices.
     .sf-mark: small yes/no/neutral circle for comparison tables or checklists.
     Markup:
       <span class="sf-mark sf-mark--yes" aria-label="Yes">✓</span>
       <span class="sf-mark sf-mark--no"  aria-label="No">✕</span> */

  .sf-table--comparison thead th:first-child { text-align: start; }
  .sf-table--comparison tbody td:first-child  { font-weight: 600; }
  .sf-table--comparison tbody td { text-align: center; vertical-align: middle; }
  .sf-table--comparison tbody td:first-child { text-align: start; }

  .sf-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 1.5em;
    block-size: 1.5em;
    border-radius: 50%;
    font-size: 0.75em;
    font-weight: 700;
    flex-shrink: 0;
  }

  .sf-mark--yes {
    background: var(--sf-success-100);
    color: var(--sf-success-600);
  }

  .sf-mark--no {
    background: var(--sf-error-100);
    color: var(--sf-error-600);
  }

  .sf-mark--neutral {
    background: var(--sf-color-surface-3);
    color: var(--sf-color-text-muted);
  }

  /* ----- Drawer (slide-in overlay panel) ----- */
  /* CSS-only baseline via hidden checkbox + :has(). Progressively enhanced by
     slashedUI.initDrawers() for focus trap, Escape-to-close, and inert.
     Markup:
       <input type="checkbox" id="nav-open" class="sf-drawer__input" hidden>
       <div class="sf-drawer sf-drawer--end">
         … nav content …
       </div>
       <label for="nav-open" class="sf-drawer__backdrop" aria-hidden="true"></label>
     The input must be a sibling preceding the drawer and backdrop. */

  .sf-drawer__input {
    position: absolute;
    opacity: 0;
    inline-size: 0;
    block-size: 0;
  }

  .sf-drawer {
    --sf-drawer-width: var(--sf-drawer-size, min(22rem, 85vw));
    position: fixed;
    inset-block: 0;
    inset-inline-end: 0;
    inline-size: var(--sf-drawer-width);
    background: var(--sf-color-surface);
    box-shadow: var(--sf-shadow-m);
    z-index: var(--sf-z-overlay);
    overflow-y: auto;
    translate: 100% 0;
    transition: translate var(--sf-duration-normal) var(--sf-ease-out),
                visibility 0s var(--sf-duration-normal);
    visibility: hidden;
  }

  .sf-drawer--start {
    inset-inline-end: unset;
    inset-inline-start: 0;
    translate: -100% 0;
  }

  .sf-drawer--top {
    inset-inline: 0;
    inset-block-start: 0;
    inset-block-end: unset;
    inline-size: 100%;
    block-size: var(--sf-drawer-size, auto);
    translate: 0 -100%;
  }

  .sf-drawer--bottom {
    inset-inline: 0;
    inset-block-end: 0;
    inset-block-start: unset;
    inline-size: 100%;
    block-size: var(--sf-drawer-size, auto);
    translate: 0 100%;
  }

  .sf-drawer__backdrop {
    position: fixed;
    inset: 0;
    background: var(--sf-color-surface-overlay);
    backdrop-filter: blur(var(--sf-blur-2xs));
    -webkit-backdrop-filter: blur(var(--sf-blur-2xs));
    z-index: calc(var(--sf-z-overlay) - 1);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--sf-duration-normal) var(--sf-ease-out),
                visibility 0s var(--sf-duration-normal);
    cursor: pointer;
  }

  /* Open state — driven by sibling checkbox. Scoped to siblings so multiple
     drawers on a page don't broadcast each other's state. The .sf-drawer__input
     must precede its .sf-drawer / .sf-drawer__backdrop / .sf-hamburger as a
     sibling, or be a sibling of an ancestor that contains them (~ * descendant). */
  .sf-drawer__input:checked ~ .sf-drawer,
  .sf-drawer__input:checked ~ * .sf-drawer {
    translate: 0 0;
    visibility: visible;
    transition: translate var(--sf-duration-normal) var(--sf-ease-out),
                visibility 0s 0s;
  }

  .sf-drawer__input:checked ~ .sf-drawer__backdrop,
  .sf-drawer__input:checked ~ * .sf-drawer__backdrop {
    opacity: 1;
    visibility: visible;
    transition: opacity var(--sf-duration-normal) var(--sf-ease-out),
                visibility 0s 0s;
  }

  @media (prefers-reduced-motion: reduce) {
    .sf-drawer,
    .sf-drawer__backdrop { transition: none; }
  }

  /* ----- Hamburger (animated ☰ → ✕ icon) ----- */
  /* Three-bar icon that morphs to X when the associated drawer is open.
     Pair with .sf-btn--icon-round for the full circle button style.
     Markup:
       <label class="sf-hamburger" for="nav-open" aria-label="Toggle menu">
         <span class="sf-hamburger__bar"></span>
         <span class="sf-hamburger__bar"></span>
         <span class="sf-hamburger__bar"></span>
       </label> */

  .sf-hamburger {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: var(--sf-hamburger-gap, 5px);
    inline-size: var(--sf-hamburger-size, 2.75rem);
    block-size: var(--sf-hamburger-size, 2.75rem);
    border-radius: 50%;
    background: var(--sf-color-surface-2);
    border: var(--sf-border-width-1) solid var(--sf-color-border);
    cursor: pointer;
    padding: var(--sf-space-xs);
  }

  @media (hover: hover) {
    .sf-hamburger:hover { background: var(--sf-color-surface-3); }
  }

  .sf-hamburger__bar {
    display: block;
    inline-size: 1.25rem;
    block-size: 2px;
    background: currentColor;
    border-radius: 2px;
    transform-origin: center;
    transition: rotate var(--sf-duration-normal) var(--sf-ease-out),
                translate var(--sf-duration-normal) var(--sf-ease-out),
                opacity var(--sf-duration-fast) var(--sf-ease-out);
  }

  /* X state when drawer is open — sibling-scoped to one drawer instance */
  .sf-drawer__input:checked ~ .sf-hamburger .sf-hamburger__bar:nth-child(1),
  .sf-drawer__input:checked ~ * .sf-hamburger .sf-hamburger__bar:nth-child(1) {
    rotate: 45deg;
    translate: 0 calc(var(--sf-hamburger-gap, 5px) + 2px);
  }

  .sf-drawer__input:checked ~ .sf-hamburger .sf-hamburger__bar:nth-child(2),
  .sf-drawer__input:checked ~ * .sf-hamburger .sf-hamburger__bar:nth-child(2) {
    opacity: 0;
    scale: 0;
  }

  .sf-drawer__input:checked ~ .sf-hamburger .sf-hamburger__bar:nth-child(3),
  .sf-drawer__input:checked ~ * .sf-hamburger .sf-hamburger__bar:nth-child(3) {
    rotate: -45deg;
    translate: 0 calc(-1 * (var(--sf-hamburger-gap, 5px) + 2px));
  }

  @media (prefers-reduced-motion: reduce) {
    .sf-hamburger__bar { transition: none; }
  }

  /* ----- Floating card (overlay pinned to a media element) ----- */
  /* Extends .sf-card. Parent must be position: relative (use .sf-floating-anchor).
     Markup:
       <div class="sf-floating-anchor">
         <img src="…" alt="…">
         <div class="sf-card sf-card--floating">
           … stat or badge content …
         </div>
       </div>
     Instance tokens: --sf-card-floating-x / --sf-card-floating-y for offset. */

  .sf-floating-anchor { position: relative; }

  .sf-card--floating {
    position: absolute;
    inset-block-end: var(--sf-card-floating-y, var(--sf-space-m));
    inset-inline-end: var(--sf-card-floating-x, var(--sf-space-m));
    inline-size: max-content;
    max-inline-size: calc(100% - var(--sf-space-l));
  }

  /* ----- Logo wall (wordmark / trusted-by bar) ----- */
  /* Distinct from .sf-brand-tile (coloured icon tile). This is the
     text-wordmark or grayscale-image trusted-by strip.
     Markup:
       <div class="sf-logo-wall">
         <p class="sf-logo-wall__label">Trusted by teams at</p>
         <div class="sf-logo-wall__items">
           <span class="sf-logo-wall__item">Nortek</span>
           …
         </div>
       </div>

     Marquee variant requires an extra .sf-logo-wall__items-track wrapper, and
     the items must be duplicated so the -50% translate keyframe loops
     seamlessly (same constraint as .sf-marquee):
       <div class="sf-logo-wall sf-logo-wall--marquee">
         <div class="sf-logo-wall__items">
           <div class="sf-logo-wall__items-track">
             <span class="sf-logo-wall__item">Nortek</span> …
             <!-- duplicate the same item set here for a seamless loop -->
             <span class="sf-logo-wall__item">Nortek</span> …
           </div>
         </div>
       </div> */

  .sf-logo-wall {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sf-space-m);
    text-align: center;
  }

  .sf-logo-wall__label {
    font-size: var(--sf-text-s);
    text-transform: uppercase;
    letter-spacing: var(--sf-tracking-wider);
    color: var(--sf-color-text-muted);
    margin: 0;
  }

  .sf-logo-wall__items {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--sf-space-l) var(--sf-space-xl);
  }

  .sf-logo-wall__item {
    font-family: var(--sf-font-heading);
    font-size: var(--sf-logo-wall-size, var(--sf-text-l));
    font-weight: 700;
    color: var(--sf-color-text-muted);
    opacity: 0.65;
    line-height: 1;
    filter: grayscale(1);
  }

  .sf-logo-wall__item img,
  .sf-logo-wall__item svg {
    display: block;
    max-block-size: var(--sf-logo-wall-size, 1.5rem);
    inline-size: auto;
    object-fit: contain;
  }

  .sf-logo-wall--start { align-items: flex-start; text-align: start; }
  .sf-logo-wall--start .sf-logo-wall__items { justify-content: flex-start; }

  /* Marquee / auto-scroll variant */
  .sf-logo-wall--marquee .sf-logo-wall__items {
    flex-wrap: nowrap;
    overflow: hidden;
    mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent);
    -webkit-mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent);
  }

  .sf-logo-wall--marquee .sf-logo-wall__items-track {
    display: flex;
    gap: var(--sf-space-l) var(--sf-space-xl);
    align-items: center;
    animation: sf-marquee var(--sf-marquee-duration, 30s) linear infinite;
    white-space: nowrap;
  }

  @keyframes sf-marquee {
    from { translate: 0 0; }
    to   { translate: -50% 0; }
  }

  @media (prefers-reduced-motion: reduce) {
    .sf-logo-wall--marquee .sf-logo-wall__items-track { animation: none; }
  }

}

/* ==========================================================================
   LOADING STATE OVERRIDES — slashed.utilities layer
   These live in slashed.utilities (above slashed.components) so they win over
   any .sf-text-* color utility applied by the consumer. In slashed-full.css
   the concat order places slashed-utilities.css BEFORE slashed-components.css,
   so these declarations appear last inside the utilities layer and win by
   order-of-appearance — no !important needed (Edgeless principle).
   ========================================================================== */

@layer slashed.utilities {

  /* Loading state: hide button text so only the spinner ::after is visible.
     .sf-btn--loading is JS-toggled and the spinner runs at all motion prefs (just slower
     under reduce), so text is always hidden.
     [aria-busy="true"] spinner is only rendered in no-preference mode (no reduced-motion
     fallback), so only hide text when the spinner is actually shown. */
  .sf-btn--loading {
    color: transparent;
    text-shadow: none;
  }
  @media (prefers-reduced-motion: no-preference) {
    :is(.sf-btn--primary, .sf-btn--destructive, .sf-btn--outline, .sf-btn--ghost)[aria-busy="true"] {
      color: transparent;
      text-shadow: none;
    }
  }

  /* Loading state: hide input text and caret (wrapper class, not on <input> directly). */
  .sf-input-wrap--loading > input {
    color: transparent;
  }

}

/* ==========================================================================
   SLASHED Utilities — Visual — v0.6.22.0
   Optional decorative-property utility layer (backgrounds, borders, radii,
   shadows, opacity, transitions, filters). Load after slashed-full.css.
   See docs/UTILITIES-VISUAL.md for loading instructions and authoring guidance.
   ========================================================================== */

@layer slashed.reset, slashed.base, slashed.layout, slashed.components, slashed.utilities, slashed.visual, slashed.animations, slashed.a11y, slashed.overrides;

@layer slashed.visual {

  /* ----- Border width / style ----- */

  .sf-border         { border: var(--sf-border-width-1) solid var(--sf-color-border); }
  .sf-border-0       { border: 0; }
  .sf-border-2       { border-width: var(--sf-border-width-2); }
  .sf-border-4       { border-width: var(--sf-border-width-4); }
  .sf-border-b       { border-block-end: var(--sf-border-width-1) solid var(--sf-color-border); }
  .sf-border-t       { border-block-start: var(--sf-border-width-1) solid var(--sf-color-border); }
  .sf-border-s       { border-inline-start: var(--sf-border-width-1) solid var(--sf-color-border); }
  .sf-border-e       { border-inline-end: var(--sf-border-width-1) solid var(--sf-color-border); }
  .sf-border-x       { border-inline: var(--sf-border-width-1) solid var(--sf-color-border); border-block: 0; }
  .sf-border-y       { border-block: var(--sf-border-width-1) solid var(--sf-color-border); border-inline: 0; }
  .sf-border-dashed  { border-style: dashed; }
  .sf-border-dotted  { border-style: dotted; }

  /* ----- Border color - semantic ----- */

  .sf-border-primary { border-color: var(--sf-primary); }
  .sf-border-strong  { border-color: var(--sf-color-border-strong); } /* color-only — composes with .sf-border / element borders */
  .sf-border-subtle  { border-color: var(--sf-color-border-subtle); }
  .sf-accent-primary { accent-color: var(--sf-primary); }

  /* ----- Border radius ----- */

  .sf-rounded-none { border-radius: 0; }
  .sf-rounded-xs   { border-radius: var(--sf-radius-xs); }
  .sf-rounded-s    { border-radius: var(--sf-radius-s); }
  .sf-rounded-m    { border-radius: var(--sf-radius-m); }
  .sf-rounded-l    { border-radius: var(--sf-radius-l); }
  .sf-rounded-xl   { border-radius: var(--sf-radius-xl); }
  .sf-rounded-2xl  { border-radius: var(--sf-radius-2xl); }
  .sf-rounded-full { border-radius: var(--sf-radius-full); }

  /* ----- Background - palette (full scale) ----- */

  .sf-bg-primary-50  { background: var(--sf-primary-50); }
  .sf-bg-primary-100 { background: var(--sf-primary-100); }
  .sf-bg-primary-200 { background: var(--sf-primary-200); }
  .sf-bg-primary-300 { background: var(--sf-primary-300); }
  .sf-bg-primary-400 { background: var(--sf-primary-400); }
  .sf-bg-primary-600 { background: var(--sf-primary-600); }
  .sf-bg-primary-700 { background: var(--sf-primary-700); }
  .sf-bg-primary-800 { background: var(--sf-primary-800); }
  .sf-bg-primary-900 { background: var(--sf-primary-900); }
  .sf-bg-primary-950 { background: var(--sf-primary-950); }

  .sf-bg-secondary-50  { background: var(--sf-secondary-50); }
  .sf-bg-secondary-100 { background: var(--sf-secondary-100); }
  .sf-bg-secondary-200 { background: var(--sf-secondary-200); }
  .sf-bg-secondary-300 { background: var(--sf-secondary-300); }
  .sf-bg-secondary-400 { background: var(--sf-secondary-400); }
  .sf-bg-secondary-600 { background: var(--sf-secondary-600); }
  .sf-bg-secondary-700 { background: var(--sf-secondary-700); }
  .sf-bg-secondary-800 { background: var(--sf-secondary-800); }
  .sf-bg-secondary-900 { background: var(--sf-secondary-900); }
  .sf-bg-secondary-950 { background: var(--sf-secondary-950); }

  .sf-bg-accent-50  { background: var(--sf-accent-50); }
  .sf-bg-accent-100 { background: var(--sf-accent-100); }
  .sf-bg-accent-200 { background: var(--sf-accent-200); }
  .sf-bg-accent-300 { background: var(--sf-accent-300); }
  .sf-bg-accent-400 { background: var(--sf-accent-400); }
  .sf-bg-accent-600 { background: var(--sf-accent-600); }
  .sf-bg-accent-700 { background: var(--sf-accent-700); }
  .sf-bg-accent-800 { background: var(--sf-accent-800); }
  .sf-bg-accent-900 { background: var(--sf-accent-900); }
  .sf-bg-accent-950 { background: var(--sf-accent-950); }

  .sf-bg-neutral-50  { background: var(--sf-neutral-50); }
  .sf-bg-neutral-100 { background: var(--sf-neutral-100); }
  .sf-bg-neutral-200 { background: var(--sf-neutral-200); }
  .sf-bg-neutral-300 { background: var(--sf-neutral-300); }
  .sf-bg-neutral-400 { background: var(--sf-neutral-400); }
  .sf-bg-neutral-500 { background: var(--sf-neutral-500); }
  .sf-bg-neutral-600 { background: var(--sf-neutral-600); }
  .sf-bg-neutral-700 { background: var(--sf-neutral-700); }
  .sf-bg-neutral-800 { background: var(--sf-neutral-800); }
  .sf-bg-neutral-900 { background: var(--sf-neutral-900); }

  .sf-bg-tertiary-50  { background: var(--sf-tertiary-50); }
  .sf-bg-tertiary-100 { background: var(--sf-tertiary-100); }
  .sf-bg-tertiary-200 { background: var(--sf-tertiary-200); }
  .sf-bg-tertiary-300 { background: var(--sf-tertiary-300); }
  .sf-bg-tertiary-400 { background: var(--sf-tertiary-400); }
  .sf-bg-tertiary-600 { background: var(--sf-tertiary-600); }
  .sf-bg-tertiary-700 { background: var(--sf-tertiary-700); }
  .sf-bg-tertiary-800 { background: var(--sf-tertiary-800); }
  .sf-bg-tertiary-900 { background: var(--sf-tertiary-900); }
  .sf-bg-tertiary-950 { background: var(--sf-tertiary-950); }

  .sf-bg-action-50  { background: var(--sf-action-50); }
  .sf-bg-action-100 { background: var(--sf-action-100); }
  .sf-bg-action-200 { background: var(--sf-action-200); }
  .sf-bg-action-300 { background: var(--sf-action-300); }
  .sf-bg-action-400 { background: var(--sf-action-400); }
  .sf-bg-action-600 { background: var(--sf-action-600); }
  .sf-bg-action-700 { background: var(--sf-action-700); }
  .sf-bg-action-800 { background: var(--sf-action-800); }
  .sf-bg-action-900 { background: var(--sf-action-900); }
  .sf-bg-action-950 { background: var(--sf-action-950); }

  .sf-bg-base-50  { background: var(--sf-base-50); }
  .sf-bg-base-100 { background: var(--sf-base-100); }
  .sf-bg-base-200 { background: var(--sf-base-200); }
  .sf-bg-base-300 { background: var(--sf-base-300); }
  .sf-bg-base-400 { background: var(--sf-base-400); }
  .sf-bg-base-600 { background: var(--sf-base-600); }
  .sf-bg-base-700 { background: var(--sf-base-700); }
  .sf-bg-base-800 { background: var(--sf-base-800); }
  .sf-bg-base-900 { background: var(--sf-base-900); }
  .sf-bg-base-950 { background: var(--sf-base-950); }

  .sf-bg-success-100 { background: var(--sf-success-100); }
  .sf-bg-success-600 { background: var(--sf-success-600); }
  .sf-bg-warning-100 { background: var(--sf-warning-100); }
  .sf-bg-warning-600 { background: var(--sf-warning-600); }
  .sf-bg-error-100   { background: var(--sf-error-100); }
  .sf-bg-error-600   { background: var(--sf-error-600); }
  .sf-bg-info-100    { background: var(--sf-info-100); }
  .sf-bg-info-600    { background: var(--sf-info-600); }

  /* ----- Text - palette (full scale) ----- */

  .sf-text-primary-50  { color: var(--sf-primary-50); }
  .sf-text-primary-100 { color: var(--sf-primary-100); }
  .sf-text-primary-200 { color: var(--sf-primary-200); }
  .sf-text-primary-300 { color: var(--sf-primary-300); }
  .sf-text-primary-400 { color: var(--sf-primary-400); }
  .sf-text-primary-600 { color: var(--sf-primary-600); }
  .sf-text-primary-700 { color: var(--sf-primary-700); }
  .sf-text-primary-800 { color: var(--sf-primary-800); }
  .sf-text-primary-900 { color: var(--sf-primary-900); }
  .sf-text-primary-950 { color: var(--sf-primary-950); }

  .sf-text-secondary-50  { color: var(--sf-secondary-50); }
  .sf-text-secondary-100 { color: var(--sf-secondary-100); }
  .sf-text-secondary-200 { color: var(--sf-secondary-200); }
  .sf-text-secondary-300 { color: var(--sf-secondary-300); }
  .sf-text-secondary-400 { color: var(--sf-secondary-400); }
  .sf-text-secondary-600 { color: var(--sf-secondary-600); }
  .sf-text-secondary-700 { color: var(--sf-secondary-700); }
  .sf-text-secondary-800 { color: var(--sf-secondary-800); }
  .sf-text-secondary-900 { color: var(--sf-secondary-900); }
  .sf-text-secondary-950 { color: var(--sf-secondary-950); }

  .sf-text-accent-50  { color: var(--sf-accent-50); }
  .sf-text-accent-100 { color: var(--sf-accent-100); }
  .sf-text-accent-200 { color: var(--sf-accent-200); }
  .sf-text-accent-300 { color: var(--sf-accent-300); }
  .sf-text-accent-400 { color: var(--sf-accent-400); }
  .sf-text-accent-600 { color: var(--sf-accent-600); }
  .sf-text-accent-700 { color: var(--sf-accent-700); }
  .sf-text-accent-800 { color: var(--sf-accent-800); }
  .sf-text-accent-900 { color: var(--sf-accent-900); }
  .sf-text-accent-950 { color: var(--sf-accent-950); }

  .sf-text-neutral-50  { color: var(--sf-neutral-50); }
  .sf-text-neutral-100 { color: var(--sf-neutral-100); }
  .sf-text-neutral-200 { color: var(--sf-neutral-200); }
  .sf-text-neutral-300 { color: var(--sf-neutral-300); }
  .sf-text-neutral-400 { color: var(--sf-neutral-400); }
  .sf-text-neutral-500 { color: var(--sf-neutral-500); }
  .sf-text-neutral-600 { color: var(--sf-neutral-600); }
  .sf-text-neutral-700 { color: var(--sf-neutral-700); }
  .sf-text-neutral-800 { color: var(--sf-neutral-800); }
  .sf-text-neutral-900 { color: var(--sf-neutral-900); }

  .sf-text-tertiary-50  { color: var(--sf-tertiary-50); }
  .sf-text-tertiary-100 { color: var(--sf-tertiary-100); }
  .sf-text-tertiary-200 { color: var(--sf-tertiary-200); }
  .sf-text-tertiary-300 { color: var(--sf-tertiary-300); }
  .sf-text-tertiary-400 { color: var(--sf-tertiary-400); }
  .sf-text-tertiary-600 { color: var(--sf-tertiary-600); }
  .sf-text-tertiary-700 { color: var(--sf-tertiary-700); }
  .sf-text-tertiary-800 { color: var(--sf-tertiary-800); }
  .sf-text-tertiary-900 { color: var(--sf-tertiary-900); }
  .sf-text-tertiary-950 { color: var(--sf-tertiary-950); }

  .sf-text-action-50  { color: var(--sf-action-50); }
  .sf-text-action-100 { color: var(--sf-action-100); }
  .sf-text-action-200 { color: var(--sf-action-200); }
  .sf-text-action-300 { color: var(--sf-action-300); }
  .sf-text-action-400 { color: var(--sf-action-400); }
  .sf-text-action-600 { color: var(--sf-action-600); }
  .sf-text-action-700 { color: var(--sf-action-700); }
  .sf-text-action-800 { color: var(--sf-action-800); }
  .sf-text-action-900 { color: var(--sf-action-900); }
  .sf-text-action-950 { color: var(--sf-action-950); }

  .sf-text-base-50  { color: var(--sf-base-50); }
  .sf-text-base-100 { color: var(--sf-base-100); }
  .sf-text-base-200 { color: var(--sf-base-200); }
  .sf-text-base-300 { color: var(--sf-base-300); }
  .sf-text-base-400 { color: var(--sf-base-400); }
  .sf-text-base-600 { color: var(--sf-base-600); }
  .sf-text-base-700 { color: var(--sf-base-700); }
  .sf-text-base-800 { color: var(--sf-base-800); }
  .sf-text-base-900 { color: var(--sf-base-900); }
  .sf-text-base-950 { color: var(--sf-base-950); }

  /* ----- Background - semantic ----- */

  .sf-bg-primary {
    background:           var(--sf-primary);
    color:                var(--sf-color-text-on-primary);
    --sf-color-text:         var(--sf-color-text-on-primary);
    --sf-color-text-body:    var(--sf-color-text-on-primary);
    --sf-color-link:         var(--sf-color-text-on-primary);
    --sf-color-link-hover:   var(--sf-color-text-on-primary);
    --sf-color-link-visited: var(--sf-color-text-on-primary);
    --sf-color-link-active:  var(--sf-color-text-on-primary);
    --sf-color-border:       color-mix(in srgb, var(--sf-primary) 70%, white);
  }
  .sf-bg-secondary {
    background:           var(--sf-secondary);
    color:                var(--sf-color-text-on-secondary);
    --sf-color-text:         var(--sf-color-text-on-secondary);
    --sf-color-text-body:    var(--sf-color-text-on-secondary);
    --sf-color-link:         var(--sf-color-text-on-secondary);
    --sf-color-link-hover:   var(--sf-color-text-on-secondary);
    --sf-color-link-visited: var(--sf-color-text-on-secondary);
    --sf-color-link-active:  var(--sf-color-text-on-secondary);
    --sf-color-border:       color-mix(in srgb, var(--sf-secondary) 70%, white);
  }
  .sf-bg-accent {
    background:           var(--sf-accent);
    color:                var(--sf-color-text-on-accent);
    --sf-color-text:         var(--sf-color-text-on-accent);
    --sf-color-text-body:    var(--sf-color-text-on-accent);
    --sf-color-link:         var(--sf-color-text-on-accent);
    --sf-color-link-hover:   var(--sf-color-text-on-accent);
    --sf-color-link-visited: var(--sf-color-text-on-accent);
    --sf-color-link-active:  var(--sf-color-text-on-accent);
    --sf-color-border:       color-mix(in srgb, var(--sf-accent) 70%, white);
  }
  .sf-bg-success     { background: var(--sf-success); }
  .sf-bg-warning     { background: var(--sf-warning); }
  .sf-bg-error       { background: var(--sf-error); }
  .sf-bg-info        { background: var(--sf-info); }
  .sf-bg-surface          { background: var(--sf-color-surface); }
  .sf-bg-surface-2        { background: var(--sf-color-surface-2); }
  .sf-bg-surface-3        { background: var(--sf-color-surface-3); }
  .sf-bg-surface-4        { background: var(--sf-color-surface-4); }
  .sf-bg-surface-elevated { background: var(--sf-color-surface-elevated); }
  .sf-bg-surface-overlay  { background: var(--sf-color-surface-overlay); }
  .sf-bg-light       { color-scheme: light; background: var(--sf-color-surface);   color: var(--sf-color-text); }
  .sf-bg-dark {
    color-scheme: dark;
    background-color: var(--sf-neutral-800);
    color: var(--sf-color-text-on-dark);
  }
  .sf-bg-ultra-light { background: var(--sf-color-surface-2); color: var(--sf-color-text); }
  .sf-bg-ultra-dark {
    color-scheme: dark;
    background-color: var(--sf-neutral-900);
    color: var(--sf-color-text-on-dark);
  }
  .sf-bg-transparent { background: transparent; }
  .sf-bg-inherit     { background: inherit; }
  .sf-bg-gradient {
    background: var(--sf-bg-gradient, linear-gradient(to bottom right, var(--sf-primary), var(--sf-accent)));
  }

  /* ----- Shadow ----- */

  .sf-shadow-none    { box-shadow: none; }
  .sf-shadow-2xs     { box-shadow: var(--sf-shadow-2xs); }
  .sf-shadow-xs      { box-shadow: var(--sf-shadow-xs); }
  .sf-shadow-s       { box-shadow: var(--sf-shadow-s); }
  .sf-shadow-m       { box-shadow: var(--sf-shadow-m); }
  .sf-shadow-l       { box-shadow: var(--sf-shadow-l); }
  .sf-shadow-xl      { box-shadow: var(--sf-shadow-xl); }
  .sf-shadow-float   { box-shadow: var(--sf-shadow-float); }
  .sf-shadow-glow    { box-shadow: var(--sf-shadow-glow); }
  .sf-shadow-colored { box-shadow: var(--sf-shadow-colored); }
  .sf-shadow-inner   { box-shadow: var(--sf-shadow-inner); }

  /* ----- Opacity ----- */

  .sf-opacity-0   { opacity: 0; }
  .sf-opacity-5   { opacity: 0.05; }
  .sf-opacity-10  { opacity: 0.1; }
  .sf-opacity-20  { opacity: 0.2; }
  .sf-opacity-25  { opacity: 0.25; }
  .sf-opacity-30  { opacity: 0.3; }
  .sf-opacity-40  { opacity: 0.4; }
  .sf-opacity-50  { opacity: 0.5; }
  .sf-opacity-60  { opacity: 0.6; }
  .sf-opacity-70  { opacity: 0.7; }
  .sf-opacity-75  { opacity: 0.75; }
  .sf-opacity-80  { opacity: 0.8; }
  .sf-opacity-90  { opacity: 0.9; }
  .sf-opacity-100 { opacity: 1; }
  .sf-opacity-var { opacity: var(--sf-opacity, 1); } /* set --sf-opacity via style or parent rule */

  /* ----- Animation / keyframes ----- */
  /* Guarded by prefers-reduced-motion so they are inert for users who prefer no motion.
     For slashed-full.css users, slashed-animations.css canonical versions (same names,
     same guard) live in the higher slashed.animations layer and share keyframes with
     slashed-core.css. These visual-layer copies ensure the classes work when
     slashed-animations.css is not loaded separately. */

  @media (prefers-reduced-motion: no-preference) {
    .sf-animate-fade-in  { animation: fade-in  var(--sf-duration-normal) var(--sf-ease-out) both; }
    .sf-animate-scale-in { animation: scale-in var(--sf-duration-normal) var(--sf-ease-out) both; }
    .sf-animate-slide-up { animation: slide-up var(--sf-duration-normal) var(--sf-ease-out) both; }
    .sf-animate-spin     { animation: spin var(--sf-spin-duration, 1s) linear infinite; }
  }

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

  .sf-transition {
    transition-property: color, background-color, border-color, outline-color,
                         box-shadow, opacity, transform, translate, scale, rotate, filter;
    transition-duration: var(--sf-duration-normal);
    transition-timing-function: var(--sf-ease-out);
  }
  .sf-transition-colors {
    transition-property: color, background-color, border-color, outline-color;
    transition-duration: var(--sf-duration-normal);
    transition-timing-function: var(--sf-ease-out);
  }
  .sf-transition-fast {
    transition-property: color, background-color, border-color, outline-color,
                         box-shadow, opacity, transform, translate, scale, rotate, filter;
    transition-duration: var(--sf-duration-fast);
    transition-timing-function: var(--sf-ease-out);
  }
  .sf-transition-none { transition: none; }
  .sf-transition-shadow {
    transition-property: box-shadow;
    transition-duration: var(--sf-duration-normal);
    transition-timing-function: var(--sf-ease-out);
  }
  .sf-transition-transform {
    transition-property: transform, translate, scale, rotate;
    transition-duration: var(--sf-duration-normal);
    transition-timing-function: var(--sf-ease-out);
  }

  /* ----- Duration / easing overrides (pair with .sf-transition) ----- */

  .sf-duration-fast   { transition-duration: var(--sf-duration-fast); }
  .sf-duration-normal { transition-duration: var(--sf-duration-normal); }
  .sf-duration-slow   { transition-duration: var(--sf-duration-slow); }

  .sf-ease-out    { transition-timing-function: var(--sf-ease-out); }
  .sf-ease-in     { transition-timing-function: var(--sf-ease-in); }
  .sf-ease-in-out { transition-timing-function: var(--sf-ease-in-out); }

  /* ----- Hover lift ----- */

  .sf-hover-lift {
    transition: box-shadow var(--sf-duration-fast) var(--sf-ease-out),
                translate   var(--sf-duration-fast) var(--sf-ease-out);
  }
  @media (hover: hover) {
    .sf-hover-lift:hover {
      translate:  0 var(--sf-hover-lift-y);
      box-shadow: var(--sf-hover-lift-shadow);
    }
  }

  /* ----- Filter / effects ----- */

  .sf-backdrop-blur { backdrop-filter: blur(var(--sf-backdrop-blur-size, var(--sf-blur-s))); -webkit-backdrop-filter: blur(var(--sf-backdrop-blur-size, var(--sf-blur-s))); }
  .sf-grayscale    { filter: grayscale(100%); }
  .sf-grayscale-0  { filter: grayscale(0); }

  /* ----- Fill / stroke - non-currentColor ----- */

  .sf-fill-primary { fill: var(--sf-primary); }
  .sf-fill-success { fill: var(--sf-success); }
  .sf-fill-warning { fill: var(--sf-warning); }
  .sf-fill-error   { fill: var(--sf-error); }
  .sf-fill-white   { fill: white; }
  .sf-fill-none    { fill: none; }
  .sf-stroke-none    { stroke: none; }
  .sf-stroke-width-1 { stroke-width: 1; }
  .sf-stroke-width-2 { stroke-width: 2; }

  /* ----- Text - decorative / gradient ----- */

  .sf-text-gradient {
    background: var(--sf-text-gradient, linear-gradient(to right, var(--sf-primary), var(--sf-accent)));
    -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
  }
  /* Optical vertical centering. Chrome 135+; ignored elsewhere. */
  @supports (text-box: trim-both cap alphabetic) {
    .sf-text-box-trim { text-box: trim-both cap alphabetic; }
  }

  /* ----- Elevation shorthand ----- */

  .sf-z-elevate {
    position: relative;
    z-index: var(--sf-z-raised);
    box-shadow: var(--sf-shadow-s);
  }

}

/* ==========================================================================
   A11Y OVERRIDES for visual utilities
   These live in @layer slashed.a11y (ranked higher than slashed.visual)
   so they can cancel visual effects when the user prefers reduced data.
   ========================================================================== */

@layer slashed.a11y {

  @media (prefers-reduced-data: reduce) {
    .sf-bg-gradient   { background: var(--sf-color-surface-2); }
    .sf-text-gradient { background: none; -webkit-text-fill-color: currentcolor; }
  }

}

/* ==========================================================================
   Dark-mode decorative variants (moved from slashed-utilities.css)
   Require slashed-utilities-visual.css to be loaded.
   ========================================================================== */
@layer slashed.utilities {

  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      .sf-dark\:sf-bg-surface      { background: var(--sf-color-surface); }
      .sf-dark\:sf-bg-neutral-dark { background: var(--sf-neutral-dark); }
      .sf-dark\:sf-border-strong   { border-color: var(--sf-color-border-strong); }
      .sf-dark\:sf-shadow-none     { box-shadow: none; }
    }
  }
  [data-theme="dark"] {
    .sf-dark\:sf-bg-surface      { background: var(--sf-color-surface); }
    .sf-dark\:sf-bg-neutral-dark { background: var(--sf-neutral-dark); }
    .sf-dark\:sf-border-strong   { border-color: var(--sf-color-border-strong); }
    .sf-dark\:sf-shadow-none     { box-shadow: none; }
  }

  /* ----- Pulse animation utility ----- */
  /* Binds the pulse @keyframes (slashed-animations.css) to a utility class.
     Use for live indicators, recording dots, announcement dots, online status.
     Pair with .sf-dot for a self-contained pulsing dot:
       <span class="sf-dot sf-pulse" aria-hidden="true"></span> */

  .sf-dot {
    display: inline-block;
    inline-size: 0.5em;
    block-size: 0.5em;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
  }

  .sf-pulse { animation: pulse 2s ease-in-out infinite; }
  .sf-pulse--slow { animation-duration: 3s; }
  .sf-pulse--fast { animation-duration: 1s; }

  @media (prefers-reduced-motion: reduce) {
    .sf-pulse,
    .sf-pulse--slow,
    .sf-pulse--fast { animation: none; }
  }

  /* ----- SVG mockup colour palette ----- */
  /* Binds framework tokens to SVG fill/stroke for browser-window mockups,
     screenshot palettes, and diagram illustrations.
     Apply classes directly to SVG paths/rects. Adapt automatically to dark mode.
     Markup:
       <svg viewBox="…" role="img" aria-label="…">
         <rect class="sf-mockup__chrome" …/>
         <path class="sf-mockup__text" …/>
       </svg> */

  .sf-mockup__chrome       { fill: var(--sf-color-surface-3); }
  .sf-mockup__chrome-dot   { fill: var(--sf-color-border-strong); }
  .sf-mockup__urlbar       { fill: var(--sf-color-surface-2); }
  .sf-mockup__surface      { fill: var(--sf-color-surface); }
  .sf-mockup__surface-alt  { fill: var(--sf-color-surface-2); }
  .sf-mockup__divider      { fill: var(--sf-color-border); stroke: none; }
  .sf-mockup__text         { fill: var(--sf-color-text); }
  .sf-mockup__text-muted   { fill: var(--sf-color-text-muted); }
  .sf-mockup__accent       { fill: var(--sf-primary); }
  .sf-mockup__accent-muted { fill: var(--sf-primary-200); }
  .sf-mockup__stroke       { fill: none; stroke: var(--sf-color-border); stroke-width: 1; }
  .sf-mockup__stroke-accent { fill: none; stroke: var(--sf-primary); stroke-width: 1.5; }

}

/* ==========================================================================
   SLASHED Animations — v0.6.19.1
   Named @keyframes library + .animate-* utility classes.

   Opt-in — link separately when needed. REQUIRES tokens-default.css (or
   slashed-full.css) to be loaded first; this file consumes --duration-*,
   --ease-* tokens with no fallbacks per the framework's anti-break-fallbacks
   policy. Loaded standalone, the .animate-* utilities resolve invalid:
     <link rel="stylesheet" href="slashed-full.css">         <!-- required -->
     <link rel="stylesheet" href="slashed-animations.css">   <!-- opt-in -->

   Layer: slashed.animations — sits between slashed.visual and slashed.a11y.
   The slashed.a11y layer beats this one, which means .motion-reduce:* and
   prefers-reduced-motion overrides in slashed-core.css always win.

   Motion safety: all .animate-* utility classes are wrapped in
   @media (prefers-reduced-motion: no-preference) so they are inert for
   users who have requested reduced motion. The @keyframes themselves are
   always defined (they must exist even if not used, so references in
   slashed.base and slashed.a11y resolve correctly).
   ========================================================================== */

@layer slashed.reset, slashed.base, slashed.layout, slashed.components, slashed.utilities, slashed.visual, slashed.animations, slashed.a11y, slashed.overrides;

/* ==========================================================================
   @KEYFRAMES — always defined, no media-query gate
   (CSS requires the name to be present for animation: references to resolve)
   ========================================================================== */

/* ----- Fade ----- */
@keyframes fade-in       { from { opacity: 0; } }
@keyframes fade-out      { to   { opacity: 0; } }

/* ----- Slide ----- */
@keyframes slide-in-up    { from { opacity: 0; translate: 0  1rem; } }
@keyframes slide-in-down  { from { opacity: 0; translate: 0 -1rem; } }
@keyframes slide-in-left  { from { opacity: 0; translate: -1rem 0; } }
@keyframes slide-in-right { from { opacity: 0; translate:  1rem 0; } }

/* ----- Scale ----- */
@keyframes scale-in  { from { opacity: 0; scale: 0.95; } }
@keyframes scale-out { to   { opacity: 0; scale: 0.95; } }

/* ----- Spin ----- */
@keyframes spin { to { rotate: 360deg; } }

/* ----- Pulse ----- */
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.5; }
}

/* ----- Ping (ripple-out) ----- */
@keyframes ping {
  75%, 100% { scale: 2; opacity: 0; }
}

/* ----- Bounce ----- */
@keyframes bounce {
  0%, 100% { translate: 0 0;      animation-timing-function: cubic-bezier(0.8, 0, 1, 1); }
  50%       { translate: 0 -25%;  animation-timing-function: cubic-bezier(0, 0, 0.2, 1); }
}

/* ----- Shake (attention-seeker) ----- */
@keyframes shake {
  0%, 100% { translate: 0; }
  10%, 50%, 90% { translate: -4px 0; }
  30%, 70%      { translate:  4px 0; }
}

/* ==========================================================================
   .animate-* UTILITY CLASSES
   Guarded by prefers-reduced-motion: no-preference — inert for reduced-motion.
   All use `animation-fill-mode: both` so the start state is applied immediately
   and the end state persists after the animation completes.
   ========================================================================== */

@layer slashed.animations {

  @media (prefers-reduced-motion: no-preference) {

    /* ----- Base animation variables ----- */
    :root {
      --sf-anim-duration: var(--sf-duration-normal);
      --sf-anim-easing:   var(--sf-ease-out);
      --sf-anim-delay:    0s;
      --sf-anim-fill:     both;
    }

    /* ----- Fade ----- */
    .sf-animate-fade-in  { animation: fade-in  var(--sf-anim-duration) var(--sf-anim-easing) var(--sf-anim-delay) var(--sf-anim-fill); }
    .sf-animate-fade-out { animation: fade-out var(--sf-anim-duration) var(--sf-anim-easing) var(--sf-anim-delay) var(--sf-anim-fill); }

    /* ----- Slide ----- */
    .sf-animate-slide-in-up    { animation: slide-in-up    var(--sf-anim-duration) var(--sf-anim-easing) var(--sf-anim-delay) var(--sf-anim-fill); }
    .sf-animate-slide-in-down  { animation: slide-in-down  var(--sf-anim-duration) var(--sf-anim-easing) var(--sf-anim-delay) var(--sf-anim-fill); }
    .sf-animate-slide-in-left  { animation: slide-in-left  var(--sf-anim-duration) var(--sf-anim-easing) var(--sf-anim-delay) var(--sf-anim-fill); }
    .sf-animate-slide-in-right { animation: slide-in-right var(--sf-anim-duration) var(--sf-anim-easing) var(--sf-anim-delay) var(--sf-anim-fill); }

    /* ----- Scale ----- */
    .sf-animate-scale-in  { animation: scale-in  var(--sf-anim-duration) var(--sf-anim-easing) var(--sf-anim-delay) var(--sf-anim-fill); }
    .sf-animate-scale-out { animation: scale-out var(--sf-anim-duration) var(--sf-anim-easing) var(--sf-anim-delay) var(--sf-anim-fill); }

    /* ----- Continuous ----- */
    /* Duration instance tokens allow per-element speed override:
       style="--sf-spin-duration: 0.5s"  — fast spinner
       style="--sf-pulse-duration: 3s"   — slow pulse     */
    .sf-animate-spin   { animation: spin   var(--sf-spin-duration,   1s) linear infinite; }
    .sf-animate-pulse  { animation: pulse  var(--sf-pulse-duration,  2s) var(--sf-ease-in-out) infinite; }
    .sf-animate-ping   { animation: ping   var(--sf-ping-duration,   1s) var(--sf-ease-out) infinite; }
    .sf-animate-bounce { animation: bounce var(--sf-bounce-duration, 1s) infinite; }

    /* ----- Attention ----- */
    .sf-animate-shake { animation: shake var(--sf-anim-duration) var(--sf-anim-easing) var(--sf-anim-delay) var(--sf-anim-fill); }

  }

  /* ----- Modifiers (intent-independent — work for any animation, including
     consumer-authored ones, regardless of prefers-reduced-motion). ----- */

  /* ----- Duration overrides ----- */
  .sf-anim-fast   { --sf-anim-duration: var(--sf-duration-fast); }
  .sf-anim-normal { --sf-anim-duration: var(--sf-duration-normal); }
  .sf-anim-slow   { --sf-anim-duration: var(--sf-duration-slow); }

  /* ----- Delay modifiers ----- */
  .sf-anim-delay-75   { --sf-anim-delay: 75ms;  }
  .sf-anim-delay-150  { --sf-anim-delay: 150ms; }
  .sf-anim-delay-300  { --sf-anim-delay: 300ms; }
  .sf-anim-delay-500  { --sf-anim-delay: 500ms; }
  .sf-anim-delay-700  { --sf-anim-delay: 700ms; }
  .sf-anim-delay-1000 { --sf-anim-delay: 1000ms; }

  /* ----- Fill mode ----- */
  .sf-anim-fill-none    { --sf-anim-fill: none; }
  .sf-anim-fill-forward { --sf-anim-fill: forwards; }
  .sf-anim-fill-both    { --sf-anim-fill: both; }

  /* ----- Play state ----- */
  .sf-anim-paused  { animation-play-state: paused; }
  .sf-anim-running { animation-play-state: running; }

  /* ----- Iteration ----- */
  .sf-anim-once     { animation-iteration-count: 1; }
  .sf-anim-infinite { animation-iteration-count: infinite; }

}

/* ==========================================================================
   SLASHED Viewport Utilities — v0.6.19.1
   Viewport-breakpoint prefix classes: sm: md: lg: xl:
   Bundled into slashed-full.css. Requires the slashed.utilities layer
   established by slashed-utilities.css (or slashed-essential.css /
   slashed-full.css).

   LOAD ORDER
     Already included in slashed-full.css.
     When using slashed-essential.css, link this file separately:
       <link rel="stylesheet" href="css/slashed-essential.css">
       <link rel="stylesheet" href="css/slashed-utilities-viewport.css">

   WHEN TO REACH FOR THESE
   Projects using the container-query path (cq-sm: cq-md: cq-lg: cq-xl:)
   and fluid tokens do not need viewport breakpoints for component or layout
   work. These classes are the escape hatch for the few cases that are
   genuinely viewport-level (e.g. collapsing a top-level navigation).

   CUSTOMISING BREAKPOINTS
   CSS cannot express @media thresholds as custom properties. To use
   different breakpoints, use slashed-essential.css and link your own
   modified copy of this file (slashed-full.css bakes in the default values
   and cannot be customised). Run four find-replace passes:
     sm:  30em  (480px)  →  find: (min-width: 30em)
     md:  48em  (768px)  →  find: (min-width: 48em)
     lg:  64em  (1024px) →  find: (min-width: 64em)
     xl:  80em  (1280px) →  find: (min-width: 80em)
   slashed-essential.css contains zero viewport-size @media rules.
   ========================================================================== */

@layer slashed.utilities {

  /* ----- Viewport responsive variants ----- */
  /* Viewport-level layout switches for the rare cases where the
     container-query path (cq-sm: / cq-md: / cq-lg: / cq-xl:) is
     insufficient — typically top-level navigation and page-structure
     concerns. For component and layout work, prefer cq-* utilities. */

  @media (min-width: 30em) { /* sm — must match sm=30em md=48em lg=64em xl=80em */
    .sm\:sf-flex      { display: flex; }
    .sm\:sf-block     { display: block; }
    .sm\:sf-grid      { display: grid; }
    .sm\:sf-hidden    { display: none; }
    .sm\:sf-flex-row  { flex-direction: row; }
    .sm\:sf-flex-col  { flex-direction: column; }
    .sm\:sf-grid-2    { grid-template-columns: repeat(2, 1fr); }
    .sm\:sf-grid-3    { grid-template-columns: repeat(3, 1fr); }
    .sm\:sf-grid-4    { grid-template-columns: repeat(4, 1fr); }
    .sm\:sf-sticky    { position: sticky; inset-block-start: var(--sf-sticky-top, 0); }
    .sm\:sf-gap-xs    { gap: var(--sf-space-xs); }
    .sm\:sf-gap-s     { gap: var(--sf-space-s); }
    .sm\:sf-gap-m     { gap: var(--sf-space-m); }
    .sm\:sf-gap-l     { gap: var(--sf-space-l); }
    .sm\:sf-gap-xl    { gap: var(--sf-space-xl); }
    .sm\:sf-gap-2xl   { gap: var(--sf-space-2xl); }
    .sm\:sf-items-start   { align-items: flex-start; }
    .sm\:sf-items-center  { align-items: center; }
    .sm\:sf-items-end     { align-items: flex-end; }
    .sm\:sf-justify-start   { justify-content: flex-start; }
    .sm\:sf-justify-center  { justify-content: center; }
    .sm\:sf-justify-between { justify-content: space-between; }
    .sm\:sf-col-span-2    { grid-column: span 2; }
    .sm\:sf-col-span-full { grid-column: 1 / -1; }
    .sm\:sf-text-left     { text-align: start; }
    .sm\:sf-text-center   { text-align: center; }
    .sm\:sf-text-right    { text-align: end; }
    .sm\:sf-p-0   { padding: 0; }
    .sm\:sf-p-xs  { padding: var(--sf-space-xs); }
    .sm\:sf-p-s   { padding: var(--sf-space-s); }
    .sm\:sf-p-m   { padding: var(--sf-space-m); }
    .sm\:sf-p-l   { padding: var(--sf-space-l); }
    .sm\:sf-p-xl  { padding: var(--sf-space-xl); }
    .sm\:sf-px-0  { padding-inline: 0; }
    .sm\:sf-px-xs { padding-inline: var(--sf-space-xs); }
    .sm\:sf-px-s  { padding-inline: var(--sf-space-s); }
    .sm\:sf-px-m  { padding-inline: var(--sf-space-m); }
    .sm\:sf-px-l  { padding-inline: var(--sf-space-l); }
    .sm\:sf-px-xl { padding-inline: var(--sf-space-xl); }
    .sm\:sf-py-0  { padding-block: 0; }
    .sm\:sf-py-xs { padding-block: var(--sf-space-xs); }
    .sm\:sf-py-s  { padding-block: var(--sf-space-s); }
    .sm\:sf-py-m  { padding-block: var(--sf-space-m); }
    .sm\:sf-py-l  { padding-block: var(--sf-space-l); }
    .sm\:sf-py-xl { padding-block: var(--sf-space-xl); }
    .sm\:sf-pt-0  { padding-block-start: 0; }
    .sm\:sf-pt-s  { padding-block-start: var(--sf-space-s); }
    .sm\:sf-pt-m  { padding-block-start: var(--sf-space-m); }
    .sm\:sf-pt-l  { padding-block-start: var(--sf-space-l); }
    .sm\:sf-pt-xl { padding-block-start: var(--sf-space-xl); }
    .sm\:sf-pb-0  { padding-block-end: 0; }
    .sm\:sf-pb-s  { padding-block-end: var(--sf-space-s); }
    .sm\:sf-pb-m  { padding-block-end: var(--sf-space-m); }
    .sm\:sf-pb-l  { padding-block-end: var(--sf-space-l); }
    .sm\:sf-pb-xl { padding-block-end: var(--sf-space-xl); }
    .sm\:sf-mt-0  { margin-block-start: 0; }
    .sm\:sf-mt-s  { margin-block-start: var(--sf-space-s); }
    .sm\:sf-mt-m  { margin-block-start: var(--sf-space-m); }
    .sm\:sf-mt-l  { margin-block-start: var(--sf-space-l); }
    .sm\:sf-mb-0  { margin-block-end: 0; }
    .sm\:sf-mb-s  { margin-block-end: var(--sf-space-s); }
    .sm\:sf-mb-m  { margin-block-end: var(--sf-space-m); }
    .sm\:sf-mb-l  { margin-block-end: var(--sf-space-l); }
    .sm\:sf-ps-0  { padding-inline-start: 0; }
    .sm\:sf-ps-s  { padding-inline-start: var(--sf-space-s); }
    .sm\:sf-ps-m  { padding-inline-start: var(--sf-space-m); }
    .sm\:sf-ps-l  { padding-inline-start: var(--sf-space-l); }
    .sm\:sf-ps-xl { padding-inline-start: var(--sf-space-xl); }
    .sm\:sf-pe-0  { padding-inline-end: 0; }
    .sm\:sf-pe-s  { padding-inline-end: var(--sf-space-s); }
    .sm\:sf-pe-m  { padding-inline-end: var(--sf-space-m); }
    .sm\:sf-pe-l  { padding-inline-end: var(--sf-space-l); }
    .sm\:sf-pe-xl { padding-inline-end: var(--sf-space-xl); }
    .sm\:sf-ms-0  { margin-inline-start: 0; }
    .sm\:sf-ms-s  { margin-inline-start: var(--sf-space-s); }
    .sm\:sf-ms-m  { margin-inline-start: var(--sf-space-m); }
    .sm\:sf-ms-l  { margin-inline-start: var(--sf-space-l); }
    .sm\:sf-me-0  { margin-inline-end: 0; }
    .sm\:sf-me-s  { margin-inline-end: var(--sf-space-s); }
    .sm\:sf-me-m  { margin-inline-end: var(--sf-space-m); }
    .sm\:sf-me-l  { margin-inline-end: var(--sf-space-l); }
    .sm\:sf-gap-0 { gap: 0; }
    .sm\:sf-order-first { order: -1; }
    .sm\:sf-order-last  { order: 13; }
    .sm\:sf-order-none  { order: 0; }
    .sm\:sf-order-0     { order: 0; }
    .sm\:sf-order-1     { order: 1; }
    .sm\:sf-order-2     { order: 2; }
    .sm\:sf-order-3     { order: 3; }
    .sm\:sf-order-4     { order: 4; }
    .sm\:sf-order-5     { order: 5; }
    .sm\:sf-order-6     { order: 6; }
    .sm\:sf-order-7     { order: 7; }
    .sm\:sf-order-8     { order: 8; }
    .sm\:sf-order-9     { order: 9; }
    .sm\:sf-order-10    { order: 10; }
    .sm\:sf-order-11    { order: 11; }
    .sm\:sf-order-12    { order: 12; }
  }

  @media (min-width: 48em) { /* md — must match sm=30em md=48em lg=64em xl=80em */
    .md\:sf-flex      { display: flex; }
    .md\:sf-block     { display: block; }
    .md\:sf-grid      { display: grid; }
    .md\:sf-hidden    { display: none; }
    .md\:sf-flex-row  { flex-direction: row; }
    .md\:sf-flex-col  { flex-direction: column; }
    .md\:sf-grid-2    { grid-template-columns: repeat(2, 1fr); }
    .md\:sf-grid-3    { grid-template-columns: repeat(3, 1fr); }
    .md\:sf-grid-4    { grid-template-columns: repeat(4, 1fr); }
    .md\:sf-gap-xs    { gap: var(--sf-space-xs); }
    .md\:sf-gap-s     { gap: var(--sf-space-s); }
    .md\:sf-gap-m     { gap: var(--sf-space-m); }
    .md\:sf-gap-l     { gap: var(--sf-space-l); }
    .md\:sf-gap-xl    { gap: var(--sf-space-xl); }
    .md\:sf-gap-2xl   { gap: var(--sf-space-2xl); }
    .md\:sf-items-start   { align-items: flex-start; }
    .md\:sf-items-center  { align-items: center; }
    .md\:sf-items-end     { align-items: flex-end; }
    .md\:sf-justify-start   { justify-content: flex-start; }
    .md\:sf-justify-center  { justify-content: center; }
    .md\:sf-justify-between { justify-content: space-between; }
    .md\:sf-col-span-2    { grid-column: span 2; }
    .md\:sf-col-span-full { grid-column: 1 / -1; }
    .md\:sf-text-left     { text-align: start; }
    .md\:sf-text-center   { text-align: center; }
    .md\:sf-text-right    { text-align: end; }
    .md\:sf-p-0   { padding: 0; }
    .md\:sf-p-xs  { padding: var(--sf-space-xs); }
    .md\:sf-p-s   { padding: var(--sf-space-s); }
    .md\:sf-p-m   { padding: var(--sf-space-m); }
    .md\:sf-p-l   { padding: var(--sf-space-l); }
    .md\:sf-p-xl  { padding: var(--sf-space-xl); }
    .md\:sf-px-0  { padding-inline: 0; }
    .md\:sf-px-xs { padding-inline: var(--sf-space-xs); }
    .md\:sf-px-s  { padding-inline: var(--sf-space-s); }
    .md\:sf-px-m  { padding-inline: var(--sf-space-m); }
    .md\:sf-px-l  { padding-inline: var(--sf-space-l); }
    .md\:sf-px-xl { padding-inline: var(--sf-space-xl); }
    .md\:sf-py-0  { padding-block: 0; }
    .md\:sf-py-xs { padding-block: var(--sf-space-xs); }
    .md\:sf-py-s  { padding-block: var(--sf-space-s); }
    .md\:sf-py-m  { padding-block: var(--sf-space-m); }
    .md\:sf-py-l  { padding-block: var(--sf-space-l); }
    .md\:sf-py-xl { padding-block: var(--sf-space-xl); }
    .md\:sf-pt-0  { padding-block-start: 0; }
    .md\:sf-pt-s  { padding-block-start: var(--sf-space-s); }
    .md\:sf-pt-m  { padding-block-start: var(--sf-space-m); }
    .md\:sf-pt-l  { padding-block-start: var(--sf-space-l); }
    .md\:sf-pt-xl { padding-block-start: var(--sf-space-xl); }
    .md\:sf-pb-0  { padding-block-end: 0; }
    .md\:sf-pb-s  { padding-block-end: var(--sf-space-s); }
    .md\:sf-pb-m  { padding-block-end: var(--sf-space-m); }
    .md\:sf-pb-l  { padding-block-end: var(--sf-space-l); }
    .md\:sf-pb-xl { padding-block-end: var(--sf-space-xl); }
    .md\:sf-mt-0  { margin-block-start: 0; }
    .md\:sf-mt-s  { margin-block-start: var(--sf-space-s); }
    .md\:sf-mt-m  { margin-block-start: var(--sf-space-m); }
    .md\:sf-mt-l  { margin-block-start: var(--sf-space-l); }
    .md\:sf-mb-0  { margin-block-end: 0; }
    .md\:sf-mb-s  { margin-block-end: var(--sf-space-s); }
    .md\:sf-mb-m  { margin-block-end: var(--sf-space-m); }
    .md\:sf-mb-l  { margin-block-end: var(--sf-space-l); }
    .md\:sf-ps-0  { padding-inline-start: 0; }
    .md\:sf-ps-s  { padding-inline-start: var(--sf-space-s); }
    .md\:sf-ps-m  { padding-inline-start: var(--sf-space-m); }
    .md\:sf-ps-l  { padding-inline-start: var(--sf-space-l); }
    .md\:sf-ps-xl { padding-inline-start: var(--sf-space-xl); }
    .md\:sf-pe-0  { padding-inline-end: 0; }
    .md\:sf-pe-s  { padding-inline-end: var(--sf-space-s); }
    .md\:sf-pe-m  { padding-inline-end: var(--sf-space-m); }
    .md\:sf-pe-l  { padding-inline-end: var(--sf-space-l); }
    .md\:sf-pe-xl { padding-inline-end: var(--sf-space-xl); }
    .md\:sf-ms-0  { margin-inline-start: 0; }
    .md\:sf-ms-s  { margin-inline-start: var(--sf-space-s); }
    .md\:sf-ms-m  { margin-inline-start: var(--sf-space-m); }
    .md\:sf-ms-l  { margin-inline-start: var(--sf-space-l); }
    .md\:sf-me-0  { margin-inline-end: 0; }
    .md\:sf-me-s  { margin-inline-end: var(--sf-space-s); }
    .md\:sf-me-m  { margin-inline-end: var(--sf-space-m); }
    .md\:sf-me-l  { margin-inline-end: var(--sf-space-l); }
    .md\:sf-gap-0 { gap: 0; }
    .md\:sf-order-first { order: -1; }
    .md\:sf-order-last  { order: 13; }
    .md\:sf-order-none  { order: 0; }
    .md\:sf-order-0     { order: 0; }
    .md\:sf-order-1     { order: 1; }
    .md\:sf-order-2     { order: 2; }
    .md\:sf-order-3     { order: 3; }
    .md\:sf-order-4     { order: 4; }
    .md\:sf-order-5     { order: 5; }
    .md\:sf-order-6     { order: 6; }
    .md\:sf-order-7     { order: 7; }
    .md\:sf-order-8     { order: 8; }
    .md\:sf-order-9     { order: 9; }
    .md\:sf-order-10    { order: 10; }
    .md\:sf-order-11    { order: 11; }
    .md\:sf-order-12    { order: 12; }
    .md\:sf-sticky      { position: sticky; inset-block-start: var(--sf-sticky-top, 0); }
  }

  @media (min-width: 64em) { /* lg — must match sm=30em md=48em lg=64em xl=80em */
    .lg\:sf-flex      { display: flex; }
    .lg\:sf-block     { display: block; }
    .lg\:sf-grid      { display: grid; }
    .lg\:sf-hidden    { display: none; }
    .lg\:sf-flex-row  { flex-direction: row; }
    .lg\:sf-flex-col  { flex-direction: column; }
    .lg\:sf-grid-2    { grid-template-columns: repeat(2, 1fr); }
    .lg\:sf-grid-3    { grid-template-columns: repeat(3, 1fr); }
    .lg\:sf-grid-4    { grid-template-columns: repeat(4, 1fr); }
    .lg\:sf-gap-xs    { gap: var(--sf-space-xs); }
    .lg\:sf-gap-s     { gap: var(--sf-space-s); }
    .lg\:sf-gap-m     { gap: var(--sf-space-m); }
    .lg\:sf-gap-l     { gap: var(--sf-space-l); }
    .lg\:sf-gap-xl    { gap: var(--sf-space-xl); }
    .lg\:sf-gap-2xl   { gap: var(--sf-space-2xl); }
    .lg\:sf-items-start   { align-items: flex-start; }
    .lg\:sf-items-center  { align-items: center; }
    .lg\:sf-items-end     { align-items: flex-end; }
    .lg\:sf-justify-start   { justify-content: flex-start; }
    .lg\:sf-justify-center  { justify-content: center; }
    .lg\:sf-justify-between { justify-content: space-between; }
    .lg\:sf-col-span-2    { grid-column: span 2; }
    .lg\:sf-col-span-full { grid-column: 1 / -1; }
    .lg\:sf-text-left     { text-align: start; }
    .lg\:sf-text-center   { text-align: center; }
    .lg\:sf-text-right    { text-align: end; }
    .lg\:sf-p-0   { padding: 0; }
    .lg\:sf-p-xs  { padding: var(--sf-space-xs); }
    .lg\:sf-p-s   { padding: var(--sf-space-s); }
    .lg\:sf-p-m   { padding: var(--sf-space-m); }
    .lg\:sf-p-l   { padding: var(--sf-space-l); }
    .lg\:sf-p-xl  { padding: var(--sf-space-xl); }
    .lg\:sf-px-0  { padding-inline: 0; }
    .lg\:sf-px-xs { padding-inline: var(--sf-space-xs); }
    .lg\:sf-px-s  { padding-inline: var(--sf-space-s); }
    .lg\:sf-px-m  { padding-inline: var(--sf-space-m); }
    .lg\:sf-px-l  { padding-inline: var(--sf-space-l); }
    .lg\:sf-px-xl { padding-inline: var(--sf-space-xl); }
    .lg\:sf-py-0  { padding-block: 0; }
    .lg\:sf-py-xs { padding-block: var(--sf-space-xs); }
    .lg\:sf-py-s  { padding-block: var(--sf-space-s); }
    .lg\:sf-py-m  { padding-block: var(--sf-space-m); }
    .lg\:sf-py-l  { padding-block: var(--sf-space-l); }
    .lg\:sf-py-xl { padding-block: var(--sf-space-xl); }
    .lg\:sf-pt-0  { padding-block-start: 0; }
    .lg\:sf-pt-s  { padding-block-start: var(--sf-space-s); }
    .lg\:sf-pt-m  { padding-block-start: var(--sf-space-m); }
    .lg\:sf-pt-l  { padding-block-start: var(--sf-space-l); }
    .lg\:sf-pt-xl { padding-block-start: var(--sf-space-xl); }
    .lg\:sf-pb-0  { padding-block-end: 0; }
    .lg\:sf-pb-s  { padding-block-end: var(--sf-space-s); }
    .lg\:sf-pb-m  { padding-block-end: var(--sf-space-m); }
    .lg\:sf-pb-l  { padding-block-end: var(--sf-space-l); }
    .lg\:sf-pb-xl { padding-block-end: var(--sf-space-xl); }
    .lg\:sf-mt-0  { margin-block-start: 0; }
    .lg\:sf-mt-s  { margin-block-start: var(--sf-space-s); }
    .lg\:sf-mt-m  { margin-block-start: var(--sf-space-m); }
    .lg\:sf-mt-l  { margin-block-start: var(--sf-space-l); }
    .lg\:sf-mb-0  { margin-block-end: 0; }
    .lg\:sf-mb-s  { margin-block-end: var(--sf-space-s); }
    .lg\:sf-mb-m  { margin-block-end: var(--sf-space-m); }
    .lg\:sf-mb-l  { margin-block-end: var(--sf-space-l); }
    .lg\:sf-ps-0  { padding-inline-start: 0; }
    .lg\:sf-ps-s  { padding-inline-start: var(--sf-space-s); }
    .lg\:sf-ps-m  { padding-inline-start: var(--sf-space-m); }
    .lg\:sf-ps-l  { padding-inline-start: var(--sf-space-l); }
    .lg\:sf-ps-xl { padding-inline-start: var(--sf-space-xl); }
    .lg\:sf-pe-0  { padding-inline-end: 0; }
    .lg\:sf-pe-s  { padding-inline-end: var(--sf-space-s); }
    .lg\:sf-pe-m  { padding-inline-end: var(--sf-space-m); }
    .lg\:sf-pe-l  { padding-inline-end: var(--sf-space-l); }
    .lg\:sf-pe-xl { padding-inline-end: var(--sf-space-xl); }
    .lg\:sf-ms-0  { margin-inline-start: 0; }
    .lg\:sf-ms-s  { margin-inline-start: var(--sf-space-s); }
    .lg\:sf-ms-m  { margin-inline-start: var(--sf-space-m); }
    .lg\:sf-ms-l  { margin-inline-start: var(--sf-space-l); }
    .lg\:sf-me-0  { margin-inline-end: 0; }
    .lg\:sf-me-s  { margin-inline-end: var(--sf-space-s); }
    .lg\:sf-me-m  { margin-inline-end: var(--sf-space-m); }
    .lg\:sf-me-l  { margin-inline-end: var(--sf-space-l); }
    .lg\:sf-gap-0 { gap: 0; }
    .lg\:sf-order-first { order: -1; }
    .lg\:sf-order-last  { order: 13; }
    .lg\:sf-order-none  { order: 0; }
    .lg\:sf-order-0     { order: 0; }
    .lg\:sf-order-1     { order: 1; }
    .lg\:sf-order-2     { order: 2; }
    .lg\:sf-order-3     { order: 3; }
    .lg\:sf-order-4     { order: 4; }
    .lg\:sf-order-5     { order: 5; }
    .lg\:sf-order-6     { order: 6; }
    .lg\:sf-order-7     { order: 7; }
    .lg\:sf-order-8     { order: 8; }
    .lg\:sf-order-9     { order: 9; }
    .lg\:sf-order-10    { order: 10; }
    .lg\:sf-order-11    { order: 11; }
    .lg\:sf-order-12    { order: 12; }
  }

  @media (min-width: 80em) { /* xl — must match sm=30em md=48em lg=64em xl=80em */
    .xl\:sf-flex      { display: flex; }
    .xl\:sf-block     { display: block; }
    .xl\:sf-grid      { display: grid; }
    .xl\:sf-hidden    { display: none; }
    .xl\:sf-flex-row  { flex-direction: row; }
    .xl\:sf-flex-col  { flex-direction: column; }
    .xl\:sf-grid-2    { grid-template-columns: repeat(2, 1fr); }
    .xl\:sf-grid-3    { grid-template-columns: repeat(3, 1fr); }
    .xl\:sf-grid-4    { grid-template-columns: repeat(4, 1fr); }
    .xl\:sf-gap-xs    { gap: var(--sf-space-xs); }
    .xl\:sf-gap-s     { gap: var(--sf-space-s); }
    .xl\:sf-gap-m     { gap: var(--sf-space-m); }
    .xl\:sf-gap-l     { gap: var(--sf-space-l); }
    .xl\:sf-gap-xl    { gap: var(--sf-space-xl); }
    .xl\:sf-gap-2xl   { gap: var(--sf-space-2xl); }
    .xl\:sf-items-start   { align-items: flex-start; }
    .xl\:sf-items-center  { align-items: center; }
    .xl\:sf-items-end     { align-items: flex-end; }
    .xl\:sf-justify-start   { justify-content: flex-start; }
    .xl\:sf-justify-center  { justify-content: center; }
    .xl\:sf-justify-between { justify-content: space-between; }
    .xl\:sf-col-span-2    { grid-column: span 2; }
    .xl\:sf-col-span-full { grid-column: 1 / -1; }
    .xl\:sf-text-left     { text-align: start; }
    .xl\:sf-text-center   { text-align: center; }
    .xl\:sf-text-right    { text-align: end; }
    .xl\:sf-p-0   { padding: 0; }
    .xl\:sf-p-xs  { padding: var(--sf-space-xs); }
    .xl\:sf-p-s   { padding: var(--sf-space-s); }
    .xl\:sf-p-m   { padding: var(--sf-space-m); }
    .xl\:sf-p-l   { padding: var(--sf-space-l); }
    .xl\:sf-p-xl  { padding: var(--sf-space-xl); }
    .xl\:sf-px-0  { padding-inline: 0; }
    .xl\:sf-px-xs { padding-inline: var(--sf-space-xs); }
    .xl\:sf-px-s  { padding-inline: var(--sf-space-s); }
    .xl\:sf-px-m  { padding-inline: var(--sf-space-m); }
    .xl\:sf-px-l  { padding-inline: var(--sf-space-l); }
    .xl\:sf-px-xl { padding-inline: var(--sf-space-xl); }
    .xl\:sf-py-0  { padding-block: 0; }
    .xl\:sf-py-xs { padding-block: var(--sf-space-xs); }
    .xl\:sf-py-s  { padding-block: var(--sf-space-s); }
    .xl\:sf-py-m  { padding-block: var(--sf-space-m); }
    .xl\:sf-py-l  { padding-block: var(--sf-space-l); }
    .xl\:sf-py-xl { padding-block: var(--sf-space-xl); }
    .xl\:sf-pt-0  { padding-block-start: 0; }
    .xl\:sf-pt-s  { padding-block-start: var(--sf-space-s); }
    .xl\:sf-pt-m  { padding-block-start: var(--sf-space-m); }
    .xl\:sf-pt-l  { padding-block-start: var(--sf-space-l); }
    .xl\:sf-pt-xl { padding-block-start: var(--sf-space-xl); }
    .xl\:sf-pb-0  { padding-block-end: 0; }
    .xl\:sf-pb-s  { padding-block-end: var(--sf-space-s); }
    .xl\:sf-pb-m  { padding-block-end: var(--sf-space-m); }
    .xl\:sf-pb-l  { padding-block-end: var(--sf-space-l); }
    .xl\:sf-pb-xl { padding-block-end: var(--sf-space-xl); }
    .xl\:sf-mt-0  { margin-block-start: 0; }
    .xl\:sf-mt-s  { margin-block-start: var(--sf-space-s); }
    .xl\:sf-mt-m  { margin-block-start: var(--sf-space-m); }
    .xl\:sf-mt-l  { margin-block-start: var(--sf-space-l); }
    .xl\:sf-mb-0  { margin-block-end: 0; }
    .xl\:sf-mb-s  { margin-block-end: var(--sf-space-s); }
    .xl\:sf-mb-m  { margin-block-end: var(--sf-space-m); }
    .xl\:sf-mb-l  { margin-block-end: var(--sf-space-l); }
    .xl\:sf-ps-0  { padding-inline-start: 0; }
    .xl\:sf-ps-s  { padding-inline-start: var(--sf-space-s); }
    .xl\:sf-ps-m  { padding-inline-start: var(--sf-space-m); }
    .xl\:sf-ps-l  { padding-inline-start: var(--sf-space-l); }
    .xl\:sf-ps-xl { padding-inline-start: var(--sf-space-xl); }
    .xl\:sf-pe-0  { padding-inline-end: 0; }
    .xl\:sf-pe-s  { padding-inline-end: var(--sf-space-s); }
    .xl\:sf-pe-m  { padding-inline-end: var(--sf-space-m); }
    .xl\:sf-pe-l  { padding-inline-end: var(--sf-space-l); }
    .xl\:sf-pe-xl { padding-inline-end: var(--sf-space-xl); }
    .xl\:sf-ms-0  { margin-inline-start: 0; }
    .xl\:sf-ms-s  { margin-inline-start: var(--sf-space-s); }
    .xl\:sf-ms-m  { margin-inline-start: var(--sf-space-m); }
    .xl\:sf-ms-l  { margin-inline-start: var(--sf-space-l); }
    .xl\:sf-me-0  { margin-inline-end: 0; }
    .xl\:sf-me-s  { margin-inline-end: var(--sf-space-s); }
    .xl\:sf-me-m  { margin-inline-end: var(--sf-space-m); }
    .xl\:sf-me-l  { margin-inline-end: var(--sf-space-l); }
    .xl\:sf-gap-0 { gap: 0; }
    .xl\:sf-order-first { order: -1; }
    .xl\:sf-order-last  { order: 13; }
    .xl\:sf-order-none  { order: 0; }
    .xl\:sf-order-0     { order: 0; }
    .xl\:sf-order-1     { order: 1; }
    .xl\:sf-order-2     { order: 2; }
    .xl\:sf-order-3     { order: 3; }
    .xl\:sf-order-4     { order: 4; }
    .xl\:sf-order-5     { order: 5; }
    .xl\:sf-order-6     { order: 6; }
    .xl\:sf-order-7     { order: 7; }
    .xl\:sf-order-8     { order: 8; }
    .xl\:sf-order-9     { order: 9; }
    .xl\:sf-order-10    { order: 10; }
    .xl\:sf-order-11    { order: 11; }
    .xl\:sf-order-12    { order: 12; }
  }

}
