/* === tokens/_primitives.css === */
/*
 * Vireo — Aurora token model · LAYER 1 PRIMITIVES
 * Source of truth: brief 01-tokens.md §1 (scales) + §2 (neutral ramps).
 * Mode-agnostic literals (one :root definition) EXCEPT shadows + semantic
 * ramps, which carry a [data-ax-theme="dark"] override. Verbatim values.
 * Token NAMES are spec; values are Aurora. Components consume Layer 2/3 only.
 */

/* ═══════════════════════════════════════════════════════════════════════
   §1 — PRIMITIVE SCALES
   ═══════════════════════════════════════════════════════════════════════ */
:root {
  /* ─────────────────────────────────────────────────────────
     SPACING — 4px base (spec 01 §6.1, unchanged)
     ───────────────────────────────────────────────────────── */
  --ax-space-0: 0;
  --ax-space-1: 4px;
  --ax-space-2: 8px;
  --ax-space-3: 12px;
  --ax-space-4: 16px;
  --ax-space-5: 20px;
  --ax-space-6: 24px;   /* default card padding */
  --ax-space-7: 28px;
  --ax-space-8: 32px;
  --ax-space-9: 36px;
  --ax-space-10: 40px;
  --ax-space-12: 48px;  /* = --ax-footer-h */
  --ax-space-16: 64px;
  --ax-space-20: 80px;

  /* ─────────────────────────────────────────────────────────
     RADIUS — Aurora HIGH-radius. Spec NAMES kept; values raised
     to match preview (--r-xl:24 --r-lg:18 --r-md:13 --r-sm:9).
     Mapping: cards=xl(24), large media=lg(18), buttons/inputs/
     popover-items=md(14), small controls/chips=sm(12), tags/
     badges/checkboxes=xs(8), pills=full.
     ───────────────────────────────────────────────────────── */
  --ax-radius-none: 0;
  --ax-radius-xs: 8px;     /* badges, tags, chips, checkboxes, legend swatches→ use 4-6px via xs scope if needed */
  --ax-radius-sm: 12px;    /* small controls, segmented-control pills(inner), donut legend dots use raw */
  --ax-radius-md: 14px;    /* buttons, inputs, dropdown items, popovers, modals (default surface radius for non-card) */
  --ax-radius-lg: 18px;    /* large cards, media tiles, image frames, promo card, gradient plate */
  --ax-radius-xl: 24px;    /* CARDS (default surface radius), customizer panel */
  --ax-radius-pill: 999px; /* toggles, avatars, status dots, true pills, search bar, chip-range, primary btn */

  /* ─────────────────────────────────────────────────────────
     TYPE SIZES + LEADING (spec 01 §4.2 NAMES kept; px values
     unchanged from spec EXCEPT base UI font-size = 14px to match
     Aurora preview body, see §7. Tracking kept from spec.)
     Each --ax-text-* is the FONT-SIZE; paired leading + weight +
     tracking listed in comment, applied via utility classes.
     ───────────────────────────────────────────────────────── */
  --ax-text-2xs: 11px;   /* lh 16  w500  +0.02em  micro-labels, super-headers, badges */
  --ax-text-xs:  12px;   /* lh 18  w500  +0.01em  captions, helper, timestamps, eyebrow */
  --ax-text-sm:  13px;   /* lh 20  w450  0        secondary body, dense table cells */
  --ax-text-base:15px;   /* lh 24  w450  0        default body (NOTE: chrome/dense UI may use 13-14, see §7) */
  --ax-text-md:  17px;   /* lh 26  w500  -0.005em lead text, card subtitles */
  --ax-text-lg:  20px;   /* lh 28  w560  -0.01em  card titles (H4) */
  --ax-text-xl:  24px;   /* lh 32  w600  -0.012em section titles (H3) */
  --ax-text-2xl: 30px;   /* lh 38  w600  -0.015em page titles (H2) */
  --ax-text-3xl: 38px;   /* lh 46  w640  -0.018em hero/greeting (H1) — Space Grotesk */
  --ax-text-4xl: 48px;   /* lh 54  w680  -0.02em  landing display — Space Grotesk */
  --ax-num-kpi:  32px;   /* lh 36  w600  -0.01em  KPI stat figures — Space Grotesk (display), tabular */

  /* line-height tokens (so utilities/components don't hard-code) */
  --ax-leading-2xs: 16px; --ax-leading-xs: 18px; --ax-leading-sm: 20px;
  --ax-leading-base: 24px; --ax-leading-md: 26px; --ax-leading-lg: 28px;
  --ax-leading-xl: 32px; --ax-leading-2xl: 38px; --ax-leading-3xl: 46px;
  --ax-leading-4xl: 54px; --ax-leading-kpi: 36px;

  /* font WEIGHTS (Inter/Space Grotesk supply 400/500/600/700;
     spec's 450/560/640/680 optical weights map to nearest loaded:
     450→400, 500→500, 560→600, 600→600, 640→700, 680→700) */
  --ax-weight-regular: 400;
  --ax-weight-text: 400;     /* spec 450 → 400 (Inter has no 450) */
  --ax-weight-medium: 500;
  --ax-weight-semibold: 600; /* spec 560 & 600 → 600 */
  --ax-weight-bold: 700;     /* spec 640 & 680 → 700 */

  /* ─────────────────────────────────────────────────────────
     ICON SIZES (spec 01 §9, unchanged)
     Tabler outline, 24x24 viewBox, currentColor, 1.75px stroke
     at 24px nominal (preview uses stroke-width="2" on its 24-grid;
     standardize to 1.75 for the build, 2.4 for delta arrows/sparks).
     ───────────────────────────────────────────────────────── */
  --ax-icon-xs: 14px;
  --ax-icon-sm: 16px;   /* default: inputs, buttons, menu items */
  --ax-icon-md: 20px;
  --ax-icon-lg: 24px;
  --ax-icon-xl: 32px;
  --ax-icon-stroke: 1.75;          /* default Tabler stroke */
  --ax-icon-stroke-bold: 2.4;      /* delta arrows, sparklines */

  /* ─────────────────────────────────────────────────────────
     Z-INDEX (spec 01 §15.3, unchanged)
     ───────────────────────────────────────────────────────── */
  --ax-z-base: 0;
  --ax-z-sticky: 100;
  --ax-z-header: 200;
  --ax-z-sidebar: 300;
  --ax-z-overlay-backdrop: 900;
  --ax-z-dropdown: 1000;
  --ax-z-drawer: 1100;
  --ax-z-modal: 1200;
  --ax-z-toast: 1300;
  --ax-z-command: 1400;
  --ax-z-customizer: 1500;

  /* ─────────────────────────────────────────────────────────
     MOTION durations + easings (spec 01 §12.1, unchanged)
     ───────────────────────────────────────────────────────── */
  --ax-motion-instant: 80ms;
  --ax-motion-fast: 140ms;
  --ax-motion-base: 200ms;
  --ax-motion-slow: 280ms;
  --ax-motion-deliberate: 380ms;
  --ax-ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --ax-ease-emphasized: cubic-bezier(0.3, 0, 0, 1);
  --ax-ease-exit: cubic-bezier(0.4, 0, 1, 1);
  --ax-ease-linear: linear;

  /* ─────────────────────────────────────────────────────────
     BREAKPOINTS (spec 01 §6.3, unchanged) — also bridged to
     Tailwind v4 --breakpoint-* in @theme (see app.css §8).
     ───────────────────────────────────────────────────────── */
  --ax-bp-xs: 0px;
  --ax-bp-sm: 576px;
  --ax-bp-md: 768px;   /* sidebar → overlay below this */
  --ax-bp-lg: 992px;
  --ax-bp-xl: 1200px;
  --ax-bp-2xl: 1400px; /* Boxed max applies */

  /* ─────────────────────────────────────────────────────────
     SHELL DIMENSION tokens (spec 01 §6.2, unchanged NAMES.
     Sidebar width nudged to Aurora preview 248px; spec says 264.
     USE 264px to honor spec contract; preview 248 is acceptable.
     Build agents: use 264px expanded / 76px compact per spec.)
     ───────────────────────────────────────────────────────── */
  --ax-sidebar-w: 264px;
  --ax-sidebar-w-compact: 76px;
  --ax-header-h: 60px;
  --ax-footer-h: 48px;
  --ax-container-boxed: 1320px;

  /* control heights (spec 01 §6.1) */
  --ax-control-h: 38px;          /* default */
  --ax-control-h-compact: 32px;
  --ax-control-h-lg: 44px;

  /* ─────────────────────────────────────────────────────────
     SHADOWS — Aurora GLOW shadows (spec NAMES kept).
     LIGHT mode = soft, low-opacity, neutral-dark glow.
     DARK mode override block below.
     none = resting cards still get the glass recipe's drop+inset,
     so --ax-shadow-none is literal `none` (recipe applies its own).
     ───────────────────────────────────────────────────────── */
  --ax-shadow-none: none;
  --ax-shadow-sm: 0 6px 18px -8px rgba(16,22,40,0.18), 0 2px 6px -2px rgba(16,22,40,0.10);
  --ax-shadow-md: 0 14px 36px -14px rgba(16,22,40,0.22), 0 4px 12px -6px rgba(16,22,40,0.12);
  --ax-shadow-lg: 0 28px 64px -20px rgba(16,22,40,0.28), 0 8px 20px -8px rgba(16,22,40,0.16);
  /* Aurora glass card resting shadow (light) — used by .ax-card recipe */
  --ax-shadow-card: 0 18px 44px -22px rgba(16,22,40,0.20), 0 2px 10px rgba(16,22,40,0.06);
  /* accent glow (re-derives from --ax-accent-rgb, see recipes §6) */
  --ax-glow-accent: 0 12px 26px -10px rgba(var(--ax-accent-rgb), 0.45);
}

/* DARK shadow override (verbatim Aurora preview --sh / --sh-sm + scaled) */
[data-ax-theme="dark"] {
  --ax-shadow-none: none;
  --ax-shadow-sm: 0 6px 18px -8px rgba(0,0,0,0.50);
  --ax-shadow-md: 0 8px 24px -6px rgba(0,0,0,0.55);
  --ax-shadow-lg: 0 18px 48px -10px rgba(0,0,0,0.65);
  --ax-shadow-card: 0 16px 44px -18px rgba(0,0,0,0.65), 0 2px 10px rgba(0,0,0,0.35);
  --ax-glow-accent: 0 12px 26px -10px rgba(var(--ax-accent-rgb), 0.75);
}

/* ═══════════════════════════════════════════════════════════════════════
   §2 — NEUTRAL RAMPS + GLASS/STROKE ALPHA PRIMITIVES + SEMANTIC RAMPS
   ═══════════════════════════════════════════════════════════════════════ */
:root {
  /* ── LIGHT Aurora neutral ramp — cool slate near-white ──────
     Canvas is a bright glassy near-white (#F6F8FC); text greys
     mirror the dark mode's cool blue-grey family inverted.
     ──────────────────────────────────────────────────────── */
  --ax-neutral-0:    #FFFFFF;  /* glass-tinted surfaces, inputs (used with alpha in recipe) */
  --ax-neutral-25:   #F6F8FC;  /* app canvas (cool near-white) */
  --ax-neutral-50:   #F0F3F9;  /* subtle/secondary surface, table stripe */
  --ax-neutral-100:  #E7ECF4;  /* hover fill, muted panel */
  --ax-neutral-150:  #DDE3EE;  /* hairline border (default) */
  --ax-neutral-200:  #CFD7E6;  /* strong border, divider */
  --ax-neutral-300:  #B7C1D5;  /* disabled border, track */
  --ax-neutral-400:  #94A0B8;  /* placeholder, disabled text */
  --ax-neutral-500:  #6E7A92;  /* muted/tertiary text, idle icons */
  --ax-neutral-600:  #535E74;  /* secondary text */
  --ax-neutral-700:  #3A4456;  /* body text */
  --ax-neutral-800:  #232B3A;  /* strong text / headings */
  --ax-neutral-900:  #151B27;  /* highest-contrast text */
  --ax-neutral-1000: #0A0E16;  /* reserved (max), matches dark canvas family */

  /* ── DARK Aurora neutral ramp — verbatim from preview ───────
     canvas #0A0C11, glass panels, strokes, cool text greys.
     Mapped onto spec's --ax-dark-50..1000 NAMES (50=lightest text).
     ──────────────────────────────────────────────────────── */
  --ax-dark-1000: #06080C;  /* deepest base (boxed gutter, below canvas) */
  --ax-dark-950:  #0A0C11;  /* APP CANVAS (preview --bg) */
  --ax-dark-900:  #0F121A;  /* base surface fallback (solid behind glass) */
  --ax-dark-850:  #161A23;  /* raised/solid panel (preview --panel-solid) header/sidebar */
  --ax-dark-800:  #1C212C;  /* hover fill / inputs (preview --panel-2 solid form) */
  --ax-dark-750:  #232A38;  /* popover / floating surface */
  --ax-dark-700:  #2D3543;  /* hairline border baseline (see stroke roles) */
  --ax-dark-600:  #3A4351;  /* strong border */
  --ax-dark-500:  #646E80;  /* disabled text / track (preview --tx-sub) */
  --ax-dark-400:  #7E889A;  /* tertiary text */
  --ax-dark-300:  #98A2B3;  /* muted text / idle icons (preview --tx-mut) */
  --ax-dark-200:  #B8C0CE;  /* secondary text */
  --ax-dark-100:  #D4DAE4;  /* body text */
  --ax-dark-50:   #EAEDF3;  /* strong text / headings (preview --tx) */

  /* ── DARK glass/stroke alpha primitives (preview verbatim) ──
     These are alpha-on-anything values; roles below reference them.
     ──────────────────────────────────────────────────────── */
  --ax-dark-panel:      rgba(22, 26, 35, 0.72);   /* preview --panel (glass card) */
  --ax-dark-panel-2:    rgba(28, 33, 44, 0.80);   /* preview --panel-2 */
  --ax-dark-glass-hi:   rgba(255, 255, 255, 0.06);/* preview --glass-hi (inset top highlight) */
  --ax-dark-stroke:     rgba(255, 255, 255, 0.07);/* preview --stroke */
  --ax-dark-stroke-2:   rgba(255, 255, 255, 0.12);/* preview --stroke-2 */
  --ax-dark-fill-1:     rgba(255, 255, 255, 0.04);/* hover bg, control bg */
  --ax-dark-fill-2:     rgba(255, 255, 255, 0.09);/* active/pressed bg, seg-on */

  /* ── LIGHT glass/stroke alpha primitives (designed) ─────────
     Light Aurora: white-tinted glass on a cool canvas; strokes
     are dark-on-light at low alpha so hairlines read on glass.
     ──────────────────────────────────────────────────────── */
  --ax-light-panel:     rgba(255, 255, 255, 0.72);  /* light glass card */
  --ax-light-panel-2:   rgba(255, 255, 255, 0.85);
  --ax-light-glass-hi:  rgba(255, 255, 255, 0.90);  /* inset top highlight (brighter rim) */
  --ax-light-stroke:    rgba(16, 22, 40, 0.08);     /* hairline on light glass */
  --ax-light-stroke-2:  rgba(16, 22, 40, 0.14);
  --ax-light-fill-1:    rgba(16, 22, 40, 0.04);     /* hover bg */
  --ax-light-fill-2:    rgba(16, 22, 40, 0.08);     /* active/pressed bg */

  /* ── SEMANTIC ramps (spec 01 §3.3) — kept as-is, they coexist
     with Aurora. Light literals; dark remap in block below. ── */
  --ax-success-50: #E7F4EC; --ax-success-200: #A8D8BC; --ax-success-500: #2E9E5B;
  --ax-warning-50: #FBF1DE; --ax-warning-200: #EBCF93; --ax-warning-500: #C8870F;
  --ax-danger-50:  #FBE9E6; --ax-danger-200:  #EFB3AA; --ax-danger-500:  #D24535;
  --ax-info-50:    #E6EFFA; --ax-info-200:    #A9C8EC; --ax-info-500:    #2D74C4;
}

[data-ax-theme="dark"] {
  /* dark semantic remaps (spec 01 §3.3 dark table) */
  --ax-success-50: #16271C; --ax-success-200: #2C5C3D; --ax-success-500: #46B36F;
  --ax-warning-50: #2A1F0A; --ax-warning-200: #5C4517; --ax-warning-500: #E0A53A;
  --ax-danger-50:  #2A1512; --ax-danger-200:  #5C2C26; --ax-danger-500:  #E26A5B;
  --ax-info-50:    #101F30; --ax-info-200:    #274A6E; --ax-info-500:    #5A95DA;
}

/* === tokens/_roles.css === */
/*
 * Vireo — Aurora token model · LAYER 2 ROLE TOKENS
 * Source of truth: brief 01-tokens.md §3.
 * Aliases components consume. Light values on :root; dark under
 * [data-ax-theme="dark"]. Spec 01 §3.4 NAMES, Aurora values.
 * Includes ambient glow blob colors --ax-glow-1/2/3 (both modes),
 * --ax-accent-rgb, and the Verdigris default accent (no attribute).
 */

:root {
  /* Sync the UA scheme to the active theme so native chrome (scrollbars, form
     controls, caret) matches — without this the root scrollbar repaints in the
     wrong scheme on theme toggle and visibly blinks. */
  color-scheme: light;

  /* Scrollbars follow the active accent preset in both themes. */
  --ax-scrollbar-thumb:       rgba(var(--ax-accent-rgb), 0.46);
  --ax-scrollbar-thumb-hover: rgba(var(--ax-accent-rgb), 0.72);

  /* ── surfaces ── */
  --ax-canvas:          var(--ax-neutral-25);     /* #F6F8FC bright glassy near-white */
  --ax-surface:         var(--ax-light-panel);    /* glass card rgba(255,255,255,.72) */
  --ax-surface-solid:   #FFFFFF;                  /* opaque fallback for non-glass contexts */
  --ax-surface-subtle:  var(--ax-neutral-50);     /* #F0F3F9 secondary surface, table header */
  --ax-surface-raised:  rgba(255,255,255,0.80);   /* header/sidebar default (glass) */
  --ax-surface-overlay: rgba(255,255,255,0.92);   /* popover/dropdown/modal (denser glass) */
  --ax-fill-hover:      var(--ax-light-fill-1);   /* hover bg */
  --ax-fill-active:     var(--ax-light-fill-2);   /* pressed/selected bg */

  /* ── borders ── */
  --ax-border:          var(--ax-light-stroke);   /* 1px hairline on glass */
  --ax-border-strong:   var(--ax-light-stroke-2);

  /* ── text ── */
  --ax-text-strong:     var(--ax-neutral-900);    /* #151B27 headings, key numbers */
  --ax-text:            var(--ax-neutral-700);     /* #3A4456 body */
  --ax-text-muted:      var(--ax-neutral-600);     /* #535E74 secondary */
  --ax-text-subtle:     var(--ax-neutral-500);     /* #6E7A92 tertiary, captions, idle icons */
  --ax-text-disabled:   var(--ax-neutral-400);     /* #94A0B8 */

  /* ── accent (Verdigris default — LIGHT base) ── */
  --ax-accent:          var(--ax-accent-500);     /* #1E856C */
  --ax-accent-hover:    var(--ax-accent-600);     /* #197059 */
  --ax-accent-wash:     var(--ax-accent-50);      /* #E8F4F0 selected-row tint */
  --ax-on-accent:       #FFFFFF;
  --ax-accent-rgb:      30, 133, 108;             /* #1E856C → for glow shadows/alpha fills */
  --ax-link:            var(--ax-accent-700);     /* #155C49 */
  --ax-focus-ring:      var(--ax-accent-500);     /* #1E856C */
  /* soft translucent focus halo — blends over any surface (card/canvas/glass),
     replaces the old hard canvas-gap double-ring. Per-accent via --ax-accent-rgb. */
  --ax-focus-shadow:    0 0 0 3px rgba(var(--ax-accent-rgb), 0.18);

  /* Verdigris default ramp (so :root w/o [data-ax-accent] resolves
     the --ax-accent-* stops the role aliases above reference) */
  --ax-accent-50:#E8F4F0; --ax-accent-100:#C9E6DD; --ax-accent-200:#9AD2C3;
  --ax-accent-300:#63B8A3; --ax-accent-400:#39A185; --ax-accent-500:#1E856C;
  --ax-accent-600:#197059; --ax-accent-700:#155C49; --ax-accent-800:#10463A; --ax-accent-900:#0B3029;

  /* ── ambient glow blob colors (light = pale/soft, see recipes §6) ── */
  --ax-glow-1: rgba(255, 176, 120, 0.16);   /* warm-amber, paler than dark */
  --ax-glow-2: rgba(120, 130, 246, 0.16);   /* indigo */
  --ax-glow-3: rgba(var(--ax-accent-rgb), 0.10); /* accent-tinted */

  /* glass inset top highlight (resolved per mode; consumed by .ax-card) */
  --ax-glass-hi: var(--ax-light-glass-hi);
}

[data-ax-theme="dark"] {
  color-scheme: dark;

  /* surfaces — Aurora preview verbatim */
  --ax-canvas:          var(--ax-dark-950);        /* #0A0C11 */
  --ax-surface:         var(--ax-dark-panel);      /* rgba(22,26,35,.72) glass card */
  --ax-surface-solid:   var(--ax-dark-850);        /* #161A23 */
  --ax-surface-subtle:  var(--ax-dark-panel-2);    /* rgba(28,33,44,.80) */
  --ax-surface-raised:  rgba(16,19,28,0.72);       /* header/sidebar glass */
  --ax-surface-overlay: rgba(20,24,33,0.92);       /* popover/dropdown/modal */
  --ax-fill-hover:      var(--ax-dark-fill-1);     /* rgba(255,255,255,.04) */
  --ax-fill-active:     var(--ax-dark-fill-2);     /* rgba(255,255,255,.09) */

  /* borders — alpha strokes */
  --ax-border:          var(--ax-dark-stroke);     /* rgba(255,255,255,.07) */
  --ax-border-strong:   var(--ax-dark-stroke-2);   /* rgba(255,255,255,.12) */

  /* text — preview verbatim */
  --ax-text-strong:     var(--ax-dark-50);         /* #EAEDF3 */
  --ax-text:            var(--ax-dark-100);         /* #D4DAE4 (body slightly below strong) */
  --ax-text-muted:      var(--ax-dark-300);         /* #98A2B3 */
  --ax-text-subtle:     var(--ax-dark-500);         /* #646E80 */
  --ax-text-disabled:   var(--ax-dark-600);         /* #3A4351 */

  /* accent — Verdigris DARK lightened base (spec §3.5.1 / preview) */
  --ax-accent:          #39A185;
  --ax-accent-hover:    #63B8A3;
  --ax-accent-wash:     #16302A;       /* ~16% L tint, dark selected-row */
  --ax-on-accent:       #0B1F1A;       /* warm dark ink on lightened accent */
  --ax-accent-rgb:      57, 161, 133;  /* #39A185 */
  --ax-link:            #63B8A3;
  --ax-focus-ring:      #63B8A3;
  --ax-focus-shadow:    0 0 0 3px rgba(var(--ax-accent-rgb), 0.30);

  /* ambient glow blobs — Aurora preview verbatim opacities */
  --ax-glow-1: rgba(255, 138, 76, 0.18);    /* warm-amber top-left */
  --ax-glow-2: rgba(99, 102, 241, 0.20);    /* indigo bottom-right */
  --ax-glow-3: rgba(var(--ax-accent-rgb), 0.12); /* accent-tinted mid-right */

  /* glass inset top highlight (dark) */
  --ax-glass-hi: var(--ax-dark-glass-hi);
}

/* === tokens/_accents.css === */
/*
 * Vireo — Aurora token model · THE 12 ACCENT PRESETS
 * Source of truth: brief 01-tokens.md §4.
 * Each preset = a light block [data-ax-accent="x"] (full --ax-accent-50..900
 * ramp + 7 accent role aliases + --ax-accent-rgb) AND a dark compound block
 * [data-ax-theme="dark"][data-ax-accent="x"] (lightened accent override).
 * Verdigris is also the :root default (see _roles.css); the explicit block
 * here makes selection symmetric. A preset block touches ONLY accent tokens.
 * Dark compound (2 attrs) outranks the light block (1 attr) — no !important.
 */

/* ════════════════ 1 · VERDIGRIS (default) ════════════════ */
[data-ax-accent="verdigris"] {
  --ax-accent-50:#E8F4F0; --ax-accent-100:#C9E6DD; --ax-accent-200:#9AD2C3;
  --ax-accent-300:#63B8A3; --ax-accent-400:#39A185; --ax-accent-500:#1E856C;
  --ax-accent-600:#197059; --ax-accent-700:#155C49; --ax-accent-800:#10463A; --ax-accent-900:#0B3029;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#FFFFFF;
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:30,133,108;
}
[data-ax-theme="dark"][data-ax-accent="verdigris"] {
  --ax-accent:#39A185; --ax-accent-hover:#63B8A3; --ax-accent-wash:#16302A;
  --ax-link:#63B8A3; --ax-focus-ring:#63B8A3; --ax-on-accent:#0B1F1A; --ax-accent-rgb:57,161,133;
}

/* ════════════════ 2 · COBALT ════════════════ */
[data-ax-accent="cobalt"] {
  --ax-accent-50:#E7EDFB; --ax-accent-100:#C9D7F4; --ax-accent-200:#9DB6EA;
  --ax-accent-300:#6E90DE; --ax-accent-400:#4A77D6; --ax-accent-500:#2A5FCC;
  --ax-accent-600:#2350AE; --ax-accent-700:#1D428F; --ax-accent-800:#163167; --ax-accent-900:#0F2145;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#FFFFFF;
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:42,95,204;
}
[data-ax-theme="dark"][data-ax-accent="cobalt"] {
  --ax-accent:#5883DD; --ax-accent-hover:#8FACE8; --ax-accent-wash:#0F182C;
  --ax-link:#8FACE8; --ax-focus-ring:#8FACE8; --ax-on-accent:#0B1F1A; --ax-accent-rgb:88,131,221;
}

/* ════════════════ 3 · INDIGO ════════════════ */
[data-ax-accent="indigo"] {
  --ax-accent-50:#ECEAFB; --ax-accent-100:#D6D2F5; --ax-accent-200:#B2ACEC;
  --ax-accent-300:#8881DF; --ax-accent-400:#665CD4; --ax-accent-500:#4F46C9;
  --ax-accent-600:#4038AC; --ax-accent-700:#332C8A; --ax-accent-800:#262164; --ax-accent-900:#191643;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#FFFFFF;
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:79,70,201;
}
[data-ax-theme="dark"][data-ax-accent="indigo"] {
  --ax-accent:#807AD8; --ax-accent-hover:#B1ADE7; --ax-accent-wash:#110F2C;
  --ax-link:#B1ADE7; --ax-focus-ring:#B1ADE7; --ax-on-accent:#0B1F1A; --ax-accent-rgb:128,122,216;
}

/* ════════════════ 4 · AMETHYST ════════════════ */
[data-ax-accent="amethyst"] {
  --ax-accent-50:#F3EAFA; --ax-accent-100:#E6D4F4; --ax-accent-200:#CFAEEA;
  --ax-accent-300:#B07AD0; --ax-accent-400:#9D5FC4; --ax-accent-500:#8A46B5;
  --ax-accent-600:#74399A; --ax-accent-700:#5D2E7C; --ax-accent-800:#44235B; --ax-accent-900:#2C173B;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#FFFFFF;
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:138,70,181;
}
[data-ax-theme="dark"][data-ax-accent="amethyst"] {
  --ax-accent:#A56EC7; --ax-accent-hover:#C29ED9; --ax-accent-wash:#20102A;
  --ax-link:#C29ED9; --ax-focus-ring:#C29ED9; --ax-on-accent:#0B1F1A; --ax-accent-rgb:165,110,199;
}

/* ════════════════ 5 · MAGENTA ════════════════ */
[data-ax-accent="magenta"] {
  --ax-accent-50:#FBE9F2; --ax-accent-100:#F6D0E3; --ax-accent-200:#EDA6C9;
  --ax-accent-300:#DE70A6; --ax-accent-400:#D15095; --ax-accent-500:#C13C84;
  --ax-accent-600:#A53170; --ax-accent-700:#85285A; --ax-accent-800:#611D42; --ax-accent-900:#3F132B;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#FFFFFF;
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:193,60,132;
}
[data-ax-theme="dark"][data-ax-accent="magenta"] {
  --ax-accent:#CD5E9A; --ax-accent-hover:#DD91BA; --ax-accent-wash:#2C0F1F;
  --ax-link:#DD91BA; --ax-focus-ring:#DD91BA; --ax-on-accent:#0B1F1A; --ax-accent-rgb:205,94,154;
}

/* ════════════════ 6 · TERRACOTTA ════════════════ */
[data-ax-accent="terracotta"] {
  --ax-accent-50:#FBEAE4; --ax-accent-100:#F6D3C7; --ax-accent-200:#EDAD97;
  --ax-accent-300:#DC7C5E; --ax-accent-400:#D2654A; --ax-accent-500:#C25339;
  --ax-accent-600:#AB4630; --ax-accent-700:#8A3826; --ax-accent-800:#65291C; --ax-accent-900:#421B12;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#FFFFFF;
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:194,83,57;
}
[data-ax-theme="dark"][data-ax-accent="terracotta"] {
  --ax-accent:#CD674F; --ax-accent-hover:#DC9382; --ax-accent-wash:#2C140F;
  --ax-link:#DC9382; --ax-focus-ring:#DC9382; --ax-on-accent:#0B1F1A; --ax-accent-rgb:205,103,79;
}

/* ════════════════ 7 · AMBER (dark ink on accent) ════════════════ */
[data-ax-accent="amber"] {
  --ax-accent-50:#FBF1DE; --ax-accent-100:#F6E2BB; --ax-accent-200:#EDC97E;
  --ax-accent-300:#DDAB3C; --ax-accent-400:#D29A1E; --ax-accent-500:#C1820E;
  --ax-accent-600:#A9720B; --ax-accent-700:#885B09; --ax-accent-800:#634207; --ax-accent-900:#412B04;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#1F1602; /* dark ink */
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:193,130,14;
}
[data-ax-theme="dark"][data-ax-accent="amber"] {
  --ax-accent:#E0A53A; --ax-accent-hover:#EDBE6A; --ax-accent-wash:#2C220F;
  --ax-link:#EDBE6A; --ax-focus-ring:#EDBE6A; --ax-on-accent:#1F1602; --ax-accent-rgb:224,165,58;
}

/* ════════════════ 8 · OLIVE ════════════════ */
[data-ax-accent="olive"] {
  --ax-accent-50:#F0F4DF; --ax-accent-100:#E0E9BC; --ax-accent-200:#C7D782;
  --ax-accent-300:#9DB83C; --ax-accent-400:#7E9722; --ax-accent-500:#647F1C;
  --ax-accent-600:#5C7419; --ax-accent-700:#495D14; --ax-accent-800:#36440F; --ax-accent-900:#232C09;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#FFFFFF;
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:100,127,28;
}
[data-ax-theme="dark"][data-ax-accent="olive"] {
  --ax-accent:#84A725; --ax-accent-hover:#AAD33B; --ax-accent-wash:#242C0F;
  --ax-link:#AAD33B; --ax-focus-ring:#AAD33B; --ax-on-accent:#0B1F1A; --ax-accent-rgb:132,167,37;
}

/* ════════════════ 9 · FOREST ════════════════ */
[data-ax-accent="forest"] {
  --ax-accent-50:#E6F2EB; --ax-accent-100:#C6E2D1; --ax-accent-200:#93C8A9;
  --ax-accent-300:#4FA871; --ax-accent-400:#37915A; --ax-accent-500:#2C7A4B;
  --ax-accent-600:#24643E; --ax-accent-700:#1D5032; --ax-accent-800:#153B25; --ax-accent-900:#0D2618;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#FFFFFF;
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:44,122,75;
}
[data-ax-theme="dark"][data-ax-accent="forest"] {
  --ax-accent:#36965C; --ax-accent-hover:#4FBF7C; --ax-accent-wash:#102B1A;
  --ax-link:#4FBF7C; --ax-focus-ring:#4FBF7C; --ax-on-accent:#0B1F1A; --ax-accent-rgb:54,150,92;
}

/* ════════════════ 10 · TEAL ════════════════ */
[data-ax-accent="teal"] {
  --ax-accent-50:#E1F1F3; --ax-accent-100:#BCDFE3; --ax-accent-200:#82C3CB;
  --ax-accent-300:#2F9AAB; --ax-accent-400:#15909F; --ax-accent-500:#10808F;
  --ax-accent-600:#0C6A77; --ax-accent-700:#0A555F; --ax-accent-800:#073F47; --ax-accent-900:#04292F;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#FFFFFF;
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:16,128,143;
}
[data-ax-theme="dark"][data-ax-accent="teal"] {
  --ax-accent:#15A4B7; --ax-accent-hover:#27D0E7; --ax-accent-wash:#0F292C;
  --ax-link:#27D0E7; --ax-focus-ring:#27D0E7; --ax-on-accent:#0B1F1A; --ax-accent-rgb:21,164,183;
}

/* ════════════════ 11 · SLATE ════════════════ */
[data-ax-accent="slate"] {
  --ax-accent-50:#EBEEF1; --ax-accent-100:#D5DBE1; --ax-accent-200:#AFBAC6;
  --ax-accent-300:#7E8EA0; --ax-accent-400:#5F7184; --ax-accent-500:#4A5A6B;
  --ax-accent-600:#3D4B59; --ax-accent-700:#313C47; --ax-accent-800:#242C34; --ax-accent-900:#171D22;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#FFFFFF;
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:74,90,107;
}
[data-ax-theme="dark"][data-ax-accent="slate"] {
  --ax-accent:#72879D; --ax-accent-hover:#99A8B9; --ax-accent-wash:#181D23;
  --ax-link:#99A8B9; --ax-focus-ring:#99A8B9; --ax-on-accent:#0B1F1A; --ax-accent-rgb:114,135,157;
}

/* ════════════════ 12 · GRAPHITE ════════════════ */
[data-ax-accent="graphite"] {
  --ax-accent-50:#EEEDEA; --ax-accent-100:#DAD9D4; --ax-accent-200:#BAB9B1;
  --ax-accent-300:#8E8D85; --ax-accent-400:#6B6A64; --ax-accent-500:#52514C;
  --ax-accent-600:#434240; --ax-accent-700:#363533; --ax-accent-800:#282826; --ax-accent-900:#1A1A18;
  --ax-accent:var(--ax-accent-500); --ax-accent-hover:var(--ax-accent-600);
  --ax-accent-wash:var(--ax-accent-50); --ax-on-accent:#FFFFFF;
  --ax-focus-ring:var(--ax-accent-500); --ax-link:var(--ax-accent-700);
  --ax-accent-rgb:82,81,76;
}
[data-ax-theme="dark"][data-ax-accent="graphite"] {
  --ax-accent:#86857D; --ax-accent-hover:#A6A59F; --ax-accent-wash:#1E1E1C;
  --ax-link:#A6A59F; --ax-focus-ring:#A6A59F; --ax-on-accent:#0B1F1A; --ax-accent-rgb:134,133,125;
}

/* === tokens/_charts.css === */
/*
 * Vireo — Aurora token model · CHART / DATA-VIZ PALETTE (Layer 1)
 * Source of truth: brief 01-tokens.md §5.
 * Constant Aurora multicolour palette (cyan/violet/pink/amber/emerald/red)
 * — same across all 12 accent presets (the Aurora differentiator).
 * Mapped onto spec --ax-chart-1..6 NAMES. --ax-chart-1 RE-BINDS to the
 * active --ax-accent so series-1 follows the theme; chart-2..6 are constant.
 * Light hues slightly deepened for contrast on the bright canvas; dark =
 * Aurora preview verbatim. financial up/down + KPI delta semantics included.
 */

:root {
  /* constant Aurora data-viz named colors (LIGHT — slightly deepened
     for contrast on the bright canvas; same hues as dark) */
  --ax-viz-cyan:    #0EA5E9;
  --ax-viz-violet:  #7C5CFC;
  --ax-viz-pink:    #EC4899;
  --ax-viz-amber:   #E0930B;
  --ax-viz-emerald: #10B981;
  --ax-viz-red:     #EF4444;

  /* ordered categorical palette (spec --ax-chart-1..6 NAMES).
     chart-1 RE-BINDS to active accent. chart-2..6 = constant Aurora. */
  --ax-chart-1: var(--ax-accent);     /* follows theme */
  --ax-chart-2: var(--ax-viz-cyan);
  --ax-chart-3: var(--ax-viz-violet);
  --ax-chart-4: var(--ax-viz-pink);
  --ax-chart-5: var(--ax-viz-amber);
  --ax-chart-6: var(--ax-viz-emerald);

  /* financial / diverging (spec 01 §11.2) */
  --ax-chart-up:   var(--ax-success-500);  /* light #2E9E5B */
  --ax-chart-down: var(--ax-danger-500);   /* light #D24535 */

  /* delta chip semantics used in KPI cards (preview --emerald/--red) */
  --ax-delta-up:   var(--ax-viz-emerald);
  --ax-delta-down: var(--ax-viz-red);
}

[data-ax-theme="dark"] {
  /* DARK — Aurora preview verbatim hexes */
  --ax-viz-cyan:    #38BDF8;
  --ax-viz-violet:  #A78BFA;
  --ax-viz-pink:    #F472B6;
  --ax-viz-amber:   #FBBF24;
  --ax-viz-emerald: #34D399;
  --ax-viz-red:     #FB7185;
  /* chart-1 still = var(--ax-accent) (now the dark lightened accent) */
  --ax-chart-up:   var(--ax-success-500);  /* dark #46B36F */
  --ax-chart-down: var(--ax-danger-500);   /* dark #E26A5B */
}

/* === tokens/_recipes.css === */
/*
 * Vireo — Aurora token model · RECIPES (Aurora identity)
 * Source of truth: brief 01-tokens.md §6 (recipes) + §7 (font var defs).
 * These ARE the Aurora identity: ambient glow backdrop, glassy card
 * primitive, accent + plate gradients, primary-button reference pill,
 * nav active glow, :focus-visible, prefers-reduced-motion. Both modes;
 * light values designed, dark verbatim from preview.
 *
 * FONT NOTE: this file defines the --ax-font-* CSS variables only
 * (§7). The body/typography BASE rules (body font-family/size 14px/
 * feature-settings, .ax-num tabular-nums, display headings, mono)
 * belong in base.css — they are page-level base rules, not token defs.
 *
 * These are token/recipe primitives, NOT component classes. The only
 * selectors here are the shared Aurora primitives (.ax-ambient, .ax-card and
 * its four material modifiers, .ax-btn-primary, .ax-nav__item.is-active)
 * referenced verbatim by the shell + components briefs. The materials are
 * here rather than in components.css because they restate .ax-card's own
 * surface — see the note above them.
 */

/* ════════════════ FONT FAMILIES (§7 var defs) ════════════════
   Spec NAMES kept; Aurora families (preview --f-sans/--f-disp/--f-mono).
   body/heading/mono BASE rules live in base.css per task split.
*/
:root {
  --ax-font-sans:    "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --ax-font-display: "Space Grotesk", var(--ax-font-sans);
  --ax-font-mono:    "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

/* ════════════════ CUSTOMIZER FONT OVERRIDE ════════════════
   The customizer can set the UI face to ANY Google family, so there is
   deliberately no per-family rule here: ~1,800 families cannot be enumerated as
   static CSS. Instead the picked family is written as an INLINE --ax-font-sans
   on <html> (js/core/fonts.js → applyFont, and the blocking script in
   partials/head.html for the pre-paint pass) — the same mechanism the custom
   accent colour uses. Inline outranks the :root block above, which is why
   returning to the default has to clear it rather than restate it.

   `data-ax-font="custom"` is written alongside it, purely so the rule below can
   match. The shipped default, Inter, removes the attribute AND the inline
   property, so the designed pairing above wins untouched.

   Picking a family retires the Space Grotesk display face on purpose: a buyer
   choosing "Poppins" wants Poppins headings too, not a pairing they did not
   ask for. Code keeps --ax-font-mono either way.

   The webfont itself is fetched on demand — see js/core/fonts.js. Nothing here
   downloads anything, so an untouched customizer costs zero bytes. */
[data-ax-font] {
  --ax-font-display: var(--ax-font-sans);
}

/* ════════════════ AMBIENT GLOW BACKDROP ════════════════
   Markup: a fixed full-bleed layer behind the app shell.
   <div class="ax-ambient" aria-hidden="true"><i></i></div>
   Three radial blobs: ::before warm-amber TL, ::after indigo BR,
   <i> accent-tinted mid-right. Colors from role tokens --ax-glow-1/2/3
   (light = paler, dark = preview opacities). z-index 0; app shell z 1.
*/
.ax-ambient {
  position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden;
}
.ax-ambient::before, .ax-ambient::after {
  content: ""; position: absolute; border-radius: 50%; filter: blur(60px);
}
.ax-ambient::before {
  width: 620px; height: 620px; left: -180px; top: -220px;
  background: radial-gradient(circle at 50% 50%, var(--ax-glow-1), transparent 62%);
}
.ax-ambient::after {
  width: 760px; height: 760px; right: -240px; bottom: -300px;
  background: radial-gradient(circle at 50% 50%, var(--ax-glow-2), transparent 62%);
}
.ax-ambient i {
  position: absolute; width: 540px; height: 540px; right: 18%; top: 30%;
  border-radius: 50%; filter: blur(70px);
  background: radial-gradient(circle at 50% 50%, var(--ax-glow-3), transparent 60%);
}
/* Light Aurora: glow is softer — reduce overall intensity */
:root .ax-ambient { opacity: 0.85; }
[data-ax-theme="dark"] .ax-ambient { opacity: 1; }

/* ════════════════ GLASSY CARD PRIMITIVE ════════════════
   .ax-card = the Aurora glass surface. Resting cards use THIS,
   not --ax-shadow-none-as-flat. Spec's "hairline" name is honored
   by the 1px --ax-border stroke; Aurora adds blur + glow + inset.
   Radius = --ax-radius-xl (24px). Nested controls step down to md/sm.
*/
.ax-card {
  position: relative; overflow: hidden;
  background: var(--ax-surface);                 /* glass rgba */
  border: 1px solid var(--ax-border);            /* hairline */
  border-radius: var(--ax-radius-xl);            /* 24px */
  box-shadow: var(--ax-shadow-card);             /* soft glow drop */
  -webkit-backdrop-filter: blur(18px) saturate(1.1);
  backdrop-filter: blur(18px) saturate(1.1);
}
/* When a combobox inside a card is open, let its absolutely-positioned panel
   escape the card's overflow:hidden, and lift the card above its siblings so the
   panel isn't painted behind the next card. Lives here (unlayered) so it beats
   the .ax-card recipe above — an 
  overflow: visible;
  z-index: var(--ax-z-sticky);

/* inset top highlight rim (preview .card::after) */
.ax-card::after {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  pointer-events: none;
  box-shadow: inset 0 1px 0 var(--ax-glass-hi);
}

/* Glass performance fallback: if backdrop-filter is unsupported,
   .ax-card falls back to --ax-surface-solid (opaque). */
@supports not (backdrop-filter: blur(1px)) {
  .ax-card { background: var(--ax-surface-solid); }
}

/* ════════════════ CARD MATERIALS ════════════════
   A dashboard built from one surface repeated reads as a single grey slab,
   however good the individual card is. These change the *material* of a card
   without touching its anatomy — header/body/footer keep working, so any
   existing card opts in by adding one class. Use one or two per page: the
   point is contrast against the default glass, which disappears the moment
   everything is tinted. Each is accent-derived, so all 12 presets and both
   themes inherit free.

   These live HERE, unlayered, and not in components.css: .ax-card above is
   unlayered too, and an unlayered rule outranks anything in 
  background: var(--ax-accent-wash);
  border-color: rgba(var(--ax-accent-rgb), 0.28);


/* Full accent gradient with inverted ink, for the one card that should be
   read first. Built from --ax-accent, never a fixed hue. */
.ax-card--gradient {
  color: var(--ax-on-accent);
  background: var(--ax-gradient-accent);
  border-color: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.ax-card--gradient .ax-card__title,
.ax-card--gradient .ax-card__eyebrow,
.ax-card--gradient .ax-card__subtitle,
.ax-card--gradient .ax-num {
  color: inherit;
}
.ax-card--gradient .ax-card__eyebrow,
.ax-card--gradient .ax-card__subtitle {
  opacity: 0.82;
}
.ax-card--gradient .ax-card__footer {
  border-top-color: rgba(255, 255, 255, 0.22);
}

/* Chart flush to the card edge. The body drops its padding so a full-bleed
   area/column chart meets the card boundary instead of floating in a well;
   text inside a bleed body needs its own padded wrapper. */
.ax-card--bleed > .ax-card__body {
  padding: 0;
}

/* Recessed and matte — supporting cards that should not compete with the
   glass ones beside them. */
.ax-card--flat {
  background: var(--ax-surface-subtle);
  box-shadow: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
.ax-card--flat::after {
  box-shadow: none;
}

/* ════════════════ ACCENT GRADIENT (primary actions, brand mark) ════════════════
   Re-derives from accent tokens automatically (preview --g-accent).
   135deg from accent → accent-2 (hover/lighter step).
*/
:root {
  --ax-gradient-accent: linear-gradient(135deg, var(--ax-accent) 0%, var(--ax-accent-hover) 100%);
  /* fixed multicolour "card plate" gradient (preview --g-card) for the
     My Card / balance plate — CONSTANT, does not follow accent */
  --ax-gradient-plate: linear-gradient(135deg, #4F7CF7 0%, #8B5CF6 48%, #EC4899 100%);
}

/* ════════════════ PRIMARY BUTTON (Aurora pill) ════════════════
   Reference recipe so components don't re-invent.
*/
.ax-btn-primary {
  display: inline-flex; align-items: center; gap: var(--ax-space-2);
  font-weight: var(--ax-weight-semibold); font-size: var(--ax-text-sm);
  color: var(--ax-on-accent); border: 0; cursor: pointer;
  padding: 11px 17px; border-radius: var(--ax-radius-pill);
  background: var(--ax-gradient-accent);
  box-shadow: var(--ax-glow-accent);
  transition: filter var(--ax-motion-instant) var(--ax-ease-standard);
}
.ax-btn-primary:hover { filter: brightness(1.06); }
.ax-btn-primary:active { filter: brightness(0.97); }

/* ════════════════ NAV ACTIVE STATE (Aurora glow bar) ════════════════
   Active nav item: accent-wash gradient fill + inset ring + leading
   glow bar (preview .nav a.on). Selected per spec 01 §13.
*/
.ax-nav__item.is-active {
  color: var(--ax-text-strong);
  background: linear-gradient(90deg, rgba(var(--ax-accent-rgb),0.16), rgba(var(--ax-accent-rgb),0.04));
  box-shadow: inset 0 0 0 1px rgba(var(--ax-accent-rgb),0.18);
}
.ax-nav__item.is-active::before {
  content: ""; position: absolute; inset-inline-start: -14px; top: 50%;
  transform: translateY(-50%); width: 3px; height: 20px;
  border-radius: 0 3px 3px 0; background: var(--ax-accent);
  box-shadow: 0 0 12px var(--ax-accent);
}
.ax-nav__item.is-active svg { color: var(--ax-accent); opacity: 1; }

/* ════════════════ FOCUS RING (spec 01 §8.4 / §13) ════════════════ */
/* Generic offset outline for tabbables WITHOUT a bespoke focus style.
   Form fields (input/select/textarea + checkbox/radio/switch) are excluded —
   they own a richer accent-border + soft halo in components.css. Listing them
   here would double-ring them: this rule is unlayered, so it outranks the
   layered .ax-input:focus { outline:none } (unlayered > 
  outline: 2px solid var(--ax-focus-ring); outline-offset: 2px;
  border-radius: inherit;


/* ════════════════ REDUCED MOTION (spec 01 §12.4, mandatory) ════════════════ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important; scroll-behavior: auto !important;
  }
  /* count-ups, shimmer, marquee disabled by component JS reading the query */
}

/* === base.css === */
/*
 * Vireo — HTML reference edition · base.css
 * ────────────────────────────────────────────────────────────────────────
 * Reset/normalize · root typography · global element defaults · scrollbars
 * AND the Aurora app-shell layout (.ax-layout / .ax-sidebar / .ax-shell /
 * .ax-header / .ax-main / .ax-footer) with the 6 sidebar styles, responsive
 * offcanvas drawer, and the [data-ax-*] layout attribute contract.
 *
 * Consumes ONLY Layer-2 role tokens (--ax-surface, --ax-text, --ax-accent,
 * --ax-border…) and Layer-1 scale tokens (--ax-space-*, --ax-radius-*,
 * --ax-sidebar-w…) declared in tokens/_primitives.css + _roles.css.
 * NEVER a raw neutral/accent stop (no --ax-neutral-NNN, no --ax-accent-500),
 * NEVER a literal themeable hex.
 *
 * Authored entirely with CSS LOGICAL PROPERTIES (inset-inline-*, margin-inline-*,
 * padding-block-*, border-inline-*) so RTL mirrors with zero duplicated rules.
 */

/* ════════════════════════════════════════════════════════════════════════
   0 · SHELL-GEOMETRY TOKENS introduced by the shell brief (02 §0.1).
   The core dimension tokens (--ax-sidebar-w/-compact, --ax-header-h,
   --ax-footer-h, --ax-container-boxed) live in _primitives.css; these two
   are shell-owned and declared here so base.css is self-sufficient.
   ════════════════════════════════════════════════════════════════════════ */
:root {
  --ax-sidebar-w-double: 296px; /* double-column rail total (76 + 220) */
  --ax-detached-inset: var(--ax-space-4); /* 16px floating-rail gutter */
  --ax-drawer-w: 288px; /* mobile offcanvas width */
  --ax-backdrop: rgba(20, 17, 13, 0.5); /* overlay scrim (mode-agnostic dim) */
}
[data-ax-theme='dark'] {
  --ax-backdrop: rgba(0, 0, 0, 0.6);
}

/* ════════════════════════════════════════════════════════════════════════
   1 · RESET / NORMALIZE  (modern, minimal — Tailwind preflight handles much;
   these rules are token-aware and shell-specific so they live with us)
   ════════════════════════════════════════════════════════════════════════ */
*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -moz-tab-size: 4;
  tab-size: 4;
  scroll-behavior: smooth;
}

body {
  min-height: 100vh;
  font-family: var(--ax-font-sans);
  font-size: 14px; /* Aurora chrome/dense UI base (spec 01 §7) */
  line-height: 1.5;
  color: var(--ax-text);
  background-color: var(--ax-canvas);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'cv05', 'ss01'; /* Inter stylistic sets */
  letter-spacing: -0.006em;
  /* color/background follow theme-token transitions, not element fades */
  transition:
    background-color var(--ax-motion-fast) var(--ax-ease-standard),
    color var(--ax-motion-fast) var(--ax-ease-standard);
}

/* media defaults */
img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
}
/* Reset only SVGs that don't declare their own fill. Outline icons set fill="none"
   explicitly; filled icons set fill="currentColor" (and dynamic :fill bindings set
   tokens). A blanket `svg { fill: none }` overrides those presentation attributes
   (CSS beats presentation attributes), which renders every filled glyph invisible. */
svg:not([fill]) {
  fill: none;
}
/* Sort-chevron glyphs sit inline within table-heading text, so they must opt out of
   the svg{display:block} media reset above. This override must also be UNLAYERED —
   a layered 
  display: inline-block;


/* form inheritance — MUST be in 
  input,
  button,
  textarea,
  select {
    font: inherit;
    color: inherit;
    letter-spacing: inherit;
  }

button {
  cursor: pointer;
}
/* Reset UA chrome only on UNCLASSED buttons so classed .ax-btn components
   (in 
  background: none;
  border: 0;


/* text wrapping */
p,
h1,
h2,
h3,
h4,
h5,
h6 {
  overflow-wrap: break-word;
}

/* lists used as nav/menus reset their list affordances */
:where(ul, ol)[role='list'],
:where(ul, ol)[role='tree'],
:where(ul, ol)[role='menu'] {
  list-style: none;
  padding: 0;
}

/* tables collapse by default */
table {
  border-collapse: collapse;
  border-spacing: 0;
}

/* hidden attribute always wins (used by sidebar filter) */
[hidden] {
  display: none !important;
}

/* ════════════════════════════════════════════════════════════════════════
   2 · ROOT TYPOGRAPHY  (headings → Space Grotesk via --ax-font-display;
   sizes/leading from --ax-text-* / --ax-leading-* token scale)
   ════════════════════════════════════════════════════════════════════════ */
h1,
h2,
.ax-display {
  font-family: var(--ax-font-display);
}
h3,
h4,
h5,
h6 {
  font-family: var(--ax-font-sans);
}

h1 {
  font-size: var(--ax-text-3xl);
  line-height: var(--ax-leading-3xl);
  font-weight: var(--ax-weight-bold);
  letter-spacing: -0.018em;
  color: var(--ax-text-strong);
}
h2 {
  font-size: var(--ax-text-2xl);
  line-height: var(--ax-leading-2xl);
  font-weight: var(--ax-weight-semibold);
  letter-spacing: -0.015em;
  color: var(--ax-text-strong);
}
h3 {
  font-size: var(--ax-text-xl);
  line-height: var(--ax-leading-xl);
  font-weight: var(--ax-weight-semibold);
  letter-spacing: -0.012em;
  color: var(--ax-text-strong);
}
h4 {
  font-size: var(--ax-text-lg);
  line-height: var(--ax-leading-lg);
  font-weight: var(--ax-weight-semibold);
  letter-spacing: -0.01em;
  color: var(--ax-text-strong);
}
h5 {
  font-size: var(--ax-text-md);
  line-height: var(--ax-leading-md);
  font-weight: var(--ax-weight-medium);
  letter-spacing: -0.005em;
  color: var(--ax-text-strong);
}
h6 {
  font-size: var(--ax-text-base);
  line-height: var(--ax-leading-base);
  font-weight: var(--ax-weight-medium);
  color: var(--ax-text-strong);
}

small {
  font-size: var(--ax-text-xs);
  line-height: var(--ax-leading-xs);
}

strong,
b {
  font-weight: var(--ax-weight-semibold);
  color: var(--ax-text-strong);
}

code,
kbd,
samp,
pre {
  font-family: var(--ax-font-mono);
  font-size: 0.92em;
}
kbd {
  font-size: var(--ax-text-2xs);
  color: var(--ax-text-subtle);
}

/* links — color MUST be in 
  a {
    color: var(--ax-link);
    text-decoration: none;
    transition: color var(--ax-motion-instant) var(--ax-ease-standard);
  }
  a:hover {
    color: var(--ax-accent-hover);
  }


hr {
  border: 0;
  block-size: 1px;
  background: var(--ax-border);
  margin-block: var(--ax-space-4);
}

/* selection */
::selection {
  background: var(--ax-accent-wash);
  color: var(--ax-text-strong);
}

/* ════════════════════════════════════════════════════════════════════════
   3 · CUSTOM SCROLLBARS  (thin, hairline thumb on --ax-border-strong)
   ════════════════════════════════════════════════════════════════════════ */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--ax-scrollbar-thumb) transparent;
}
/* Opt-outs have to live HERE, beside the `*` rule: this file is unlayered, so
   `*` beats any selector declared inside 
  scrollbar-width: none;

.ax-tabs--scrollable .ax-tabs__list::-webkit-scrollbar {
  display: none;
}
*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
*::-webkit-scrollbar-track {
  background: transparent;
}
*::-webkit-scrollbar-thumb {
  background-color: var(--ax-scrollbar-thumb);
  border-radius: var(--ax-radius-pill);
  border: 3px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover {
  background-color: var(--ax-scrollbar-thumb-hover);
  border: 2px solid transparent;
  background-clip: padding-box;
}
*::-webkit-scrollbar-corner {
  background: transparent;
}

/* directional icons flip in RTL; non-directional never flip (shell brief §12) */
[dir='rtl'] .ax-icon--directional {
  transform: scaleX(-1);
}
/* keep numeric / mono runs LTR even in RTL context */
.ax-num,
.ax-mono,
[data-ax-tabular] {
  unicode-bidi: plaintext;
}

/* ════════════════════════════════════════════════════════════════════════
   4 · APP-SHELL LAYOUT
   Skeleton (task contract):
     <div class="ax-ambient"><i></i></div>
     <div class="ax-layout">
       <aside class="ax-sidebar">…</aside>
       <div class="ax-shell">
         <header class="ax-header">…</header>
         <main class="ax-main" id="ax-main">…</main>
         <footer class="ax-footer">…</footer>
       </div>
     </div>
     <aside class="ax-customizer">…</aside>
   ════════════════════════════════════════════════════════════════════════ */

/* root scope — sits above the fixed .ax-ambient glow layer (z-base 0) */
.ax-layout {
  position: relative;
  z-index: 1;
  min-block-size: 100vh;
  isolation: isolate;
}

/* ── SIDEBAR rail — fixed, full height, width = active style token ── */
.ax-sidebar {
  position: fixed;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: var(--ax-sidebar-w);
  z-index: var(--ax-z-sidebar);
  display: flex;
  flex-direction: column;
  background: var(--ax-sidebar-bg, var(--ax-surface-raised));
  color: var(--ax-sidebar-fg, var(--ax-text));
  border-inline-end: 1px solid var(--ax-sidebar-border, var(--ax-border));
  -webkit-backdrop-filter: blur(14px) saturate(1.05);
  backdrop-filter: blur(14px) saturate(1.05);
  transition:
    inline-size var(--ax-motion-base) var(--ax-ease-standard),
    transform var(--ax-motion-slow) var(--ax-ease-emphasized);
  overflow: hidden; /* nav owns the scroll */
}

/* ── SHELL column — offset by the sidebar via logical margin ── */
.ax-shell {
  display: flex;
  flex-direction: column;
  min-block-size: 100vh;
  margin-inline-start: var(--ax-sidebar-w);
  transition: margin-inline-start var(--ax-motion-base) var(--ax-ease-standard);
}

/* ── HEADER — sticky/fixed glass topbar aligned to the rail edge ── */
.ax-header {
  position: fixed;
  inset-block-start: 0;
  inset-inline-start: var(--ax-sidebar-w);
  inset-inline-end: 0;
  z-index: var(--ax-z-header);
  display: flex;
  align-items: center;
  gap: var(--ax-space-2);
  block-size: var(--ax-header-h);
  padding-inline: var(--ax-space-5);
  background: var(--ax-header-bg, var(--ax-surface-raised));
  color: var(--ax-header-fg, var(--ax-text));
  border-block-end: 1px solid var(--ax-header-border, var(--ax-border));
  -webkit-backdrop-filter: blur(12px) saturate(1.05);
  backdrop-filter: blur(12px) saturate(1.05);
  transition:
    inset-inline-start var(--ax-motion-base) var(--ax-ease-standard),
    box-shadow var(--ax-motion-fast) var(--ax-ease-standard);
}
/* sticky-shadow when content is scrolled (Alpine toggles .is-scrolled) */
.ax-header.is-scrolled {
  box-shadow: var(--ax-shadow-sm);
}

/* ── MAIN — the scroll/padding region, offset below the fixed header ── */
.ax-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding-block-start: var(--ax-header-h); /* clear the fixed header */
  min-block-size: 0;
}
/* page padding (Fluid default); width modes override below.
   `--ax-page-pad` mirrors the inline padding and inherits down the page, so
   full-bleed children (sticky action bars) can cancel the gutter with
   `margin-inline: calc(-1 * var(--ax-page-pad))` and stay correct in every
   width/page mode AND on phones. Hard-coding space-6 there bled 8px past the
   viewport once the phone breakpoint tightened the gutter to space-4. */
.ax-main > :not(.ax-footer) {
  --ax-page-pad: var(--ax-space-6);
  padding-inline: var(--ax-page-pad);
  padding-block: var(--ax-space-6);
}

/* ── FOOTER — pinned to column bottom, hairline top edge ── */
.ax-footer {
  margin-block-start: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ax-space-4);
  min-block-size: var(--ax-footer-h);
  padding-block: var(--ax-space-4);
  padding-inline: var(--ax-space-6);
  border-block-start: 1px solid var(--ax-border);
  color: var(--ax-text-muted);
  font-size: var(--ax-text-sm);
}
.ax-footer a {
  color: var(--ax-text-muted);
}
.ax-footer a:hover {
  color: var(--ax-text);
}
.ax-footer__links {
  display: flex;
  gap: var(--ax-space-4);
  flex-wrap: wrap;
}

/* ════════════════════════════════════════════════════════════════════════
   5 · WIDTH MODES  [data-ax-width="fluid|full"]
   fluid = padded (default) · full = edge-to-edge
   ════════════════════════════════════════════════════════════════════════ */
[data-ax-width='full'] .ax-main > :not(.ax-footer) {
  --ax-page-pad: var(--ax-space-4);
  padding-inline: var(--ax-page-pad);
}

/* ════════════════════════════════════════════════════════════════════════
   6 · HEADER POSITION  [data-ax-header-position="fixed|static"]
   fixed (default) = chrome pinned · static = scrolls away with content
   ════════════════════════════════════════════════════════════════════════ */
[data-ax-header-position='static'] .ax-header {
  /* static = scroll away with content. Must be `static` (not sticky): the base
     rule leaves inset-block-start:0, which would keep a sticky header pinned. */
  position: static;
  inset-inline-start: auto;
  inset-inline-end: auto;
}
[data-ax-header-position='static'] .ax-main {
  padding-block-start: 0; /* header is in flow, no offset needed */
}

/* SIDEBAR POSITION [data-ax-sidebar-position="fixed|static"]
   static = rail scrolls away with the page. `position:absolute` inside the
   `position:relative` .ax-layout keeps it a 264px left column out of flow, so
   .ax-shell's existing margin-inline-start and the fixed-header offset stay valid
   (a sticky rail in the non-flex .ax-layout would stack ABOVE the shell). */
[data-ax-sidebar-position='static'] .ax-sidebar {
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;
  block-size: auto;
  min-block-size: 100vh;
}

/* ════════════════════════════════════════════════════════════════════════
   7 · THE SIX SIDEBAR STYLES  [data-ax-sidebar-style]
   All consume the SAME nav data; switching only re-binds --ax-sidebar-w
   and toggles label/flyout affordances. (shell brief §3.5)
   ════════════════════════════════════════════════════════════════════════ */

/* width re-bind: compact-family rails collapse to the 76px icon token */
[data-ax-sidebar-style='compact'],
[data-ax-sidebar-style='icon-text'],
[data-ax-sidebar-style='icon-overlay'] {
  --ax-sidebar-w: var(--ax-sidebar-w-compact);
}
[data-ax-sidebar-style='double'] {
  --ax-sidebar-w: var(--ax-sidebar-w-double);
}
/* JS-driven temporary collapse via the header toggle (no style chosen) OR the
   'compact' BEHAVIOR (locked icon rail, any style). The §7b icon-rail treatment
   below shares the same :is() prefix so both look identical. Mobile-safe: the
   drawer hard-sets .ax-sidebar inline-size + zeroes the shell offset. */
:is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) {
  --ax-sidebar-w: var(--ax-sidebar-w-compact);
}

/* ── SIDEBAR BEHAVIOR  [data-ax-sidebar-behavior="collapsible|expanded|compact"]
   collapsible (default) keeps the header collapse toggle. expanded & compact
   LOCK the rail, so the toggle button is removed (JS also no-ops it). ── */
[data-ax-sidebar-behavior='expanded'] .ax-nav-toggle,
[data-ax-sidebar-behavior='compact'] .ax-nav-toggle {
  display: none;
}

/* ── DEFAULT (264px, icon + label) — hide compact-only affordances ── */
.ax-sidebar__flyout {
  display: none;
}

/* ── COMPACT (76px, icons only) ─────────────────────────────────────────
   Hide labels/wordmark/section eyebrows/foot meta; reveal flyout on hover. */
[data-ax-sidebar-style='compact'] .ax-sidebar__wordmark,
[data-ax-sidebar-style='compact'] .ax-nav__label,
[data-ax-sidebar-style='compact'] .ax-nav__badge,
[data-ax-sidebar-style='compact'] .ax-nav__caret,
[data-ax-sidebar-style='compact'] .ax-sidebar__section,
[data-ax-sidebar-style='compact'] .ax-sidebar__search,
[data-ax-sidebar-style='compact'] .ax-sidebar__promo,
[data-ax-sidebar-style='compact'] .ax-sidebar__user-meta,
[data-ax-sidebar-style='icon-overlay'] .ax-sidebar__wordmark,
[data-ax-sidebar-style='icon-overlay'] .ax-nav__label,
[data-ax-sidebar-style='icon-overlay'] .ax-nav__badge,
[data-ax-sidebar-style='icon-overlay'] .ax-nav__caret,
[data-ax-sidebar-style='icon-overlay'] .ax-sidebar__section,
[data-ax-sidebar-style='icon-overlay'] .ax-sidebar__search,
[data-ax-sidebar-style='icon-overlay'] .ax-sidebar__promo,
[data-ax-sidebar-style='icon-overlay'] .ax-sidebar__user-meta {
  display: none;
}
/* compact nav items center their icon; section becomes a hairline divider */
[data-ax-sidebar-style='compact'] .ax-nav__item,
[data-ax-sidebar-style='icon-overlay'] .ax-nav__item {
  justify-content: center;
  padding-inline: 0;
}
[data-ax-sidebar-style='compact'] .ax-sidebar__section,
[data-ax-sidebar-style='icon-overlay'] .ax-sidebar__section {
  display: block;
  block-size: 1px;
  margin: var(--ax-space-2) var(--ax-space-4);
  padding: 0;
  background: var(--ax-border);
  overflow: hidden;
  text-indent: -999px;
}
/* compact flyout (label tooltip / submenu panel) floats out on hover/focus */
[data-ax-sidebar-style='compact'] .ax-nav__item:hover > .ax-sidebar__flyout,
[data-ax-sidebar-style='compact'] .ax-nav__item:focus-visible > .ax-sidebar__flyout,
[data-ax-sidebar-style='icon-overlay'] .ax-nav__item:hover > .ax-sidebar__flyout,
[data-ax-sidebar-style='icon-overlay'] .ax-nav__item:focus-visible > .ax-sidebar__flyout {
  display: block;
  position: absolute;
  inset-inline-start: calc(100% + var(--ax-space-2));
  inset-block-start: 50%;
  transform: translateY(-50%);
  z-index: var(--ax-z-dropdown);
  min-inline-size: 180px;
  padding: var(--ax-space-2) var(--ax-space-3);
  white-space: nowrap;
  background: var(--ax-surface-overlay);
  color: var(--ax-text);
  border: 1px solid var(--ax-border);
  border-radius: var(--ax-radius-md);
  box-shadow: var(--ax-shadow-md);
  -webkit-backdrop-filter: blur(18px) saturate(1.1);
  backdrop-filter: blur(18px) saturate(1.1);
}
[data-ax-sidebar-style='compact'] .ax-nav__item,
[data-ax-sidebar-style='icon-overlay'] .ax-nav__item {
  position: relative;
}

/* ════════════════════════════════════════════════════════════════════════
   7b · HEADER-TOGGLE COLLAPSE  [data-ax-collapsed] (no explicit style chosen)
   The header collapse button only re-binds --ax-sidebar-w to the 76px icon
   token (§7 width re-bind above). On its own that just squeezes the full 264px
   rail content into 76px — clipping the wordmark, search, labels and promo (the
   promo text wraps one char per line). Give it the real icon-rail treatment:
   hide the text-bearing affordances, centre the brand mark + icons + avatar,
   and drop the expanded child panels (leaf rows carry no icon, and there is no
   hover flyout to reveal them). Desktop only — under md the rail is an offcanvas
   drawer that must keep its full labels. */
@media (min-width: 768px) {
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-sidebar__wordmark,
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-nav__label,
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-nav__badge,
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-nav__caret,
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-sidebar__search,
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-sidebar__promo,
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-sidebar__user-meta,
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-sidebar__user-avatar,
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-nav__children {
    display: none;
  }
  /* brand → centred logo mark (drop the wordmark gutter) */
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-sidebar__brand {
    justify-content: center;
    padding-inline: 0;
  }
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-sidebar__logo {
    gap: 0;
  }
  /* nav rows → centred icon, no label gutter */
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-nav__item {
    justify-content: center;
    gap: 0;
    padding-inline: 0;
  }
  /* active-section indicator: when the active leaf lives in a now-hidden child
     panel, surface its trail PARENT as active so the rail still shows where you
     are (mirrors the .is-active recipe, minus the off-rail leading glow bar). */
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-nav__item--trail {
    color: var(--ax-text-strong);
    background: linear-gradient(90deg, rgba(var(--ax-accent-rgb), 0.16), rgba(var(--ax-accent-rgb), 0.04));
    box-shadow: inset 0 0 0 1px rgba(var(--ax-accent-rgb), 0.18);
  }
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-nav__item--trail .ax-nav__icon {
    color: var(--ax-accent);
    opacity: 1;
  }
  /* section eyebrow → hairline divider (label text clipped away) */
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-sidebar__section {
    block-size: 1px;
    margin: var(--ax-space-2) var(--ax-space-4);
    padding: 0;
    overflow: hidden;
    text-indent: -999px;
    white-space: nowrap;
    background: var(--ax-border);
  }
  /* foot → keep ONLY the logout icon, centred (avatar + meta both hidden) */
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-sidebar__user {
    justify-content: center;
  }
  :is([data-ax-collapsed]:not([data-ax-sidebar-style]), [data-ax-sidebar-behavior='compact']) .ax-sidebar__foot {
    padding-inline: var(--ax-space-3);
  }
}

/* ── ICON-TEXT HOVER (rest 76px → 264px overlay on hover, no reflow) ──────
   The rail keeps the shell offset at 76px; hovering expands the rail itself
   as a floating overlay. We expand inline-size only on the rail, not the
   shell margin, so content never reflows. */
[data-ax-sidebar-style='icon-text'] .ax-sidebar__wordmark,
[data-ax-sidebar-style='icon-text'] .ax-nav__label,
[data-ax-sidebar-style='icon-text'] .ax-nav__badge,
[data-ax-sidebar-style='icon-text'] .ax-nav__caret,
[data-ax-sidebar-style='icon-text'] .ax-sidebar__section,
[data-ax-sidebar-style='icon-text'] .ax-sidebar__promo,
[data-ax-sidebar-style='icon-text'] .ax-sidebar__user-meta {
  opacity: 0;
  transition: opacity var(--ax-motion-fast) var(--ax-ease-standard);
}
[data-ax-sidebar-style='icon-text'] .ax-sidebar {
  overflow: visible;
}
[data-ax-sidebar-style='icon-text'] .ax-sidebar:hover,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:focus-within {
  inline-size: var(--ax-sidebar-w-expanded, 264px);
  box-shadow: var(--ax-shadow-md);
  overflow: hidden;
}
[data-ax-sidebar-style='icon-text'] .ax-sidebar:hover .ax-sidebar__wordmark,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:hover .ax-nav__label,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:hover .ax-nav__badge,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:hover .ax-nav__caret,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:hover .ax-sidebar__section,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:hover .ax-sidebar__promo,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:hover .ax-sidebar__user-meta,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:focus-within .ax-sidebar__wordmark,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:focus-within .ax-nav__label,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:focus-within .ax-nav__badge,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:focus-within .ax-nav__caret,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:focus-within .ax-sidebar__section,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:focus-within .ax-sidebar__promo,
[data-ax-sidebar-style='icon-text'] .ax-sidebar:focus-within .ax-sidebar__user-meta {
  opacity: 1;
}

/* ── ICON-OVERLAY (76px rail; submenu opens as a separate floating panel) ──
   Width handled above (compact-family). The submenu overlay panel is the
   sidebar JS concern; we provide the floating-panel skin via .ax-nav__overlay. */
.ax-nav__overlay {
  position: fixed;
  inset-inline-start: var(--ax-sidebar-w-compact);
  inset-block-start: var(--ax-header-h);
  inline-size: 240px;
  z-index: var(--ax-z-dropdown);
  padding: var(--ax-space-3);
  background: var(--ax-surface);
  border: 1px solid var(--ax-border);
  border-radius: var(--ax-radius-lg);
  box-shadow: var(--ax-shadow-md);
  -webkit-backdrop-filter: blur(18px) saturate(1.1);
  backdrop-filter: blur(18px) saturate(1.1);
}

/* ── DETACHED (floating inset cards; the ONLY shell style that casts a shadow) ──
   The Shell Style control: BOTH the sidebar AND the header float as inset cards
   with matching radius + shadow; content sits beside/below them with a consistent
   gutter. The header float is desktop-only (min-width:768px) so the mobile
   drawer/header are untouched; with a top menu bar it docks (Horizontal/Hybrid
   override below) so it never floats over the bar. */
[data-ax-shell-style='detached'] .ax-sidebar {
  inset-block: var(--ax-detached-inset);
  inset-inline-start: var(--ax-detached-inset);
  block-size: auto;
  border: 1px solid var(--ax-border);
  border-radius: var(--ax-radius-lg);
  box-shadow: var(--ax-shadow-sm);
}
[data-ax-shell-style='detached'] .ax-shell {
  margin-inline-start: calc(var(--ax-sidebar-w) + var(--ax-detached-inset) * 2);
}
@media (min-width: 768px) {
  /* header floats to the right of the rail, aligned to the content column,
     tops level with the sidebar card (both start at --ax-detached-inset) */
  [data-ax-shell-style='detached'] .ax-header {
    inset-block-start: var(--ax-detached-inset);
    inset-inline-start: calc(var(--ax-sidebar-w) + var(--ax-detached-inset) * 2);
    inset-inline-end: var(--ax-detached-inset);
    border: 1px solid var(--ax-header-border, var(--ax-border));
    border-radius: var(--ax-radius-lg);
    box-shadow: var(--ax-shadow-sm);
  }
  /* clear the floated header: its height + the top inset + the gap below it */
  [data-ax-shell-style='detached'] .ax-main {
    padding-block-start: calc(var(--ax-header-h) + var(--ax-detached-inset) * 2);
  }
  /* static header is in flow (takes its own space) — no extra top padding */
  [data-ax-header-position='static'][data-ax-shell-style='detached'] .ax-main {
    padding-block-start: 0;
  }
  /* …but `position:static` ignores the float's inset-* offsets, so the card would
     jam flush to the top + right with only its left gutter (the shell margin) left
     intact, misaligned with the floated sidebar. Recreate the gutters with margins
     instead. Vertical nav only — Horizontal/Hybrid dock the header to a flush band
     (no float), so they must keep their full-bleed edges. */
  [data-ax-header-position='static'][data-ax-shell-style='detached']:not([data-ax-nav='horizontal']):not([data-ax-nav='hybrid']) .ax-header {
    margin-block: var(--ax-detached-inset);
    margin-inline-end: var(--ax-detached-inset);
  }
  /* With a top menu bar (Horizontal/Hybrid) the header can't float over the bar —
     dock it (flush band) there; only the sidebar detaches. */
  [data-ax-nav='horizontal'][data-ax-shell-style='detached'] .ax-header,
  [data-ax-nav='hybrid'][data-ax-shell-style='detached'] .ax-header {
    inset-block-start: 0;
    border: 0;
    border-block-end: 1px solid var(--ax-header-border, var(--ax-border));
    border-radius: 0;
    box-shadow: none;
  }
  [data-ax-nav='horizontal'][data-ax-shell-style='detached'] .ax-header {
    inset-inline-start: 0;
    inset-inline-end: 0;
  }
  [data-ax-nav='hybrid'][data-ax-shell-style='detached'] .ax-header {
    inset-inline-start: calc(var(--ax-sidebar-w) + var(--ax-detached-inset) * 2);
    inset-inline-end: 0;
  }
}

/* ── DOUBLE-COLUMN ────────────────────────────────────────────────────────
   Only the 296px width re-bind ships today (see §7 width re-bind above). A true
   two-column icon-rail + labeled-panel needs dedicated `.ax-sidebar__rail` /
   `.ax-sidebar__panel` markup + JS that no edition emits, so `flex-direction:row`
   on the single-column flex children only scrambled/clipped them. Renders as a
   wider labeled rail until that markup exists. */

/* ════════════════════════════════════════════════════════════════════════
   8 · HORIZONTAL / HYBRID NAV  [data-ax-nav]
   Horizontal hides the rail (header full width, no shell offset) and shows the
   top menu bar instead. Hybrid keeps the rail AND shows the bar. The bar itself
   is built from the sidebar tree by core/topnav.js and lives as a direct child
   of `.ax-shell`; CSS here only gates its visibility + skins the dropdowns.
   ════════════════════════════════════════════════════════════════════════ */
[data-ax-nav='horizontal'] .ax-sidebar {
  display: none;
}
[data-ax-nav='horizontal'] .ax-shell {
  margin-inline-start: 0;
}
[data-ax-nav='horizontal'] .ax-header {
  inset-inline-start: 0;
}
/* No rail in Horizontal mode (the sidebar is display:none at every width), so
   the header's collapse toggle has nothing to act on — hide it. Hybrid keeps
   the rail, so its toggle stays. */
[data-ax-nav='horizontal'] .ax-nav-toggle {
  display: none;
}

/* base bar skin (also used by the standalone .ax-topnav showcase patterns) */
.ax-topnav {
  position: sticky;
  inset-block-start: var(--ax-header-h);
  z-index: var(--ax-z-sticky);
  display: flex;
  align-items: center;
  gap: var(--ax-space-1);
  block-size: 48px;
  padding-inline: var(--ax-space-6);
  background: var(--ax-surface-raised);
  border-block-end: 1px solid var(--ax-border);
  -webkit-backdrop-filter: blur(12px) saturate(1.05);
  backdrop-filter: blur(12px) saturate(1.05);
}

/* shell-injected bar: hidden in Vertical; fixed under the header for
   Horizontal & Hybrid. NO backdrop-filter here — a filtered ancestor would
   become a containing block and clip the position:fixed dropdown panels.
   The bar itself NEVER scrolls (overflow:hidden); the inner __track scrolls and
   the edge chevrons + fades (built by core/topnav.js) page it left/right. */
.ax-shell > .ax-topnav {
  display: none;
}
[data-ax-nav='horizontal'] .ax-shell > .ax-topnav,
[data-ax-nav='hybrid'] .ax-shell > .ax-topnav {
  display: flex;
  align-items: stretch;
  position: fixed;
  inset-block-start: var(--ax-header-h);
  inset-inline-start: 0;
  inset-inline-end: 0;
  z-index: calc(var(--ax-z-header) - 1);
  block-size: 48px;
  padding-inline: 0;
  overflow: hidden;
  background: var(--ax-surface-overlay);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
[data-ax-nav='hybrid'] .ax-shell > .ax-topnav {
  inset-inline-start: var(--ax-sidebar-w);
}
/* clear the fixed header + the fixed top bar */
[data-ax-nav='horizontal'] .ax-main,
[data-ax-nav='hybrid'] .ax-main {
  padding-block-start: calc(var(--ax-header-h) + 48px);
}

/* HEADER POSITION = STATIC → the header scrolls away with content, so the bar
   must too: ride in normal flow directly under the (now in-flow) header and
   STICK to the top once the header clears, leaving no empty gap above it. */
[data-ax-header-position='static'][data-ax-nav='horizontal'] .ax-shell > .ax-topnav,
[data-ax-header-position='static'][data-ax-nav='hybrid'] .ax-shell > .ax-topnav {
  position: sticky;
  inset-block-start: 0;
  inset-inline: auto;
}
[data-ax-header-position='static'][data-ax-nav='horizontal'] .ax-main,
[data-ax-header-position='static'][data-ax-nav='hybrid'] .ax-main {
  padding-block-start: 0;
}

/* ── scrollable track (scrollbar hidden) ── */
.ax-topnav__track {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: var(--ax-space-1);
  block-size: 100%;
  padding-inline: var(--ax-space-5);
  overflow-x: auto;
  overflow-y: hidden;
  scroll-behavior: smooth;
  scrollbar-width: none; /* Firefox */
}
.ax-topnav__track::-webkit-scrollbar {
  display: none; /* WebKit/Blink */
}

/* ── edge chevrons + fade (shown by JS only when overflowing that side) ── */
.ax-topnav__edge {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  display: none;
  align-items: center;
  justify-content: center;
  inline-size: 40px;
  block-size: 100%;
  padding: 0;
  color: var(--ax-text-muted);
  background: var(--ax-surface-overlay);
  border: 0;
  cursor: pointer;
  transition: color var(--ax-motion-fast) var(--ax-ease-standard);
}
.ax-topnav__edge.is-visible {
  display: inline-flex;
}
.ax-topnav__edge:hover {
  color: var(--ax-text-strong);
}
/* the fade that bleeds the scrolling track under the chevron */
.ax-topnav__edge::before {
  content: '';
  position: absolute;
  inset-block: 0;
  inline-size: 28px;
  pointer-events: none;
}
.ax-topnav__edge--prev::before {
  inset-inline-start: 100%;
  background: linear-gradient(to right, var(--ax-surface-overlay), transparent);
}
.ax-topnav__edge--next::before {
  inset-inline-end: 100%;
  background: linear-gradient(to left, var(--ax-surface-overlay), transparent);
}
[dir='rtl'] .ax-topnav__edge--prev::before {
  background: linear-gradient(to left, var(--ax-surface-overlay), transparent);
}
[dir='rtl'] .ax-topnav__edge--next::before {
  background: linear-gradient(to right, var(--ax-surface-overlay), transparent);
}

/* ── bar entries (triggers + direct links) ── */
.ax-topnav__item {
  flex: 0 0 auto;
}
.ax-topnav__trigger,
.ax-topnav__link {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-space-1);
  block-size: 32px;
  padding-inline: var(--ax-space-3);
  font-size: var(--ax-text-sm);
  font-weight: var(--ax-weight-medium);
  color: var(--ax-text-muted);
  white-space: nowrap;
  background: transparent;
  border: 0;
  border-radius: var(--ax-radius-md);
  cursor: pointer;
  transition:
    color var(--ax-motion-fast) var(--ax-ease-standard),
    background var(--ax-motion-fast) var(--ax-ease-standard);
}
.ax-topnav__trigger:hover,
.ax-topnav__link:hover {
  color: var(--ax-text-strong);
  background: var(--ax-fill-hover);
}
.ax-topnav__item.is-open .ax-topnav__trigger,
.ax-topnav__link.is-active {
  color: var(--ax-accent);
  background: var(--ax-fill-hover);
}
.ax-topnav__caret {
  transition: transform var(--ax-motion-fast) var(--ax-ease-standard);
}
.ax-topnav__item.is-open .ax-topnav__caret {
  transform: rotate(180deg);
}

/* ── dropdown panels (position:fixed, placed by core/topnav.js) ── */
.ax-topnav__menu {
  position: fixed;
  z-index: var(--ax-z-dropdown);
  display: none;
  flex-direction: column;
  gap: 1px;
  min-inline-size: 200px;
  max-inline-size: 280px;
  padding: var(--ax-space-2);
  background: var(--ax-surface-overlay);
  border: 1px solid var(--ax-border);
  border-radius: var(--ax-radius-lg);
  box-shadow: var(--ax-shadow-lg);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-backdrop-filter: blur(18px) saturate(1.1);
  backdrop-filter: blur(18px) saturate(1.1);
}
.ax-topnav__item.is-open .ax-topnav__menu {
  display: flex;
}
.ax-topnav__menu-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--ax-space-2);
  padding: var(--ax-space-2) var(--ax-space-3);
  font-size: var(--ax-text-sm);
  color: var(--ax-text-muted);
  white-space: nowrap;
  border-radius: var(--ax-radius-sm);
}
.ax-topnav__menu-link:hover {
  color: var(--ax-text-strong);
  background: var(--ax-fill-hover);
}
.ax-topnav__menu-link.is-active {
  color: var(--ax-accent);
  background: var(--ax-accent-wash);
}
.ax-topnav__menu-heading {
  padding: var(--ax-space-3) var(--ax-space-3) var(--ax-space-1);
  font-size: var(--ax-text-xs);
  font-weight: var(--ax-weight-semibold);
  color: var(--ax-text-subtle);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.ax-topnav__menu-heading:first-child {
  padding-block-start: var(--ax-space-1);
}

/* ════════════════════════════════════════════════════════════════════════
   9 · SIDEBAR INTERNALS  (brand / search / nav scroll / foot scaffolding)
   Detailed nav-item visuals (active gradient, glow bar) are owned by the
   recipes + components briefs; here we lay out the rail's flex regions.
   ════════════════════════════════════════════════════════════════════════ */
.ax-sidebar__brand {
  display: flex;
  align-items: center;
  block-size: var(--ax-header-h);
  padding-inline: var(--ax-space-5);
  flex: 0 0 auto;
}
.ax-sidebar__logo {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-space-3);
  color: var(--ax-text-strong);
}
.ax-sidebar__wordmark {
  font-family: var(--ax-font-display);
  font-size: var(--ax-text-lg);
  font-weight: var(--ax-weight-bold);
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.ax-sidebar__search {
  flex: 0 0 auto;
  padding-inline: var(--ax-space-4);
  /* gap below is a MARGIN (not padding) so the relative box equals the input
     height — keeps the search icon + clear button vertically centred on it. */
  margin-block-end: var(--ax-space-3);
}
.ax-sidebar__nav {
  flex: 1;
  min-block-size: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-inline: var(--ax-space-3);
  padding-block: var(--ax-space-2);
}
.ax-sidebar__foot {
  flex: 0 0 auto;
  padding: var(--ax-space-4);
  border-block-start: 1px solid var(--ax-border);
}

/* section eyebrow inside the rail */
.ax-sidebar__section {
  font-size: var(--ax-text-2xs);
  line-height: var(--ax-leading-2xs);
  font-weight: var(--ax-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--ax-text-subtle);
  padding: var(--ax-space-3) var(--ax-space-3) var(--ax-space-2);
}

/* ════════════════════════════════════════════════════════════════════════
   10 · RESPONSIVE  (auto-collapse 768–992, offcanvas drawer < md)
   ════════════════════════════════════════════════════════════════════════ */

/* 768–992: force compact rail unless the user explicitly chose a wider style */
@media (min-width: 768px) and (max-width: 991.98px) {
  :where(html):not([data-ax-shell-style='detached']) {
    --ax-sidebar-w: var(--ax-sidebar-w-compact);
  }
  /* The width rebind alone squeezes the full 264px rail into 76px — clipping the
     wordmark and wrapping the "MAIN" section eyebrow one char per line. Give the
     DEFAULT sidebar the SAME icon-rail treatment as §7b (hide text affordances,
     centre the brand + icons + avatar, eyebrow → hairline). Explicit styles
     (icon-text / icon-overlay / compact / double) keep their own width + label
     handling, so we exclude [data-ax-sidebar-style]. Keep in sync with §7b. */
  :where(html):not([data-ax-shell-style='detached']):not([data-ax-sidebar-style]) :is(
      .ax-sidebar__wordmark, .ax-nav__label, .ax-nav__badge, .ax-nav__caret,
      .ax-sidebar__search, .ax-sidebar__promo, .ax-sidebar__user-meta,
      .ax-sidebar__user-avatar, .ax-nav__children) {
    display: none;
  }
  :where(html):not([data-ax-shell-style='detached']):not([data-ax-sidebar-style]) .ax-sidebar__brand {
    justify-content: center;
    padding-inline: 0;
  }
  :where(html):not([data-ax-shell-style='detached']):not([data-ax-sidebar-style]) .ax-sidebar__logo {
    gap: 0;
  }
  :where(html):not([data-ax-shell-style='detached']):not([data-ax-sidebar-style]) .ax-nav__item {
    justify-content: center;
    gap: 0;
    padding-inline: 0;
  }
  :where(html):not([data-ax-shell-style='detached']):not([data-ax-sidebar-style]) .ax-nav__item--trail {
    color: var(--ax-text-strong);
    background: linear-gradient(90deg, rgba(var(--ax-accent-rgb), 0.16), rgba(var(--ax-accent-rgb), 0.04));
    box-shadow: inset 0 0 0 1px rgba(var(--ax-accent-rgb), 0.18);
  }
  :where(html):not([data-ax-shell-style='detached']):not([data-ax-sidebar-style]) .ax-nav__item--trail .ax-nav__icon {
    color: var(--ax-accent);
    opacity: 1;
  }
  :where(html):not([data-ax-shell-style='detached']):not([data-ax-sidebar-style]) .ax-sidebar__section {
    block-size: 1px;
    margin: var(--ax-space-2) var(--ax-space-4);
    padding: 0;
    overflow: hidden;
    text-indent: -999px;
    white-space: nowrap;
    background: var(--ax-border);
  }
  :where(html):not([data-ax-shell-style='detached']):not([data-ax-sidebar-style]) .ax-sidebar__user {
    justify-content: center;
  }
  :where(html):not([data-ax-shell-style='detached']):not([data-ax-sidebar-style]) .ax-sidebar__foot {
    padding-inline: var(--ax-space-3);
  }
  /* The rail is locked to the icon width here, so the header toggle has no work
     to do (same as the expanded / compact behavior locks above). Remove it —
     the JS toggleSidebar() also no-ops via isAutoRail(). */
  :where(html):not([data-ax-shell-style='detached']):not([data-ax-sidebar-style]) .ax-nav-toggle {
    display: none;
  }
}

/* < md: sidebar becomes an offcanvas drawer; shell reclaims full width */
@media (max-width: 767.98px) {
  .ax-shell,
  [data-ax-shell-style='detached'] .ax-shell {
    margin-inline-start: 0;
  }
  .ax-header {
    inset-inline-start: 0;
    inset-inline-end: 0;
  }
  .ax-sidebar {
    inline-size: var(--ax-drawer-w);
    --ax-sidebar-w: var(--ax-drawer-w);
    transform: translateX(-100%); /* logical: hidden off inline-start */
    box-shadow: var(--ax-shadow-lg);
    border-radius: 0;
    inset-block: 0;
    inset-inline-start: 0;
    z-index: var(--ax-z-drawer);
  }
  [dir='rtl'] .ax-sidebar {
    transform: translateX(100%);
  }
  /* drawer open state (core/sidebar.js sets data-ax-drawer="open" on <html>) */
  [data-ax-drawer='open'] .ax-sidebar {
    transform: translateX(0);
  }
  /* labels/sections always visible inside the drawer regardless of style */
  [data-ax-sidebar-style] .ax-nav__label,
  [data-ax-sidebar-style] .ax-sidebar__wordmark,
  [data-ax-sidebar-style] .ax-sidebar__section,
  [data-ax-sidebar-style] .ax-nav__caret,
  [data-ax-sidebar-style] .ax-nav__badge {
    display: revert;
    opacity: 1;
  }
  /* tighter page padding on phones */
  .ax-main > :not(.ax-footer) {
    --ax-page-pad: var(--ax-space-4);
    padding-inline: var(--ax-page-pad);
    padding-block: var(--ax-space-4);
  }
  /* footer stacks */
  .ax-footer {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--ax-space-2);
  }
}

/* ── BACKDROP (drawer + offcanvas scrim) ── */
.ax-backdrop {
  position: fixed;
  inset: 0;
  z-index: var(--ax-z-overlay-backdrop);
  background: var(--ax-backdrop);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  border: 0;
}
/* RESTING STATE for the drawer scrim. core/sidebar.js builds the element on the
   first open and then LEAVES IT MOUNTED, toggling `.is-visible` — but nothing
   here ever defined the hidden half of that pair, so the rule above painted a
   full-viewport dim that survived closeDrawer(). Scoped by the attribute, not
   the bare class: content pages (crm/*, apps/contacts, jobs/*) reuse
   `.ax-backdrop` with their own x-show and must keep their default-visible
   behaviour. `visibility` (not `display`) so the fade can run, and so the dead
   scrim cannot swallow taps while it is hidden. */
.ax-backdrop[data-ax-drawer-scrim] {
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--ax-motion-base) var(--ax-ease-standard),
    visibility var(--ax-motion-base) var(--ax-ease-standard);
}
.ax-backdrop[data-ax-drawer-scrim].is-visible {
  opacity: 1;
  visibility: visible;
}

/* body scroll-lock while a full overlay is open (drawer/modal/customizer) */
[data-ax-scroll-lock] body,
body.is-locked {
  overflow: hidden;
}

/* ════════════════════════════════════════════════════════════════════════
   11 · IN-CONTENT PAGE HEADER  (.ax-page-head — breadcrumb + title + actions)
   ════════════════════════════════════════════════════════════════════════ */
.ax-page-head {
  margin-block-end: var(--ax-space-6);
}
/* Breathing room between the breadcrumb trail and the page title below it. */
.ax-page-head .ax-breadcrumb {
  margin-block-end: var(--ax-space-3);
}
.ax-page-head__row {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: var(--ax-space-4);
}
.ax-page-head__title {
  font-family: var(--ax-font-display);
  font-size: var(--ax-text-2xl);
  line-height: var(--ax-leading-2xl);
  font-weight: var(--ax-weight-bold);
  letter-spacing: -0.015em;
  color: var(--ax-text-strong);
}
.ax-page-head__subtitle {
  margin-block-start: var(--ax-space-1);
  font-size: var(--ax-text-md);
  color: var(--ax-text-muted);
}
.ax-page-head__actions {
  margin-inline-start: auto;
  display: flex;
  align-items: center;
  gap: var(--ax-space-2);
  flex-wrap: wrap;
}
/* shared flex spacer used in header + page-head rows */
.ax-header__spacer {
  flex: 1 1 auto;
}

/* ════════════════════════════════════════════════════════════════════════
   12 · PAGE STYLE  [data-ax-page="regular|classic|compact"]
   Regular = glass canvas (default). Classic = solid surface canvas.
   Compact = tighter gutters + smaller page-head spacing (denser layout).
   ════════════════════════════════════════════════════════════════════════ */
[data-ax-page='classic'] {
  --ax-canvas: var(--ax-surface-subtle);
}
/* classic = flat/opaque cards (kill the glass): the actual "classic" tell, so it
   reads distinct from regular beyond the one-step canvas shift. */
[data-ax-page='classic'] .ax-card {
  background: var(--ax-surface-solid);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: var(--ax-shadow-sm);
}
[data-ax-page='classic'] .ax-page-head {
  border-block-end: 1px solid var(--ax-border);
  padding-block-end: var(--ax-space-4);
}
[data-ax-page='compact'] .ax-main > :not(.ax-footer) {
  --ax-page-pad: var(--ax-space-4);
  padding-inline: var(--ax-page-pad);
  padding-block: var(--ax-space-4);
}
[data-ax-page='compact'] .ax-page-head {
  margin-block-end: var(--ax-space-4);
}
/* …and tighten the gutter between cards on the page grid (space-6 → space-4). */
[data-ax-page='compact'] .ax-dash-grid {
  gap: var(--ax-space-4);
}

/* ════════════════════════════════════════════════════════════════════════
   13 · STANDALONE / NO-SHELL pages (auth, error, coming-soon, lock)
   Center their content on the canvas; the shell partials are simply absent.
   ════════════════════════════════════════════════════════════════════════ */
.ax-standalone {
  position: relative;
  z-index: 1;
  min-block-size: 100vh;
  display: grid;
  place-items: center;
  padding: var(--ax-space-6);
}
/* Grid items keep `min-width:auto`, so a centred card can never render narrower
   than its own min-content — the 6-cell OTP row and the signed-out card both sat
   ~370px wide and pushed the whole page sideways on a 390px phone. Opting every
   centring level out of that automatic minimum lets the card shrink instead. */
.ax-standalone > *,
.ax-standalone .ax-center > * {
  min-inline-size: 0;
  max-inline-size: 100%;
}
@media (max-width: 480px) {
  .ax-standalone {
    padding: var(--ax-space-4);
  }
  /* Several standalone pages also pad their inner .ax-center inline, so the
     gutter is paid twice — 96px of a 360px screen. !important is the only way
     past an inline declaration, and the outer padding above already covers it. */
  .ax-standalone > .ax-center {
    padding: 0 !important;
  }
}

/* ════════════════════════════════════════════════════════════════════════
   14 · PAGE LOADER  [data-ax-loader] (visual owned by components; base hides
   it on load and respects the off setting + reduced motion)
   ════════════════════════════════════════════════════════════════════════ */
.ax-loader {
  position: fixed;
  inset: 0;
  z-index: var(--ax-z-customizer);
  display: grid;
  place-items: center;
  background: var(--ax-canvas);
  transition: opacity var(--ax-motion-slow) var(--ax-ease-exit);
}
.ax-loader.is-hidden {
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
}
[data-ax-loader='off'] .ax-loader {
  display: none;
}

/* === components.css === */
/*
 * Vireo — HTML reference edition · COMPONENT LIBRARY (Aurora)
 * ----------------------------------------------------------------------------
 * One block per component, per BUILD BRIEF 04 (the contract). Everything lives
 * in 
  /* ========================================================================
     0 · SHARED PRIMITIVES (mixins / helpers used across many components)
     ======================================================================== */

  /* Aurora glass surface — compose into menu / modal / popover / toast.
     Cards use the dedicated .ax-card below; this is the generic floating glass. */
  .ax-glass {
    position: relative;
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
    box-shadow: var(--ax-shadow-md);
    -webkit-backdrop-filter: blur(18px) saturate(1.1);
    backdrop-filter: blur(18px) saturate(1.1);
  }
  .ax-glass::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    box-shadow: inset 0 1px 0 var(--ax-glass-hi);
  }
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .ax-glass {
      background: var(--ax-surface-solid);
    }
  }

  /* visually-hidden (a11y) — avatars/spinners/ratings/icon-only labels */
  .ax-visually-hidden {
    position: absolute !important;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  /* tabular numerics helper (also in primitives; safe to repeat) */
  .ax-num {
    font-variant-numeric: tabular-nums;
  }

  /* shared keyframes */
  @keyframes ax-spin {
    to {
      transform: rotate(360deg);
    }
  }

  /* ========================================================================
     1 · BUTTONS — .ax-btn
     Style variants: --primary(gradient pill glow), --solid(flat accent),
       --secondary/--outline, --tertiary/--tonal, --ghost, --link,
       --soft-{success|warning|info|danger}.
     Tones: --accent(default), --neutral, --success, --warning, --danger, --info.
     Sizes: --sm/--compact(32), default(38), --lg(44). Plus --icon, --block, --pill.
     States: hover / :focus-visible / active / disabled / is-loading.
     Alpine: none for base (toggles add aria-pressed; openers aria-expanded).
     ======================================================================== */
  .ax-btn {
    --_btn-h: var(--ax-control-h); /* 38 */
    --_btn-px: var(--ax-space-4);
    --_btn-fz: var(--ax-text-sm);
    --_btn-icon: var(--ax-icon-sm);
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ax-space-2);
    min-height: var(--_btn-h);
    padding-block: 0;
    padding-inline: var(--_btn-px);
    font-family: var(--ax-font-sans);
    font-size: var(--_btn-fz);
    font-weight: var(--ax-weight-semibold);
    line-height: 1;
    color: var(--ax-text);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--ax-radius-sm);
    transition: background var(--ax-motion-instant) var(--ax-ease-standard),
      border-color var(--ax-motion-instant) var(--ax-ease-standard),
      color var(--ax-motion-instant) var(--ax-ease-standard),
      box-shadow var(--ax-motion-fast) var(--ax-ease-standard),
      filter var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-btn__icon {
    flex: 0 0 auto;
    width: var(--_btn-icon);
    height: var(--_btn-icon);
    color: currentColor;
  }
  .ax-btn__label {
    overflow: hidden;
    text-overflow: ellipsis;
    /* .ax-btn sets line-height:1 (for icon centring), but that makes the label's
       line box = em-size, so overflow:hidden clips glyph descenders (g/j/p/q/y).
       Restore enough leading to contain them; flex align-items:center keeps it
       vertically centred regardless. */
    line-height: 1.25;
    padding-block: 0.05em;
  }
  .ax-btn__spinner {
    position: absolute;
    inset-inline-start: 50%;
    top: 50%;
    width: var(--_btn-icon);
    height: var(--_btn-icon);
    /* Centre via translate, not negative margins: the unlayered `* { margin:0 }`
       reset in base.css beats this layered rule (unlayered > layered), so margins
       compute to 0. `translate` is independent of the rotate animation's
       `transform`, so both apply. */
    translate: -50% -50%;
    border-radius: 50%;
    border: 2px solid currentColor;
    border-inline-end-color: transparent;
    opacity: 0;
    animation: ax-spin 0.7s var(--ax-ease-linear) infinite;
  }

  /* — sizes — */
  .ax-btn--sm,
  .ax-btn--compact {
    --_btn-h: var(--ax-control-h-compact);
    --_btn-px: var(--ax-space-3);
    --_btn-fz: var(--ax-text-xs);
  }
  .ax-btn--lg {
    --_btn-h: var(--ax-control-h-lg);
    --_btn-px: var(--ax-space-5);
    --_btn-fz: var(--ax-text-base);
    --_btn-icon: var(--ax-icon-md);
  }

  /* — icon-only — square; label hidden; REQUIRES aria-label — */
  .ax-btn--icon {
    padding-inline: 0;
    width: var(--_btn-h);
    aspect-ratio: 1;
  }
  .ax-btn--block {
    display: flex;
    width: 100%;
  }
  .ax-btn--pill {
    border-radius: var(--ax-radius-pill);
  }

  /* — PRIMARY: Aurora gradient + accent glow (signature) — */
  .ax-btn--primary {
    color: var(--ax-on-accent);
    background: var(--ax-gradient-accent);
    border-color: transparent;
    box-shadow: var(--ax-glow-accent);
  }
  .ax-btn--primary:hover {
    filter: brightness(1.06);
    box-shadow: var(--ax-glow-accent), var(--ax-shadow-sm);
  }
  .ax-btn--primary:active {
    filter: brightness(0.97);
  }

  /* — SOLID: flat accent fill — */
  .ax-btn--solid {
    color: var(--ax-on-accent);
    background: var(--ax-accent);
    border-color: transparent;
  }
  .ax-btn--solid:hover {
    background: var(--ax-accent-hover);
  }
  .ax-btn--solid:active {
    filter: brightness(0.97);
  }

  /* — SECONDARY / OUTLINE — */
  .ax-btn--secondary,
  .ax-btn--outline {
    color: var(--ax-text);
    background: transparent;
    border-color: var(--ax-border-strong);
  }
  .ax-btn--secondary:hover,
  .ax-btn--outline:hover {
    background: var(--ax-fill-hover);
    color: var(--ax-text-strong);
  }
  .ax-btn--secondary:active,
  .ax-btn--outline:active {
    background: var(--ax-fill-active);
  }

  /* — TERTIARY / TONAL — */
  .ax-btn--tertiary,
  .ax-btn--tonal {
    color: var(--ax-text-strong);
    background: var(--ax-fill-hover);
    border-color: transparent;
  }
  .ax-btn--tertiary:hover,
  .ax-btn--tonal:hover {
    background: var(--ax-fill-active);
  }

  /* — GHOST — */
  .ax-btn--ghost {
    color: var(--ax-text);
    background: transparent;
    border-color: transparent;
  }
  .ax-btn--ghost:hover {
    background: var(--ax-fill-hover);
    color: var(--ax-text-strong);
  }
  .ax-btn--ghost:active {
    background: var(--ax-fill-active);
  }

  /* — LINK — */
  .ax-btn--link {
    min-height: 0;
    padding: 0;
    color: var(--ax-link);
    background: transparent;
    border: 0;
    border-radius: var(--ax-radius-xs);
  }
  .ax-btn--link:hover {
    color: var(--ax-accent-hover);
    text-decoration: underline;
    text-underline-offset: 2px;
  }

  /* — TONE modifiers: locally remap the accent role to a semantic so
       --primary/--solid/--ghost pick it up automatically — */
  .ax-btn--success {
    --ax-accent: var(--ax-success-500);
    --ax-accent-hover: var(--ax-success-500);
    --ax-on-accent: #fff;
    --ax-link: var(--ax-success-500);
    --ax-focus-ring: var(--ax-success-500);
  }
  .ax-btn--warning {
    --ax-accent: var(--ax-warning-500);
    --ax-accent-hover: var(--ax-warning-500);
    --ax-on-accent: #fff;
    --ax-link: var(--ax-warning-500);
    --ax-focus-ring: var(--ax-warning-500);
  }
  .ax-btn--danger {
    --ax-accent: var(--ax-danger-500);
    --ax-accent-hover: var(--ax-danger-500);
    --ax-on-accent: #fff;
    --ax-link: var(--ax-danger-500);
    --ax-focus-ring: var(--ax-danger-500);
  }
  .ax-btn--info {
    --ax-accent: var(--ax-info-500);
    --ax-accent-hover: var(--ax-info-500);
    --ax-on-accent: #fff;
    --ax-link: var(--ax-info-500);
    --ax-focus-ring: var(--ax-info-500);
  }
  .ax-btn--neutral {
    --ax-accent: var(--ax-text-strong);
    --ax-accent-hover: var(--ax-text);
    --ax-on-accent: var(--ax-canvas);
    --ax-link: var(--ax-text);
    --ax-focus-ring: var(--ax-text-strong);
  }
  /* semantic tones lack an --ax-accent-rgb glow pair → flatten primary fill */
  .ax-btn--success.ax-btn--primary,
  .ax-btn--warning.ax-btn--primary,
  .ax-btn--danger.ax-btn--primary,
  .ax-btn--info.ax-btn--primary,
  .ax-btn--neutral.ax-btn--primary {
    background: var(--ax-accent);
    box-shadow: var(--ax-shadow-sm);
  }

  /* — SOFT semantic buttons — */
  .ax-btn--soft-success {
    color: var(--ax-success-500);
    background: var(--ax-success-50);
  }
  .ax-btn--soft-warning {
    color: var(--ax-warning-500);
    background: var(--ax-warning-50);
  }
  .ax-btn--soft-danger {
    color: var(--ax-danger-500);
    background: var(--ax-danger-50);
  }
  .ax-btn--soft-info {
    color: var(--ax-info-500);
    background: var(--ax-info-50);
  }
  .ax-btn--soft-success:hover,
  .ax-btn--soft-warning:hover,
  .ax-btn--soft-danger:hover,
  .ax-btn--soft-info:hover {
    filter: brightness(0.97);
  }

  /* — disabled — */
  .ax-btn:disabled,
  .ax-btn[aria-disabled="true"],
  .ax-btn.is-disabled {
    color: var(--ax-text-disabled);
    background: var(--ax-fill-hover);
    border-color: transparent;
    box-shadow: none;
    filter: none;
    cursor: not-allowed;
    pointer-events: none;
  }

  /* — loading: reveal spinner, dim label, preserve width, block clicks — */
  .ax-btn.is-loading {
    pointer-events: none;
  }
  .ax-btn.is-loading .ax-btn__label {
    opacity: 0;
  }
  .ax-btn.is-loading .ax-btn__icon {
    opacity: 0;
  }
  .ax-btn.is-loading .ax-btn__spinner {
    opacity: 1;
  }

  @media (prefers-reduced-motion: reduce) {
    .ax-btn__spinner {
      animation-duration: 1.2s;
    }
  }

  /* ========================================================================
     2 · BUTTON GROUP / SEGMENTED — .ax-btn-group
     Variants: --action, --segmented(radio), --multi, --split, --vertical.
     Members share one hairline seam; only outer corners rounded.
     Selected (segmented) = accent-wash + accent text (NOT hover).
     Alpine: axTabs-style roving tabindex; split caret uses axDropdown.
     ======================================================================== */
  .ax-btn-group {
    display: inline-flex;
    align-items: stretch;
  }
  .ax-btn-group > .ax-btn {
    border-radius: 0;
  }
  .ax-btn-group > .ax-btn:not(:first-child) {
    margin-inline-start: -1px;
  }
  .ax-btn-group > .ax-btn:first-child {
    border-start-start-radius: var(--ax-radius-sm);
    border-end-start-radius: var(--ax-radius-sm);
  }
  .ax-btn-group > .ax-btn:last-child {
    border-start-end-radius: var(--ax-radius-sm);
    border-end-end-radius: var(--ax-radius-sm);
  }
  .ax-btn-group > .ax-btn:hover,
  .ax-btn-group > .ax-btn:focus-visible {
    z-index: 1;
  }

  .ax-btn-group--vertical {
    flex-direction: column;
  }
  .ax-btn-group--vertical > .ax-btn:not(:first-child) {
    margin-inline-start: 0;
    margin-top: -1px;
  }
  .ax-btn-group--vertical > .ax-btn:first-child {
    border-radius: var(--ax-radius-sm) var(--ax-radius-sm) 0 0;
  }
  .ax-btn-group--vertical > .ax-btn:last-child {
    border-radius: 0 0 var(--ax-radius-sm) var(--ax-radius-sm);
  }

  /* segmented: boxed track + accent-wash selection */
  .ax-btn-group--segmented {
    padding: var(--ax-space-1);
    gap: var(--ax-space-1);
    background: var(--ax-fill-hover);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
  }
  .ax-btn-group--segmented > .ax-btn {
    border: 0;
    margin-inline-start: 0;
    border-radius: var(--ax-radius-sm) !important;
    color: var(--ax-text-muted);
    background: transparent;
  }
  .ax-btn-group--segmented > .ax-btn:hover {
    color: var(--ax-text-strong);
    background: var(--ax-fill-hover);
  }
  .ax-btn-group--segmented > .ax-btn[aria-checked="true"],
  .ax-btn-group--segmented > .ax-btn.is-selected,
  .ax-btn-group--segmented > .ax-btn[aria-pressed="true"] {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
    box-shadow: var(--ax-shadow-sm);
  }

  .ax-btn-group--split > .ax-btn-group__caret {
    padding-inline: var(--ax-space-2);
  }

  /* ========================================================================
     3 · CARDS — .ax-card  (THE glass recipe surface)
     Sub: __header/__titles/__eyebrow/__title/__subtitle/__actions/__media/
          __body/__footer/__handle.
     Variants: --stat/--chart/--media/--collapsible/--accent-edge/--interactive/
               --compact/--selected. States: hover/selected/loading/dragging.
     Alpine: --collapsible→axCollapse; --draggable→axSortable.
     ======================================================================== */
  .ax-card {
    position: relative;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    color: var(--ax-text);
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-xl);
    box-shadow: var(--ax-shadow-card);
    -webkit-backdrop-filter: blur(18px) saturate(1.1);
    backdrop-filter: blur(18px) saturate(1.1);
    transition: box-shadow var(--ax-motion-base) var(--ax-ease-standard),
      border-color var(--ax-motion-base) var(--ax-ease-standard),
      transform var(--ax-motion-base) var(--ax-ease-standard);
  }
  .ax-card::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    box-shadow: inset 0 1px 0 var(--ax-glass-hi);
  }
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .ax-card {
      background: var(--ax-surface-solid);
    }
  }
  .ax-card__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--ax-space-3);
    padding: var(--ax-space-5) var(--ax-space-6);
  }
  .ax-card__header + .ax-card__body {
    padding-top: 0;
  }
  .ax-card__titles {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
  }
  .ax-card__eyebrow {
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ax-text-subtle);
  }
  .ax-card__title {
    margin: 0;
    font-family: var(--ax-font-display);
    font-size: var(--ax-text-lg);
    font-weight: var(--ax-weight-semibold);
    line-height: var(--ax-leading-lg);
    color: var(--ax-text-strong);
  }
  .ax-card__subtitle {
    margin: 0;
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
  }
  .ax-card__actions {
    display: flex;
    align-items: center;
    gap: var(--ax-space-2);
    flex: 0 0 auto;
  }
  .ax-card__media {
    position: relative;
    overflow: hidden;
  }
  .ax-card__body {
    padding: var(--ax-space-6);
    flex: 1 1 auto;
  }
  .ax-card__footer {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
    padding: var(--ax-space-4) var(--ax-space-6);
    border-top: 1px solid var(--ax-border);
  }
  .ax-card__handle {
    display: inline-flex;
    color: var(--ax-text-subtle);
    background: none;
    border: 0;
    cursor: grab;
  }
  .ax-card__handle:active {
    cursor: grabbing;
  }

  .ax-card--compact .ax-card__header {
    padding: var(--ax-space-4) var(--ax-space-5);
  }
  .ax-card--compact .ax-card__body {
    padding: var(--ax-space-5);
  }

  /* Balance plate: stack the header so the currency switcher drops to its own
     line instead of squeezing the title in the narrow (col--4) header. */
  .ax-card--balance .ax-card__header {
    flex-direction: column;
    align-items: flex-start;
  }

  .ax-card--accent-edge::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    width: 3px;
    background: var(--ax-accent);
    z-index: 1;
  }

  .ax-card--interactive {
    cursor: pointer;
  }
  .ax-card--interactive:hover {
    box-shadow: var(--ax-shadow-lg);
    border-color: var(--ax-border-strong);
  }
  .ax-card--interactive:focus-visible {
    outline: 2px solid var(--ax-focus-ring);
    outline-offset: 2px;
  }

  .ax-card.is-selected,
  .ax-card--selected {
    border-color: var(--ax-accent);
  }
  .ax-card.is-selected .ax-card__header,
  .ax-card--selected .ax-card__header {
    background: var(--ax-accent-wash);
  }

  .ax-card.is-loading {
    pointer-events: none;
  }
  .ax-card.is-dragging {
    opacity: 0.6;
    box-shadow: var(--ax-shadow-lg);
  }
  .ax-card--media .ax-card__media {
    border-radius: var(--ax-radius-xl) var(--ax-radius-xl) 0 0;
  }

  /* ── CARD MATERIALS ─────────────────────────────────────────────────────
     --filled / --gradient / --bleed / --flat live UNLAYERED in
     tokens/_recipes.css, directly under the .ax-card primitive they override.
     They cannot live here: .ax-card is itself unlayered, and an unlayered
     rule beats every rule in @layer components no matter how specific — so a
     material declared here would lose its background and paint white ink on
     the untouched glass surface. Keep them next to the primitive. */

  /* ========================================================================
     4 · KPI WIDGET — .ax-kpi (standalone) + .ax-card--stat (card flavour)
     __icon tile (c1..c4 = accent/cyan/violet/amber), __value (display, tabular),
     __delta up/down chip, __label, optional __spark.
     Alpine: none (count-up via page JS; disabled under reduced-motion).
     ======================================================================== */
  .ax-kpi {
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-3);
  }
  .ax-kpi__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ax-space-3);
  }
  .ax-kpi__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--ax-radius-md);
    color: var(--ax-accent);
    background: rgba(var(--ax-accent-rgb), 0.14);
  }
  .ax-kpi__icon svg {
    width: var(--ax-icon-md);
    height: var(--ax-icon-md);
  }
  .ax-kpi__icon--c1 {
    color: var(--ax-accent);
    background: rgba(var(--ax-accent-rgb), 0.14);
  }
  .ax-kpi__icon--c2 {
    color: var(--ax-viz-cyan);
    background: color-mix(in oklab, var(--ax-viz-cyan) 14%, transparent);
  }
  .ax-kpi__icon--c3 {
    color: var(--ax-viz-violet);
    background: color-mix(in oklab, var(--ax-viz-violet) 14%, transparent);
  }
  .ax-kpi__icon--c4 {
    color: var(--ax-viz-amber);
    background: color-mix(in oklab, var(--ax-viz-amber) 14%, transparent);
  }
  .ax-kpi__label {
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
  }
  .ax-kpi__value {
    font-family: var(--ax-font-display);
    font-size: var(--ax-num-kpi);
    line-height: var(--ax-leading-kpi);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
  }
  .ax-kpi__meta {
    display: flex;
    align-items: center;
    gap: var(--ax-space-2);
    flex-wrap: wrap;
  }
  .ax-kpi__delta,
  .ax-card__delta {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 2px var(--ax-space-2);
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-semibold);
    font-variant-numeric: tabular-nums;
    border-radius: var(--ax-radius-pill);
  }
  .ax-kpi__delta svg,
  .ax-card__delta svg {
    width: var(--ax-icon-xs);
    height: var(--ax-icon-xs);
    stroke-width: var(--ax-icon-stroke-bold);
  }
  .ax-kpi__delta--up,
  .ax-card__delta--up {
    color: var(--ax-delta-up);
    background: color-mix(in oklab, var(--ax-delta-up) 14%, transparent);
  }
  .ax-kpi__delta--down,
  .ax-card__delta--down {
    color: var(--ax-delta-down);
    background: color-mix(in oklab, var(--ax-delta-down) 14%, transparent);
  }
  .ax-kpi__caption {
    font-size: var(--ax-text-xs);
    color: var(--ax-text-subtle);
  }
  .ax-kpi__spark {
    margin-top: var(--ax-space-2);
  }

  /* ── KPI layout: icon top-left · title + delta stacked top-right ·
     value and spark each on their own row. The grid container is whatever
     directly holds .ax-kpi__top — the card body, or the bare wrapper used in
     the skeletons "loaded" preview — so every KPI card is patched uniformly
     with no markup change. :has + display:contents sit inside the Tailwind v4
     browser baseline this stack already targets. */
  :has(> .ax-kpi__top) {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: var(--ax-space-3);
    row-gap: var(--ax-space-2);
    align-items: center;
  }
  /* dissolve the icon/delta and value/spark wrappers so all five pieces
     become direct grid items of the container above */
  :has(> .ax-kpi__top) > .ax-kpi__top,
  :has(> .ax-kpi__meta) > .ax-kpi__meta {
    display: contents;
  }
  :has(> .ax-kpi__top) > .ax-kpi__top > .ax-kpi__icon {
    grid-column: 1;
    grid-row: 1 / span 2;
    align-self: start;
  }
  :has(> .ax-kpi__top) > .ax-kpi__label {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
    text-align: end;
  }
  :has(> .ax-kpi__top) > .ax-kpi__top > .ax-kpi__delta {
    grid-column: 2;
    grid-row: 2;
    justify-self: end;
  }
  :has(> .ax-kpi__top) > .ax-kpi__value,
  :has(> .ax-kpi__meta) > .ax-kpi__meta > .ax-kpi__value {
    grid-column: 1 / -1;
    grid-row: 3;
    margin: 0;
  }
  :has(> .ax-kpi__meta) > .ax-kpi__meta > .ax-kpi__spark {
    grid-column: 1 / -1;
    grid-row: 4;
    width: 100%;
    margin: 0;
  }

  /* card-stat flavour reuses kpi internals */
  .ax-card--stat .ax-card__body {
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-3);
  }
  .ax-card__kpi-val {
    font-family: var(--ax-font-display);
    font-size: var(--ax-num-kpi);
    line-height: var(--ax-leading-kpi);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
    font-variant-numeric: tabular-nums;
  }
  .ax-card__kpi-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--ax-radius-md);
    color: var(--ax-accent);
    background: rgba(var(--ax-accent-rgb), 0.14);
  }
  .ax-card__kpi-icon--c1 {
    color: var(--ax-accent);
    background: rgba(var(--ax-accent-rgb), 0.14);
  }
  .ax-card__kpi-icon--c2 {
    color: var(--ax-viz-cyan);
    background: color-mix(in oklab, var(--ax-viz-cyan) 14%, transparent);
  }
  .ax-card__kpi-icon--c3 {
    color: var(--ax-viz-violet);
    background: color-mix(in oklab, var(--ax-viz-violet) 14%, transparent);
  }
  .ax-card__kpi-icon--c4 {
    color: var(--ax-viz-amber);
    background: color-mix(in oklab, var(--ax-viz-amber) 14%, transparent);
  }

  /* ========================================================================
     4b · DASHBOARD COMPOSITION BLOCKS
     Six openers and summarisers that give a dashboard a silhouette of its
     own. Without them every page can only be built as "four KPI tiles, then
     an 8+4 chart row", which is exactly how 17 dashboards end up looking
     like one dashboard. Each is a plain block usable inside any .ax-card.
       .ax-welcome    greeting band — the page's own voice, replaces a KPI row
       .ax-statgroup  4–6 metrics inside ONE card, not four cards
       .ax-quicktiles action tile grid
       .ax-gauge      radial figure + supporting rows
       .ax-ranklist   ranked rows with an inline proportion bar
       .ax-spotlight  one figure, oversized, for a --gradient/--filled card
     ======================================================================== */

  /* ── Welcome band. Sits at col--12 or col--8; the stat rail wraps under the
     copy on narrow columns. The glow is decorative and accent-derived. */
  .ax-welcome {
    position: relative;
    overflow: hidden;
  }
  .ax-welcome::before {
    content: "";
    position: absolute;
    inset-block-start: -60%;
    inset-inline-end: -10%;
    width: 420px;
    height: 420px;
    border-radius: 50%;
    background: radial-gradient(
      circle,
      rgba(var(--ax-accent-rgb), 0.18) 0%,
      transparent 70%
    );
    pointer-events: none;
  }
  .ax-welcome__body {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--ax-space-6);
    padding: var(--ax-space-6);
  }
  /* Spaced with flex GAP, not child margins. base.css's reset is unlayered, and
     its `* { margin: 0 }` beats anything declared here in @layer components no
     matter how specific — so the eyebrow's margin-bottom, the lede's margin-top
     and the action row's margin-top all computed to 0 and the four rows sat
     flush against each other, separated only by their line-box leading. gap is
     set by the container, so the reset can't reach it. */
  .ax-welcome__text {
    min-width: 0;
    flex: 1 1 260px;
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-2);
  }
  .ax-welcome__eyebrow {
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ax-text-subtle);
  }
  .ax-welcome__title {
    font-family: var(--ax-font-display);
    font-size: var(--ax-text-2xl);
    font-weight: var(--ax-weight-semibold);
    line-height: 1.15;
    letter-spacing: -0.01em;
    color: var(--ax-text-strong);
  }
  .ax-welcome__lede {
    max-width: 52ch;
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
  }
  /* The action row is a step down in the hierarchy, not another paragraph: it
     needs the same air the card gives its own edges, otherwise the buttons read
     as attached to the last line of the lede. Padding rather than margin, for
     the reason above — it stacks on the column's 8px gap to make 24. */
  .ax-welcome__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ax-space-2);
    padding-block-start: var(--ax-space-4);
  }
  .ax-welcome__stats {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ax-space-6);
    margin: 0;
    flex: 0 1 auto;
  }
  .ax-welcome__stat {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 92px;
  }
  .ax-welcome__stat dt {
    font-size: var(--ax-text-xs);
    color: var(--ax-text-subtle);
  }
  .ax-welcome__stat dd {
    margin: 0;
    font-family: var(--ax-font-display);
    font-size: var(--ax-text-xl);
    font-weight: var(--ax-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--ax-text-strong);
  }
  /* On a gradient card the band inherits inverted ink. */
  .ax-card--gradient .ax-welcome__title,
  .ax-card--gradient .ax-welcome__stat dd {
    color: inherit;
  }
  .ax-card--gradient .ax-welcome__eyebrow,
  .ax-card--gradient .ax-welcome__lede,
  .ax-card--gradient .ax-welcome__stat dt {
    color: inherit;
    opacity: 0.82;
  }
  .ax-card--gradient .ax-welcome::before {
    background: radial-gradient(circle, rgba(255, 255, 255, 0.18) 0%, transparent 70%);
  }

  /* ── Stat group: the anti-KPI-row. Cells share one card, divided by
     hairlines each cell draws on its own leading and trailing edge. The
     dividers are box-shadows rather than a painted grid background: a group
     whose count does not divide by the column count leaves empty tracks in
     the last row, and a painted background turns those into a grey slab. A
     shadow is drawn by the cell, so an absent cell draws nothing and the card
     material shows through instead. overflow:hidden clips the outermost rules,
     so no edge of the block carries a dangling hairline.
     Cells stay transparent for the same reason — an opaque cell would paint
     over the accent wash of a --filled card or the matte of a --flat one. */
  .ax-statgroup {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    border-radius: var(--ax-radius-md);
    overflow: hidden;
  }
  /* Stacked: a vertical KPI rail for the 4-column slot beside a hero chart,
     which is the whole point of leading a page with the chart instead of a
     row of tiles. */
  .ax-statgroup--stack {
    grid-template-columns: 1fr;
  }
  /* Six is the one count that reliably orphans: five 210px tracks fit across a
     12-column card before six do, so a six-cell group runs 5 + 1 with a lone
     cell stranded on its own row. Capping the track at a third of the block
     makes it wrap as two full rows of three, and the 210px floor still takes
     over on narrow screens (2 + 2 + 2, then stacked). */
  .ax-statgroup:not(.ax-statgroup--stack):has(> .ax-statgroup__cell:nth-child(6)):not(
      :has(> .ax-statgroup__cell:nth-child(7))
    ) {
    grid-template-columns: repeat(auto-fit, minmax(max(210px, 33.333%), 1fr));
  }
  .ax-statgroup__cell {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
    padding: var(--ax-space-4);
    /* leading rule + rule underneath; both fall outside the block on the
       first column and the last row, where overflow:hidden removes them. */
    box-shadow: -1px 0 0 var(--ax-border), 0 1px 0 var(--ax-border);
  }
  [dir="rtl"] .ax-statgroup__cell {
    box-shadow: 1px 0 0 var(--ax-border), 0 1px 0 var(--ax-border);
  }
  .ax-statgroup__icon {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: var(--ax-radius-sm);
    color: var(--ax-accent);
    background: rgba(var(--ax-accent-rgb), 0.14);
  }
  .ax-statgroup__icon svg {
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
  }
  .ax-statgroup__icon--c2 {
    color: var(--ax-viz-cyan);
    background: color-mix(in oklab, var(--ax-viz-cyan) 14%, transparent);
  }
  .ax-statgroup__icon--c3 {
    color: var(--ax-viz-violet);
    background: color-mix(in oklab, var(--ax-viz-violet) 14%, transparent);
  }
  .ax-statgroup__icon--c4 {
    color: var(--ax-viz-amber);
    background: color-mix(in oklab, var(--ax-viz-amber) 14%, transparent);
  }
  .ax-statgroup__icon--c5 {
    color: var(--ax-viz-emerald);
    background: color-mix(in oklab, var(--ax-viz-emerald) 14%, transparent);
  }
  .ax-statgroup__icon--c6 {
    color: var(--ax-viz-pink);
    background: color-mix(in oklab, var(--ax-viz-pink) 14%, transparent);
  }
  .ax-statgroup__text {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
  }
  /* Labels wrap rather than ellipsize: a two-word metric name clipped to
     "Cus…" tells the reader nothing, and the row simply grows to fit. */
  .ax-statgroup__label {
    font-size: var(--ax-text-xs);
    line-height: 1.35;
    color: var(--ax-text-muted);
  }
  /* The figure is the one thing that must not wrap, so it is also the one
     thing that can outgrow a squeezed cell — clip it rather than let it run
     under the delta. */
  .ax-statgroup__value {
    font-family: var(--ax-font-display);
    font-size: var(--ax-text-lg);
    font-weight: var(--ax-weight-semibold);
    font-variant-numeric: tabular-nums;
    line-height: 1.2;
    color: var(--ax-text-strong);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .ax-statgroup__delta {
    flex: 0 0 auto;
    margin-inline-start: auto;
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-semibold);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
  .ax-statgroup__delta--up {
    color: var(--ax-delta-up);
  }
  .ax-statgroup__delta--down {
    color: var(--ax-delta-down);
  }

  /* ── Quick-action tiles. */
  .ax-quicktiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(104px, 1fr));
    gap: var(--ax-space-3);
  }
  .ax-quicktiles--ecommerce {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .ax-quicktiles__tile {
    display: flex;
    min-height: 94px;
    min-width: 0;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: var(--ax-space-2);
    padding: var(--ax-space-4) var(--ax-space-2);
    text-align: right;
    color: var(--ax-text-muted);
    background: var(--ax-surface-subtle);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
    cursor: pointer;
    text-decoration: none;
    transition: color var(--ax-motion-base) var(--ax-ease-standard),
      border-color var(--ax-motion-base) var(--ax-ease-standard),
      background var(--ax-motion-base) var(--ax-ease-standard),
      transform var(--ax-motion-base) var(--ax-ease-standard);
  }
  .ax-quicktiles__tile:hover {
    transform: translateY(-2px);
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
    border-color: rgba(var(--ax-accent-rgb), 0.35);
  }
  .ax-quicktiles__tile:focus-visible {
    outline: 2px solid var(--ax-focus-ring);
    outline-offset: 2px;
  }
  .ax-quicktiles__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    align-self: flex-start;
    width: 38px;
    height: 38px;
    border-radius: var(--ax-radius-md);
    color: var(--ax-accent);
    background: rgba(var(--ax-accent-rgb), 0.12);
  }
  .ax-quicktiles__icon svg {
    width: var(--ax-icon-md);
    height: var(--ax-icon-md);
  }
  .ax-quicktiles__label {
    min-width: 0;
    max-width: 100%;
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-medium);
    line-height: 1.25;
    overflow-wrap: anywhere;
  }

  @media (max-width: 640px) {
    .ax-quicktiles--ecommerce {
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: var(--ax-space-2);
    }
    .ax-quicktiles--ecommerce .ax-quicktiles__tile {
      padding-inline: 4px;
    }
    .ax-quicktiles--ecommerce .ax-quicktiles__icon {
      width: 34px;
      height: 34px;
    }
  }

  /* ── Gauge card: one radial figure with supporting rows beneath. */
  .ax-gauge {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--ax-space-3);
  }
  .ax-gauge__chart {
    width: 100%;
    min-height: 0;
  }
  .ax-gauge__caption {
    font-size: var(--ax-text-sm);
    text-align: center;
    color: var(--ax-text-muted);
  }
  .ax-gauge__rows {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
    gap: var(--ax-space-3);
    width: 100%;
    padding-top: var(--ax-space-3);
    border-top: 1px solid var(--ax-border);
  }
  .ax-gauge__row {
    display: flex;
    flex-direction: column;
    gap: 2px;
    text-align: center;
  }
  .ax-gauge__row-label {
    font-size: var(--ax-text-xs);
    color: var(--ax-text-subtle);
  }
  .ax-gauge__row-value {
    font-family: var(--ax-font-display);
    font-size: var(--ax-text-md);
    font-weight: var(--ax-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--ax-text-strong);
  }

  /* ── Rank list: ranked rows carrying their own proportion bar, so a
     leaderboard reads as a chart without costing a chart mount. */
  .ax-ranklist {
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-4);
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .ax-ranklist__item {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    column-gap: var(--ax-space-3);
    row-gap: var(--ax-space-2);
  }
  .ax-ranklist__rank {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--ax-text-muted);
    background: var(--ax-surface-subtle);
    border-radius: var(--ax-radius-sm);
  }
  .ax-ranklist__item:first-child .ax-ranklist__rank {
    color: var(--ax-accent);
    background: rgba(var(--ax-accent-rgb), 0.14);
  }
  .ax-ranklist__label {
    min-width: 0;
    font-size: var(--ax-text-sm);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-strong);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .ax-ranklist__meta {
    display: block;
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-regular);
    color: var(--ax-text-subtle);
  }
  .ax-ranklist__value {
    font-family: var(--ax-font-mono);
    font-size: var(--ax-text-sm);
    font-variant-numeric: tabular-nums;
    color: var(--ax-text-strong);
  }
  .ax-ranklist__bar {
    grid-column: 2 / -1;
    height: 4px;
    background: var(--ax-fill-hover);
    border-radius: var(--ax-radius-pill);
    overflow: hidden;
  }
  .ax-ranklist__bar > i {
    display: block;
    height: 100%;
    background: var(--ax-accent);
    border-radius: inherit;
  }

  /* ── Spotlight: one oversized figure. Designed for a --gradient or
     --filled card, where it inherits the inverted ink. */
  .ax-spotlight {
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-2);
  }
  .ax-spotlight__label {
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-medium);
    letter-spacing: 0.03em;
    text-transform: uppercase;
    opacity: 0.82;
  }
  .ax-spotlight__value {
    font-family: var(--ax-font-display);
    font-size: var(--ax-text-3xl);
    font-weight: var(--ax-weight-bold);
    line-height: 1.05;
    letter-spacing: -0.02em;
    font-variant-numeric: tabular-nums;
  }
  .ax-spotlight__foot {
    display: flex;
    align-items: center;
    gap: var(--ax-space-2);
    font-size: var(--ax-text-sm);
    opacity: 0.9;
  }
  .ax-spotlight__chip {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 2px var(--ax-space-2);
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-semibold);
    font-variant-numeric: tabular-nums;
    border-radius: var(--ax-radius-pill);
    background: rgba(255, 255, 255, 0.22);
  }
  .ax-spotlight__chip svg {
    width: var(--ax-icon-xs);
    height: var(--ax-icon-xs);
    stroke-width: var(--ax-icon-stroke-bold);
  }
  /* Outside a gradient card the chip needs a real tone, not white-on-white. */
  .ax-card:not(.ax-card--gradient) .ax-spotlight__label,
  .ax-card:not(.ax-card--gradient) .ax-spotlight__foot {
    color: var(--ax-text-muted);
    opacity: 1;
  }
  .ax-card:not(.ax-card--gradient) .ax-spotlight__value {
    color: var(--ax-text-strong);
  }
  .ax-card:not(.ax-card--gradient) .ax-spotlight__chip {
    color: var(--ax-delta-up);
    background: color-mix(in oklab, var(--ax-delta-up) 14%, transparent);
  }

  /* ========================================================================
     5 · BADGES — .ax-badge
     Variants: --soft(default)/--solid/--outline/--dot/--count/--pill/--chip/--filter.
     Tones: --success/--warning/--danger/--info/--neutral/--accent.
     Sizes: --sm/default. Alpine: --chip remove / --filter toggles aria-pressed.
     ======================================================================== */
  .ax-badge {
    --_badge-50: var(--ax-fill-hover);
    --_badge-500: var(--ax-text-muted);
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-1);
    height: 20px;
    padding-inline: var(--ax-space-2);
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-semibold);
    line-height: 1;
    white-space: nowrap;
    border: 1px solid transparent;
    border-radius: var(--ax-radius-xs);
    color: var(--_badge-500);
    background: var(--_badge-50);
  }
  .ax-badge__dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
  }
  .ax-badge__icon {
    width: var(--ax-icon-xs);
    height: var(--ax-icon-xs);
  }
  .ax-badge__remove {
    display: inline-flex;
    margin-inline-start: 2px;
    color: currentColor;
    background: none;
    border: 0;
    cursor: pointer;
    opacity: 0.7;
  }
  .ax-badge__remove svg {
    width: var(--ax-icon-xs);
    height: var(--ax-icon-xs);
  }
  .ax-badge__remove:hover {
    color: var(--ax-danger-500);
    opacity: 1;
  }

  /* tones */
  .ax-badge--success {
    --_badge-50: var(--ax-success-50);
    --_badge-500: var(--ax-success-500);
  }
  .ax-badge--warning {
    --_badge-50: var(--ax-warning-50);
    --_badge-500: var(--ax-warning-500);
  }
  .ax-badge--danger {
    --_badge-50: var(--ax-danger-50);
    --_badge-500: var(--ax-danger-500);
  }
  .ax-badge--info {
    --_badge-50: var(--ax-info-50);
    --_badge-500: var(--ax-info-500);
  }
  .ax-badge--accent {
    --_badge-50: var(--ax-accent-wash);
    --_badge-500: var(--ax-accent);
  }
  .ax-badge--neutral {
    --_badge-50: var(--ax-fill-hover);
    --_badge-500: var(--ax-text-muted);
  }

  /* styles */
  .ax-badge--soft {
    color: var(--_badge-500);
    background: var(--_badge-50);
  }
  .ax-badge--solid {
    color: #fff;
    background: var(--_badge-500);
  }
  .ax-badge--solid.ax-badge--accent {
    color: var(--ax-on-accent);
    background: var(--ax-accent);
  }
  .ax-badge--outline {
    color: var(--_badge-500);
    background: transparent;
    border-color: var(--_badge-500);
  }
  .ax-badge--pill,
  .ax-badge--chip,
  .ax-badge--count {
    border-radius: var(--ax-radius-pill);
  }
  .ax-badge--count {
    min-width: 18px;
    height: 18px;
    padding-inline: 5px;
    justify-content: center;
    font-family: var(--ax-font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--ax-on-accent);
    background: var(--ax-accent);
  }
  .ax-badge--count.ax-badge--danger {
    color: #fff;
    background: var(--ax-danger-500);
  }

  /* sizes */
  .ax-badge--sm {
    height: 16px;
    padding-inline: var(--ax-space-1);
    font-size: var(--ax-text-2xs);
  }

  /* interactive */
  .ax-badge--chip,
  .ax-badge--filter {
    cursor: pointer;
  }
  .ax-badge--filter:hover {
    background: var(--ax-fill-active);
  }
  .ax-badge--filter[aria-pressed="true"],
  .ax-badge--filter.is-selected {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
    border-color: transparent;
  }

  /* ========================================================================
     6 · AVATARS — .ax-avatar
     image / __initials / __icon fallback. Shapes --circle(default)/--squircle.
     Sizes --xs/--sm/--md(default)/--lg/--xl/--2xl. Status dot. Group + overflow.
     Alpine: __overflow → axPopover list.
     ======================================================================== */
  .ax-avatar {
    --_av-size: 36px;
    --_av-status: 8px;
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--_av-size);
    height: var(--_av-size);
    flex: 0 0 auto;
    overflow: hidden;
    font-size: calc(var(--_av-size) * 0.38);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-muted);
    background: var(--ax-fill-active);
    border-radius: var(--ax-radius-pill);
    user-select: none;
  }
  .ax-avatar__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
  }
  /* `.ax-avatar` is normally the CONTAINER and `.ax-avatar__img` the portrait
     inside it, but the shell partials collapse both roles onto one <img> (header
     trigger, profile card, notification chips, sidebar user). That element gets
     the box without the portrait rule, so the first non-square photo a buyer
     drops in is stretched to fit by the initial `object-fit: fill`. */
  img.ax-avatar {
    object-fit: cover;
  }
  .ax-avatar__initials {
    line-height: 1;
  }
  .ax-avatar__icon {
    width: 60%;
    height: 60%;
    color: var(--ax-text-subtle);
  }
  .ax-avatar--squircle {
    border-radius: var(--ax-radius-sm);
  }
  .ax-avatar--xs {
    --_av-size: 20px;
    --_av-status: 6px;
  }
  .ax-avatar--sm {
    --_av-size: 28px;
    --_av-status: 8px;
  }
  .ax-avatar--md {
    --_av-size: 36px;
  }
  .ax-avatar--lg {
    --_av-size: 48px;
    --_av-status: 10px;
  }
  .ax-avatar--xl {
    --_av-size: 64px;
    --_av-status: 12px;
  }
  .ax-avatar--2xl {
    --_av-size: 96px;
    --_av-status: 14px;
  }
  .ax-avatar--ringed {
    box-shadow: 0 0 0 2px var(--ax-surface-solid), 0 0 0 3px var(--ax-border-strong);
  }
  .ax-avatar.is-current,
  .ax-avatar--selected {
    box-shadow: 0 0 0 2px var(--ax-surface-solid), 0 0 0 4px var(--ax-accent);
  }
  .ax-avatar__status {
    position: absolute;
    inset-block-end: 0;
    inset-inline-end: 0;
    width: var(--_av-status);
    height: var(--_av-status);
    border-radius: 50%;
    box-shadow: 0 0 0 2px var(--ax-surface-solid);
    background: var(--ax-text-subtle);
  }
  .ax-avatar__status--online {
    background: var(--ax-viz-emerald);
  }
  .ax-avatar__status--away {
    background: var(--ax-viz-amber);
  }
  .ax-avatar__status--busy {
    background: var(--ax-viz-red);
  }
  .ax-avatar__status--offline {
    background: var(--ax-text-subtle);
  }

  .ax-avatar-group {
    display: inline-flex;
    align-items: center;
  }
  .ax-avatar-group > .ax-avatar:not(:first-child) {
    margin-inline-start: -10px;
  }
  .ax-avatar-group > .ax-avatar {
    box-shadow: 0 0 0 2px var(--ax-surface-solid);
  }
  .ax-avatar__overflow {
    font-size: var(--ax-text-xs);
    color: var(--ax-text-muted);
    background: var(--ax-fill-active);
    border: 0;
    cursor: pointer;
  }

  /* ========================================================================
     7 · ALERTS — .ax-alert
     Tones + --solid/--inline/--dismissible/--with-actions/--accent-edge.
     Alpine: dismiss removes node + returns focus.
     ======================================================================== */
  .ax-alert {
    --_a-50: var(--ax-fill-hover);
    --_a-500: var(--ax-text-muted);
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: var(--ax-space-3);
    padding: var(--ax-space-4) var(--ax-space-5);
    color: var(--ax-text);
    background: var(--_a-50);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
  }
  .ax-alert__icon {
    flex: 0 0 auto;
    width: var(--ax-icon-md);
    height: var(--ax-icon-md);
    color: var(--_a-500);
  }
  .ax-alert__content {
    flex: 1 1 auto;
    min-width: 0;
  }
  .ax-alert__title {
    margin: 0;
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
  }
  .ax-alert__message {
    margin: 2px 0 0;
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
  }
  .ax-alert__actions {
    display: flex;
    gap: var(--ax-space-2);
    margin-top: var(--ax-space-2);
  }
  .ax-alert__dismiss {
    flex: 0 0 auto;
    display: inline-flex;
    color: var(--ax-text-subtle);
    background: none;
    border: 0;
    cursor: pointer;
  }
  .ax-alert__dismiss svg {
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
  }
  .ax-alert__dismiss:hover {
    color: var(--ax-text-strong);
  }
  .ax-alert--info {
    --_a-50: var(--ax-info-50);
    --_a-500: var(--ax-info-500);
  }
  .ax-alert--success {
    --_a-50: var(--ax-success-50);
    --_a-500: var(--ax-success-500);
  }
  .ax-alert--warning {
    --_a-50: var(--ax-warning-50);
    --_a-500: var(--ax-warning-500);
  }
  .ax-alert--danger {
    --_a-50: var(--ax-danger-50);
    --_a-500: var(--ax-danger-500);
  }
  .ax-alert--accent {
    --_a-50: var(--ax-accent-wash);
    --_a-500: var(--ax-accent);
  }
  .ax-alert--neutral {
    --_a-50: var(--ax-fill-hover);
    --_a-500: var(--ax-text-muted);
  }
  .ax-alert--accent-edge {
    border-inline-start: 3px solid var(--_a-500);
  }
  .ax-alert--solid {
    color: #fff;
    background: var(--_a-500);
    border-color: transparent;
  }
  .ax-alert--solid .ax-alert__icon,
  .ax-alert--solid .ax-alert__title,
  .ax-alert--solid .ax-alert__message,
  .ax-alert--solid .ax-alert__dismiss {
    color: inherit;
  }
  .ax-alert--inline {
    align-items: center;
    padding: var(--ax-space-2) var(--ax-space-4);
    font-size: var(--ax-text-sm);
  }
  .ax-alert.is-dismissing {
    opacity: 0;
    transition: opacity var(--ax-motion-base) var(--ax-ease-exit);
  }

  /* ========================================================================
     8 · TOASTS — .ax-toast (region .ax-toast-region)
     positions: top/bottom × start/center/end. Stack gap. Timer line.
     Alpine: axToast global store (queue/timers/promise/politeness).
     ======================================================================== */
  .ax-toast-region {
    position: fixed;
    z-index: var(--ax-z-toast);
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-2);
    width: min(380px, calc(100vw - var(--ax-space-8)));
    padding: var(--ax-space-4);
    pointer-events: none;
  }
  .ax-toast-region--bottom-end {
    inset-block-end: 0;
    inset-inline-end: 0;
  }
  .ax-toast-region--bottom-start {
    inset-block-end: 0;
    inset-inline-start: 0;
  }
  .ax-toast-region--bottom-center {
    inset-block-end: 0;
    inset-inline: 0;
    margin-inline: auto;
  }
  .ax-toast-region--top-end {
    inset-block-start: 0;
    inset-inline-end: 0;
  }
  .ax-toast-region--top-start {
    inset-block-start: 0;
    inset-inline-start: 0;
  }
  .ax-toast-region--top-center {
    inset-block-start: 0;
    inset-inline: 0;
    margin-inline: auto;
  }
  .ax-toast {
    --_t-500: var(--ax-text-muted);
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: var(--ax-space-3);
    overflow: hidden;
    padding: var(--ax-space-4);
    pointer-events: auto;
    color: var(--ax-text);
    background: var(--ax-surface-overlay);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-lg);
    box-shadow: var(--ax-shadow-lg);
    -webkit-backdrop-filter: blur(18px) saturate(1.1);
    backdrop-filter: blur(18px) saturate(1.1);
    transition: opacity var(--ax-motion-base) var(--ax-ease-standard),
      transform var(--ax-motion-base) var(--ax-ease-standard);
  }
  .ax-toast__icon {
    flex: 0 0 auto;
    width: var(--ax-icon-md);
    height: var(--ax-icon-md);
    color: var(--_t-500);
  }
  .ax-toast__content {
    flex: 1 1 auto;
    min-width: 0;
  }
  .ax-toast__title {
    margin: 0;
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
  }
  .ax-toast__message {
    margin: 2px 0 0;
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
  }
  .ax-toast__action {
    flex: 0 0 auto;
    align-self: center;
    font-size: var(--ax-text-sm);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-link);
    background: none;
    border: 0;
    cursor: pointer;
  }
  .ax-toast__dismiss {
    flex: 0 0 auto;
    display: inline-flex;
    color: var(--ax-text-subtle);
    background: none;
    border: 0;
    cursor: pointer;
    opacity: 0;
    transition: opacity var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-toast__dismiss svg {
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
  }
  .ax-toast:hover .ax-toast__dismiss,
  .ax-toast:focus-within .ax-toast__dismiss {
    opacity: 1;
  }
  .ax-toast__timer {
    position: absolute;
    inset-block-end: 0;
    inset-inline-start: 0;
    height: 2px;
    width: 100%;
    transform-origin: left center;
    background: var(--ax-accent);
  }
  .ax-toast--info {
    --_t-500: var(--ax-info-500);
  }
  .ax-toast--success {
    --_t-500: var(--ax-success-500);
  }
  .ax-toast--warning {
    --_t-500: var(--ax-warning-500);
  }
  .ax-toast--danger {
    --_t-500: var(--ax-danger-500);
  }
  .ax-toast--accent {
    --_t-500: var(--ax-accent);
  }
  .ax-toast.is-entering {
    opacity: 0;
    transform: translateY(8px);
  }
  .ax-toast.is-leaving {
    opacity: 0;
    transform: translateY(4px);
    transition-timing-function: var(--ax-ease-exit);
  }
  @media (prefers-reduced-motion: reduce) {
    .ax-toast.is-entering,
    .ax-toast.is-leaving {
      transform: none;
    }
  }

  /* ========================================================================
     9 · DROPDOWN / MENU — .ax-dropdown / .ax-menu (glass overlay)
     __item/__icon/__shortcut/__divider/__section-label/__check, --item--danger.
     Alpine: axDropdown.
     ======================================================================== */
  .ax-dropdown {
    position: relative;
    display: inline-flex;
  }
  .ax-menu {
    position: absolute;
    z-index: var(--ax-z-dropdown);
    min-width: 200px;
    max-height: min(70vh, 420px);
    overflow-y: auto;
    padding: var(--ax-space-2);
    color: var(--ax-text);
    /* Opaque, no backdrop-filter — dropdown menus read cleaner solid, and when
       nested in a glass card the blur can't reach the page anyway. */
    background: var(--ax-surface-solid);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-lg);
    box-shadow: var(--ax-shadow-lg);
  }
  .ax-menu__section-label {
    padding: var(--ax-space-2) var(--ax-space-3) var(--ax-space-1);
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ax-text-subtle);
  }
  .ax-menu__item {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
    width: 100%;
    padding: var(--ax-space-2) var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text);
    text-align: start;
    text-decoration: none;
    background: transparent;
    border: 0;
    border-radius: var(--ax-radius-md);
    cursor: pointer;
    transition: background var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-menu__item:hover,
  .ax-menu__item.is-active,
  .ax-menu__item:focus-visible {
    background: var(--ax-fill-hover);
    color: var(--ax-text-strong);
    outline: none;
  }
  .ax-menu__icon {
    flex: 0 0 auto;
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
    color: var(--ax-text-subtle);
  }
  .ax-menu__shortcut {
    margin-inline-start: auto;
    font-family: var(--ax-font-mono);
    font-size: var(--ax-text-2xs);
    color: var(--ax-text-subtle);
  }
  .ax-menu__check {
    margin-inline-start: auto;
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
    color: var(--ax-accent);
    opacity: 0;
  }
  .ax-menu__item[aria-checked="true"] .ax-menu__check,
  .ax-menu__item.is-selected .ax-menu__check {
    opacity: 1;
  }
  .ax-menu__item[aria-checked="true"],
  .ax-menu__item.is-selected {
    color: var(--ax-accent);
  }
  .ax-menu__item--danger {
    color: var(--ax-danger-500);
  }
  .ax-menu__item--danger .ax-menu__icon {
    color: var(--ax-danger-500);
  }
  .ax-menu__item:disabled,
  .ax-menu__item[aria-disabled="true"] {
    color: var(--ax-text-disabled);
    pointer-events: none;
  }
  .ax-menu__divider {
    height: 1px;
    margin: var(--ax-space-1) 0;
    border: 0;
    background: var(--ax-border);
  }

  /* ========================================================================
     10 · MODALS — .ax-modal
     __backdrop/__dialog/__header/__title/__close/__body/__footer/__status/__counter.
     Sizes --sm/default/--lg/--xl/--fullscreen. --scrollable / --centered.
     Alpine: axModal.
     ======================================================================== */
  .ax-modal {
    position: fixed;
    inset: 0;
    z-index: var(--ax-z-modal);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: var(--ax-space-8) var(--ax-space-4);
    overflow-y: auto;
  }
  .ax-modal--centered {
    align-items: center;
  }
  .ax-modal__backdrop {
    position: fixed;
    inset: 0;
    background: rgba(8, 10, 16, 0.6);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
  }
  .ax-modal__dialog {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    width: 100%;
    max-width: 560px;
    max-height: calc(100vh - var(--ax-space-16));
    margin: auto;
    color: var(--ax-text);
    background: var(--ax-surface-overlay);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-lg);
    box-shadow: var(--ax-shadow-lg);
    -webkit-backdrop-filter: blur(18px) saturate(1.1);
    backdrop-filter: blur(18px) saturate(1.1);
  }
  .ax-modal__dialog--sm {
    max-width: 420px;
  }
  .ax-modal__dialog--lg {
    max-width: 760px;
  }
  .ax-modal__dialog--xl {
    max-width: 960px;
  }
  .ax-modal__dialog--fullscreen {
    max-width: none;
    width: 100vw;
    height: 100vh;
    max-height: 100vh;
    border-radius: 0;
  }
  .ax-modal__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--ax-space-3);
    padding: var(--ax-space-5) var(--ax-space-6);
    border-bottom: 1px solid var(--ax-border);
  }
  .ax-modal__title {
    margin: 0;
    font-family: var(--ax-font-display);
    font-size: var(--ax-text-lg);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
  }
  .ax-modal__close {
    flex: 0 0 auto;
    display: inline-flex;
    color: var(--ax-text-subtle);
    background: none;
    border: 0;
    cursor: pointer;
  }
  .ax-modal__close svg {
    width: var(--ax-icon-md);
    height: var(--ax-icon-md);
  }
  .ax-modal__close:hover {
    color: var(--ax-text-strong);
  }
  .ax-modal__body {
    padding: var(--ax-space-6);
    overflow-y: auto;
  }
  .ax-modal__footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--ax-space-3);
    padding: var(--ax-space-4) var(--ax-space-6);
    border-top: 1px solid var(--ax-border);
  }
  .ax-modal__dialog--scrollable .ax-modal__header,
  .ax-modal__dialog--scrollable .ax-modal__footer {
    flex: 0 0 auto;
  }
  .ax-modal__dialog--scrollable .ax-modal__body {
    flex: 1 1 auto;
  }
  .ax-modal__status {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 48px;
    border-radius: var(--ax-radius-pill);
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
  }
  .ax-modal__status--success {
    color: var(--ax-success-500);
    background: var(--ax-success-50);
  }
  .ax-modal__status--warning {
    color: var(--ax-warning-500);
    background: var(--ax-warning-50);
  }
  .ax-modal__status--danger {
    color: var(--ax-danger-500);
    background: var(--ax-danger-50);
  }
  .ax-modal__status--info {
    color: var(--ax-info-500);
    background: var(--ax-info-50);
  }
  .ax-modal__counter {
    font-family: var(--ax-font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--ax-text-muted);
  }

  /* ========================================================================
     11 · OFFCANVAS (drawer) — .ax-offcanvas (4 edges)
     __backdrop/__panel/__header/__body/__footer. --start/--end/--top/--bottom.
     Alpine: axOffcanvas.
     ======================================================================== */
  .ax-offcanvas {
    position: fixed;
    inset: 0;
    z-index: var(--ax-z-drawer);
  }
  .ax-offcanvas__backdrop {
    position: fixed;
    inset: 0;
    background: rgba(8, 10, 16, 0.55);
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
  }
  .ax-offcanvas__panel {
    position: fixed;
    display: flex;
    flex-direction: column;
    color: var(--ax-text);
    background: var(--ax-surface-overlay);
    border: 1px solid var(--ax-border);
    box-shadow: var(--ax-shadow-lg);
    -webkit-backdrop-filter: blur(18px) saturate(1.1);
    backdrop-filter: blur(18px) saturate(1.1);
  }
  .ax-offcanvas__panel--end,
  .ax-offcanvas__panel--start {
    inset-block: 0;
    width: min(420px, 92vw);
  }
  .ax-offcanvas__panel--end {
    inset-inline-end: 0;
    border-start-start-radius: var(--ax-radius-lg);
    border-end-start-radius: var(--ax-radius-lg);
  }
  .ax-offcanvas__panel--start {
    inset-inline-start: 0;
    border-start-end-radius: var(--ax-radius-lg);
    border-end-end-radius: var(--ax-radius-lg);
  }
  .ax-offcanvas__panel--top,
  .ax-offcanvas__panel--bottom {
    inset-inline: 0;
    height: min(420px, 80vh);
  }
  .ax-offcanvas__panel--top {
    inset-block-start: 0;
    border-end-start-radius: var(--ax-radius-lg);
    border-end-end-radius: var(--ax-radius-lg);
  }
  .ax-offcanvas__panel--bottom {
    inset-block-end: 0;
    border-start-start-radius: var(--ax-radius-lg);
    border-start-end-radius: var(--ax-radius-lg);
  }
  .ax-offcanvas__panel--sm.ax-offcanvas__panel--end,
  .ax-offcanvas__panel--sm.ax-offcanvas__panel--start {
    width: min(320px, 92vw);
  }
  .ax-offcanvas__panel--lg.ax-offcanvas__panel--end,
  .ax-offcanvas__panel--lg.ax-offcanvas__panel--start {
    width: min(540px, 96vw);
  }
  .ax-offcanvas__panel--full.ax-offcanvas__panel--end,
  .ax-offcanvas__panel--full.ax-offcanvas__panel--start {
    width: 100vw;
    border-radius: 0;
  }
  .ax-offcanvas__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ax-space-3);
    padding: var(--ax-space-5) var(--ax-space-6);
    border-bottom: 1px solid var(--ax-border);
  }
  .ax-offcanvas__header h2,
  .ax-offcanvas__title {
    margin: 0;
    font-family: var(--ax-font-display);
    font-size: var(--ax-text-lg);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
  }
  .ax-offcanvas__close {
    display: inline-flex;
    color: var(--ax-text-subtle);
    background: none;
    border: 0;
    cursor: pointer;
  }
  .ax-offcanvas__close svg {
    width: var(--ax-icon-md);
    height: var(--ax-icon-md);
  }
  .ax-offcanvas__close:hover {
    color: var(--ax-text-strong);
  }
  .ax-offcanvas__body {
    flex: 1 1 auto;
    padding: var(--ax-space-6);
    overflow-y: auto;
  }
  .ax-offcanvas__footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--ax-space-3);
    padding: var(--ax-space-4) var(--ax-space-6);
    border-top: 1px solid var(--ax-border);
  }

  /* ========================================================================
     12 · TABS / NAVS / PILLS — .ax-tabs
     --line(default)/--pill/--segmented/--vertical/--scrollable.
     __list/__tab/__icon/__badge/__indicator/__panel. Alpine: axTabs.
     ======================================================================== */
  .ax-tabs {
    display: flex;
    flex-direction: column;
  }
  .ax-tabs__list {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--ax-space-1);
    border-bottom: 1px solid var(--ax-border);
  }
  .ax-tabs__tab {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-2);
    min-height: 40px;
    padding: var(--ax-space-2) var(--ax-space-3);
    font-size: var(--ax-text-sm);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-muted);
    background: none;
    border: 0;
    cursor: pointer;
    transition: color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-tabs__icon {
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
  }
  .ax-tabs__badge {
    margin-inline-start: var(--ax-space-1);
  }
  .ax-tabs__tab:hover {
    color: var(--ax-text);
  }
  .ax-tabs__tab[aria-selected="true"],
  .ax-tabs__tab.is-active {
    color: var(--ax-text-strong);
  }
  .ax-tabs__tab:disabled,
  .ax-tabs__tab[aria-disabled="true"] {
    color: var(--ax-text-disabled);
    pointer-events: none;
  }
  .ax-tabs__indicator {
    position: absolute;
    inset-block-end: -1px;
    inset-inline-start: 0;
    height: 2px;
    width: var(--ax-tabs-ind-w, 0);
    transform: translateX(var(--ax-tabs-ind-x, 0));
    background: var(--ax-accent);
    border-radius: 2px;
    transition: transform var(--ax-motion-base) var(--ax-ease-standard),
      width var(--ax-motion-base) var(--ax-ease-standard);
  }
  .ax-tabs__panel {
    padding-top: var(--ax-space-5);
  }
  .ax-tabs__panel[hidden] {
    display: none;
  }
  .ax-tabs--pill .ax-tabs__list {
    border-bottom: 0;
    gap: var(--ax-space-2);
  }
  .ax-tabs--pill .ax-tabs__tab {
    border-radius: var(--ax-radius-pill);
    padding-inline: var(--ax-space-4);
  }
  .ax-tabs--pill .ax-tabs__tab[aria-selected="true"],
  .ax-tabs--pill .ax-tabs__tab.is-active {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
  }
  .ax-tabs--pill .ax-tabs__indicator {
    display: none;
  }
  .ax-tabs--segmented .ax-tabs__list {
    gap: var(--ax-space-1);
    padding: var(--ax-space-1);
    background: var(--ax-fill-hover);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
  }
  .ax-tabs--segmented .ax-tabs__tab {
    border-radius: var(--ax-radius-sm);
  }
  .ax-tabs--segmented .ax-tabs__tab[aria-selected="true"],
  .ax-tabs--segmented .ax-tabs__tab.is-active {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
    box-shadow: var(--ax-shadow-sm);
  }
  .ax-tabs--segmented .ax-tabs__indicator {
    display: none;
  }
  .ax-tabs--vertical {
    flex-direction: row;
    gap: var(--ax-space-5);
  }
  .ax-tabs--vertical .ax-tabs__list {
    flex-direction: column;
    align-items: stretch;
    border-bottom: 0;
    border-inline-start: 1px solid var(--ax-border);
  }
  .ax-tabs--vertical .ax-tabs__tab {
    justify-content: flex-start;
  }
  .ax-tabs--vertical .ax-tabs__indicator {
    inset-block-start: 0;
    inset-inline-start: -1px;
    width: 2px;
    height: var(--ax-tabs-ind-h, 0);
    transform: translateY(var(--ax-tabs-ind-y, 0));
    transition: transform var(--ax-motion-base) var(--ax-ease-standard),
      height var(--ax-motion-base) var(--ax-ease-standard);
  }
  .ax-tabs--vertical .ax-tabs__panel {
    flex: 1 1 auto;
    padding-top: 0;
  }
  .ax-tabs--scrollable .ax-tabs__list {
    overflow-x: auto;
    flex-wrap: nowrap;
  }
  /* Without these the tabs just SHRINK to fit — flex items default to
     flex-shrink:1, so the row never overflows and never scrolls; labels wrap
     to two lines instead. Opting out of shrink is what makes it scrollable. */
  .ax-tabs--scrollable .ax-tabs__tab {
    flex: 0 0 auto;
    white-space: nowrap;
  }
  /* The bar itself is hidden in base.css §3 — the global `*` scrollbar rule is
     unlayered and would beat anything declared here inside @layer components. */

  /* ========================================================================
     13 · BREADCRUMB — .ax-breadcrumb (chevron separators)
     Alpine: collapsed overflow → axDropdown.
     ======================================================================== */
  .ax-breadcrumb__list {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ax-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--ax-text-sm);
  }
  .ax-breadcrumb__item {
    display: inline-flex;
    align-items: center;
    min-width: 0;
  }
  .ax-breadcrumb__item a {
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-1);
    color: var(--ax-text-muted);
    text-decoration: none;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .ax-breadcrumb__item a:hover {
    color: var(--ax-text);
    text-decoration: underline;
    text-underline-offset: 2px;
  }
  .ax-breadcrumb__item [aria-current="page"] {
    color: var(--ax-text-strong);
    font-weight: var(--ax-weight-medium);
  }
  .ax-breadcrumb__home {
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
  }
  .ax-breadcrumb__sep {
    display: inline-flex;
    color: var(--ax-text-subtle);
  }
  .ax-breadcrumb__sep svg {
    width: var(--ax-icon-xs);
    height: var(--ax-icon-xs);
  }
  [dir="rtl"] .ax-breadcrumb__sep svg {
    transform: scaleX(-1);
  }

  /* ========================================================================
     14 · PAGINATION — .ax-pagination
     __prev/__next/__pages/__page/__ellipsis/__summary. current = accent-wash.
     Alpine: none (anchors/buttons).
     ======================================================================== */
  .ax-pagination {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ax-space-3);
  }
  .ax-pagination__pages {
    display: flex;
    align-items: center;
    gap: var(--ax-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .ax-pagination__page,
  .ax-pagination__prev,
  .ax-pagination__next {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    height: 36px;
    padding-inline: var(--ax-space-2);
    font-size: var(--ax-text-sm);
    font-variant-numeric: tabular-nums;
    color: var(--ax-text);
    text-decoration: none;
    background: transparent;
    border: 0;
    border-radius: var(--ax-radius-sm);
    cursor: pointer;
    transition: background var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-pagination__page:hover,
  .ax-pagination__prev:hover,
  .ax-pagination__next:hover {
    background: var(--ax-fill-hover);
  }
  .ax-pagination__page[aria-current="page"],
  .ax-pagination__page.is-active {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
    font-weight: var(--ax-weight-semibold);
  }
  .ax-pagination__prev svg,
  .ax-pagination__next svg {
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
  }
  [dir="rtl"] .ax-pagination__prev svg,
  [dir="rtl"] .ax-pagination__next svg {
    transform: scaleX(-1);
  }
  .ax-pagination__prev:disabled,
  .ax-pagination__next:disabled,
  .ax-pagination__prev[aria-disabled="true"],
  .ax-pagination__next[aria-disabled="true"] {
    color: var(--ax-text-disabled);
    pointer-events: none;
  }
  .ax-pagination__ellipsis {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    height: 36px;
    color: var(--ax-text-subtle);
  }
  .ax-pagination__summary {
    color: var(--ax-text-muted);
    font-size: var(--ax-text-sm);
  }

  /* ========================================================================
     15 · PROGRESS — .ax-progress (linear + striped + circle + segmented)
     __track/__fill/__value/__center/__ring-track/__ring-fill.
     Alpine: none (style/aria driven).
     ======================================================================== */
  .ax-progress {
    --_p-h: 6px;
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
  }
  .ax-progress__track {
    position: relative;
    flex: 1 1 auto;
    height: var(--_p-h);
    overflow: hidden;
    background: var(--ax-fill-hover);
    border-radius: var(--ax-radius-pill);
  }
  .ax-progress__fill {
    height: 100%;
    width: 0;
    background: var(--ax-gradient-accent);
    border-radius: inherit;
    transition: width var(--ax-motion-base) var(--ax-ease-standard);
  }
  .ax-progress__value {
    flex: 0 0 auto;
    min-width: 3ch;
    text-align: end;
    font-size: var(--ax-text-xs);
    font-variant-numeric: tabular-nums;
    color: var(--ax-text-muted);
  }
  .ax-progress--xs {
    --_p-h: 4px;
  }
  .ax-progress--sm {
    --_p-h: 6px;
  }
  .ax-progress--md {
    --_p-h: 8px;
  }
  .ax-progress--lg {
    --_p-h: 12px;
  }
  .ax-progress--success .ax-progress__fill {
    background: var(--ax-success-500);
  }
  .ax-progress--warning .ax-progress__fill {
    background: var(--ax-warning-500);
  }
  .ax-progress--danger .ax-progress__fill {
    background: var(--ax-danger-500);
  }
  .ax-progress--striped .ax-progress__fill {
    background-image: linear-gradient(
      45deg,
      rgba(255, 255, 255, 0.2) 25%,
      transparent 25%,
      transparent 50%,
      rgba(255, 255, 255, 0.2) 50%,
      rgba(255, 255, 255, 0.2) 75%,
      transparent 75%
    );
    background-size: 16px 16px;
    background-color: var(--ax-accent);
  }
  .ax-progress--animated .ax-progress__fill {
    animation: ax-progress-stripe 1s var(--ax-ease-linear) infinite;
  }
  .ax-progress--indeterminate .ax-progress__fill {
    width: 35%;
    background: var(--ax-accent);
    animation: ax-progress-indeterminate 1.4s var(--ax-ease-standard) infinite;
  }
  .ax-progress--stacked .ax-progress__track,
  .ax-progress--segmented .ax-progress__track {
    display: flex;
    gap: 2px;
  }
  .ax-progress--circle {
    display: inline-flex;
    position: relative;
  }
  .ax-progress--circle .ax-progress__ring-track {
    stroke: var(--ax-fill-hover);
    fill: none;
  }
  .ax-progress--circle .ax-progress__ring-fill {
    stroke: var(--ax-accent);
    fill: none;
    stroke-linecap: round;
    transition: stroke-dashoffset var(--ax-motion-base) var(--ax-ease-standard);
  }
  .ax-progress__center {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--ax-font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--ax-text-strong);
  }
  @keyframes ax-progress-stripe {
    from {
      background-position: 0 0;
    }
    to {
      background-position: 16px 0;
    }
  }
  @keyframes ax-progress-indeterminate {
    0% {
      margin-inline-start: -35%;
    }
    100% {
      margin-inline-start: 100%;
    }
  }
  @media (prefers-reduced-motion: reduce) {
    .ax-progress--animated .ax-progress__fill,
    .ax-progress--indeterminate .ax-progress__fill {
      animation: none;
    }
    .ax-progress--indeterminate .ax-progress__fill {
      width: 100%;
    }
  }

  /* ========================================================================
     16 · SPINNERS & LOADERS — .ax-spinner / .ax-page-loader
     Alpine: none. data-ax-loader="off" hides page loader.
     ======================================================================== */
  .ax-spinner {
    --_s-size: 24px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--_s-size);
    height: var(--_s-size);
    color: var(--ax-accent);
  }
  .ax-spinner__glyph {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    border: 2px solid currentColor;
    border-inline-end-color: transparent;
    animation: ax-spin 0.7s var(--ax-ease-linear) infinite;
  }
  .ax-spinner--xs {
    --_s-size: 12px;
  }
  .ax-spinner--sm {
    --_s-size: 16px;
  }
  .ax-spinner--md {
    --_s-size: 24px;
  }
  .ax-spinner--lg {
    --_s-size: 40px;
  }
  .ax-spinner--lg .ax-spinner__glyph {
    border-width: 3px;
  }
  .ax-spinner--inline {
    vertical-align: text-bottom;
  }
  .ax-page-loader {
    position: fixed;
    inset: 0;
    z-index: var(--ax-z-command);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--ax-space-5);
    background: var(--ax-canvas);
  }
  .ax-page-loader__mark {
    color: var(--ax-text-strong);
  }
  [data-ax-loader="off"] .ax-page-loader {
    display: none;
  }
  @media (prefers-reduced-motion: reduce) {
    .ax-spinner__glyph {
      animation-duration: 1.4s;
    }
  }

  /* ========================================================================
     17 · SKELETONS — .ax-skeleton (+ composites)
     --line/--circle/--rect, --shimmer(default)/--pulse/--static.
     Alpine: none (CSS); container toggles aria-busy.
     ======================================================================== */
  .ax-skeleton {
    position: relative;
    overflow: hidden;
    background: var(--ax-fill-hover);
    border-radius: var(--ax-radius-md);
  }
  .ax-skeleton--line {
    height: 0.75em;
    width: 100%;
    border-radius: var(--ax-radius-xs);
  }
  .ax-skeleton--circle {
    border-radius: var(--ax-radius-pill);
    aspect-ratio: 1;
  }
  .ax-skeleton--rect {
    border-radius: var(--ax-radius-md);
  }
  .ax-skeleton::after,
  .ax-skeleton--shimmer::after {
    content: "";
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(
      90deg,
      transparent,
      var(--ax-fill-active),
      transparent
    );
    animation: ax-shimmer 1.4s var(--ax-ease-standard) infinite;
  }
  .ax-skeleton--pulse::after {
    animation: none;
  }
  .ax-skeleton--pulse {
    animation: ax-pulse 1.4s var(--ax-ease-standard) infinite;
  }
  .ax-skeleton--static::after {
    display: none;
  }
  .ax-skeleton-card,
  .ax-skeleton-stat {
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-3);
  }
  .ax-skeleton-row {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
  }
  @keyframes ax-shimmer {
    to {
      transform: translateX(100%);
    }
  }
  @keyframes ax-pulse {
    50% {
      opacity: 0.5;
    }
  }
  @media (prefers-reduced-motion: reduce) {
    .ax-skeleton::after,
    .ax-skeleton--shimmer::after {
      animation: none;
    }
    .ax-skeleton--pulse {
      animation: none;
    }
  }

  /* ========================================================================
     18 · LIST GROUPS — .ax-list
     __row/__leading/__content/__title/__meta/__trailing/__group-label.
     --flush/--inset/--linked/--selectable/--actionable/--grouped + densities.
     Alpine: --selectable roving; --sortable → axSortable.
     ======================================================================== */
  .ax-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
  }
  .ax-list__row {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
    min-height: 44px;
    padding: var(--ax-space-3) var(--ax-space-4);
    color: var(--ax-text);
    text-decoration: none;
    border-bottom: 1px solid var(--ax-border);
    transition: background var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-list__row:last-child {
    border-bottom: 0;
  }
  .ax-list__leading {
    flex: 0 0 auto;
    display: inline-flex;
  }
  .ax-list__content {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 1px;
  }
  .ax-list__title {
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-strong);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .ax-list__meta {
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
  }
  .ax-list__trailing {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-2);
    color: var(--ax-text-subtle);
  }
  .ax-list--compact .ax-list__row {
    min-height: 36px;
  }
  .ax-list--comfortable .ax-list__row {
    min-height: 56px;
  }
  a.ax-list__row,
  .ax-list--linked .ax-list__row,
  .ax-list--selectable .ax-list__row,
  .ax-list--actionable .ax-list__row {
    cursor: pointer;
  }
  a.ax-list__row:hover,
  .ax-list--linked .ax-list__row:hover,
  .ax-list--selectable .ax-list__row:hover {
    background: var(--ax-fill-hover);
  }
  .ax-list__row.is-active {
    background: var(--ax-fill-active);
  }
  .ax-list__row.is-selected,
  .ax-list__row[aria-selected="true"] {
    background: var(--ax-accent-wash);
  }
  .ax-list__row.is-selected .ax-list__title,
  .ax-list__row[aria-selected="true"] .ax-list__title {
    color: var(--ax-accent);
  }
  .ax-list__row[aria-disabled="true"] {
    color: var(--ax-text-disabled);
    pointer-events: none;
  }
  .ax-list__group-label {
    padding: var(--ax-space-2) var(--ax-space-4);
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ax-text-subtle);
  }

  /* ========================================================================
     19 · TIMELINE — .ax-timeline
     __item/__marker/__content/__time/__title/__body. Hairline rail.
     Alpine: none (expandable items use axCollapse).
     ======================================================================== */
  .ax-timeline {
    position: relative;
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .ax-timeline__item {
    position: relative;
    display: flex;
    gap: var(--ax-space-4);
    padding-bottom: var(--ax-space-5);
  }
  .ax-timeline__item:last-child {
    padding-bottom: 0;
  }
  .ax-timeline__marker {
    position: relative;
    z-index: 1;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--ax-radius-pill);
    color: var(--ax-text-muted);
    background: var(--ax-surface-subtle);
    border: 1px solid var(--ax-border);
  }
  .ax-timeline__marker svg {
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
  }
  .ax-timeline__item:not(:last-child) .ax-timeline__marker::before {
    content: "";
    position: absolute;
    top: 100%;
    inset-inline-start: 50%;
    width: 1px;
    height: calc(var(--ax-space-5) + var(--ax-space-2));
    transform: translateX(-50%);
    background: var(--ax-border);
  }
  [dir="rtl"] .ax-timeline__item:not(:last-child) .ax-timeline__marker::before {
    transform: translateX(50%);
  }
  .ax-timeline__content {
    flex: 1 1 auto;
    min-width: 0;
    padding-top: 2px;
  }
  .ax-timeline__time {
    font-family: var(--ax-font-mono);
    font-size: var(--ax-text-xs);
    color: var(--ax-text-subtle);
  }
  .ax-timeline__title {
    margin: 2px 0 0;
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-strong);
  }
  .ax-timeline__body {
    margin-top: var(--ax-space-1);
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
  }
  .ax-timeline__item.is-current .ax-timeline__marker {
    color: var(--ax-on-accent);
    background: var(--ax-accent);
    border-color: transparent;
  }
  .ax-timeline__item--success .ax-timeline__marker {
    color: #fff;
    background: var(--ax-success-500);
    border-color: transparent;
  }
  .ax-timeline__item--danger .ax-timeline__marker {
    color: #fff;
    background: var(--ax-danger-500);
    border-color: transparent;
  }
  .ax-timeline__item--pending .ax-timeline__marker {
    color: var(--ax-text-subtle);
  }
  .ax-timeline__item--pending:not(:last-child) .ax-timeline__marker::before {
    background: repeating-linear-gradient(
      var(--ax-border) 0 4px,
      transparent 4px 8px
    );
  }

  /* ========================================================================
     20 · RIBBONS — .ax-ribbon (host must be position:relative; overflow:hidden)
     --corner(--top-start/--top-end), --edge/--flag, --pill, semantic tones.
     Alpine: none.
     ======================================================================== */
  .ax-ribbon {
    position: absolute;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-semibold);
    letter-spacing: 0.02em;
    line-height: 1;
    color: var(--ax-on-accent);
    background: var(--ax-accent);
    pointer-events: none;
  }
  .ax-ribbon--corner {
    inset-block-start: 14px;
    width: 150px;
    height: 22px;
    transform: rotate(45deg);
    box-shadow: var(--ax-shadow-sm);
  }
  .ax-ribbon--corner.ax-ribbon--top-end {
    inset-inline-end: -40px;
  }
  .ax-ribbon--corner.ax-ribbon--top-start {
    inset-inline-start: -40px;
    transform: rotate(-45deg);
  }
  [dir="rtl"] .ax-ribbon--corner.ax-ribbon--top-end {
    inset-inline-end: auto;
    inset-inline-start: -40px;
    transform: rotate(-45deg);
  }
  .ax-ribbon--edge,
  .ax-ribbon--flag {
    inset-block-start: var(--ax-space-3);
    inset-inline-start: 0;
    height: 22px;
    padding-inline: var(--ax-space-3);
    border-start-end-radius: var(--ax-radius-xs);
    border-end-end-radius: var(--ax-radius-xs);
  }
  .ax-ribbon--pill {
    inset-block-start: var(--ax-space-3);
    inset-inline-end: var(--ax-space-3);
    height: 20px;
    padding-inline: var(--ax-space-2);
    border-radius: var(--ax-radius-pill);
  }
  .ax-ribbon--success {
    color: #fff;
    background: var(--ax-success-500);
  }
  .ax-ribbon--warning {
    color: #fff;
    background: var(--ax-warning-500);
  }
  .ax-ribbon--danger {
    color: #fff;
    background: var(--ax-danger-500);
  }

  /* ========================================================================
     21 · RATINGS — .ax-rating
     __star(--full/--half/--empty), __value. Amber fill (documented exception).
     Alpine: axRating (input).
     ======================================================================== */
  .ax-rating {
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-1);
  }
  .ax-rating__star {
    --_r-size: 18px;
    width: var(--_r-size);
    height: var(--_r-size);
    color: var(--ax-text-subtle);
  }
  .ax-rating--sm .ax-rating__star {
    --_r-size: 14px;
  }
  .ax-rating--lg .ax-rating__star {
    --_r-size: 24px;
  }
  .ax-rating__star--full {
    color: var(--ax-warning-500);
    fill: currentColor;
  }
  .ax-rating__star--half {
    color: var(--ax-warning-500);
  }
  .ax-rating__value {
    margin-inline-start: var(--ax-space-2);
    font-variant-numeric: tabular-nums;
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
  }
  .ax-rating--input .ax-rating__star {
    cursor: pointer;
    transition: color var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-rating--input .ax-rating__star.is-preview,
  .ax-rating--input .ax-rating__star.is-selected {
    color: var(--ax-warning-500);
    fill: currentColor;
  }

  /* ========================================================================
     22 · ACCORDION / COLLAPSE — .ax-accordion / .ax-collapse
     __item/__header/__title/__chevron/__panel. --bordered/--flush.
     Alpine: axCollapse / axAccordion.
     ======================================================================== */
  .ax-accordion {
    display: flex;
    flex-direction: column;
  }
  .ax-accordion__item {
    border-bottom: 1px solid var(--ax-border);
  }
  .ax-accordion__item:last-child {
    border-bottom: 0;
  }
  .ax-accordion__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ax-space-3);
    width: 100%;
    min-height: 48px;
    padding: var(--ax-space-3) var(--ax-space-4);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-strong);
    text-align: start;
    background: transparent;
    border: 0;
    cursor: pointer;
    transition: background var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-accordion__header:hover {
    background: var(--ax-fill-hover);
  }
  .ax-accordion__title {
    flex: 1 1 auto;
    min-width: 0;
  }
  .ax-accordion__chevron {
    flex: 0 0 auto;
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
    color: var(--ax-text-subtle);
    transition: transform var(--ax-motion-base) var(--ax-ease-standard);
  }
  .ax-accordion__header[aria-expanded="true"] {
    background: var(--ax-fill-hover);
  }
  .ax-accordion__header[aria-expanded="true"] .ax-accordion__chevron {
    transform: rotate(180deg);
  }
  .ax-accordion__panel {
    padding: 0 var(--ax-space-4) var(--ax-space-5);
    color: var(--ax-text-muted);
    font-size: var(--ax-text-sm);
  }
  .ax-accordion__panel[hidden] {
    display: none;
  }
  .ax-accordion--bordered {
    gap: var(--ax-space-3);
  }
  .ax-accordion--bordered .ax-accordion__item {
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
    overflow: hidden;
    background: var(--ax-surface);
  }
  .ax-collapse[hidden] {
    display: none;
  }
  @media (prefers-reduced-motion: reduce) {
    .ax-accordion__chevron {
      transition: none;
    }
  }

  /* ========================================================================
     23 · TOOLTIP — .ax-tooltip (inverse dark bubble default)
     __text/__arrow/__key. placements --top/--bottom/--start/--end.
     Alpine: axTooltip.
     ======================================================================== */
  .ax-tooltip {
    position: absolute;
    z-index: var(--ax-z-dropdown);
    max-width: 240px;
    padding: var(--ax-space-2) var(--ax-space-3);
    font-size: var(--ax-text-xs);
    line-height: var(--ax-leading-xs);
    color: var(--ax-text-strong);
    background: var(--ax-surface-overlay);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-sm);
    box-shadow: var(--ax-shadow-md);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    pointer-events: none;
  }
  .ax-tooltip--inverse {
    color: var(--ax-canvas);
    background: var(--ax-text-strong);
    border-color: transparent;
  }
  [data-ax-theme="dark"] .ax-tooltip--inverse {
    color: var(--ax-text-strong);
    background: var(--ax-surface-overlay);
    border-color: var(--ax-border);
  }
  .ax-tooltip__arrow {
    position: absolute;
    width: 8px;
    height: 8px;
    background: inherit;
    border: inherit;
    transform: rotate(45deg);
  }
  .ax-tooltip__key {
    margin-inline-start: var(--ax-space-2);
    padding: 1px 5px;
    font-family: var(--ax-font-mono);
    font-size: var(--ax-text-2xs);
    border: 1px solid var(--ax-border-strong);
    border-radius: var(--ax-radius-xs);
  }

  /* ========================================================================
     24 · POPOVER — .ax-popover (mini glass card)
     __panel/__header/__body/__footer/__arrow. Alpine: axPopover.
     ======================================================================== */
  .ax-popover {
    position: relative;
    display: inline-flex;
  }
  .ax-popover__panel {
    position: absolute;
    z-index: var(--ax-z-dropdown);
    min-width: 200px;
    max-width: 360px;
    color: var(--ax-text);
    /* Opaque, no backdrop-filter (see .ax-menu / .ax-combobox__panel). */
    background: var(--ax-surface-solid);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-lg);
    box-shadow: var(--ax-shadow-md);
  }
  .ax-popover__header {
    padding: var(--ax-space-3) var(--ax-space-4);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
    border-bottom: 1px solid var(--ax-border);
  }
  .ax-popover__body {
    padding: var(--ax-space-4);
    font-size: var(--ax-text-sm);
  }
  .ax-popover__footer {
    display: flex;
    justify-content: flex-end;
    gap: var(--ax-space-2);
    padding: var(--ax-space-3) var(--ax-space-4);
    border-top: 1px solid var(--ax-border);
  }
  .ax-popover__arrow {
    position: absolute;
    width: 10px;
    height: 10px;
    background: var(--ax-surface-overlay);
    border: 1px solid var(--ax-border);
    transform: rotate(45deg);
  }

  /* ========================================================================
     25 · TABLES — .ax-table (wrap + base/striped/bordered/hover/compact)
     sticky header, selected row = accent-wash + accent marker, status pills.
     Alpine: axTableSelect, sticky shadow toggle, column-vis via axDropdown.
     ======================================================================== */
  .ax-table-wrap {
    position: relative;
    width: 100%;
    overflow-x: auto;
  }
  .ax-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--ax-text-sm);
    color: var(--ax-text);
  }
  .ax-table__head {
    background: var(--ax-surface-subtle);
  }
  .ax-table__th {
    padding: var(--ax-space-3) var(--ax-space-4);
    text-align: start;
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ax-text-muted);
    white-space: nowrap;
    border-bottom: 1px solid var(--ax-border-strong);
  }
  .ax-table__td {
    padding: var(--ax-space-3) var(--ax-space-4);
    border-bottom: 1px solid var(--ax-border);
    vertical-align: middle;
  }
  .ax-table__td--num,
  .ax-table__th--num {
    text-align: end;
    font-family: var(--ax-font-mono);
    font-variant-numeric: tabular-nums;
  }
  .ax-table__foot {
    background: var(--ax-surface-subtle);
  }
  .ax-table__foot td {
    padding: var(--ax-space-3) var(--ax-space-4);
    border-top: 1px solid var(--ax-border-strong);
    font-weight: var(--ax-weight-semibold);
  }
  .ax-table--striped tbody tr:nth-child(even) {
    background: var(--ax-surface-subtle);
  }
  .ax-table--bordered .ax-table__th,
  .ax-table--bordered .ax-table__td {
    border: 1px solid var(--ax-border);
  }
  .ax-table--hover tbody tr:hover,
  .ax-table__row:hover {
    background: var(--ax-fill-hover);
  }
  .ax-table--compact .ax-table__th,
  .ax-table--compact .ax-table__td {
    padding: var(--ax-space-2) var(--ax-space-3);
  }
  .ax-table--sticky .ax-table__head {
    position: sticky;
    top: 0;
    z-index: 1;
  }
  .ax-table--sticky.is-stuck .ax-table__head {
    box-shadow: var(--ax-shadow-sm);
  }
  .ax-table__row.is-selected,
  .ax-table__row[aria-selected="true"] {
    background: var(--ax-accent-wash);
  }
  .ax-table__row.is-selected .ax-table__td:first-child,
  .ax-table__row[aria-selected="true"] .ax-table__td:first-child {
    box-shadow: inset 2px 0 0 var(--ax-accent);
  }
  .ax-table__row:focus-visible {
    outline: 2px solid var(--ax-focus-ring);
    outline-offset: -2px;
  }
  .ax-table__row--success {
    background: var(--ax-success-50);
  }
  .ax-table__row--warning {
    background: var(--ax-warning-50);
  }
  .ax-table__row--danger {
    background: var(--ax-danger-50);
  }
  .ax-table__th--sortable {
    cursor: pointer;
    user-select: none;
  }
  .ax-table__th--sortable:hover {
    color: var(--ax-text-strong);
  }
  .ax-table__sort {
    margin-inline-start: var(--ax-space-1);
    width: var(--ax-icon-xs);
    height: var(--ax-icon-xs);
    opacity: 0.5;
    vertical-align: middle;
  }
  .ax-table__th[aria-sort] .ax-table__sort {
    opacity: 1;
    color: var(--ax-accent);
  }
  .ax-table__status {
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-1);
    padding: 2px var(--ax-space-2);
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-semibold);
    border-radius: var(--ax-radius-pill);
  }

  /* ========================================================================
     26 · FORMS — fields, inputs, selects, textarea, checks/radios/switch,
     input-group, range, file/dropzone, combobox, labels/help/error, validation.
     Alpine: axCombobox, axRange, axFileDrop (where noted).
     ======================================================================== */

  /* — field wrapper — */
  .ax-field {
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-2);
  }
  .ax-field__label,
  .ax-label {
    font-size: var(--ax-text-sm);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-strong);
  }
  .ax-field__required {
    color: var(--ax-danger-500);
  }
  .ax-field__hint,
  .ax-help {
    font-size: var(--ax-text-xs);
    color: var(--ax-text-subtle);
  }
  .ax-field__message {
    min-height: var(--ax-leading-xs);
    font-size: var(--ax-text-xs);
  }
  .ax-error,
  .ax-field__message--error {
    color: var(--ax-danger-500);
  }
  .ax-field__message--success {
    color: var(--ax-success-500);
  }

  /* — glass field recipe (input / textarea / select) — */
  .ax-input,
  .ax-textarea,
  .ax-select {
    --_f-h: var(--ax-control-h);
    width: 100%;
    min-height: var(--_f-h);
    padding: 0 var(--ax-space-3);
    font-family: var(--ax-font-sans);
    font-size: var(--ax-text-sm);
    color: var(--ax-text);
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-sm);
    transition: border-color var(--ax-motion-instant) var(--ax-ease-standard),
      box-shadow var(--ax-motion-fast) var(--ax-ease-standard),
      background var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-textarea {
    padding: var(--ax-space-3);
    min-height: calc(var(--ax-space-10) + var(--ax-space-6));
    line-height: 1.5;
    resize: vertical;
  }
  .ax-textarea[contenteditable="true"] {
    display: block;
    cursor: text;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
  }
  #b-body {
    direction: auto;
    text-align: start;
  }
  #b-body [dir="auto"] {
    text-align: start;
  }
  #b-body a,
  #news-body a,
  .blog-content-link {
    color: var(--ax-link);
    text-decoration-line: underline;
    text-decoration-color: hsl(var(--primary));
    text-underline-offset: 3px;
  }
  #b-body a:hover,
  #b-body a:focus-visible,
  #news-body a:hover,
  #news-body a:focus-visible,
  .blog-content-link:hover,
  .blog-content-link:focus-visible {
    color: var(--ax-accent-hover);
    text-decoration-thickness: 2px;
  }
  #b-body:focus,
  #b-body:focus-visible {
    border-color: var(--ax-border-strong);
    outline: 2px solid var(--ax-border-strong);
    outline-offset: 1px;
    box-shadow: none;
    caret-color: var(--ax-text-strong);
  }
  .blog-editor-typing-char {
    display: inline;
    animation: blog-editor-character-in 75ms cubic-bezier(0.16, 1, 0.3, 1) both;
  }
  @keyframes blog-editor-character-in {
    from {
      opacity: 0.82;
    }
    to {
      opacity: 1;
    }
  }
  @media (prefers-reduced-motion: reduce) {
    .blog-editor-typing-char {
      animation: none;
    }
  }
  .ax-input::placeholder,
  .ax-textarea::placeholder {
    color: var(--ax-text-disabled);
  }
  .ax-input:hover,
  .ax-textarea:hover,
  .ax-select:hover {
    border-color: var(--ax-border-strong);
  }
  .ax-input:focus-visible,
  .ax-textarea:focus-visible,
  .ax-select:focus-visible,
  .ax-input:focus,
  .ax-textarea:focus,
  .ax-select:focus {
    outline: none;
    border-color: var(--ax-accent);
    box-shadow: var(--ax-focus-shadow);
  }
  .ax-input:disabled,
  .ax-textarea:disabled,
  .ax-select:disabled {
    color: var(--ax-text-disabled);
    background: var(--ax-fill-hover);
    cursor: not-allowed;
  }
  .ax-input[readonly],
  .ax-textarea[readonly] {
    background: var(--ax-surface-subtle);
  }
  .ax-input--sm,
  .ax-select--sm {
    --_f-h: var(--ax-control-h-compact);
  }
  .ax-input--lg,
  .ax-select--lg {
    --_f-h: var(--ax-control-h-lg);
  }
  .ax-select {
    appearance: none;
    -webkit-appearance: none;
    padding-inline-end: var(--ax-space-8);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%238A93A4' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--ax-space-3) center;
  }
  [dir="rtl"] .ax-select {
    background-position: left var(--ax-space-3) center;
  }
  .ax-input.is-invalid,
  .ax-textarea.is-invalid,
  .ax-select.is-invalid,
  .ax-input[aria-invalid="true"],
  .ax-textarea[aria-invalid="true"] {
    border-color: var(--ax-danger-500);
  }
  .ax-input.is-invalid:focus-visible,
  .ax-textarea.is-invalid:focus-visible {
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--ax-danger-500) 26%, transparent);
  }
  .ax-input.is-valid,
  .ax-textarea.is-valid,
  .ax-select.is-valid {
    border-color: var(--ax-success-500);
  }

  /* — affixes (leading/trailing icon or button) — */
  .ax-field__control {
    position: relative;
    display: flex;
    align-items: center;
  }
  .ax-field__control .ax-input {
    flex: 1 1 auto;
  }
  .ax-input--with-leading-icon {
    padding-inline-start: var(--ax-space-8);
  }
  .ax-input--with-trailing {
    padding-inline-end: var(--ax-space-8);
  }
  .ax-field__affix {
    position: absolute;
    display: inline-flex;
    align-items: center;
    color: var(--ax-text-subtle);
    pointer-events: none;
  }
  .ax-field__affix--leading {
    inset-inline-start: var(--ax-space-3);
  }
  .ax-field__affix--trailing {
    inset-inline-end: var(--ax-space-3);
  }
  .ax-field__affix svg {
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
  }
  .ax-field__affix--button {
    pointer-events: auto;
    cursor: pointer;
    background: none;
    border: 0;
  }

  /* — floating label — */
  .ax-input--floating {
    position: relative;
  }

  /* — checkbox — */
  .ax-check {
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-2);
    cursor: pointer;
    min-height: var(--ax-control-h);
  }
  .ax-checkbox {
    position: relative;
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    appearance: none;
    -webkit-appearance: none;
    background: var(--ax-surface);
    border: 1px solid var(--ax-border-strong);
    border-radius: var(--ax-radius-xs);
    cursor: pointer;
    transition: background var(--ax-motion-instant) var(--ax-ease-standard),
      border-color var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-checkbox:hover {
    border-color: var(--ax-accent);
  }
  .ax-checkbox:checked,
  .ax-checkbox:indeterminate {
    background: var(--ax-accent);
    border-color: var(--ax-accent);
  }
  .ax-checkbox:checked::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12l5 5L20 7'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: center;
  }
  .ax-checkbox:indeterminate::after {
    content: "";
    position: absolute;
    inset-inline: 3px;
    top: 50%;
    height: 2px;
    transform: translateY(-50%);
    background: #fff;
    border-radius: 1px;
  }
  .ax-checkbox:focus-visible {
    outline: none;
    box-shadow: var(--ax-focus-shadow);
  }
  .ax-checkbox:disabled {
    background: var(--ax-fill-hover);
    border-color: var(--ax-border);
    cursor: not-allowed;
  }
  .ax-checkbox.is-invalid {
    border-color: var(--ax-danger-500);
  }

  /* — radio — */
  .ax-radio {
    position: relative;
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    appearance: none;
    -webkit-appearance: none;
    background: var(--ax-surface);
    border: 1px solid var(--ax-border-strong);
    border-radius: var(--ax-radius-pill);
    cursor: pointer;
    transition: border-color var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-radio:hover {
    border-color: var(--ax-accent);
  }
  .ax-radio:checked {
    border-color: var(--ax-accent);
  }
  .ax-radio:checked::after {
    content: "";
    position: absolute;
    inset: 4px;
    border-radius: 50%;
    background: var(--ax-accent);
  }
  .ax-radio:focus-visible {
    outline: none;
    box-shadow: var(--ax-focus-shadow);
  }
  .ax-radio:disabled {
    background: var(--ax-fill-hover);
    cursor: not-allowed;
  }

  /* — switch (track → accent when on) — */
  .ax-switch {
    position: relative;
    flex: 0 0 auto;
    width: 36px;
    height: 20px;
    appearance: none;
    -webkit-appearance: none;
    background: var(--ax-border-strong);
    border-radius: var(--ax-radius-pill);
    cursor: pointer;
    transition: background var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-switch::after {
    content: "";
    position: absolute;
    top: 2px;
    inset-inline-start: 2px;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: var(--ax-surface-solid);
    box-shadow: var(--ax-shadow-sm);
    transition: transform var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-switch:checked {
    background: var(--ax-accent);
  }
  .ax-switch:checked::after {
    transform: translateX(16px);
  }
  [dir="rtl"] .ax-switch:checked::after {
    transform: translateX(-16px);
  }
  .ax-switch:focus-visible {
    outline: none;
    box-shadow: var(--ax-focus-shadow);
  }
  .ax-switch:disabled {
    background: var(--ax-fill-hover);
    cursor: not-allowed;
  }
  .ax-switch--sm {
    width: 30px;
    height: 16px;
  }
  .ax-switch--sm::after {
    width: 12px;
    height: 12px;
  }
  .ax-switch--sm:checked::after {
    transform: translateX(14px);
  }
  .ax-switch--lg {
    width: 44px;
    height: 24px;
  }
  .ax-switch--lg::after {
    width: 20px;
    height: 20px;
  }
  .ax-switch--lg:checked::after {
    transform: translateX(20px);
  }
  @media (prefers-reduced-motion: reduce) {
    .ax-switch,
    .ax-switch::after {
      transition: none;
    }
  }

  /* — input group — */
  .ax-input-group {
    display: flex;
    align-items: stretch;
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-sm);
    overflow: hidden;
    background: var(--ax-surface);
  }
  .ax-input-group:hover {
    border-color: var(--ax-border-strong);
  }
  .ax-input-group:focus-within {
    border-color: var(--ax-accent);
    box-shadow: var(--ax-focus-shadow);
  }
  .ax-input-group .ax-input,
  .ax-input-group .ax-select {
    border: 0;
    border-radius: 0;
    background: transparent;
  }
  .ax-input-group .ax-input:focus-visible,
  .ax-input-group .ax-select:focus-visible {
    box-shadow: none;
  }
  .ax-input-group__addon {
    display: inline-flex;
    align-items: center;
    padding-inline: var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text-subtle);
    background: var(--ax-surface-subtle);
    white-space: nowrap;
  }
  .ax-input-group__addon:not(:last-child) {
    border-inline-end: 1px solid var(--ax-border);
  }
  .ax-input-group__addon:not(:first-child) {
    border-inline-start: 1px solid var(--ax-border);
  }
  .ax-input-group.is-invalid {
    border-color: var(--ax-danger-500);
  }

  /* — range slider — Alpine: axRange — */
  .ax-range {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
    width: 100%;
  }
  .ax-range__track {
    position: relative;
    flex: 1 1 auto;
    height: 4px;
    background: var(--ax-fill-hover);
    border-radius: var(--ax-radius-pill);
  }
  .ax-range__fill {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    background: var(--ax-accent);
    border-radius: inherit;
  }
  .ax-range__handle {
    position: absolute;
    top: 50%;
    width: 16px;
    height: 16px;
    transform: translate(-50%, -50%);
    background: var(--ax-surface-solid);
    border: 2px solid var(--ax-accent);
    border-radius: 50%;
    box-shadow: var(--ax-shadow-sm);
    cursor: grab;
    transition: width var(--ax-motion-instant) var(--ax-ease-standard),
      height var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-range__handle:hover,
  .ax-range__handle:active {
    width: 18px;
    height: 18px;
  }
  .ax-range__handle:focus-visible {
    outline: none;
    box-shadow: var(--ax-focus-shadow);
  }
  .ax-range__bubble {
    flex: 0 0 auto;
    min-width: 4ch;
    padding: 2px var(--ax-space-2);
    font-size: var(--ax-text-xs);
    font-variant-numeric: tabular-nums;
    color: var(--ax-text-strong);
    background: var(--ax-surface-overlay);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-sm);
    box-shadow: var(--ax-shadow-md);
  }
  .ax-range--native {
    -webkit-appearance: none;
    appearance: none;
    height: 4px;
    background: var(--ax-fill-hover);
    border-radius: var(--ax-radius-pill);
  }
  .ax-range--native::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 16px;
    height: 16px;
    background: var(--ax-surface-solid);
    border: 2px solid var(--ax-accent);
    border-radius: 50%;
  }
  .ax-range--native::-moz-range-thumb {
    width: 16px;
    height: 16px;
    background: var(--ax-surface-solid);
    border: 2px solid var(--ax-accent);
    border-radius: 50%;
  }

  /* — file upload / dropzone — Alpine: axFileDrop — */
  .ax-file {
    display: inline-flex;
  }
  .ax-dropzone {
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-3);
  }
  .ax-dropzone__area {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--ax-space-2);
    padding: var(--ax-space-8);
    text-align: center;
    color: var(--ax-text-muted);
    background: var(--ax-surface);
    border: 1.5px dashed var(--ax-border-strong);
    border-radius: var(--ax-radius-md);
    cursor: pointer;
    transition: border-color var(--ax-motion-fast) var(--ax-ease-standard),
      background var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-dropzone__area svg {
    width: var(--ax-icon-lg);
    height: var(--ax-icon-lg);
    color: var(--ax-text-subtle);
  }
  .ax-dropzone.is-dragover .ax-dropzone__area {
    border-color: var(--ax-accent);
    background: var(--ax-accent-wash);
  }
  .ax-dropzone__list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-2);
  }
  .ax-dropzone__file {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
    padding: var(--ax-space-2) var(--ax-space-3);
    background: var(--ax-surface-subtle);
    border-radius: var(--ax-radius-sm);
  }
  .ax-dropzone__name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: var(--ax-text-sm);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .ax-dropzone__remove {
    flex: 0 0 auto;
    color: var(--ax-text-subtle);
    background: none;
    border: 0;
    cursor: pointer;
  }
  .ax-dropzone__remove:hover {
    color: var(--ax-danger-500);
  }

  /* — combobox / enhanced select — Alpine: axCombobox — */
  .ax-combobox {
    position: relative;
    width: 100%;
  }
  .ax-combobox__trigger {
    display: flex;
    align-items: center;
    gap: var(--ax-space-2);
    width: 100%;
    min-height: var(--ax-control-h);
    padding: 0 var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text);
    text-align: start;
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-sm);
    cursor: pointer;
  }
  .ax-combobox__trigger:hover {
    border-color: var(--ax-border-strong);
  }
  .ax-combobox__trigger[aria-expanded="true"] {
    border-color: var(--ax-accent);
    box-shadow: var(--ax-focus-shadow);
  }
  .ax-combobox__value {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .ax-combobox__caret {
    flex: 0 0 auto;
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
    color: var(--ax-text-subtle);
  }
  .ax-combobox__clear {
    color: var(--ax-text-subtle);
    background: none;
    border: 0;
    cursor: pointer;
  }
  .ax-combobox__panel {
    position: absolute;
    z-index: var(--ax-z-dropdown);
    inset-inline: 0;
    margin-top: var(--ax-space-1);
    max-height: 320px;
    overflow-y: auto;
    padding: var(--ax-space-2);
    /* Opaque surface, no backdrop-filter: the panel lives inside a glass card
       (a backdrop root), so its own backdrop-filter could only blur the card's
       flat surface, never the page — solid reads cleaner for option lists. */
    background: var(--ax-surface-solid);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-lg);
    box-shadow: var(--ax-shadow-md);
  }
  .ax-combobox__search {
    width: 100%;
    margin-bottom: var(--ax-space-2);
    padding: var(--ax-space-2) var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text);
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-sm);
  }
  .ax-combobox__group-label {
    padding: var(--ax-space-2) var(--ax-space-3) var(--ax-space-1);
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-semibold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ax-text-subtle);
  }
  .ax-combobox__option {
    display: flex;
    align-items: center;
    gap: var(--ax-space-2);
    padding: var(--ax-space-2) var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text);
    border-radius: var(--ax-radius-md);
    cursor: pointer;
  }
  .ax-combobox__option:hover,
  .ax-combobox__option.is-active {
    background: var(--ax-fill-hover);
  }
  .ax-combobox__option.is-highlighted {
    position: relative;
    background: var(--ax-accent-wash);
  }
  .ax-combobox__option.is-highlighted::before {
    content: "";
    position: absolute;
    inset-block: 4px;
    inset-inline-start: 0;
    width: 2px;
    border-radius: 0 2px 2px 0;
    background: var(--ax-accent);
  }
  .ax-combobox__option[aria-selected="true"] {
    color: var(--ax-accent);
    font-weight: var(--ax-weight-medium);
  }
  .ax-combobox__empty {
    padding: var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
    text-align: center;
  }
  .ax-combobox__chips {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--ax-space-1);
  }

  /* — tags input — */
  .ax-tags {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ax-space-1);
    min-height: var(--ax-control-h);
    padding: var(--ax-space-1) var(--ax-space-2);
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-sm);
  }
  .ax-tags:focus-within {
    border-color: var(--ax-accent);
    box-shadow: var(--ax-focus-shadow);
  }
  .ax-tags__input {
    flex: 1 1 80px;
    min-width: 80px;
    border: 0;
    background: transparent;
    color: var(--ax-text);
    font-size: var(--ax-text-sm);
    outline: none;
  }

  /* — password strength meter — */
  .ax-strength {
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-1);
  }
  .ax-strength__bars {
    display: flex;
    gap: 4px;
  }
  .ax-strength__bar {
    flex: 1 1 0;
    height: 4px;
    background: var(--ax-fill-hover);
    border-radius: var(--ax-radius-pill);
  }
  .ax-strength__bar.is-weak {
    background: var(--ax-danger-500);
  }
  .ax-strength__bar.is-medium {
    background: var(--ax-warning-500);
  }
  .ax-strength__bar.is-strong {
    background: var(--ax-success-500);
  }
  .ax-strength__label {
    font-size: var(--ax-text-2xs);
    color: var(--ax-text-subtle);
  }

  /* — OTP — */
  .ax-otp {
    display: inline-flex;
    gap: var(--ax-space-2);
    max-inline-size: 100%;
  }
  .ax-otp__cell {
    width: 44px;
    /* 44px is the ideal, not a floor: six fixed cells plus five gaps need 304px,
       more than a 360px phone leaves inside a card, and the last cell was
       clipped. flex-shrink lets the row give way instead. */
    flex: 0 1 44px;
    min-inline-size: 0;
    height: 48px;
    text-align: center;
    font-family: var(--ax-font-mono);
    font-size: var(--ax-text-lg);
    color: var(--ax-text-strong);
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-sm);
  }
  .ax-otp__cell:focus-visible {
    outline: none;
    border-color: var(--ax-accent);
    box-shadow: var(--ax-focus-shadow);
  }

  /* ========================================================================
     27 · SEGMENT — .ax-segment (theme/dir/density segmented toggles)
     Used by customizer + header. Active = accent-wash + accent text.
     Alpine: none (buttons set data-ax-* / aria-pressed).
     ======================================================================== */
  .ax-segment {
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-1);
    padding: var(--ax-space-1);
    background: var(--ax-fill-hover);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
  }
  .ax-segment__option {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ax-space-1);
    min-height: 30px;
    padding: 0 var(--ax-space-3);
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-muted);
    background: transparent;
    border: 0;
    border-radius: var(--ax-radius-sm);
    cursor: pointer;
    transition: background var(--ax-motion-instant) var(--ax-ease-standard),
      color var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-segment__option svg {
    width: var(--ax-icon-sm);
    height: var(--ax-icon-sm);
  }
  .ax-segment__option:hover {
    color: var(--ax-text-strong);
  }
  .ax-segment__option[aria-pressed="true"],
  .ax-segment__option.is-active,
  .ax-segment__option[aria-checked="true"] {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
    box-shadow: var(--ax-shadow-sm);
  }

  /* ========================================================================
     28 · CHART WRAPPER — .ax-chart (JS-mounted box: ApexCharts/Chart.js/ECharts)
     Sized container + legend + a11y data-mirror table styling.
     Alpine: none (charts init by src/js/charts/* via data-ax-chart-*).
     ======================================================================== */
  .ax-chart {
    position: relative;
    width: 100%;
    min-height: 120px;
  }
  .ax-chart__legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ax-space-3);
    margin-top: var(--ax-space-3);
    font-size: var(--ax-text-xs);
    color: var(--ax-text-muted);
  }
  .ax-chart__legend-item {
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-1);
  }
  .ax-chart__swatch {
    width: 9px;
    height: 9px;
    border-radius: 3px;
    flex: 0 0 auto;
  }
  .ax-chart__table[hidden] {
    display: none;
  }
  .ax-chart--sparkline {
    min-height: 40px;
  }

  /* ========================================================================
     29 · INLINE TYPOGRAPHY HELPERS — link/code/kbd/mark/eyebrow/truncate
     (consume role tokens; pages use these inline)
     ======================================================================== */
  .ax-link {
    color: var(--ax-link);
    text-decoration: none;
  }
  .ax-link:hover {
    color: var(--ax-accent-hover);
    text-decoration: underline;
    text-underline-offset: 2px;
  }
  .ax-code {
    font-family: var(--ax-font-mono);
    font-size: 0.9em;
    padding: 1px 5px;
    color: var(--ax-text-strong);
    background: var(--ax-fill-hover);
    border-radius: var(--ax-radius-xs);
  }
  .ax-kbd {
    font-family: var(--ax-font-mono);
    font-size: var(--ax-text-2xs);
    padding: 2px 6px;
    color: var(--ax-text);
    background: var(--ax-surface-subtle);
    border: 1px solid var(--ax-border-strong);
    border-radius: var(--ax-radius-xs);
    box-shadow: 0 1px 0 var(--ax-border-strong);
  }
  .ax-mark {
    background: var(--ax-accent-wash);
    color: var(--ax-text-strong);
    border-radius: 2px;
    padding: 0 2px;
  }
  .ax-eyebrow {
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ax-text-subtle);
  }
  .ax-text-truncate {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }


/* === nav.css === */
/*
 * Vireo — Sidebar navigation tree
 * The base layout for the manifest-driven sidebar menu (.ax-sidebar__nav /
 * .ax-nav__*). Active state + glow bar live in tokens/_recipes.css; the six
 * sidebar STYLES (compact/overlay/…) live in base.css; this file owns the
 * default tree: rows, nesting, collapse, carets, badges. Logical props (RTL).
 */

/* ── scroll region ── */
.ax-sidebar__nav {
  display: flex;
  flex-direction: column;
  gap: 2px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding: var(--ax-space-2) var(--ax-space-3) var(--ax-space-4);
  /* Scroll stays functional (long menus must remain reachable) but the rail
     itself shows no scrollbar — cleaner sidebar edge. Firefox: none; WebKit
     via the ::-webkit-scrollbar rule below. */
  scrollbar-width: none;
}
.ax-sidebar__nav::-webkit-scrollbar {
  inline-size: 0;
  block-size: 0;
}

/* ── section eyebrow ── */
.ax-sidebar__section {
  margin: var(--ax-space-4) var(--ax-space-3) var(--ax-space-1);
  font-size: var(--ax-text-2xs);
  font-weight: var(--ax-weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
  user-select: none;
}
.ax-sidebar__nav > .ax-sidebar__section:first-child {
  margin-top: var(--ax-space-1);
}

/* ── group container ── */
.ax-nav__group {
  display: block;
}

/* ── row (link or group-toggle button share .ax-nav__item) ── */
.ax-nav__item {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--ax-space-3);
  inline-size: 100%;
  margin: 0;
  padding-block: 9px;
  padding-inline: var(--ax-space-3);
  border: 0;
  border-radius: var(--ax-radius-md);
  background: transparent;
  color: var(--ax-text-muted);
  font-family: inherit;
  font-size: var(--ax-text-sm);
  font-weight: var(--ax-weight-medium);
  line-height: 1.2;
  text-align: start;
  text-decoration: none;
  cursor: pointer;
  transition:
    background var(--ax-motion-fast) var(--ax-ease-standard),
    color var(--ax-motion-fast) var(--ax-ease-standard);
}
.ax-nav__item:hover {
  background: var(--ax-fill-hover);
  color: var(--ax-text-strong);
}
.ax-nav__item:hover .ax-nav__icon {
  opacity: 1;
}

/* ── icon + label + caret ── */
.ax-nav__icon {
  inline-size: var(--ax-icon-md);
  block-size: var(--ax-icon-md);
  flex: 0 0 auto;
  opacity: 0.85;
}
.ax-nav__label {
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.ax-nav__caret {
  inline-size: var(--ax-icon-sm);
  block-size: var(--ax-icon-sm);
  flex: 0 0 auto;
  color: var(--ax-text-subtle);
  transition: transform var(--ax-motion-base) var(--ax-ease-standard);
}
.ax-nav__item--parent[aria-expanded='true'] .ax-nav__caret {
  transform: rotate(90deg);
}

/* ── collapsible children ── */
.ax-nav__children {
  display: flex;
  flex-direction: column;
  gap: 1px;
  position: relative;
  margin-block: 2px;
  /* tree guide hairline aligned under the parent icon centre */
  margin-inline-start: calc(var(--ax-space-3) + (var(--ax-icon-md) / 2));
  padding-inline-start: var(--ax-space-3);
  border-inline-start: 1px solid var(--ax-border);
}
.ax-nav__children[hidden] {
  display: none;
}

/* nested rows: tighter, lighter, indented by aria-level */
.ax-nav__item--child {
  padding-block: 7px;
  font-size: var(--ax-text-sm);
  color: var(--ax-text-muted);
}
.ax-nav__item[aria-level='3'] {
  padding-inline-start: var(--ax-space-5);
}
.ax-nav__item[aria-level='4'] {
  padding-inline-start: var(--ax-space-8);
}
/* the leading active marker (hidden until active) */
.ax-nav__bar {
  display: none;
}

/* ── badges ── */
.ax-nav__badge {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 18px;
  padding: 1px 7px;
  border-radius: var(--ax-radius-pill);
  font-size: var(--ax-text-2xs);
  font-weight: var(--ax-weight-semibold);
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
}
.ax-nav__badge--count {
  background: var(--ax-fill-active);
  color: var(--ax-text-muted);
}
.ax-nav__badge--new {
  background: var(--ax-accent-wash);
  color: var(--ax-accent);
}
.ax-nav__badge--hot {
  background: color-mix(in srgb, var(--ax-danger-500) 16%, transparent);
  color: var(--ax-danger-500);
}
.ax-nav__badge--beta {
  background: var(--ax-fill-active);
  color: var(--ax-text-subtle);
}

/* ── single top-level link (no children) keeps icon+label only ── */
.ax-nav__item--single .ax-nav__caret {
  display: none;
}

/* ── filter: dim non-matches, highlight matches (sidebar.js sets .is-hidden) ── */
.ax-nav__group.is-hidden,
.ax-nav__item.is-hidden {
  display: none !important;
}
.ax-sidebar__nav mark {
  background: var(--ax-accent-wash);
  color: var(--ax-accent);
  border-radius: 3px;
  padding: 0 1px;
}

/* ── collapsed-rail flyout popover ────────────────────────────────────────
   When the header-toggle collapse is active (base.css §7b) the in-rail child
   panels are hidden. core/sidebar-flyout.js mounts this popover on <body> and
   positions it beside the rail so a collapsed icon still reaches its sub-pages.
   Body-level + ax-flyout__* classes keep it clear of the rail's overflow clip
   and the §7b hide rules (which match .ax-nav__* under [data-ax-collapsed]). */
.ax-flyout {
  position: fixed;
  z-index: var(--ax-z-dropdown);
  display: flex;
  flex-direction: column;
  min-inline-size: 200px;
  max-inline-size: 280px;
  max-block-size: calc(100vh - 16px);
  padding: var(--ax-space-2);
  /* Opaque, no backdrop-filter — matches the rest of the dropdown family. */
  background: var(--ax-surface-solid);
  color: var(--ax-text);
  border: 1px solid var(--ax-border);
  border-radius: var(--ax-radius-lg);
  box-shadow: var(--ax-shadow-lg);
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: none; /* match the rail: scroll works, no visible bar */
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateX(-4px);
  transition:
    opacity var(--ax-motion-fast) var(--ax-ease-standard),
    transform var(--ax-motion-fast) var(--ax-ease-standard),
    visibility 0s linear var(--ax-motion-fast);
}
[dir='rtl'] .ax-flyout {
  transform: translateX(4px);
}
.ax-flyout::-webkit-scrollbar {
  inline-size: 0;
  block-size: 0;
}
.ax-flyout.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
  transition:
    opacity var(--ax-motion-fast) var(--ax-ease-standard),
    transform var(--ax-motion-fast) var(--ax-ease-standard);
}
/* invisible bridge spanning the rail→popover gap so the pointer can cross
   diagonally without the hover dropping (paired with the JS close delay) */
.ax-flyout::before {
  content: '';
  position: absolute;
  inset-block: 0;
  inset-inline-start: calc((var(--ax-space-2) + 8px) * -1);
  inline-size: calc(var(--ax-space-2) + 8px);
}
[dir='rtl'] .ax-flyout::before {
  inset-inline-start: auto;
  inset-inline-end: calc((var(--ax-space-2) + 8px) * -1);
}

.ax-flyout__title {
  padding: var(--ax-space-1) var(--ax-space-3) var(--ax-space-2);
  font-size: var(--ax-text-2xs);
  font-weight: var(--ax-weight-semibold);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}
.ax-flyout__list {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.ax-flyout__group {
  margin-block-start: var(--ax-space-1);
  padding: var(--ax-space-1) var(--ax-space-3);
  font-size: var(--ax-text-2xs);
  font-weight: var(--ax-weight-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ax-text-subtle);
}
.ax-flyout__item {
  display: flex;
  align-items: center;
  gap: var(--ax-space-2);
  padding: 7px var(--ax-space-3);
  border-radius: var(--ax-radius-md);
  color: var(--ax-text-muted);
  font-size: var(--ax-text-sm);
  font-weight: var(--ax-weight-medium);
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  transition:
    background var(--ax-motion-fast) var(--ax-ease-standard),
    color var(--ax-motion-fast) var(--ax-ease-standard);
}
.ax-flyout__item:hover,
.ax-flyout__item:focus-visible {
  background: var(--ax-fill-hover);
  color: var(--ax-text-strong);
  outline: none;
}
.ax-flyout__item.is-active {
  background: var(--ax-fill-active);
  color: var(--ax-text-strong);
}
.ax-flyout__label {
  flex: 1 1 auto;
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ax-flyout__badge {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 18px;
  padding: 1px 7px;
  border-radius: var(--ax-radius-pill);
  font-size: var(--ax-text-2xs);
  font-weight: var(--ax-weight-semibold);
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
}
.ax-flyout__badge--count {
  background: var(--ax-fill-active);
  color: var(--ax-text-muted);
}
.ax-flyout__badge--new {
  background: var(--ax-accent-wash);
  color: var(--ax-accent);
}
.ax-flyout__badge--hot {
  background: color-mix(in srgb, var(--ax-danger-500) 16%, transparent);
  color: var(--ax-danger-500);
}
.ax-flyout__badge--beta {
  background: var(--ax-fill-active);
  color: var(--ax-text-subtle);
}

/* === shell.css === */
/*
 * Vireo — HTML reference edition · SHELL-CHROME components (Aurora)
 * ----------------------------------------------------------------------------
 * Fills the component-CSS gaps for the six shell partials (head/sidebar/header/
 * footer/customizer/scripts). The design-system foundation (tokens, .ax-card,
 * .ax-btn, .ax-nav__*, sidebar/header LAYOUT in base.css, surface schemes in
 * schemes.css, the .ax-menu dropdown recipe) was already built — this file ONLY
 * adds the bespoke chrome classes the partials reference that had no rule:
 *
 *   · Alpine x-cloak guard (prevents customizer/dropdown flash before boot)
 *   · .ax-customizer  full drawer (off-canvas → slide-in, glass, sticky head/foot)
 *   · customizer controls: .ax-segmented, .ax-swatch grid, .ax-scheme / .ax-style
 *     / .ax-thumb / .ax-tint previews, .ax-color-field / .ax-hex / .ax-recent-*,
 *     .ax-toggle switch, .ax-note
 *   · header chrome: .ax-icon-btn, .ax-search (⌘K trigger),
 *     .ax-badge-count, and the .ax-dropdown PANEL + all .ax-dropdown__* internals
 *     used by language / app-grid / cart / notifications / profile / overflow
 *   · command palette: .ax-command__* (JS-emitted rows)
 *   · sidebar content gaps: filter input, mark, nav-empty, promo, mini user card
 *   · footer link row + two missing .ax-btn modifiers (--accent, --ghost-danger)
 *
 * TOKEN LAW (locked): Layer-2 role tokens / scales only; literal colour solely
 * inside rgba(var(--ax-accent-rgb), a). CSS logical properties throughout (RTL).
 * Open/close HOOKS match the JS that already exists — NOT invented:
 *   · customizer  → Alpine `x-show="open"` + x-transition classes
 *                   `.ax-customizer--enter` / `.ax-customizer--leave`
 *   · dropdowns   → Alpine `x-show="open"` (display toggle; opacity transition)
 *   · command     → `.is-open` class + `hidden` attr on `#ax-command` (vanilla JS)
 * ----------------------------------------------------------------------------
 */

/*
 * LAYER NOTE: this file is intentionally UNLAYERED (like base.css + schemes.css).
 * base.css ships an unlayered reset `button { background: none }`; an unlayered
 * rule beats ANY 
    display: none !important;
  

  /* ════════════════════════════════════════════════════════════════════════
     1 · ICON BUTTON  .ax-icon-btn  (square ghost icon control — header + close)
     base.css only paints `.ax-header .ax-icon-btn:hover`; the box is defined
     here so it works in the header AND inside the customizer.
     ════════════════════════════════════════════════════════════════════════ */
  .ax-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    inline-size: 38px;
    block-size: 38px;
    padding: 0;
    color: var(--ax-text-muted);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--ax-radius-md);
    cursor: pointer;
    -webkit-appearance: none;
    appearance: none;
    transition:
      background var(--ax-motion-fast) var(--ax-ease-standard),
      color var(--ax-motion-fast) var(--ax-ease-standard),
      border-color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-icon-btn:hover {
    color: var(--ax-text-strong);
    background: var(--ax-fill-hover);
  }
  .ax-icon-btn:active {
    background: var(--ax-fill-active);
  }
  .ax-icon-btn[aria-expanded='true'],
  .ax-icon-btn[aria-pressed='true'] {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
  }
  .ax-icon-btn .ax-icon {
    inline-size: var(--ax-icon-md);
    block-size: var(--ax-icon-md);
  }

  /* ════════════════════════════════════════════════════════════════════════
     2 · HEADER ⌘K SEARCH TRIGGER + COUNT BADGE
     ════════════════════════════════════════════════════════════════════════ */
  /* ⌘K search pill (header.html §2) */
  .ax-search {
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-2);
    min-inline-size: 0;
    max-inline-size: 280px;
    block-size: 38px;
    padding-inline: var(--ax-space-3);
    color: var(--ax-text-muted);
    background: var(--ax-surface-subtle);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-pill);
    cursor: text;
    transition:
      background var(--ax-motion-fast) var(--ax-ease-standard),
      border-color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-search:hover {
    background: var(--ax-fill-hover);
    border-color: var(--ax-border-strong);
  }
  .ax-search__icon {
    flex: 0 0 auto;
    inline-size: var(--ax-icon-sm);
    block-size: var(--ax-icon-sm);
    color: var(--ax-text-subtle);
  }
  .ax-search__placeholder {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--ax-text-sm);
    text-align: start;
  }
  .ax-search__keycap {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    padding-inline: var(--ax-space-2);
    block-size: 20px;
    font-family: var(--ax-font-mono);
    font-size: var(--ax-text-2xs);
    color: var(--ax-text-subtle);
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-xs);
  }

  /* count bubble on cart / notifications triggers (partial uses .ax-badge-count;
     the styled token in components.css is .ax-badge--count, so this is a gap) */
  .ax-badge-count {
    position: absolute;
    inset-block-start: 2px;
    inset-inline-end: 2px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-inline-size: 16px;
    block-size: 16px;
    padding-inline: 4px;
    font-family: var(--ax-font-mono);
    font-size: 10px;
    font-weight: var(--ax-weight-semibold);
    line-height: 1;
    color: var(--ax-on-accent);
    background: var(--ax-accent);
    border-radius: var(--ax-radius-pill);
    box-shadow: 0 0 0 2px var(--ax-header-bg, var(--ax-surface-raised));
    pointer-events: none;
  }
  .ax-badge-count--dot {
    min-inline-size: 8px;
    block-size: 8px;
    padding: 0;
    font-size: 0;
    color: transparent;
  }
  /* trigger buttons that host a count need positioning context */
  .ax-cart__trigger,
  .ax-notif__trigger {
    position: relative;
  }

  /* ════════════════════════════════════════════════════════════════════════
     3 · HEADER DROPDOWN PANEL  .ax-dropdown (+ __* internals)
     base.css gives `.ax-dropdown { position:relative; display:inline-flex }`
     for the WRAPPER, but the header panels are `<div class="ax-dropdown …__menu">`
     elements that float — so the floating glass surface + every interior item is
     defined here (mirrors the .ax-menu recipe with the .ax-dropdown__ vocabulary
     the partials actually use). Each cluster wrapper (.ax-lang/.ax-apps/.ax-cart/
     .ax-notif/.ax-profile/.ax-overflow) is the relative anchor.
     ════════════════════════════════════════════════════════════════════════ */
  .ax-lang,
  .ax-apps,
  .ax-cart,
  .ax-notif,
  .ax-profile,
  .ax-overflow {
    position: relative;
    display: inline-flex;
    flex: 0 0 auto;
  }

  /* the floating panel itself — scoped to the header menu panels (each carries a
     `.ax-…__menu` class) so it does NOT hijack the generic `.ax-dropdown` WRAPPER
     that content pages use as a relative anchor (components.css defines that as
     `position:relative; inline-flex`). `display:block` makes the items stack. */
  .ax-lang__menu,
  .ax-apps__menu,
  .ax-cart__menu,
  .ax-notif__menu,
  .ax-profile__menu,
  .ax-overflow__menu {
    display: block;
    position: absolute;
    inset-block-start: calc(100% + var(--ax-space-2));
    inset-inline-end: 0;
    z-index: var(--ax-z-dropdown);
    inline-size: max-content;
    min-inline-size: 220px;
    max-inline-size: min(92vw, 360px);
    max-block-size: min(72vh, 480px);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--ax-space-2);
    color: var(--ax-text);
    /* Opaque, no backdrop-filter — header dropdowns read cleaner solid
       (matches .ax-menu / .ax-combobox__panel / .ax-popover__panel). */
    background: var(--ax-surface-solid);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-lg);
    box-shadow: var(--ax-shadow-lg);
  }
  /* the base.css wrapper rule (position:relative) must NOT defeat the panel:
     re-assert inline-flex only on the cluster wrappers above, not the panel. */

  .ax-dropdown__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ax-space-2);
    padding: var(--ax-space-2) var(--ax-space-3) var(--ax-space-1);
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ax-text-subtle);
  }
  .ax-dropdown__item {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
    inline-size: 100%;
    padding: var(--ax-space-2) var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text);
    text-align: start;
    text-decoration: none;
    background: transparent;
    border: 0;
    border-radius: var(--ax-radius-md);
    cursor: pointer;
    transition: background var(--ax-motion-instant) var(--ax-ease-standard);
  }
  .ax-dropdown__item:hover,
  .ax-dropdown__item:focus-visible {
    background: var(--ax-fill-hover);
    color: var(--ax-text-strong);
    outline: none;
  }
  .ax-dropdown__item.is-active,
  .ax-dropdown__item[aria-checked='true'] {
    color: var(--ax-accent);
  }
  .ax-dropdown__lead {
    flex: 0 0 auto;
    inline-size: var(--ax-icon-md);
    block-size: var(--ax-icon-md);
    color: var(--ax-text-subtle);
  }
  .ax-dropdown__item:hover .ax-dropdown__lead,
  .ax-dropdown__item.is-active .ax-dropdown__lead {
    color: inherit;
  }
  .ax-dropdown__check {
    margin-inline-start: auto;
    flex: 0 0 auto;
    inline-size: var(--ax-icon-sm);
    block-size: var(--ax-icon-sm);
    color: var(--ax-accent);
    opacity: 0;
  }
  .ax-dropdown__item.is-active .ax-dropdown__check,
  .ax-dropdown__item[aria-checked='true'] .ax-dropdown__check {
    opacity: 1;
  }
  .ax-dropdown__item--danger {
    color: var(--ax-danger-500);
  }
  .ax-dropdown__item--danger .ax-dropdown__lead {
    color: var(--ax-danger-500);
  }
  .ax-dropdown__item--danger:hover,
  .ax-dropdown__item--danger:focus-visible {
    background: color-mix(in oklab, var(--ax-danger-500) 12%, transparent);
    color: var(--ax-danger-500);
  }
  .ax-dropdown__divider {
    block-size: 1px;
    margin-block: var(--ax-space-1);
    margin-inline: calc(-1 * var(--ax-space-1));
    background: var(--ax-border);
  }
  .ax-dropdown__foot {
    display: block;
    margin-block-start: var(--ax-space-1);
    padding: var(--ax-space-2) var(--ax-space-3);
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-link);
    text-align: center;
    text-decoration: none;
    border-block-start: 1px solid var(--ax-border);
    border-radius: 0 0 var(--ax-radius-sm) var(--ax-radius-sm);
  }
  .ax-dropdown__foot:hover {
    background: var(--ax-fill-hover);
  }

  /* ── LANGUAGE menu ── */
  .ax-lang__code {
    font-family: var(--ax-font-mono);
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-semibold);
    letter-spacing: 0.02em;
  }
  .ax-lang__menu {
    min-inline-size: 200px;
  }
  .ax-lang__name {
    color: var(--ax-text-muted);
  }
  .ax-dropdown__item.is-active .ax-lang__name {
    color: inherit;
  }

  /* ── APP-GRID menu ── */
  .ax-apps__menu {
    inline-size: 320px;
  }
  .ax-apps__grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ax-space-1);
    padding: var(--ax-space-1);
  }
  .ax-apps__tile {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--ax-space-2);
    padding-block: var(--ax-space-3);
    padding-inline: var(--ax-space-2);
    color: var(--ax-text-muted);
    text-decoration: none;
    border-radius: var(--ax-radius-md);
    transition:
      background var(--ax-motion-fast) var(--ax-ease-standard),
      color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-apps__tile:hover,
  .ax-apps__tile:focus-visible {
    background: var(--ax-fill-hover);
    color: var(--ax-text-strong);
    outline: none;
  }
  .ax-apps__tile-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 38px;
    block-size: 38px;
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
    border-radius: var(--ax-radius-md);
  }
  .ax-apps__tile-icon .ax-icon {
    inline-size: var(--ax-icon-md);
    block-size: var(--ax-icon-md);
  }
  .ax-apps__tile-label {
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-medium);
  }

  /* ── CART menu ── */
  .ax-cart__menu {
    inline-size: 340px;
  }
  .ax-cart__count {
    text-transform: none;
    letter-spacing: 0;
    color: var(--ax-text-muted);
  }
  .ax-cart__list {
    margin: 0;
    padding: 0;
    list-style: none;
  }
  .ax-cart__row {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
    padding: var(--ax-space-2) var(--ax-space-3);
    border-radius: var(--ax-radius-md);
  }
  .ax-cart__row:hover {
    background: var(--ax-fill-hover);
  }
  .ax-cart__thumb {
    flex: 0 0 auto;
    inline-size: 40px;
    block-size: 40px;
    object-fit: cover;
    border-radius: var(--ax-radius-sm);
    border: 1px solid var(--ax-border);
  }
  .ax-cart__meta {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
    flex: 1 1 auto;
  }
  .ax-cart__name {
    font-size: var(--ax-text-sm);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .ax-cart__qty {
    font-size: var(--ax-text-xs);
    color: var(--ax-text-muted);
  }
  .ax-cart__remove {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 28px;
    block-size: 28px;
    color: var(--ax-text-subtle);
    background: transparent;
    border: 0;
    border-radius: var(--ax-radius-sm);
    cursor: pointer;
    transition: color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-cart__remove:hover {
    color: var(--ax-danger-500);
    background: var(--ax-fill-hover);
  }
  .ax-cart__remove .ax-icon {
    inline-size: var(--ax-icon-sm);
    block-size: var(--ax-icon-sm);
  }
  .ax-cart__subtotal {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--ax-space-3);
    margin-block-start: var(--ax-space-1);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
    border-block-start: 1px solid var(--ax-border);
  }
  .ax-cart__actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ax-space-2);
    padding: var(--ax-space-1) var(--ax-space-2) var(--ax-space-2);
  }

  /* ── NOTIFICATIONS panel ── */
  .ax-notif__menu {
    inline-size: 360px;
  }
  .ax-notif__mark-all {
    text-transform: none;
    letter-spacing: 0;
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-link);
    background: transparent;
    border: 0;
    cursor: pointer;
  }
  .ax-notif__mark-all:hover {
    text-decoration: underline;
  }
  .ax-notif__tabs {
    display: inline-flex;
    gap: 2px;
    margin: var(--ax-space-1) var(--ax-space-2) var(--ax-space-2);
    padding: 3px;
    background: var(--ax-surface-subtle);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-pill);
  }
  .ax-notif__tab {
    padding: 4px var(--ax-space-3);
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-muted);
    background: transparent;
    border: 0;
    border-radius: var(--ax-radius-pill);
    cursor: pointer;
    transition:
      background var(--ax-motion-fast) var(--ax-ease-standard),
      color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-notif__tab.is-active {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
  }
  .ax-notif__list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-1);
  }
  .ax-notif__row {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: var(--ax-space-3);
    padding: var(--ax-space-3);
    border-radius: var(--ax-radius-md);
  }
  .ax-notif__row:hover {
    background: var(--ax-fill-hover);
  }
  .ax-notif__row.is-unread {
    background: var(--ax-accent-wash);
  }
  .ax-notif__chip {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 34px;
    block-size: 34px;
    color: var(--ax-text-subtle);
    background: var(--ax-surface-subtle);
    border-radius: var(--ax-radius-pill);
    overflow: hidden;
  }
  .ax-notif__chip .ax-icon {
    inline-size: var(--ax-icon-sm);
    block-size: var(--ax-icon-sm);
  }
  /* the chip IS the 34px circle; a bare .ax-avatar defaults to 36 and had its
     rim shaved off by the chip's overflow clip */
  .ax-notif__chip .ax-avatar {
    --_av-size: 34px;
  }
  .ax-notif__chip--success {
    color: var(--ax-success-500);
    background: var(--ax-success-50);
  }
  .ax-notif__chip--warning {
    color: var(--ax-warning-500);
    background: var(--ax-warning-50);
  }
  .ax-notif__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
    flex: 1 1 auto;
  }
  .ax-notif__title {
    font-size: var(--ax-text-sm);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
  }
  .ax-notif__text {
    font-size: var(--ax-text-xs);
    line-height: var(--ax-leading-xs);
    color: var(--ax-text-muted);
  }
  .ax-notif__time {
    font-size: var(--ax-text-2xs);
    color: var(--ax-text-subtle);
  }
  .ax-notif__dot {
    flex: 0 0 auto;
    align-self: center;
    inline-size: 8px;
    block-size: 8px;
    background: var(--ax-accent);
    border-radius: var(--ax-radius-pill);
  }
  .ax-notif__empty {
    padding: var(--ax-space-5) var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
    text-align: center;
  }
  .ax-notif__live {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  /* ── PROFILE menu ── */
  /* The trigger carries ONLY the avatar — no name, no caret — so it has to be a
     SQUARE box. `padding: 4px var(--ax-space-2) 4px 4px` made it 50×46 around a
     36px circle, so every ring the button paints (hover fill, pill border, the
     global :focus-visible outline) came out as a lozenge sitting 4px off-centre
     from the avatar inside it. Sized to .ax-icon-btn's 38px instead: the rings
     land concentric with the avatar and the utility run keeps one rhythm. */
  .ax-profile__trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    inline-size: 38px;
    block-size: 38px;
    padding: 0;
    color: var(--ax-text);
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--ax-radius-pill);
    cursor: pointer;
    transition:
      background var(--ax-motion-fast) var(--ax-ease-standard),
      border-color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-profile__trigger:hover {
    background: var(--ax-fill-hover);
    border-color: var(--ax-border);
  }
  /* open state, matching the icon-button triggers beside it */
  .ax-profile__trigger[aria-expanded='true'] {
    background: var(--ax-accent-wash);
    border-color: transparent;
  }
  /* 32px — what the markup's width/height attributes always declared — leaving
     the 3px the hover fill needs to read as a ring rather than a smudge. */
  .ax-profile__avatar {
    --_av-size: 32px;
  }
  .ax-profile__menu {
    inline-size: 264px;
  }
  .ax-profile__card {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
    padding: var(--ax-space-3);
    margin-block-end: var(--ax-space-1);
  }
  .ax-profile__card-meta {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-inline-size: 0;
  }
  .ax-profile__card-meta b {
    font-size: var(--ax-text-sm);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
  }
  .ax-profile__card-meta small {
    font-size: var(--ax-text-xs);
    color: var(--ax-text-muted);
  }
  /* the card portrait is a size up from the trigger's — and its markup already
     asks for 40, which the .ax-avatar default (36) was quietly overriding */
  .ax-profile__card .ax-avatar {
    --_av-size: 40px;
  }

  /* ── OVERFLOW (mobile shed) — same panel system ── */
  .ax-overflow__menu {
    min-inline-size: 200px;
  }

  /* ════════════════════════════════════════════════════════════════════════
     4 · THEME CUSTOMIZER DRAWER  .ax-customizer
     HOOK: Alpine `x-show="open"` toggles display; the panel ELEMENT is the
     360px drawer (glass), its `.ax-customizer__backdrop` child is a fixed
     full-viewport scrim (z-index:-1) that dims the page. NOTE: a negative-z child
     paints ABOVE its own parent's background, so head/body/foot each carry their
     own `--ax-surface-overlay` fill to stay opaque over the scrim. RESTING =
     translateX(100%) off the inline end; the x-transition classes slide it in/out.
     ════════════════════════════════════════════════════════════════════════ */
  .ax-customizer {
    position: fixed;
    inset-block: 0;
    inset-inline-end: 0;
    z-index: var(--ax-z-customizer);
    display: flex;
    flex-direction: column;
    inline-size: 360px;
    max-inline-size: 100vw;
    color: var(--ax-text);
    background: var(--ax-surface-overlay);
    border-start-start-radius: var(--ax-radius-xl);
    border-end-start-radius: var(--ax-radius-xl);
    border-inline-start: 1px solid var(--ax-border);
    box-shadow: var(--ax-shadow-lg);
    -webkit-backdrop-filter: blur(22px) saturate(1.1);
    backdrop-filter: blur(22px) saturate(1.1);
    transform: translateX(0); /* shown state (x-show controls display) */
  }
  [dir='rtl'] .ax-customizer {
    transform: translateX(0);
  }

  /* fixed full-viewport scrim — painted behind the panel via negative z-index */
  .ax-customizer__backdrop {
    position: fixed;
    inset: 0;
    z-index: -1;
    inline-size: 100vw;
    block-size: 100vh;
    padding: 0;
    background: var(--ax-backdrop);
    border: 0;
    cursor: pointer;
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
  }

  /* Alpine x-transition classes (slide + fade). Enter: start off-canvas →
     rest; Leave: rest → off-canvas. These classes are present for the whole
     transition; we drive the motion through `transition` + the start/rest
     transforms Alpine snapshots. */
  .ax-customizer--enter,
  .ax-customizer--leave {
    transition:
      transform var(--ax-motion-slow) var(--ax-ease-emphasized),
      opacity var(--ax-motion-base) var(--ax-ease-standard);
  }
  .ax-customizer--leave {
    transform: translateX(100%);
    opacity: 0;
  }
  [dir='rtl'] .ax-customizer--leave {
    transform: translateX(-100%);
  }

  /* sticky head */
  .ax-customizer__head {
    position: sticky;
    inset-block-start: 0;
    z-index: 1;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--ax-space-3);
    flex: 0 0 auto;
    padding: var(--ax-space-5);
    background: var(--ax-surface-overlay);
    border-block-end: 1px solid var(--ax-border);
  }
  .ax-customizer__head-text {
    min-inline-size: 0;
  }
  .ax-customizer__title {
    font-family: var(--ax-font-display);
    font-size: var(--ax-text-lg);
    font-weight: var(--ax-weight-bold);
    color: var(--ax-text-strong);
  }
  .ax-customizer__sub {
    margin-block-start: 2px;
    font-size: var(--ax-text-xs);
    color: var(--ax-text-muted);
  }

  /* scrolling body — needs its own opaque surface: the `.ax-customizer__backdrop`
     scrim is a z-index:-1 child, and a negative-z child paints ABOVE its parent's
     own background (it cannot sit behind the parent box). __head/__foot escape via
     their own bg + positioned layer; the body must match them or the dark scrim
     bleeds through the whole scroll region (the grey slab in light mode). */
  .ax-customizer__body {
    flex: 1 1 auto;
    min-block-size: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--ax-space-5);
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-6);
    background: var(--ax-surface-overlay);
  }
  .ax-customizer__section {
    display: flex;
    flex-direction: column;
    gap: var(--ax-space-3);
  }
  .ax-customizer__section.is-disabled {
    opacity: 0.55;
    pointer-events: none;
  }
  .ax-customizer__label {
    margin-block-start: var(--ax-space-1);
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-muted);
  }

  /* sticky foot */
  .ax-customizer__foot {
    position: sticky;
    inset-block-end: 0;
    z-index: 1;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--ax-space-2);
    flex: 0 0 auto;
    padding: var(--ax-space-4) var(--ax-space-5);
    background: var(--ax-surface-overlay);
    border-block-start: 1px solid var(--ax-border);
  }
  .ax-customizer__live {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  /* ════════════════════════════════════════════════════════════════════════
     5 · SEGMENTED CONTROL  .ax-segmented / __btn  (hairline pill row)
     ════════════════════════════════════════════════════════════════════════ */
  .ax-segmented {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 2px;
    padding: 3px;
    background: var(--ax-surface-subtle);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
  }
  .ax-segmented__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ax-space-1);
    padding: var(--ax-space-2) var(--ax-space-2);
    font-size: var(--ax-text-xs);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-muted);
    background: transparent;
    border: 0;
    border-radius: var(--ax-radius-sm);
    cursor: pointer;
    transition:
      background var(--ax-motion-fast) var(--ax-ease-standard),
      color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-segmented__btn .ax-icon {
    inline-size: var(--ax-icon-sm);
    block-size: var(--ax-icon-sm);
  }
  .ax-segmented__btn:hover {
    color: var(--ax-text-strong);
    background: var(--ax-fill-hover);
  }
  .ax-segmented__btn.is-active {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
    box-shadow: inset 0 0 0 1px var(--ax-accent);
  }

  /* ════════════════════════════════════════════════════════════════════════
     5b · FONT PICKER  .ax-font-active / .ax-font-search / .ax-font-results
     A read-out of the family in use, over a search field that reaches every
     Google family — there is no shortlist to style. The read-out and every
     result row carry an INLINE font-family so each prints its own name in its
     own typeface; those faces arrive one batched request per result set
     (core/fonts.js → ensureSearchPreviews), so a row may specimen in the
     fallback for a beat before its own face lands — expected, not a bug.
     Lettered to keep the existing section numbering stable (cf. 12b below).
     ════════════════════════════════════════════════════════════════════════ */
  .ax-font-active {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ax-space-2);
    padding: var(--ax-space-2) var(--ax-space-3);
    background: var(--ax-surface-subtle);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
    transition:
      color var(--ax-motion-fast) var(--ax-ease-standard),
      background var(--ax-motion-fast) var(--ax-ease-standard),
      border-color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  /* anything other than the shipped default reads as an active choice */
  .ax-font-active.is-custom {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
    border-color: var(--ax-accent);
  }
  .ax-font-active__text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-inline-size: 0;
  }
  .ax-font-active__label {
    font-family: var(--ax-font-sans); /* the label is chrome, not a specimen */
    font-size: 10px;
    font-weight: var(--ax-weight-medium);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ax-text-subtle);
  }
  .ax-font-active.is-custom .ax-font-active__label {
    color: inherit;
    opacity: 0.75;
  }
  /* the name is the specimen — never wrap a long family onto a second line */
  .ax-font-active__name {
    min-inline-size: 0;
    overflow: hidden;
    font-size: var(--ax-text-md);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-strong);
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  .ax-font-active.is-custom .ax-font-active__name {
    color: inherit;
  }
  .ax-font-active__clear {
    flex: 0 0 auto;
    font-size: var(--ax-text-xs);
    color: inherit;
    background: transparent;
    border: 0;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 2px;
  }

  /* ── Google Fonts search: input + result list ──
     Searches a bundled catalog snapshot offline (js/data/google-fonts.js), so
     no API key is involved and a query costs nothing over the wire. */
  .ax-font-search {
    position: relative;
    margin-block-start: var(--ax-space-3);
  }
  .ax-font-search__icon {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: var(--ax-space-3);
    transform: translateY(-50%);
    inline-size: var(--ax-icon-sm);
    block-size: var(--ax-icon-sm);
    color: var(--ax-text-subtle);
    pointer-events: none;
  }
  .ax-font-search__input {
    inline-size: 100%;
    padding-block: var(--ax-space-2);
    padding-inline-start: calc(var(--ax-space-3) + var(--ax-icon-sm) + var(--ax-space-2));
    padding-inline-end: calc(var(--ax-space-3) + 22px);
    font-size: var(--ax-text-sm);
    color: var(--ax-text-strong);
    background: var(--ax-surface-subtle);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
  }
  .ax-font-search__input::placeholder {
    color: var(--ax-text-subtle);
  }
  .ax-font-search__input:focus-visible {
    outline: none;
    border-color: var(--ax-accent);
  }
  /* the UA's own clear affordance would sit on top of ours */
  .ax-font-search__input::-webkit-search-cancel-button {
    appearance: none;
  }
  .ax-font-search__clear {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-end: var(--ax-space-2);
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 22px;
    block-size: 22px;
    color: var(--ax-text-subtle);
    background: transparent;
    border: 0;
    border-radius: var(--ax-radius-pill);
    cursor: pointer;
  }
  .ax-font-search__clear:hover {
    color: var(--ax-text-strong);
    background: var(--ax-fill-hover);
  }
  .ax-font-search__clear .ax-icon {
    inline-size: 14px;
    block-size: 14px;
  }

  .ax-font-results {
    max-block-size: 232px;
    margin-block-start: var(--ax-space-2);
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--ax-surface-subtle);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
  }
  .ax-font-result {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--ax-space-2);
    inline-size: 100%;
    padding: var(--ax-space-2) var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text);
    text-align: start;
    background: transparent;
    border: 0;
    cursor: pointer;
    transition:
      background var(--ax-motion-fast) var(--ax-ease-standard),
      color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-font-result:hover,
  .ax-font-result:focus-visible {
    outline: none;
    color: var(--ax-text-strong);
    background: var(--ax-fill-hover);
  }
  .ax-font-result.is-active {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
  }
  /* the name is the specimen — never wrap a long family onto a second line */
  .ax-font-result__name {
    min-inline-size: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  .ax-font-result__cat {
    flex: 0 0 auto;
    font-family: var(--ax-font-sans); /* chrome, not a specimen */
    font-size: 10px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ax-text-subtle);
  }
  .ax-font-results__msg {
    padding: var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
  }

  /* ════════════════════════════════════════════════════════════════════════
     6 · ACCENT SWATCH GRID  .ax-swatch-grid / .ax-swatch (--sw per swatch)
     Each swatch's fill comes from its inline `style="--sw:#hex"`.
     ════════════════════════════════════════════════════════════════════════ */
  .ax-swatch-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: var(--ax-space-3);
  }
  .ax-swatch {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    inline-size: 100%;
    color: #fff;
    background: var(--sw, var(--ax-accent));
    border: 0;
    border-radius: var(--ax-radius-pill);
    cursor: pointer;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.08);
    transition:
      transform var(--ax-motion-fast) var(--ax-ease-standard),
      box-shadow var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-swatch:hover {
    transform: scale(1.08);
  }
  .ax-swatch.is-active {
    box-shadow:
      0 0 0 2px var(--ax-surface-overlay),
      0 0 0 4px var(--ax-accent);
  }
  .ax-swatch__check {
    inline-size: var(--ax-icon-sm);
    block-size: var(--ax-icon-sm);
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.35));
  }

  /* recent-colour swatches + bg tint dots (smaller round chips) */
  .ax-recent-swatches,
  .ax-tint-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ax-space-2);
  }
  .ax-recent-swatch,
  .ax-tint {
    inline-size: 26px;
    block-size: 26px;
    background: var(--sw, var(--ax-surface));
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-pill);
    cursor: pointer;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.06);
    transition: transform var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-recent-swatch:hover,
  .ax-tint:hover {
    transform: scale(1.1);
  }

  /* ════════════════════════════════════════════════════════════════════════
     7 · CUSTOM COLOUR FIELDS  .ax-color-field / __label / __controls
     .ax-color-input (native picker) / .ax-hex (text)
     ════════════════════════════════════════════════════════════════════════ */
  .ax-color-field {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ax-space-3);
  }
  .ax-color-field__label {
    font-size: var(--ax-text-sm);
    color: var(--ax-text);
  }
  .ax-color-field__controls {
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-2);
  }
  .ax-color-input {
    inline-size: 34px;
    block-size: 34px;
    padding: 0;
    background: transparent;
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-sm);
    cursor: pointer;
  }
  .ax-color-input::-webkit-color-swatch-wrapper {
    padding: 3px;
  }
  .ax-color-input::-webkit-color-swatch {
    border: 0;
    border-radius: calc(var(--ax-radius-sm) - 4px);
  }
  .ax-color-input::-moz-color-swatch {
    border: 0;
    border-radius: calc(var(--ax-radius-sm) - 4px);
  }
  .ax-hex {
    inline-size: 96px;
    padding: var(--ax-space-2) var(--ax-space-3);
    font-family: var(--ax-font-mono);
    font-size: var(--ax-text-xs);
    color: var(--ax-text-strong);
    background: var(--ax-surface-subtle);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-sm);
  }
  .ax-hex:focus-visible {
    outline: none;
    border-color: var(--ax-accent);
  }

  /* ════════════════════════════════════════════════════════════════════════
     8 · SIDEBAR/HEADER SCHEME MINI-PREVIEWS  .ax-scheme-row / .ax-scheme--*
     Small tiles showing the chrome colour; active = accent ring + check.
     ════════════════════════════════════════════════════════════════════════ */
  .ax-scheme-row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ax-space-2);
  }
  .ax-scheme {
    position: relative;
    inline-size: 44px;
    block-size: 32px;
    background: var(--ax-surface-solid);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-sm);
    cursor: pointer;
    overflow: hidden;
    transition: box-shadow var(--ax-motion-fast) var(--ax-ease-standard);
  }
  /* a left "rail" stripe to read as chrome */
  .ax-scheme::before {
    content: '';
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    inline-size: 14px;
  }
  .ax-scheme.is-active {
    box-shadow:
      0 0 0 1px var(--ax-accent),
      0 0 0 3px var(--ax-accent-wash);
    border-color: var(--ax-accent);
  }
  .ax-scheme.is-active::after {
    content: '';
    position: absolute;
    inset-block-start: 3px;
    inset-inline-end: 3px;
    inline-size: 6px;
    block-size: 6px;
    background: var(--ax-accent);
    border-radius: var(--ax-radius-pill);
  }
  .ax-scheme--light {
    background: #eef1f6;
  }
  .ax-scheme--light::before {
    background: #ffffff;
    box-shadow: inset -1px 0 0 rgba(16, 22, 40, 0.14);
  }
  .ax-scheme--dark {
    background: #2a2f3a;
  }
  .ax-scheme--dark::before {
    background: #141821;
  }
  .ax-scheme--brand::before {
    background: var(--ax-accent);
  }
  .ax-scheme--brand {
    background: var(--ax-accent-wash);
  }
  /* light: --ax-accent-wash (accent-50) is near-white and reads edgeless on the
     light panel — give the brand body a clearer accent tint (dark already reads). */
  [data-ax-theme='light'] .ax-scheme--brand {
    background: color-mix(in srgb, var(--ax-accent) 12%, #fff);
  }
  .ax-scheme--gradient::before {
    background: var(--ax-gradient-accent);
  }
  .ax-scheme--gradient {
    background: var(--ax-accent-wash);
  }
  .ax-scheme--transparent {
    background:
      repeating-conic-gradient(var(--ax-surface-subtle) 0% 25%, var(--ax-surface) 0% 50%)
      0 / 12px 12px;
  }
  .ax-scheme--transparent::before {
    background: rgba(var(--ax-accent-rgb), 0.12);
  }

  /* ════════════════════════════════════════════════════════════════════════
     9 · SIDEBAR-STYLE DIAGRAMS  .ax-style-list / .ax-style / __diagram--*
     Tiny schematic of each sidebar layout (rail + content blocks).
     ════════════════════════════════════════════════════════════════════════ */
  .ax-style-list {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ax-space-2);
  }
  /* Docked / Detached are the only two styles now — give them equal halves. */
  .ax-style-list--pair {
    grid-template-columns: repeat(2, 1fr);
  }
  .ax-style {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--ax-space-2);
    padding: var(--ax-space-2);
    background: transparent;
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
    cursor: pointer;
    transition:
      border-color var(--ax-motion-fast) var(--ax-ease-standard),
      background var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-style:hover {
    background: var(--ax-fill-hover);
  }
  .ax-style.is-active {
    border-color: var(--ax-accent);
    background: var(--ax-accent-wash);
  }
  .ax-style__label {
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-medium);
    color: var(--ax-text-muted);
  }
  .ax-style.is-active .ax-style__label {
    color: var(--ax-accent);
  }
  .ax-style__diagram {
    position: relative;
    inline-size: 100%;
    aspect-ratio: 16 / 11;
    background: var(--ax-surface-solid);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-xs);
    overflow: hidden;
  }
  /* default: full rail */
  .ax-style__diagram::before {
    content: '';
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    inline-size: 32%;
    background: var(--ax-accent);
    opacity: 0.85;
  }
  .ax-style__diagram--compact::before {
    inline-size: 16%;
  }
  .ax-style__diagram--icon-text::before {
    inline-size: 22%;
  }
  .ax-style__diagram--icon-overlay::before {
    inline-size: 14%;
  }
  .ax-style__diagram--detached::before {
    inset-block: 12%;
    inset-inline-start: 8%;
    inline-size: 26%;
    border-radius: 3px;
  }
  /* double: thin icon rail + secondary panel */
  .ax-style__diagram--double::before {
    inline-size: 14%;
  }
  .ax-style__diagram--double::after {
    content: '';
    position: absolute;
    inset-block: 0;
    inset-inline-start: 14%;
    inline-size: 20%;
    background: var(--ax-accent);
    opacity: 0.4;
  }

  /* ════════════════════════════════════════════════════════════════════════
     10 · SIDEBAR BACKGROUND-IMAGE THUMBS  .ax-thumb-strip / .ax-thumb(--none)
     ════════════════════════════════════════════════════════════════════════ */
  .ax-thumb-strip {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: var(--ax-space-2);
  }
  .ax-thumb {
    aspect-ratio: 1;
    background: var(--ax-accent-wash);
    background-size: cover;
    background-position: center;
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-xs);
    cursor: pointer;
    transition: box-shadow var(--ax-motion-fast) var(--ax-ease-standard);
  }
  /* per-texture previews — mirror the real sidebar gradients (schemes.css §6)
     keyed on the thumb's own data-ax-value, layered over the accent-wash base. */
  .ax-thumb[data-ax-value='texture-1'] {
    background-image: radial-gradient(circle at 1px 1px, var(--ax-border-strong) 1px, transparent 0);
    background-size: 6px 6px;
  }
  .ax-thumb[data-ax-value='texture-2'] {
    background-image: repeating-linear-gradient(45deg, var(--ax-fill-hover) 0 4px, transparent 4px 8px);
  }
  .ax-thumb[data-ax-value='texture-3'] {
    background-image: linear-gradient(160deg, var(--ax-accent-wash), transparent 60%);
  }
  .ax-thumb[data-ax-value='texture-4'] {
    background-image: repeating-linear-gradient(90deg, var(--ax-fill-hover) 0 1px, transparent 1px 7px);
  }
  .ax-thumb[data-ax-value='texture-5'] {
    background-image: radial-gradient(circle at 80% 0, var(--ax-accent-wash), transparent 55%);
  }
  .ax-thumb[data-ax-value='texture-6'] {
    background-image: conic-gradient(from 180deg at 50% 0, var(--ax-fill-hover), transparent 40%);
  }
  .ax-thumb--none {
    background:
      linear-gradient(
        to top left,
        transparent calc(50% - 1px),
        var(--ax-danger-500),
        transparent calc(50% + 1px)
      ),
      var(--ax-surface-subtle);
  }
  .ax-thumb.is-active {
    box-shadow:
      0 0 0 1px var(--ax-accent),
      0 0 0 3px var(--ax-accent-wash);
    border-color: var(--ax-accent);
  }
  .ax-thumb-strip[aria-disabled='true'] {
    opacity: 0.5;
    pointer-events: none;
  }

  /* ════════════════════════════════════════════════════════════════════════
     11 · TOGGLE SWITCH  .ax-toggle / __label / __input / __track / __thumb
     ════════════════════════════════════════════════════════════════════════ */
  .ax-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--ax-space-3);
    cursor: pointer;
  }
  .ax-toggle__label {
    font-size: var(--ax-text-sm);
    color: var(--ax-text);
  }
  .ax-toggle__input {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }
  .ax-toggle__track {
    position: relative;
    flex: 0 0 auto;
    inline-size: 40px;
    block-size: 22px;
    background: var(--ax-border-strong);
    border-radius: var(--ax-radius-pill);
    transition: background var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-toggle__thumb {
    position: absolute;
    inset-block-start: 2px;
    inset-inline-start: 2px;
    inline-size: 18px;
    block-size: 18px;
    background: #fff;
    border-radius: var(--ax-radius-pill);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
    transition: transform var(--ax-motion-fast) var(--ax-ease-emphasized);
  }
  .ax-toggle__input:checked + .ax-toggle__track {
    background: var(--ax-accent);
  }
  .ax-toggle__input:checked + .ax-toggle__track .ax-toggle__thumb {
    transform: translateX(18px);
  }
  [dir='rtl'] .ax-toggle__input:checked + .ax-toggle__track .ax-toggle__thumb {
    transform: translateX(-18px);
  }
  .ax-toggle__input:focus-visible + .ax-toggle__track {
    outline: 2px solid var(--ax-focus-ring);
    outline-offset: 2px;
  }

  /* ════════════════════════════════════════════════════════════════════════
     12 · HELPER NOTE  .ax-note (+ --warn)
     ════════════════════════════════════════════════════════════════════════ */
  .ax-note {
    font-size: var(--ax-text-xs);
    line-height: var(--ax-leading-xs);
    color: var(--ax-text-subtle);
  }
  .ax-note--warn {
    padding: var(--ax-space-2) var(--ax-space-3);
    color: var(--ax-warning-500);
    background: var(--ax-warning-50);
    border-radius: var(--ax-radius-sm);
  }

  /* ════════════════════════════════════════════════════════════════════════
     12b · LIGHT-MODE TILE DEFINITION
     The customizer preview tiles (scheme/style/thumb/tint/swatch chips) use
     white / near-white fills. On the dark panel they pop; on the near-white
     LIGHT panel the default 8% hairline (--ax-border) leaves them edgeless and
     they read as floating shapes. Promote their resting stroke to the stronger
     14% hairline in LIGHT only — dark already reads, and active states (handled
     above with their own accent border/ring) are excluded so they keep it.
     ════════════════════════════════════════════════════════════════════════ */
  [data-ax-theme='light'] :is(
      .ax-scheme,
      .ax-style,
      .ax-style__diagram,
      .ax-thumb,
      .ax-tint,
      .ax-recent-swatch,
      .ax-color-input
    ):not(.is-active) {
    border-color: var(--ax-border-strong);
  }

  /* ════════════════════════════════════════════════════════════════════════
     13 · COMMAND PALETTE  #ax-command / .ax-command__*
     HOOK: command-palette.js toggles `.is-open` + the `hidden` attr on the
     #ax-command root (partials/command.html, included at body level next to the
     customizer). Rows/groups/empty are emitted by the module into
     .ax-command__results; the JS bails gracefully when the root is absent.
     ════════════════════════════════════════════════════════════════════════ */
  .ax-command {
    position: fixed;
    inset: 0;
    z-index: var(--ax-z-command);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-block-start: 12vh;
    padding-inline: var(--ax-space-4);
  }
  .ax-command[hidden] {
    display: none;
  }
  .ax-command__backdrop {
    position: fixed;
    inset: 0;
    background: var(--ax-backdrop);
    border: 0;
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
  }
  .ax-command__panel {
    position: relative;
    inline-size: min(640px, 100%);
    max-block-size: 70vh;
    display: flex;
    flex-direction: column;
    color: var(--ax-text);
    background: var(--ax-surface-overlay);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-xl);
    box-shadow: var(--ax-shadow-lg);
    -webkit-backdrop-filter: blur(22px) saturate(1.1);
    backdrop-filter: blur(22px) saturate(1.1);
    overflow: hidden;
  }
  .ax-command__input {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
    padding: var(--ax-space-4) var(--ax-space-5);
    border-block-end: 1px solid var(--ax-border);
  }
  .ax-command__input .ax-icon {
    flex: 0 0 auto;
    inline-size: var(--ax-icon-md);
    block-size: var(--ax-icon-md);
    color: var(--ax-text-subtle);
  }
  .ax-command__input input {
    flex: 1 1 auto;
    min-inline-size: 0;
    font-size: var(--ax-text-base);
    color: var(--ax-text-strong);
    background: transparent;
    border: 0;
    outline: none;
  }
  .ax-command__results {
    flex: 1 1 auto;
    min-block-size: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--ax-space-2);
  }
  .ax-command__group {
    padding: var(--ax-space-3) var(--ax-space-3) var(--ax-space-1);
    font-size: var(--ax-text-2xs);
    font-weight: var(--ax-weight-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ax-text-subtle);
  }
  .ax-command__row {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
    inline-size: 100%;
    padding: var(--ax-space-2) var(--ax-space-3);
    color: var(--ax-text);
    text-align: start;
    background: transparent;
    border: 0;
    border-radius: var(--ax-radius-md);
    cursor: pointer;
  }
  .ax-command__row.is-active {
    background: var(--ax-accent-wash);
    color: var(--ax-accent);
  }
  .ax-command__row-title {
    flex: 1 1 auto;
    font-size: var(--ax-text-sm);
    font-weight: var(--ax-weight-medium);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .ax-command__crumb {
    flex: 0 0 auto;
    font-size: var(--ax-text-2xs);
    color: var(--ax-text-subtle);
  }
  .ax-command__row.is-active .ax-command__crumb {
    color: inherit;
  }
  .ax-command__empty {
    padding: var(--ax-space-6) var(--ax-space-4);
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
    text-align: center;
  }
  /* keycaps — the esc affordance in the query row and the foot's hint keys */
  .ax-command__keycap {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-inline-size: 20px;
    block-size: 20px;
    padding-inline: var(--ax-space-1);
    font-family: var(--ax-font-mono);
    font-size: var(--ax-text-2xs);
    line-height: 1;
    color: var(--ax-text-subtle);
    background: var(--ax-surface);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-xs);
  }
  /* the × is the touch equivalent of the esc keycap — only one shows at a time
     (swapped at the phone breakpoint below) */
  .ax-command__close {
    display: none;
    margin-inline-end: calc(var(--ax-space-2) * -1);
  }
  .ax-command__foot {
    display: flex;
    align-items: center;
    gap: var(--ax-space-4);
    padding: var(--ax-space-2) var(--ax-space-5);
    border-block-start: 1px solid var(--ax-border);
  }
  .ax-command__hint {
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-1);
    font-size: var(--ax-text-2xs);
    color: var(--ax-text-subtle);
  }
  /* entrance — the module only swaps `hidden`/.is-open, so the animation has to
     ride the class. Globally neutered under prefers-reduced-motion. */
  .ax-command.is-open .ax-command__panel {
    animation: ax-command-rise var(--ax-motion-base) var(--ax-ease-emphasized) both;
  }
  @keyframes ax-command-rise {
    from {
      opacity: 0;
      transform: translateY(-8px) scale(0.99);
    }
    to {
      opacity: 1;
      transform: none;
    }
  }

  /* ── phones: the palette is the ONLY search surface here (the header pill is
     an icon button at this width), so it gets more of the viewport, a tap
     target in place of the esc keycap, and a 16px field — anything smaller and
     iOS Safari zooms the whole page in on focus. `dvh` keeps it inside the
     visual viewport once the on-screen keyboard is up; browsers without it fall
     through to the 70vh above. ── */
  @media (max-width: 767.98px) {
    .ax-command {
      padding-block-start: 8vh;
      padding-inline: var(--ax-space-3);
    }
    .ax-command__panel {
      max-block-size: 76dvh;
    }
    .ax-command__input {
      padding: var(--ax-space-3) var(--ax-space-4);
    }
    .ax-command__input input {
      font-size: 16px;
    }
    .ax-command__keycap--esc,
    .ax-command__foot {
      display: none;
    }
    .ax-command__close {
      display: inline-flex;
    }
  }

  /* ════════════════════════════════════════════════════════════════════════
     14 · SIDEBAR CONTENT GAPS (containers are laid out in base.css; these are
     the unstyled inner pieces: filter input/icon/clear, brand mark, nav-empty,
     promo copy + CTA, mini user card + logout).
     ════════════════════════════════════════════════════════════════════════ */
  .ax-sidebar__mark {
    display: inline-flex;
    color: var(--ax-accent);
  }
  .ax-sidebar__mark .ax-icon {
    inline-size: 24px;
    block-size: 24px;
  }
  .ax-sidebar__search {
    position: relative;
  }
  .ax-sidebar__search-icon {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: calc(var(--ax-space-4) + var(--ax-space-3));
    transform: translateY(-50%);
    inline-size: var(--ax-icon-sm);
    block-size: var(--ax-icon-sm);
    color: var(--ax-text-subtle);
    pointer-events: none;
  }
  .ax-sidebar__filter {
    inline-size: 100%;
    padding-block: var(--ax-space-2);
    padding-inline-start: calc(var(--ax-space-3) + var(--ax-icon-sm) + var(--ax-space-2));
    padding-inline-end: var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text-strong);
    background: var(--ax-surface-subtle);
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
  }
  .ax-sidebar__filter::placeholder {
    color: var(--ax-text-subtle);
  }
  .ax-sidebar__filter:focus-visible {
    outline: none;
    border-color: var(--ax-accent);
  }
  .ax-sidebar__filter-clear {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-end: calc(var(--ax-space-4) + 6px);
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 22px;
    block-size: 22px;
    color: var(--ax-text-subtle);
    background: transparent;
    border: 0;
    border-radius: var(--ax-radius-pill);
    cursor: pointer;
  }
  .ax-sidebar__filter-clear:hover {
    color: var(--ax-text-strong);
    background: var(--ax-fill-hover);
  }
  .ax-sidebar__filter-clear .ax-icon {
    inline-size: 14px;
    block-size: 14px;
  }
  .ax-sidebar__nav-empty {
    padding: var(--ax-space-5) var(--ax-space-3);
    font-size: var(--ax-text-sm);
    color: var(--ax-text-muted);
    text-align: center;
  }

  /* mini user card */
  .ax-sidebar__user {
    display: flex;
    align-items: center;
    gap: var(--ax-space-3);
  }
  .ax-sidebar__user-avatar {
    flex: 0 0 auto;
  }
  .ax-sidebar__user-meta {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-inline-size: 0;
    flex: 1 1 auto;
  }
  .ax-sidebar__user-name {
    font-size: var(--ax-text-sm);
    font-weight: var(--ax-weight-semibold);
    color: var(--ax-text-strong);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .ax-sidebar__user-mail {
    font-size: var(--ax-text-xs);
    color: var(--ax-text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .ax-sidebar__logout {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    inline-size: 32px;
    block-size: 32px;
    color: var(--ax-text-subtle);
    background: transparent;
    border-radius: var(--ax-radius-md);
    text-decoration: none;
    transition:
      color var(--ax-motion-fast) var(--ax-ease-standard),
      background var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-sidebar__logout:hover {
    color: var(--ax-danger-500);
    background: var(--ax-fill-hover);
  }
  .ax-sidebar__logout .ax-icon {
    inline-size: var(--ax-icon-md);
    block-size: var(--ax-icon-md);
  }

  /* ════════════════════════════════════════════════════════════════════════
     15 · FOOTER  .ax-footer__* link row (base.css lays out .ax-footer/.ax-footer__links)
     ════════════════════════════════════════════════════════════════════════ */
  .ax-footer__left {
    display: inline-flex;
    align-items: center;
    gap: var(--ax-space-2);
    font-size: var(--ax-text-xs);
    color: var(--ax-text-muted);
  }
  .ax-footer__sep {
    color: var(--ax-text-disabled);
  }
  .ax-footer__version {
    font-size: var(--ax-text-xs);
    color: var(--ax-text-subtle);
  }
  .ax-footer__link {
    font-size: var(--ax-text-xs);
    color: var(--ax-text-muted);
    text-decoration: none;
    transition: color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-footer__link:hover {
    color: var(--ax-accent);
  }

  /* ════════════════════════════════════════════════════════════════════════
     16 · MISSING BUTTON MODIFIERS used by chrome (cart / promo / customizer foot)
     base.css/components.css define .ax-btn + --ghost/--primary/--sm; these two
     are referenced by partials but had no rule.
     ════════════════════════════════════════════════════════════════════════ */
  .ax-btn--accent {
    color: var(--ax-on-accent);
    background: var(--ax-gradient-accent);
    border-color: transparent;
    box-shadow: var(--ax-glow-accent);
  }
  .ax-btn--accent:hover {
    background: var(--ax-accent-hover);
  }
  .ax-btn--ghost-danger {
    color: var(--ax-danger-500);
    background: transparent;
    border-color: transparent;
  }
  .ax-btn--ghost-danger:hover {
    background: color-mix(in oklab, var(--ax-danger-500) 12%, transparent);
    color: var(--ax-danger-500);
  }

  /* ════════════════════════════════════════════════════════════════════════
     17 · REDUCED MOTION — instant for the drawer/scrim/transitions
     ════════════════════════════════════════════════════════════════════════ */
  @media (prefers-reduced-motion: reduce) {
    .ax-customizer,
    .ax-customizer--enter,
    .ax-customizer--leave,
    .ax-toggle__thumb,
    .ax-swatch,
    .ax-apps__tile,
    .ax-segmented__btn {
      transition-duration: 1ms !important;
    }
  }

  /* ════════════════════════════════════════════════════════════════════════
     18 · RESPONSIVE HEADER — the utility SHED (02-shell §4.12)
     The cluster is eleven controls wide. Left alone on a phone it is ~525px of
     content in a 390px bar: the profile, the cog and the "More" trigger itself
     all fall off the inline end, and the ⌘K pill gets squeezed to a 26px stub.
     Each band therefore hides its controls in the bar and reveals the matching
     `[data-ax-shed]` row inside the overflow menu (partials/header-utils.html),
     so every control keeps exactly ONE reachable copy.

     BANDS — keep in lockstep with _bindBands() in js/alpine/index.js, which
     fills $store.ax.overflow and is what makes the "More" trigger appear:
       < 992px (lg) … language · fullscreen · app-grid
       < 768px (md) … + cart · customizer
     Leaving on a phone: menu · search · theme · notifications · profile · More.
     ════════════════════════════════════════════════════════════════════════ */

  /* Shed rows are opt-in — hidden until their band sheds the header copy. */
  .ax-overflow__menu [data-ax-shed] {
    display: none;
  }

  /* ── shed rows: chrome shared by both bands ── */
  .ax-overflow__group {
    padding-block-end: var(--ax-space-1);
  }
  /* hairline between adjacent shed blocks (a hidden row draws nothing, so the
     rule stays correct in both bands without per-band exceptions) */
  .ax-overflow__menu [data-ax-shed] + [data-ax-shed] {
    border-block-start: 1px solid var(--ax-border);
    margin-block-start: var(--ax-space-1);
    padding-block-start: var(--ax-space-1);
  }
  .ax-overflow__langs {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: var(--ax-space-1);
    padding-inline: var(--ax-space-1);
  }
  .ax-overflow__lang {
    padding-block: var(--ax-space-2);
    color: var(--ax-text-muted);
    background: transparent;
    border: 1px solid var(--ax-border);
    border-radius: var(--ax-radius-md);
    cursor: pointer;
    transition:
      background var(--ax-motion-fast) var(--ax-ease-standard),
      color var(--ax-motion-fast) var(--ax-ease-standard),
      border-color var(--ax-motion-fast) var(--ax-ease-standard);
  }
  .ax-overflow__lang:hover,
  .ax-overflow__lang:focus-visible {
    color: var(--ax-text-strong);
    background: var(--ax-fill-hover);
    outline: none;
  }
  .ax-overflow__lang.is-active {
    color: var(--ax-accent);
    background: var(--ax-accent-wash);
    border-color: transparent;
  }
  /* trailing count on the cart row — pushed to the inline end */
  .ax-overflow__count {
    margin-inline-start: auto;
    font-size: var(--ax-text-xs);
    color: var(--ax-text-subtle);
  }

  /* ── < lg: language · fullscreen · app-grid move into "More" ── */
  @media (max-width: 991.98px) {
    .ax-lang,
    .ax-fullscreen,
    .ax-apps {
      display: none;
    }
    .ax-overflow__menu [data-ax-shed='lang'],
    .ax-overflow__menu [data-ax-shed='apps'] {
      display: block;
    }
    .ax-overflow__menu [data-ax-shed='fullscreen'] {
      display: flex;
    }
  }

  /* ── < md: cart + customizer follow; the ⌘K pill becomes an icon button ── */
  @media (max-width: 767.98px) {
    .ax-cart,
    .ax-cog {
      display: none;
    }
    .ax-overflow__menu [data-ax-shed='cart'],
    .ax-overflow__menu [data-ax-shed='customizer'] {
      display: flex;
    }

    /* tighter gutter + gap so six controls sit comfortably at 360px */
    .ax-header {
      padding-inline: var(--ax-space-3);
      gap: var(--ax-space-1);
    }

    /* The pill has no room for its label or keycap here, and `min-inline-size:0`
       let flex crush it to a stub. Lock it to the icon-button box instead — the
       palette still opens on tap, and on ⌘K where there is a keyboard. */
    .ax-search {
      inline-size: 38px;
      min-inline-size: 38px;
      max-inline-size: 38px;
      padding-inline: 0;
      justify-content: center;
      border-radius: var(--ax-radius-md);
    }
    .ax-search__placeholder,
    .ax-search__keycap {
      display: none;
    }
    .ax-search__icon {
      inline-size: var(--ax-icon-md);
      block-size: var(--ax-icon-md);
    }

    /* ── panels pin to the BAR, not to their trigger ──
       Every panel anchors `inset-inline-end:0` to its own cluster wrapper, which
       only stays on-screen while the trigger is the last control in the run. It
       is not: notifications still has the avatar and "More" to its inline end,
       so a 360px panel hung off it started ~60px past the leading edge of a
       390px screen and the heading was clipped mid-word.

       Taking the wrappers out of the positioning chain re-points the panels at
       the nearest positioned ancestor — the fixed `.ax-header` / relative
       `.ax-appbar`, both full-bleed at this width — so both insets can be
       pinned to the viewport gutters. Standard phone treatment, and it hands
       the overflow shed the extra width its app tiles were short of.
       (`inset-block-start:100%` now measures the BAR's height, which is where
       these panels should have been dropping from anyway.) */
    .ax-lang,
    .ax-apps,
    .ax-cart,
    .ax-notif,
    .ax-profile,
    .ax-overflow {
      position: static;
    }
    .ax-lang__menu,
    .ax-apps__menu,
    .ax-cart__menu,
    .ax-notif__menu,
    .ax-profile__menu,
    .ax-overflow__menu {
      inset-inline: var(--ax-space-3);
      inline-size: auto;
      min-inline-size: 0;
      max-inline-size: none;
    }
    /* the shed needs the height to show all five rows without a scroll */
    .ax-overflow__menu {
      max-block-size: min(80vh, 560px);
    }
    /* …which the app tiles pay for by going a size down */
    .ax-overflow__menu .ax-apps__grid {
      gap: 2px;
    }
    .ax-overflow__menu .ax-apps__tile {
      padding-block: var(--ax-space-2);
      gap: var(--ax-space-1);
    }
    .ax-overflow__menu .ax-apps__tile-icon {
      inline-size: 32px;
      block-size: 32px;
    }
  }

/* === appshell.css === */
/*
 * Vireo — HTML reference edition · appshell.css
 * ────────────────────────────────────────────────────────────────────────
 * FULL-SCREEN APP SHELL — the chrome for the 13 standalone app pages under
 * src/html/apps/**. These pages deliberately have NO sidebar and NO regular
 * header; they own the whole viewport, the way a real mail/chat/board client
 * does, and each app scrolls inside its own panes rather than scrolling the
 * document.
 *
 * Skeleton (partials/app-bar.html + the page):
 *   <body class="ax-app-body">
 *     <div class="ax-ambient"><i></i></div>
 *     <div class="ax-applayout">
 *       <header class="ax-appbar">…</header>          ← this file
 *       <main class="ax-appmain" id="ax-main">
 *         <div class="ax-apphead">…status + actions…</div>   (optional)
 *         <div class="… ax-app-fill">…the app…</div>         (fills the rest)
 *       </main>
 *     </div>
 *     <aside class="ax-customizer">…</aside>
 *
 * WHY .ax-appbar AND NOT .ax-header --
 *   base.css moves .ax-header around for six shell styles / nav modes /
 *   header positions, with selectors reaching 0,5,0 specificity
 *   ([data-ax-header-position][data-ax-shell-style]:not()… .ax-header). Those
 *   attributes persist on <html> from localStorage, so an app page opened
 *   after the user picked "detached" would inherit a floating, sidebar-offset
 *   bar. A separate class is immune by construction. schemes.css widens its
 *   selectors to :is(.ax-header, .ax-appbar) so the chosen HEADER SCHEME
 *   (dark / brand / gradient / transparent) still applies to both.
 *
 * Unlayered on purpose — same as base.css/shell.css chrome.
 */

/* ════════════════════════════════════════════════════════════════════════
   1 · VIEWPORT FRAME
   The document itself never scrolls: the bar is a fixed-height row and the
   app column takes the remaining space. Uses svh so mobile browser chrome
   collapsing doesn't leave a gap under the app.
   ════════════════════════════════════════════════════════════════════════ */
.ax-app-body {
  overflow: hidden;
}

.ax-applayout {
  position: relative;
  z-index: 1; /* above the fixed .ax-ambient glow layer */
  isolation: isolate;
  display: flex;
  flex-direction: column;
  block-size: 100vh;
  block-size: 100svh;
  overflow: hidden;
}

/* ════════════════════════════════════════════════════════════════════════
   2 · APP BAR — in-flow first row (mirrors .ax-header's glass chrome)
   ════════════════════════════════════════════════════════════════════════ */
.ax-appbar {
  position: relative;
  z-index: var(--ax-z-header);
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--ax-space-2);
  block-size: var(--ax-header-h);
  padding-inline: var(--ax-space-4);
  background: var(--ax-header-bg, var(--ax-surface-raised));
  color: var(--ax-header-fg, var(--ax-text));
  border-block-end: 1px solid var(--ax-header-border, var(--ax-border));
  -webkit-backdrop-filter: blur(12px) saturate(1.05);
  backdrop-filter: blur(12px) saturate(1.05);
}

/* ── BRAND — doubles as the way out, back to the dashboard ── */
.ax-appbar__brand {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-space-2);
  flex: 0 0 auto;
  padding-inline: var(--ax-space-2);
  padding-block: var(--ax-space-1);
  border-radius: var(--ax-radius-md);
  color: var(--ax-header-fg-strong, var(--ax-text-strong));
  text-decoration: none;
  transition: background var(--ax-motion-fast) var(--ax-ease-standard);
}
.ax-appbar__brand:hover,
.ax-appbar__brand:focus-visible {
  background: var(--ax-header-hover, var(--ax-fill-hover));
  outline: none;
}
.ax-appbar__mark {
  display: inline-flex;
  flex: 0 0 auto;
}
.ax-appbar__wordmark {
  font-family: var(--ax-font-display);
  font-size: var(--ax-text-sm);
  font-weight: var(--ax-weight-bold);
  letter-spacing: 0.08em;
}
/* the ← glyph only appears on hover/focus, so the bar reads as a brand at
   rest and as an exit affordance the moment it's a target */
.ax-appbar__exit {
  inline-size: var(--ax-icon-sm);
  block-size: var(--ax-icon-sm);
  opacity: 0;
  margin-inline-start: calc(var(--ax-space-1) * -1);
  transition: opacity var(--ax-motion-fast) var(--ax-ease-standard);
}
.ax-appbar__brand:hover .ax-appbar__exit,
.ax-appbar__brand:focus-visible .ax-appbar__exit {
  opacity: 1;
}

.ax-appbar__divider {
  flex: 0 0 auto;
  inline-size: 1px;
  block-size: 22px;
  margin-inline: var(--ax-space-1);
  background: var(--ax-header-border, var(--ax-border));
}

/* ════════════════════════════════════════════════════════════════════════
   3 · APP SWITCHER — current app name + jump to any other app
   ════════════════════════════════════════════════════════════════════════ */
.ax-appswitch {
  position: relative;
  display: inline-flex;
  flex: 0 1 auto;
  min-inline-size: 0;
}
.ax-appswitch__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--ax-space-2);
  min-inline-size: 0;
  block-size: 34px;
  padding-inline: var(--ax-space-3);
  font-family: inherit;
  font-size: var(--ax-text-sm);
  font-weight: var(--ax-weight-semibold);
  color: var(--ax-header-fg-strong, var(--ax-text-strong));
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--ax-radius-md);
  cursor: pointer;
  transition:
    background var(--ax-motion-fast) var(--ax-ease-standard),
    border-color var(--ax-motion-fast) var(--ax-ease-standard);
}
.ax-appswitch__trigger:hover,
.ax-appswitch__trigger[aria-expanded='true'] {
  background: var(--ax-header-hover, var(--ax-fill-hover));
  border-color: var(--ax-header-border, var(--ax-border));
}
.ax-appswitch__name {
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.ax-appswitch__caret {
  flex: 0 0 auto;
  inline-size: var(--ax-icon-sm);
  block-size: var(--ax-icon-sm);
  color: var(--ax-header-fg, var(--ax-text-muted));
  transition: transform var(--ax-motion-fast) var(--ax-ease-standard);
}
.ax-appswitch__trigger[aria-expanded='true'] .ax-appswitch__caret {
  transform: rotate(180deg);
}

/* floating panel — same recipe as the header menus, but anchored to the
   INLINE-START edge because the switcher sits on the leading side of the bar */
.ax-appswitch__menu {
  display: block;
  position: absolute;
  inset-block-start: calc(100% + var(--ax-space-2));
  inset-inline-start: 0;
  z-index: var(--ax-z-dropdown);
  inline-size: max-content;
  min-inline-size: 248px;
  max-inline-size: min(92vw, 320px);
  max-block-size: min(72vh, 560px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--ax-space-2);
  color: var(--ax-text);
  background: var(--ax-surface-solid);
  border: 1px solid var(--ax-border);
  border-radius: var(--ax-radius-lg);
  box-shadow: var(--ax-shadow-lg);
}
.ax-appswitch__item {
  display: flex;
  align-items: center;
  gap: var(--ax-space-3);
  inline-size: 100%;
  padding: var(--ax-space-2) var(--ax-space-3);
  font-size: var(--ax-text-sm);
  color: var(--ax-text);
  text-decoration: none;
  border-radius: var(--ax-radius-md);
  transition: background var(--ax-motion-instant) var(--ax-ease-standard);
}
.ax-appswitch__item:hover,
.ax-appswitch__item:focus-visible {
  background: var(--ax-fill-hover);
  color: var(--ax-text-strong);
  outline: none;
}
/* current app — set by the partial's x-init from <html data-ax-route> */
.ax-appswitch__item.is-active {
  color: var(--ax-accent);
  background: var(--ax-accent-wash);
  font-weight: var(--ax-weight-semibold);
}
.ax-appswitch__icon {
  flex: 0 0 auto;
  inline-size: var(--ax-icon-md);
  block-size: var(--ax-icon-md);
  color: var(--ax-text-subtle);
}
.ax-appswitch__item:hover .ax-appswitch__icon,
.ax-appswitch__item.is-active .ax-appswitch__icon {
  color: inherit;
}
.ax-appswitch__label {
  flex: 1 1 auto;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.ax-appswitch__item .ax-badge {
  flex: 0 0 auto;
}

/* the bar's search sits between the switcher and the spacer — let it shrink
   before the app name does */
.ax-search--app {
  flex: 0 1 auto;
  margin-inline-start: var(--ax-space-2);
}

/* ════════════════════════════════════════════════════════════════════════
   4 · APP COLUMN
   .ax-appmain is the only scroll container. Children are laid out in a
   column; ONE child per page may carry .ax-app-fill to claim the leftover
   height (the 3-pane clients, the board, the player). Pages whose content is
   a long list (gallery, tasks, settings) simply omit it and scroll.
   ════════════════════════════════════════════════════════════════════════ */
.ax-appmain {
  flex: 1 1 auto;
  min-block-size: 0;
  display: flex;
  flex-direction: column;
  gap: var(--ax-space-4);
  padding: var(--ax-space-4) var(--ax-space-5) var(--ax-space-5);
  overflow: auto;
  overscroll-behavior: contain;
}
.ax-appmain > * {
  flex: 0 0 auto;
  min-block-size: 0;
}
.ax-appmain > .ax-app-fill {
  flex: 1 1 auto;
}
/* a filling child owns its own internal scrolling, so the column must not
   also scroll — otherwise a nested pane can push the page taller */
.ax-appmain:has(> .ax-app-fill) {
  overflow: hidden;
}

/* Below the pane breakpoint the multi-pane clients collapse to a single
   column, and a stacked pane has no height to inherit. Hand the column its
   scrollbar back and give the app a workable fixed height instead — the same
   deal the pre-app-shell pages had. */
@media (max-width: 991.98px) {
  .ax-appmain:has(> .ax-app-fill) {
    overflow: auto;
  }
  .ax-appmain > .ax-app-fill {
    flex: 0 0 auto;
    min-block-size: 560px;
  }
}

/* ── APP HEAD — slim status + actions strip.
      Replaces .ax-page-head on these pages: the breadcrumb and <h1> are gone
      (the bar names the app), leaving only the live status line and the
      page's primary actions. ── */
.ax-apphead {
  display: flex;
  align-items: center;
  gap: var(--ax-space-3);
  flex-wrap: wrap;
}
.ax-apphead__status {
  flex: 1 1 auto;
  min-inline-size: 0;
  margin: 0;
  font-size: var(--ax-text-sm);
  color: var(--ax-text-muted);
}
.ax-apphead__actions {
  display: flex;
  align-items: center;
  gap: var(--ax-space-2);
  flex: 0 0 auto;
  flex-wrap: wrap;
}

/* ════════════════════════════════════════════════════════════════════════
   5 · RESPONSIVE
   ════════════════════════════════════════════════════════════════════════ */
@media (max-width: 991.98px) {
  /* The ⌘K FIELD is the first thing to go — the app switcher matters more on a
     narrow bar. The TRIGGER stays: dropping it (as this did) left the command
     palette reachable only by ⌘K, i.e. not at all on the phones and tablets
     this breakpoint is for. Collapse it to the 38px icon button instead —
     exactly what the main header does below md. */
  .ax-search--app {
    flex: 0 0 auto;
    inline-size: 38px;
    min-inline-size: 38px;
    max-inline-size: 38px;
    padding-inline: 0;
    justify-content: center;
    border-radius: var(--ax-radius-md);
  }
  .ax-search--app .ax-search__placeholder,
  .ax-search--app .ax-search__keycap {
    display: none;
  }
  .ax-search--app .ax-search__icon {
    inline-size: var(--ax-icon-md);
    block-size: var(--ax-icon-md);
  }
}

@media (max-width: 767.98px) {
  /* tighter gutter + gap, mirroring .ax-header at this width: the eight-slot bar
     has no spare pixels here, and at the default 8px gap the app name was being
     squeezed to a 2px sliver next to its chevron */
  .ax-appbar {
    padding-inline: var(--ax-space-3);
    gap: var(--ax-space-1);
  }
  .ax-appbar__wordmark,
  .ax-appbar__divider {
    display: none;
  }
  /* the ← exit glyph only ever reveals itself on hover, which a phone does not
     have — so here it is 16px of permanently invisible bar */
  .ax-appbar__exit {
    display: none;
  }
  /* and the last few px the app name needs to spell itself out */
  .ax-appswitch__trigger {
    padding-inline: var(--ax-space-2);
    gap: var(--ax-space-1);
  }
  .ax-appmain {
    gap: var(--ax-space-3);
    padding: var(--ax-space-3);
  }
  .ax-apphead {
    gap: var(--ax-space-2);
  }
}

/* ── RTL: the exit chevron is directional ── */
[dir='rtl'] .ax-appbar__exit {
  transform: scaleX(-1);
}

/* === utilities.css === */
/*
 * Vireo — HTML reference edition · utilities.css
 * ────────────────────────────────────────────────────────────────────────
 * Token-driven helper classes that Tailwind's built-ins don't cleanly cover.
 * Kept deliberately MINIMAL — Tailwind utilities handle most spacing/flex/
 * color needs; these encode Aurora/spec-specific micro-patterns.
 *
 * All values reference Layer-2 role tokens or Layer-1 scale tokens — never a
 * raw stop, never a themeable literal hex.
 */

/* ── Numerics ───────────────────────────────────────────────────────────
   Tabular figures for KPIs, table columns, ledgers, axis labels (spec 01 §4.1). */
.ax-num,
[data-ax-tabular] {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}
.ax-mono {
  font-family: var(--ax-font-mono);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}

/* ── Display / eyebrow type ─────────────────────────────────────────────── */
.ax-display {
  font-family: var(--ax-font-display);
  font-weight: var(--ax-weight-bold);
  letter-spacing: -0.015em;
}
.ax-eyebrow {
  display: block;
  font-size: var(--ax-text-2xs);
  line-height: var(--ax-leading-2xs);
  font-weight: var(--ax-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--ax-text-subtle);
}

/* ── Accessibility ──────────────────────────────────────────────────────── */
.visually-hidden,
.sr-only {
  position: absolute !important;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
/* skip-link / focusable variant: reveals itself when focused */
.visually-hidden-focusable:not(:focus):not(:focus-within) {
  position: absolute !important;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ── Truncation / clamping ──────────────────────────────────────────────── */
.ax-truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-inline-size: 0;
}
.ax-clamp-2 {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.ax-clamp-3 {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ── Flex helpers ───────────────────────────────────────────────────────
   .ax-stack = vertical flow with gap · .ax-cluster = inline-wrap with gap.
   Gap defaults to --ax-space-4; override via inline --ax-gap. */
.ax-stack {
  display: flex;
  flex-direction: column;
  gap: var(--ax-gap, var(--ax-space-4));
}
.ax-cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--ax-gap, var(--ax-space-2));
}
.ax-cluster--between {
  justify-content: space-between;
}
.ax-center {
  display: grid;
  place-items: center;
}
/* logical-flow spacer (pushes siblings apart in flex rows/columns) */
.ax-spacer {
  flex: 1 1 auto;
}

/* ── Scroll region (overlay, contained) ─────────────────────────────────── */
.ax-scroll {
  overflow: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--ax-scrollbar-thumb) transparent;
}
.ax-scroll-x {
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
}
.ax-scroll-y {
  overflow-y: auto;
  overflow-x: hidden;
  overscroll-behavior-y: contain;
}

/* ── Hairline divider ───────────────────────────────────────────────────── */
.ax-divider {
  border: 0;
  block-size: 1px;
  inline-size: 100%;
  background: var(--ax-border);
}
.ax-divider--vertical {
  inline-size: 1px;
  block-size: auto;
  align-self: stretch;
}
.ax-divider--strong {
  background: var(--ax-border-strong);
}

/* ── Skeleton shimmer (loading placeholder; reduced-motion safe) ─────────── */
.ax-skeleton {
  position: relative;
  overflow: hidden;
  background: var(--ax-fill-hover);
  border-radius: var(--ax-radius-sm);
}
.ax-skeleton::after {
  content: '';
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(
    90deg,
    transparent 0%,
    var(--ax-fill-active) 50%,
    transparent 100%
  );
  animation: ax-shimmer 1.4s var(--ax-ease-linear) infinite;
}
@keyframes ax-shimmer {
  100% {
    transform: translateX(100%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .ax-skeleton::after {
    animation: none;
    /* steady mid-tone so it still reads as a placeholder without motion */
    background: var(--ax-fill-active);
    transform: none;
    opacity: 0.6;
  }
}

/* ── Aspect-ratio media frame ───────────────────────────────────────────── */
.ax-ratio {
  position: relative;
  aspect-ratio: var(--ax-ratio, 16 / 9);
  overflow: hidden;
  border-radius: var(--ax-radius-md);
}
.ax-ratio > img,
.ax-ratio > video,
.ax-ratio > iframe {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* ── Status / utility text colors (role-token aliases) ──────────────────── */
.ax-text-strong {
  color: var(--ax-text-strong);
}
.ax-text-muted {
  color: var(--ax-text-muted);
}
.ax-text-subtle {
  color: var(--ax-text-subtle);
}
.ax-text-accent {
  color: var(--ax-accent);
}
.ax-text-success {
  color: var(--ax-success-500);
}
.ax-text-warning {
  color: var(--ax-warning-500);
}
.ax-text-danger {
  color: var(--ax-danger-500);
}
.ax-text-info {
  color: var(--ax-info-500);
}

/* ── Interaction guards ─────────────────────────────────────────────────── */
.ax-no-select {
  user-select: none;
  -webkit-user-select: none;
}
.ax-pointer-none {
  pointer-events: none;
}
.ax-fill {
  inline-size: 100%;
  block-size: 100%;
}

/* ── Reduced-motion escape hatch (opt-in per element) ───────────────────── */
@media (prefers-reduced-motion: reduce) {
  .ax-motion-safe {
    animation: none !important;
    transition: none !important;
  }
}

/* ─────────────────────────────────────────────────────────────────────────
   DASHBOARD / PAGE GRID — the 12-column layout primitive every content page
   uses instead of inlining `style="display:grid…"`. Gutter 24px (16px <md).
   Span helpers `ax-col--N`; auto-stack at lg / sm per the responsive contract.
   ───────────────────────────────────────────────────────────────────────── */
.ax-dash-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--ax-space-6);
  align-items: stretch;        /* cards in the same row match height; shorter ones gain inner blank space */
}
.ax-dash-grid--ecommerce,
.ax-dash-grid--ecommerce *:not(svg):not(svg *) {
  text-align: right !important;
}
.lms-dashboard {
  direction: rtl;
}
.lms-dashboard,
.lms-dashboard * {
  text-align: right !important;
}
@media (max-width: 768px) {
  .ax-dash-grid {
    gap: var(--ax-space-4);
  }
}

/* Defaults for grid children, written with `:where()` so they carry no
   specificity of their own and any explicit `ax-col--N` below always wins.
   Order matters: these must precede the span helpers.
     · anything unclassed spans the full row (a safe, never-broken fallback —
       the old failure mode was a stray card collapsing to 1/12 of a row);
     · a bare KPI card takes a quarter, which is what every KPI row wants, so
       the four-across rhythm needs no per-card class. */
.ax-dash-grid > :where(*) { grid-column: 1 / -1; }
.ax-dash-grid > :where(.ax-kpi) { grid-column: span 3; }
@media (max-width: 992px) {
  .ax-dash-grid > :where(.ax-kpi) { grid-column: span 6; }
}
@media (max-width: 576px) {
  .ax-dash-grid > :where(.ax-kpi) { grid-column: span 12; }
}

.ax-col--12 { grid-column: span 12; }
.ax-col--11 { grid-column: span 11; }
.ax-col--10 { grid-column: span 10; }
.ax-col--9  { grid-column: span 9; }
.ax-col--8  { grid-column: span 8; }
.ax-col--7  { grid-column: span 7; }
.ax-col--6  { grid-column: span 6; }
.ax-col--5  { grid-column: span 5; }
.ax-col--4  { grid-column: span 4; }
.ax-col--3  { grid-column: span 3; }
.ax-col--2  { grid-column: span 2; }

/* lg: halves/two-thirds → full; quarters/thirds → halves */
@media (max-width: 992px) {
  .ax-col--11, .ax-col--10, .ax-col--9, .ax-col--8, .ax-col--7, .ax-col--6 {
    grid-column: span 12;
  }
  .ax-col--5, .ax-col--4, .ax-col--3, .ax-col--2 {
    grid-column: span 6;
  }
}
/* sm: everything stacks */
@media (max-width: 576px) {
  [class*="ax-col--"] {
    grid-column: span 12;
  }
}

/* Display utilities for elements toggled by Alpine x-show.
   x-show strips the inline `display` property when showing an element, which
   silently destroys an inline `display:grid`/`display:flex` (the element falls
   back to `display:block`). Driving display from a class survives the toggle:
   x-show sets inline `display:none` to hide, and removing it falls back here. */
.ax-grid { display: grid; }
.ax-flex { display: flex; }

/* === schemes.css === */
/*
 * Vireo — HTML reference edition · schemes.css
 * ────────────────────────────────────────────────────────────────────────
 * SURFACE SCHEMES for the shell chrome (sidebar + header), independent of
 * content cards. Each scheme remaps the Layer-3 chrome tokens that .ax-sidebar
 * / .ax-header paint from:
 *
 * The header selectors are written :is(.ax-header, .ax-appbar) so the
 * full-screen app bar (styles/appshell.css) tracks the same header scheme —
 * it is a header, it just isn't the dashboard one.
 *
 *   --ax-sidebar-bg / --ax-sidebar-fg / --ax-sidebar-fg-strong /
 *   --ax-sidebar-border / --ax-sidebar-hover / --ax-sidebar-active-bg
 *   (and the --ax-header-* mirror).
 *
 * Rules (shell brief 02 §11 / spec 04 §8):
 *  - Chrome tokens DERIVE from Layer-2 role tokens (--ax-surface-raised,
 *    --ax-text, --ax-accent, --ax-on-accent, dark-ramp surfaces…).
 *  - brand/gradient FOLLOW the active --ax-accent automatically.
 *  - A "dark" chrome scheme stays dark even while the app is in LIGHT mode
 *    (it pins explicit dark-ramp surfaces, not theme-relative roles).
 *  - Schemes compose with mode + accent with no per-component branching.
 *  - Sidebar bg-image renders over the Light scheme ONLY.
 *  - Author with logical properties so RTL needs no scheme changes.
 *
 * NOTE: base.css already wires .ax-sidebar/.ax-header to paint from
 *   background: var(--ax-sidebar-bg, var(--ax-surface-raised));
 *   color:      var(--ax-sidebar-fg, var(--ax-text));
 *   border:     var(--ax-sidebar-border, var(--ax-border));
 * so a scheme only needs to (re)declare those custom properties.
 */

/* ════════════════════════════════════════════════════════════════════════
   0 · DEFAULT (LIGHT) chrome — explicit so all 5 schemes are uniform.
   This is the resting glass topbar/rail; values track the theme roles, so
   it inverts correctly in dark mode via the role tokens themselves.
   ════════════════════════════════════════════════════════════════════════ */
.ax-sidebar {
  --ax-sidebar-bg: var(--ax-surface-raised);
  --ax-sidebar-fg: var(--ax-text-muted);
  --ax-sidebar-fg-strong: var(--ax-text-strong);
  --ax-sidebar-border: var(--ax-border);
  --ax-sidebar-hover: var(--ax-fill-hover);
  --ax-sidebar-active-bg: var(--ax-accent-wash);
}
:is(.ax-header, .ax-appbar) {
  --ax-header-bg: var(--ax-surface-raised);
  --ax-header-fg: var(--ax-text-muted);
  --ax-header-fg-strong: var(--ax-text-strong);
  --ax-header-border: var(--ax-border);
  --ax-header-hover: var(--ax-fill-hover);
}

/* Offcanvas drawer (< md): the scrim sits BEHIND the rail, so the default glass
   would read that dim straight through itself and the whole menu would look
   greyed out. The panel goes opaque (and drops the now-pointless blur) for the
   drawer only. Must live HERE, right after the default above — an equal-
   specificity rule in shell.css would lose to it on source order. The named
   schemes below are 0,2,0 selectors and keep winning, as they should. */
@media (max-width: 767.98px) {
  .ax-sidebar {
    --ax-sidebar-bg: var(--ax-surface-solid);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

/* ════════════════════════════════════════════════════════════════════════
   1 · DARK chrome  [data-ax-sidebar="dark"] / [data-ax-header="dark"]
   Pins explicit dark-ramp surfaces + alpha strokes so the chrome stays dark
   regardless of app theme. fg uses the dark-ramp text stops directly here
   (this is the ONE sanctioned place to reach the dark ramp, because the
   chrome is forced dark independent of [data-ax-theme]).
   ════════════════════════════════════════════════════════════════════════ */
[data-ax-sidebar='dark'] .ax-sidebar {
  --ax-sidebar-bg: var(--ax-dark-850);
  --ax-sidebar-fg: var(--ax-dark-300);
  --ax-sidebar-fg-strong: var(--ax-dark-50);
  --ax-sidebar-border: var(--ax-dark-stroke);
  --ax-sidebar-hover: var(--ax-dark-fill-1);
  --ax-sidebar-active-bg: color-mix(in oklab, var(--ax-accent) 18%, transparent);
  color: var(--ax-dark-300);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
[data-ax-header='dark'] :is(.ax-header, .ax-appbar) {
  --ax-header-bg: var(--ax-dark-850);
  --ax-header-fg: var(--ax-dark-300);
  --ax-header-fg-strong: var(--ax-dark-50);
  --ax-header-border: var(--ax-dark-stroke);
  --ax-header-hover: var(--ax-dark-fill-1);
  color: var(--ax-dark-300);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
/* strong text inside dark chrome (brand, active labels, KPI) reads bright */
[data-ax-sidebar='dark'] .ax-sidebar__wordmark,
[data-ax-sidebar='dark'] .ax-sidebar__logo {
  color: var(--ax-dark-50);
}

/* ════════════════════════════════════════════════════════════════════════
   2 · BRAND chrome  — solid --ax-accent fill, follows the active preset.
   fg uses --ax-on-accent so it stays legible across all 12 accents
   (incl. Amber's dark ink).
   ════════════════════════════════════════════════════════════════════════ */
[data-ax-sidebar='brand'] .ax-sidebar {
  --ax-sidebar-bg: var(--ax-accent);
  --ax-sidebar-fg: color-mix(in oklab, var(--ax-on-accent) 78%, transparent);
  --ax-sidebar-fg-strong: var(--ax-on-accent);
  --ax-sidebar-border: color-mix(in oklab, var(--ax-on-accent) 16%, transparent);
  --ax-sidebar-hover: color-mix(in oklab, var(--ax-on-accent) 12%, transparent);
  --ax-sidebar-active-bg: color-mix(in oklab, var(--ax-on-accent) 18%, transparent);
  color: var(--ax-on-accent);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
[data-ax-header='brand'] :is(.ax-header, .ax-appbar) {
  --ax-header-bg: var(--ax-accent);
  --ax-header-fg: color-mix(in oklab, var(--ax-on-accent) 78%, transparent);
  --ax-header-fg-strong: var(--ax-on-accent);
  --ax-header-border: color-mix(in oklab, var(--ax-on-accent) 16%, transparent);
  --ax-header-hover: color-mix(in oklab, var(--ax-on-accent) 12%, transparent);
  color: var(--ax-on-accent);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
[data-ax-sidebar='brand'] .ax-sidebar__wordmark,
[data-ax-sidebar='brand'] .ax-sidebar__logo {
  color: var(--ax-on-accent);
}

/* ════════════════════════════════════════════════════════════════════════
   3 · GRADIENT chrome — vertical accent gradient (accent-600 → accent-800),
   also derives from the active preset's ramp.
   ════════════════════════════════════════════════════════════════════════ */
[data-ax-sidebar='gradient'] .ax-sidebar {
  --ax-sidebar-bg: linear-gradient(180deg, var(--ax-accent-600), var(--ax-accent-800));
  --ax-sidebar-fg: color-mix(in oklab, var(--ax-on-accent) 80%, transparent);
  --ax-sidebar-fg-strong: var(--ax-on-accent);
  --ax-sidebar-border: color-mix(in oklab, var(--ax-on-accent) 14%, transparent);
  --ax-sidebar-hover: color-mix(in oklab, var(--ax-on-accent) 12%, transparent);
  --ax-sidebar-active-bg: color-mix(in oklab, var(--ax-on-accent) 20%, transparent);
  color: var(--ax-on-accent);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
[data-ax-header='gradient'] :is(.ax-header, .ax-appbar) {
  --ax-header-bg: linear-gradient(90deg, var(--ax-accent-600), var(--ax-accent-800));
  --ax-header-fg: color-mix(in oklab, var(--ax-on-accent) 80%, transparent);
  --ax-header-fg-strong: var(--ax-on-accent);
  --ax-header-border: color-mix(in oklab, var(--ax-on-accent) 14%, transparent);
  --ax-header-hover: color-mix(in oklab, var(--ax-on-accent) 12%, transparent);
  color: var(--ax-on-accent);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
[data-ax-sidebar='gradient'] .ax-sidebar__wordmark,
[data-ax-sidebar='gradient'] .ax-sidebar__logo {
  color: var(--ax-on-accent);
}

/* ════════════════════════════════════════════════════════════════════════
   4 · TRANSPARENT chrome — no fill; chrome floats over the canvas/glow.
   fg keeps theme text roles so it reads on either mode's canvas.
   ════════════════════════════════════════════════════════════════════════ */
[data-ax-sidebar='transparent'] .ax-sidebar {
  --ax-sidebar-bg: transparent;
  --ax-sidebar-fg: var(--ax-text-muted);
  --ax-sidebar-fg-strong: var(--ax-text-strong);
  --ax-sidebar-border: transparent;
  --ax-sidebar-hover: var(--ax-fill-hover);
  --ax-sidebar-active-bg: var(--ax-accent-wash);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
[data-ax-header='transparent'] :is(.ax-header, .ax-appbar) {
  --ax-header-bg: transparent;
  --ax-header-fg: var(--ax-text-muted);
  --ax-header-fg-strong: var(--ax-text-strong);
  --ax-header-border: transparent;
  --ax-header-hover: var(--ax-fill-hover);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* ════════════════════════════════════════════════════════════════════════
   5 · CHROME TEXT/HOVER WIRING — make the remapped fg/hover tokens actually
   paint inside the rail/header so every scheme reads correctly without each
   component re-deriving colors.
   ════════════════════════════════════════════════════════════════════════ */
.ax-sidebar .ax-sidebar__section {
  color: color-mix(in oklab, var(--ax-sidebar-fg) 80%, transparent);
}
.ax-sidebar .ax-nav__item {
  color: var(--ax-sidebar-fg);
}
.ax-sidebar .ax-nav__item:hover {
  background: var(--ax-sidebar-hover);
  color: var(--ax-sidebar-fg-strong);
}
/* active item on the accent-filled rails (brand/gradient): the _recipes.css
   active recipe paints the pill/glow/text/icon all in --ax-accent, which is the
   rail's own background — accent-on-accent makes the current page vanish. Consume
   the already-computed contrasting --ax-sidebar-active-bg (on-accent based) here.
   light/dark/transparent keep the default accent-glow (no override targets them). */
[data-ax-sidebar='brand'] .ax-sidebar .ax-nav__item.is-active,
[data-ax-sidebar='gradient'] .ax-sidebar .ax-nav__item.is-active {
  background: var(--ax-sidebar-active-bg);
  color: var(--ax-sidebar-fg-strong);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--ax-on-accent) 22%, transparent);
}
[data-ax-sidebar='brand'] .ax-sidebar .ax-nav__item.is-active::before,
[data-ax-sidebar='gradient'] .ax-sidebar .ax-nav__item.is-active::before {
  background: var(--ax-on-accent);
  box-shadow: none;
}
[data-ax-sidebar='brand'] .ax-sidebar .ax-nav__item.is-active svg,
[data-ax-sidebar='gradient'] .ax-sidebar .ax-nav__item.is-active svg {
  color: var(--ax-on-accent);
}
:is(.ax-header, .ax-appbar) .ax-icon-btn:hover {
  background: var(--ax-header-hover);
}
/* header interactive chrome must follow the remapped --ax-header-* tokens too,
   else dark/brand/gradient/transparent recolor only the bar and leave the icon
   buttons + search field on hardcoded light-theme tokens (invisible/low-contrast).
   The default (light) scheme maps these tokens to the same role values used
   elsewhere, so the light header is visually unchanged — only non-default
   schemes start tracking. */
:is(.ax-header, .ax-appbar) .ax-icon-btn {
  color: var(--ax-header-fg);
}
:is(.ax-header, .ax-appbar) .ax-icon-btn:hover,
:is(.ax-header, .ax-appbar) .ax-icon-btn[aria-expanded='true'],
:is(.ax-header, .ax-appbar) .ax-icon-btn[aria-pressed='true'] {
  color: var(--ax-header-fg-strong);
  background: var(--ax-header-hover);
}
:is(.ax-header, .ax-appbar) .ax-search {
  color: var(--ax-header-fg);
  background: color-mix(in oklab, var(--ax-header-fg) 10%, transparent);
  border-color: var(--ax-header-border);
}
:is(.ax-header, .ax-appbar) .ax-search:hover {
  background: color-mix(in oklab, var(--ax-header-fg) 16%, transparent);
  border-color: var(--ax-header-fg-strong);
}
:is(.ax-header, .ax-appbar) .ax-search__icon,
:is(.ax-header, .ax-appbar) .ax-search__keycap {
  color: var(--ax-header-fg);
}
:is(.ax-header, .ax-appbar) .ax-search__keycap {
  background: color-mix(in oklab, var(--ax-header-fg) 12%, transparent);
  border-color: var(--ax-header-border);
}

/* ════════════════════════════════════════════════════════════════════════
   6 · SIDEBAR BACKGROUND IMAGE  [data-ax-sidebar-image="texture-1..6"]
   Renders over the LIGHT scheme ONLY (suppressed for dark/brand/gradient/
   transparent, where a textured overlay would clash). The texture tile lives
   in a ::before so it sits behind the rail's flex regions; foreground stays
   readable via a canvas-tinted scrim.
   ════════════════════════════════════════════════════════════════════════ */
/* `data-ax-sidebar-image` lives on <html> (where the setter/anti-flash write it),
   NOT on `.ax-sidebar`. Read it off the same element as the scheme attribute, then
   reach the rail via a descendant combinator. `.ax-sidebar` is already positioned
   (fixed/absolute) in base.css, so the absolute ::before has its containing block. */
:where([data-ax-sidebar='light'], html:not([data-ax-sidebar]))[data-ax-sidebar-image]:not([data-ax-sidebar-image='none'])
  .ax-sidebar::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: var(--ax-sidebar-texture, none);
  background-size: cover;
  background-position: center;
  opacity: 0.5;
  /* canvas-tinted veil keeps nav text legible over the texture */
  box-shadow: inset 0 0 0 100vmax color-mix(in oklab, var(--ax-surface-raised) 72%, transparent);
}
/* suppress texture entirely for non-light schemes */
[data-ax-sidebar='dark'] .ax-sidebar::before,
[data-ax-sidebar='brand'] .ax-sidebar::before,
[data-ax-sidebar='gradient'] .ax-sidebar::before,
[data-ax-sidebar='transparent'] .ax-sidebar::before {
  display: none;
}

/* texture token slots (1–6). Real tile assets are wired by the build/assets
   layer; these provide deterministic, theme-safe placeholders so the control
   demonstrates live without shipping binary art in CSS. */
[data-ax-sidebar-image='texture-1'] {
  --ax-sidebar-texture: radial-gradient(
    circle at 1px 1px,
    var(--ax-border-strong) 1px,
    transparent 0
  );
}
[data-ax-sidebar-image='texture-2'] {
  --ax-sidebar-texture: repeating-linear-gradient(
    45deg,
    var(--ax-fill-hover) 0 8px,
    transparent 8px 16px
  );
}
[data-ax-sidebar-image='texture-3'] {
  --ax-sidebar-texture: linear-gradient(160deg, var(--ax-accent-wash), transparent 60%);
}
[data-ax-sidebar-image='texture-4'] {
  --ax-sidebar-texture: repeating-linear-gradient(
    90deg,
    var(--ax-fill-hover) 0 1px,
    transparent 1px 14px
  );
}
[data-ax-sidebar-image='texture-5'] {
  --ax-sidebar-texture: radial-gradient(
    circle at 80% 0,
    var(--ax-accent-wash),
    transparent 55%
  );
}
[data-ax-sidebar-image='texture-6'] {
  --ax-sidebar-texture: conic-gradient(
    from 180deg at 50% 0,
    var(--ax-fill-hover),
    transparent 40%
  );
}


/* minimal utility polyfills used by screens */
.flex { display: flex; }
.grid { display: grid; }
.items-center { align-items: center; }
.justify-between { justify-content: space-between; }
.gap-2 { gap: 0.5rem; }
.gap-3 { gap: 0.75rem; }
.text-xs { font-size: 0.75rem; }
.text-sm { font-size: 0.875rem; }
.text-2xl { font-size: 1.5rem; }
.text-muted, .text-subtle { color: var(--ax-text-muted, #6b7280); }
