/* EXSA Bundle — exsa.bundle.css. Generated by tools/build-bundle.mjs (theme: breeze, no skin). Do not edit by hand.
   https://exsa.dev · v1.0.0-rc.1 · MIT License
*/

/* Copyright © 2026 Saif Almarri. MIT License. See LICENSE.
   Cascade: tokens → themes → skins → (fluid — optional) → reset → utilities → elements → components → layouts → overrides.
*/

@layer exsa.tokens, exsa.themes, exsa.skins, exsa.fluid, exsa.reset, exsa.utilities, exsa.elements, exsa.components, exsa.layouts, exsa.overrides;

@layer exsa.tokens {

/* 94 design tokens */

:root {
  color-scheme: light dark;
  --color-bg:light-dark(#fff,#333);--color-bg-secondary:light-dark(#e9e9e9,#555);--color-text:light-dark(#000,#f7f7f7);--color-text-secondary:light-dark(#757575,#aaa);
  --color-link:light-dark(#118bee,#0097fc);--color-secondary:light-dark(#920de9,#e20de9);--color-secondary-accent:light-dark(#920de90b,#e20de94f);
  --color-accent:light-dark(#118bee15,#0097fc4f);--color-shadow:light-dark(#f4f4f4,#bbbbbb20);--color-overlay:light-dark(rgba(0,0,0,.5),rgba(0,0,0,.65));--color-scrollbar:color-mix(in srgb,var(--color-text)25%,transparent);
  --color-success:light-dark(#16a34a,#22c55e);--color-success-hover:light-dark(#15803d,#16a34a);--color-danger:light-dark(#dc2626,#ef4444);
  --color-danger-hover:light-dark(#b91c1c,#dc2626);--color-warning:light-dark(#d97706,#f59e0b);--color-warning-hover:light-dark(#b45309,#d97706);
  --color-button-text:#fff;--color-button-text-inverse:light-dark(#000,#eee);--color-border:light-dark(#e9e9e9,#555); /* hover variants & --color-button-text consumed by component CSS files */
  --font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
  --font-family-mono:'SF Mono','Cascadia Code','Fira Code',Consolas,monospace;
  --font-family-heading:var(--font-family);
  --font-weight-normal:400;--font-weight-bold:700;--font-weight-heavy:800;
  --font-size-xs:.7rem;--font-size-sm:.78rem;--font-size-base:.88rem;--font-size-md:.95rem;--font-size-lg:1.08rem;--font-size-xl:1.3rem;--font-size-2xl:1.8rem;
  --line-height:1.5;--border-radius:5px;--box-shadow:2px 2px 10px;
  --hover-brightness:1.2;--active-brightness:0.85;
  --justify-heading:center;--justify-body:start;--justify-nav:space-between;--blockquote-border:4px solid var(--color-secondary);
  --width-card:285px;--width-card-medium:460px;--width-card-wide:800px;--width-content:1080px;--scroll-margin-top:80px;
  --gap-xs:0.25rem;--gap-sm:0.5rem;--gap-md:0.75rem;--gap:1rem;--gap-lg:1.5rem;--gap-xl:2rem;--gap-2xl:3rem;
  --bp-sm:575px;--bp-md:768px;--bp-lg:1024px;--bp-xl:1280px;--bp-xxl:1440px;
  --space-factor:1;--radius-factor:1;--font-factor:1;--motion-factor:1; /* global scaling knobs — consumed by JS / components */
  /* z-index scale — one stack for the whole framework. Override any layer in your theme. */
  --z-floating:10;          /* in-component floating controls (carousel arrows) */
  --z-dropdown:100;         /* dropdowns, tooltips, date/color picker popups */
  --z-back-top:800;         /* back-to-top button */
  --z-drawer:900;           /* drawer backdrop */
  --z-drawer-panel:901;     /* drawer panel */
  --z-cookiebar:950;        /* cookie consent bar */
  --z-topbar:1000;          /* fixed topbar */
  --z-topbar-dropdown:1002; /* topbar dropdown menus (above topbar + announce) */
  --z-modal:1050;           /* modal dialogs + video modals (above topbar) */
  --z-lightbox:1100;        /* fullscreen lightbox */
  --z-popover-backdrop:9995;
  --z-popover:9996;         /* popover content */
  --z-context-backdrop:9997;
  --z-context-menu:9998;    /* context menu */
  --z-toast:9999;           /* toast notifications */
  --z-skip:10000;           /* skip link */
  --z-layout-aside:90;      /* fixed sidebars in layout shells (below bars/overlays) */
  --z-layout-footer:95;     /* footer above aside in aside-full mode */
  --z-announce:1001;        /* store announcement bar (above topbar) */
  /* surface material — the skin axis (overridden by dist/skins/*.css).
     Defaults mirror today's rendered pixels: zero visual change without a skin. */
  --surface-bg:var(--color-bg);
  --surface-bg-elevated:color-mix(in srgb,var(--color-bg) 97%,var(--color-text));
  --surface-border:1px solid var(--color-border);
  --surface-border-control:1px solid var(--color-border); /* control boundary — skins must keep it visible (never none) */
  --surface-radius:var(--border-radius);
  --surface-shadow-sm:2px 2px 10px; /* color omitted = currentColor — matches legacy --box-shadow hover */
  --surface-shadow-md:0 4px 16px color-mix(in srgb,var(--color-text) 8%,transparent);
  --surface-shadow-lg:0 8px 32px color-mix(in srgb,var(--color-text) 12%,transparent);
  --surface-shadow-side:8px 0 32px color-mix(in srgb,var(--color-text) 14%,transparent);
  --surface-inset:inset 0 0 0 0 transparent; /* no-op — composable in shadow lists; clay/skeuomorphic/glow replace it */
  --surface-backdrop:none;
  /* page canvas — the skin-preferred page backdrop (page chrome consumes it) */
  --surface-canvas:var(--color-bg);
}

/* Dark/light — one definition per token via light-dark(); forced mode flips color-scheme */

/* Forced dark — <html data-theme-mode="dark">, ignores OS preference */
:root[data-theme-mode="dark"] { color-scheme: dark; }

/* Forced light — <html data-theme-mode="light">, ignores OS preference */
:root[data-theme-mode="light"] { color-scheme: light; }

/* Legacy fallback  */
@supports not (color: light-dark(#000, #fff)) {
  :root {
    --color-bg: Canvas;
    --color-bg-secondary: ButtonFace;
    --color-text: CanvasText;
    --color-text-secondary: GrayText;
    --color-link: LinkText;
    --color-secondary: VisitedText;
    --color-secondary-accent: ButtonFace;
    --color-accent: ButtonFace;
    --color-border: GrayText;
    --color-overlay: rgba(0, 0, 0, .55);
    --color-button-text-inverse: CanvasText;
    --color-success: #16a34a;
    --color-success-hover: #15803d;
    --color-danger: #dc2626;
    --color-danger-hover: #b91c1c;
    --color-warning: #d97706;
    --color-warning-hover: #b45309;
  }
}

} /* tokens */

@layer exsa.reset {

*,*::before,*::after{box-sizing:border-box}
:focus-visible{outline:2px solid var(--color-link);outline-offset:2px}
:focus:not(:focus-visible){outline:none}

/* Universal a11y utility — intentionally unscoped, works without class="exsa" */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin: calc(-1px * var(--space-factor, 1));overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}

/* Windows High Contrast Mode */
@media(forced-colors:active){
  :focus-visible{outline:2px solid Highlight;outline-offset:2px}
  .sr-only{clip:auto;clip-path:none;position:static;width:auto;height:auto}
  .skip-link{background:Highlight;color:HighlightText}
}
/* High contrast preference — boost borders and text weight */
@media(prefers-contrast:high){
  body{text-shadow:none}
  :where(.exsa a){text-decoration-thickness:2px}
  *,*::before,*::after{border-color:currentColor}
}
@media(prefers-contrast:low){
  /* Low contrast = softer borders, not thinner text */
  *,*::before,*::after{border-color:color-mix(in srgb,currentColor 40%,transparent)}
}
*{scrollbar-width:thin;scrollbar-color:var(--color-scrollbar) transparent}
*::-webkit-scrollbar{width:5px;height:5px}
*::-webkit-scrollbar-track{background:transparent}
*::-webkit-scrollbar-thumb{background-color:var(--color-scrollbar);border-radius:10px}
html{scroll-behavior:smooth}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}:target{animation:none}*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}
@media(prefers-reduced-data:reduce){img,video{min-height:0;height:auto}}
[dir=rtl]{direction:rtl;unicode-bidi:isolate}
body{background:var(--color-bg);color:var(--color-text);font-family:var(--font-family);line-height:var(--line-height);margin:0;padding:0}
h1,h2,h3,h4,h5,h6{font-family:var(--font-family-heading);line-height:var(--line-height);text-wrap:balance;margin:0 0 var(--gap-md)}
img,svg,video{max-width:100%;height:auto}
figure{margin:0;padding:0}
[hidden]{display:none!important}

/* Universal a11y utilities — intentionally unscoped, work without class="exsa" */
.skip-link{position:absolute;top:-100px;inset-inline-start:0;background:var(--color-link);color:#fff;padding:var(--gap-sm) var(--gap);z-index:var(--z-skip);font-weight:700;border-radius:0 0 var(--border-radius) var(--border-radius);text-decoration:none;transition:top .15s}
.skip-link:focus{top:0}
[dir=rtl] .skip-link{border-radius:0 0 var(--border-radius) 0}
/* Intentionally unscoped — anchor-target flash highlight works globally */
:target{scroll-margin-top:var(--scroll-margin-top);animation:exsa-target-flash 1.2s ease-out}
@keyframes exsa-target-flash{0%{background:var(--color-accent)}100%{background:transparent}}

} /* reset */

@layer exsa.utilities {

/* Layout only — unprefixed utilities lose to elements/components/layouts;
   use u-* (exsa.overrides) to force-win. */
.container{max-width:var(--width-content);margin:0 auto;padding:0 var(--gap)}
.container-sm{max-width:var(--width-card-wide);margin:0 auto;padding:0 var(--gap-sm)}
.container-full{width:100%}
.flex{display:flex}.flex-inline{display:inline-flex}
.flex-col{flex-direction:column}.flex-col-rev{flex-direction:column-reverse}.flex-row-rev{flex-direction:row-reverse}
.flex-wrap{flex-wrap:wrap}.flex-nowrap{flex-wrap:nowrap}
.flex-1{flex:1}.flex-auto{flex:0 1 auto}.flex-none{flex:none}
.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}
.justify-between{justify-content:space-between}.justify-around{justify-content:space-around}.justify-evenly{justify-content:space-evenly}
.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}
.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}
.self-start{align-self:flex-start}.self-end{align-self:flex-end}.self-center{align-self:center}.self-stretch{align-self:stretch}
.content-start{align-content:flex-start}.content-end{align-content:flex-end}.content-center{align-content:center}
.content-between{align-content:space-between}.content-around{align-content:space-around}
.gap-0{gap:0}.gap-xs{gap:var(--gap-xs)}.gap-sm{gap:var(--gap-sm)}.gap-md{gap:var(--gap-md)}.gap{gap:var(--gap)}
.gap-lg{gap:var(--gap-lg)}.gap-xl{gap:var(--gap-xl)}.gap-2xl{gap:var(--gap-2xl)}
.col-1{flex:0 0 100%}.col-2{flex:0 0 50%}.col-3{flex:0 0 33.333%}
.col-4{flex:0 0 25%}.col-5{flex:0 0 20%}.col-6{flex:0 0 16.667%}
.grid{display:grid}
.grid-cols-1{grid-template-columns:repeat(1,1fr)}.grid-cols-2{grid-template-columns:repeat(2,1fr)}
.grid-cols-3{grid-template-columns:repeat(3,1fr)}.grid-cols-4{grid-template-columns:repeat(4,1fr)}
.grid-cols-5{grid-template-columns:repeat(5,1fr)}.grid-cols-6{grid-template-columns:repeat(6,1fr)}
.grid-auto-fit{grid-template-columns:repeat(auto-fit,minmax(200px,1fr))}
/* Position */
.relative{position:relative}.absolute{position:absolute}.fixed{position:fixed}.sticky{position:sticky}
.inset-0{inset:0}
/* Sizing */
.w-full{width:100%}.h-full{height:100%}
/* Overflow */
.overflow-hidden{overflow:hidden}.overflow-auto{overflow:auto}
/* Order (flex/grid children) */
.order-first{order:-1}.order-last{order:999}
@media(max-width:575px){.col-2,.col-3,.col-4,.col-5,.col-6{flex:0 0 100%}.sm\:flex-col{flex-direction:column}.sm\:flex-wrap{flex-wrap:wrap}.sm\:grid-cols-1{grid-template-columns:repeat(1,1fr)}}
@media(min-width:768px){.md\:col-2{flex:0 0 50%}.md\:col-3{flex:0 0 33.333%}.md\:col-4{flex:0 0 25%}.md\:col-5{flex:0 0 20%}.md\:col-6{flex:0 0 16.667%}.md\:grid-cols-2{grid-template-columns:repeat(2,1fr)}.md\:grid-cols-3{grid-template-columns:repeat(3,1fr)}.md\:grid-cols-4{grid-template-columns:repeat(4,1fr)}.md\:grid-cols-5{grid-template-columns:repeat(5,1fr)}.md\:grid-cols-6{grid-template-columns:repeat(6,1fr)}}
@media(min-width:1024px){.lg\:col-2{flex:0 0 50%}.lg\:col-3{flex:0 0 33.333%}.lg\:col-4{flex:0 0 25%}.lg\:col-5{flex:0 0 20%}.lg\:col-6{flex:0 0 16.667%}.lg\:grid-cols-3{grid-template-columns:repeat(3,1fr)}.lg\:grid-cols-4{grid-template-columns:repeat(4,1fr)}.lg\:grid-cols-5{grid-template-columns:repeat(5,1fr)}.lg\:grid-cols-6{grid-template-columns:repeat(6,1fr)}}
@media(min-width:1280px){.xl\:col-2{flex:0 0 50%}.xl\:col-3{flex:0 0 33.333%}.xl\:col-4{flex:0 0 25%}.xl\:col-5{flex:0 0 20%}.xl\:col-6{flex:0 0 16.667%}.xl\:grid-cols-3{grid-template-columns:repeat(3,1fr)}.xl\:grid-cols-4{grid-template-columns:repeat(4,1fr)}.xl\:grid-cols-5{grid-template-columns:repeat(5,1fr)}.xl\:grid-cols-6{grid-template-columns:repeat(6,1fr)}}
@media(min-width:1440px){.xxl\:col-2{flex:0 0 50%}.xxl\:col-3{flex:0 0 33.333%}.xxl\:col-4{flex:0 0 25%}.xxl\:col-5{flex:0 0 20%}.xxl\:col-6{flex:0 0 16.667%}.xxl\:grid-cols-3{grid-template-columns:repeat(3,1fr)}.xxl\:grid-cols-4{grid-template-columns:repeat(4,1fr)}.xxl\:grid-cols-5{grid-template-columns:repeat(5,1fr)}.xxl\:grid-cols-6{grid-template-columns:repeat(6,1fr)}}

} /* utilities */

@layer exsa.elements {

/* ── Inline text ── */
:where(.exsa p) {
  margin: var(--gap-md) 0;
  padding: 0;
}
:where(.exsa a) {
  color: var(--color-link);
  font-weight: bold;
  text-decoration: underline;
}
:where(.exsa a:visited) {
  color: var(--color-secondary);
}
:where(.exsa a:hover) {
  filter: brightness(var(--hover-brightness));
}
:where(.exsa a:active) {
  filter: brightness(var(--active-brightness));
}
:where(.exsa small:not([class])) {
  color: var(--color-text-secondary);
}
:where(.exsa mark:not([class])) {
  padding: calc(0.1rem * var(--space-factor, 1));
}
:where(.exsa kbd:not([class])) {
  background: var(--color-bg-secondary);
  border: 1px solid var(--color-border);
  border-radius: 3px;
  box-shadow: 0 1px 0 var(--color-border);
  font-family: var(--font-family-mono);
  font-size: .85em;
  padding: .15em .4em;
}
:where(.exsa abbr:not([class])) {
  cursor: help;
  text-decoration: underline dotted;
}
:where(.exsa del:not([class])) {
  color: var(--color-danger);
}
:where(.exsa ins:not([class])) {
  color: var(--color-success);
  text-decoration: none;
}
:where(.exsa cite:not([class])) {
  font-style: italic;
  color: var(--color-text-secondary);
}
:where(.exsa sup:not([class])) {
  background-color: var(--color-secondary);
  border-radius: var(--border-radius);
  color: var(--color-bg);
  font-size: xx-small;
  font-weight: bold;
  margin: calc(0.2rem * var(--space-factor, 1));
  padding: calc(0.2rem * var(--space-factor, 1)) calc(0.3rem * var(--space-factor, 1));
  vertical-align: super;
  position: relative;
}

/* ── Code ── */
:where(.exsa code) {
  background-color: var(--color-accent);
  border-radius: var(--border-radius);
  color: var(--color-text);
  display: inline-block;
  font-family: var(--font-family-mono);
  margin: 0 calc(0.1rem * var(--space-factor, 1));
  padding: 0 var(--gap-sm);
}
:where(.exsa pre) {
  font-family: var(--font-family-mono);
  margin: var(--gap) 0;
  max-width: var(--width-card-wide);
  padding: var(--gap);
  overflow: auto;
}
:where(.exsa pre code) {
  display: block;
  max-width: var(--width-card-wide);
  padding: var(--gap-sm) var(--gap-xl);
  white-space: pre-wrap;
}

/* ── Lists & dividers ──
   Guarded at the LIST level — a class on ul/ol opts the whole subtree out,
   so component lists (tree, sidebar, breadcrumbs, …) stop matching. */
:where(.exsa ol:not([class]) li),
:where(.exsa ul:not([class]) li) {
  padding: 0;
  padding-inline-start: 1.2em;
}
:where(.exsa hr) {
  background: var(--color-text);
  opacity: .12;
  border: none;
  height: 1px;
  margin: var(--gap-2xl) 0;
  width: 100%;
}
:where(.exsa details:not([class])) {
  margin: var(--gap) 0;
}
:where(.exsa details:not([class]) summary) {
  font-weight: bold;
  cursor: pointer;
}
:where(.exsa details:not([class]) details) {
  margin-inline-start: var(--gap-lg);
  border-inline-start: 2px solid var(--color-border);
  padding-inline-start: var(--gap);
}

/* ── Figure & caption ── */
:where(.exsa figure:not([class])) {
  margin: var(--gap-xl) auto;
  max-width: 100%;
  text-align: center;
}
:where(.exsa figure:not([class]) img),
:where(.exsa figure:not([class]) svg),
:where(.exsa figure:not([class]) video) {
  max-width: 100%;
  height: auto;
  display: block;
  margin: 0 auto;
}
:where(.exsa figure:not([class]) figcaption) {
  color: var(--color-text-secondary);
  font-size: var(--font-size-sm);
  margin-top: var(--gap-sm);
}

/* ── Structural containers ──
   Guarded — a class on header/main/footer opts the WHOLE subtree out. */
:where(.exsa header:not([class])),
:where(.exsa main:not([class])),
:where(.exsa footer:not([class])) {
  margin: 0 auto;
  max-width: var(--width-content);
  padding: var(--gap-2xl) var(--gap);
  text-align: var(--justify-heading);
}
:where(.exsa main:not([class])) {
  text-align: var(--justify-body);
}
:where(.exsa article header),
:where(.exsa div header),
:where(.exsa main header) {
  padding-top: 0;
}
:where(.exsa header:not([class]) nav img) {
  margin: var(--gap) 0;
}

/* ── Section (container queries on classless sections only) ── */
:where(.exsa section:not([class])) {
  container-type: inline-size;
  display: flex;
  flex-wrap: wrap;
  justify-content: var(--justify-heading);
}
:where(.exsa section header) {
  padding-top: 0;
  width: 100%;
}
:where(.exsa section img),
:where(.exsa article img) {
  max-width: 100%;
}
:where(.exsa section pre) {
  overflow: auto;
}

/* ── Card (<section> <aside>) ── */
:where(.exsa section:not([class]) aside) {
  --card-padding: var(--gap-lg);
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius);
  box-shadow: var(--box-shadow) var(--color-shadow);
  margin: var(--gap);
  padding: var(--card-padding);
  width: var(--width-card);
}
:where(.exsa section:not([class]) aside:hover) {
  box-shadow: var(--box-shadow) var(--color-bg-secondary);
}
/* Full-bleed image at top of card — flush with edges */
:where(.exsa section:not([class]) aside > svg:first-child),
:where(.exsa section:not([class]) aside > img:first-child):not(:only-child) {
  display: block;
  width: calc(100% + var(--card-padding) * 2);
  max-width: calc(100% + var(--card-padding) * 2);
  height: auto;
  margin: calc(var(--card-padding) * -1) calc(var(--card-padding) * -1) var(--gap) calc(var(--card-padding) * -1);
  border-radius: var(--border-radius) var(--border-radius) 0 0;
}
@container (max-width: 320px) {
  :where(.exsa section:not([class]) aside) {
    --card-padding: var(--gap-md);
    margin: var(--gap-sm);
    padding: var(--card-padding);
    width: auto;
  }
}
@container (min-width: 500px) {
  :where(.exsa section:not([class]) aside) {
    padding: var(--gap-lg);
  }
}

/* Classless horizontal card — :has() auto-detects <img>/<figure>/<video> */
:where(.exsa section:not([class]) aside:has(> img, > figure, > video)) {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: stretch;
  width: auto;
  padding: 0;
  overflow: hidden;
}
:where(.exsa section:not([class]) aside:has(> img, > figure, > video)) > img,
:where(.exsa section:not([class]) aside:has(> img, > figure, > video)) > figure,
:where(.exsa section:not([class]) aside:has(> img, > figure, > video)) > video {
  width: clamp(150px, 30vw, 260px);
  height: calc(100% + 2px);
  margin: calc(-1px * var(--space-factor, 1)) 0;
  padding: 0;
  align-self: stretch;
  border-radius: var(--border-radius) 0 0 var(--border-radius);
  overflow: hidden;
}
:where(.exsa section:not([class]) aside:has(> img, > figure, > video)) > img,
:where(.exsa section:not([class]) aside:has(> img, > figure, > video)) > video {
  object-fit: cover;
}
:where(.exsa section:not([class]) aside:has(> img, > figure)) > figure img,
:where(.exsa section:not([class]) aside:has(> img, > figure)) > figure svg,
:where(.exsa section:not([class]) aside:has(> img, > figure)) > figure video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Content area — wrapping <div> */
:where(.exsa section:not([class]) aside:has(> img, > figure, > video)) > div {
  padding: var(--gap-lg);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
/* Content card — aside with wrapper <div> but no media (shares row with siblings) */
:where(.exsa section:not([class]) aside:has(> div)):not(:has(> img)):not(:has(> figure)):not(:has(> video)) {
  flex: 1;
  min-width: 260px;
  padding: var(--gap-lg);
}
/* No <div> wrapper fallback — text children wrap and stack */
:where(.exsa section:not([class]) aside:has(> img, > figure)):not(:has(> div)) {
  grid-template-columns: auto 1fr;
  overflow: hidden;
}
:where(.exsa section:not([class]) aside:has(> img, > figure)):not(:has(> div)) > :not(img):not(figure) {
  margin: 0 var(--gap-lg);
}
:where(.exsa section:not([class]) aside:has(> img, > figure)):not(:has(> div)) > :is(h1,h2,h3,h4,h5,h6):first-of-type {
  margin-top: var(--gap-lg);
}
:where(.exsa section:not([class]) aside:has(> img, > figure)):not(:has(> div)) > p:last-of-type {
  margin-bottom: var(--gap-lg);
}

/* Collapse to vertical on narrow containers */
@container (max-width: 380px) {
  :where(.exsa section:not([class]) aside:has(> img, > figure)) {
    grid-template-columns: 1fr;
  }
  :where(.exsa section:not([class]) aside:has(> img, > figure)) > img,
  :where(.exsa section:not([class]) aside:has(> img, > figure)) > figure {
    width: 100%;
    height: auto;
    max-height: 220px;
  }
}

/* ── Callout (<article> <aside>) ── */
:where(.exsa article:not([class]) > aside) {
  background: var(--callout-bg, var(--color-secondary-accent));
  border-inline-start: 4px solid var(--callout-accent, var(--color-secondary));
  border-radius: var(--border-radius);
  padding: var(--gap) var(--gap-lg);
  margin: var(--gap) 0;
  color: var(--color-text-secondary);
  font-size: .9rem;
  line-height: 1.6;
}
:where(.exsa article:not([class]) > aside p) {
  margin: 0;
}
:where(.exsa article:not([class]) > aside p + p) {
  margin-top: var(--gap-sm);
}
:where(.exsa article:not([class]) > aside strong) {
  color: var(--callout-accent, var(--color-secondary));
}
:where(.exsa article:not([class]) > aside code) {
  font-family: var(--font-family-mono);
  font-size: .85em;
  background: var(--color-bg-secondary);
  padding: calc(1px * var(--space-factor, 1)) calc(6px * var(--space-factor, 1));
  border-radius: 3px;
  color: var(--color-text);
}
:where(.exsa article:not([class]) > aside a) {
  color: var(--callout-accent, var(--color-secondary));
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ── Nav ── */
:where(.exsa nav:not([class])) {
  align-items: center;
  display: flex;
  font-weight: bold;
  justify-content: var(--justify-nav, space-between);
  margin-bottom: var(--gap-xl);
}
:where(.exsa nav:not([class]) ul:not([class])) {
  list-style: none;
  padding: 0;
}
:where(.exsa nav:not([class]) ul:not([class]) li) {
  display: inline-block;
  margin: 0 var(--gap-sm);
  text-align: start;
}
@media (max-width: 768px) {
  :where(.exsa nav:not([class])) {
    flex-wrap: wrap;
  }
  :where(.exsa nav:not([class]) ul:not([class]) li) {
    width: calc(100% - 1em);
  }
}

/* ── Table ── */
:where(.exsa table:not([class])) {
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius);
  border-spacing: 0;
  border-collapse: separate;
  display: table;
  width: 100%;
  max-width: 100%;
  padding: 0;
  font-size: .84rem; /* deliberate — sits between --font-size-sm (.78rem) and --font-size-base (.88rem) */
  color: var(--color-text);
}
:where(.exsa table:not([class]) td),
:where(.exsa table:not([class]) th) {
  padding: calc(0.4rem * var(--space-factor, 1)) calc(0.8rem * var(--space-factor, 1));
  text-align: var(--justify-heading);
}
:where(.exsa table:not([class]) thead) {
  background-color: var(--color-link);
  border-collapse: collapse;
  border-radius: var(--border-radius);
  color: var(--color-bg);
  margin: 0;
  padding: 0;
}
:where(.exsa table:not([class]) thead tr:first-child th:first-child) {
  border-start-start-radius: var(--border-radius);
}
:where(.exsa table:not([class]) thead tr:first-child th:last-child) {
  border-start-end-radius: var(--border-radius);
}
:where(.exsa table:not([class]) thead th:first-child),
:where(.exsa table:not([class]) tr td:first-child) {
  text-align: var(--justify-body);
}

/* ── Form ── */
:where(.exsa form:not([class])) {
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius);
  box-shadow: var(--box-shadow) var(--color-shadow);
  display: block;
  max-width: var(--width-card-wide);
  min-width: var(--width-card);
  padding: calc(1.5rem * var(--space-factor, 1));
  text-align: var(--justify-body);
}
:where(.exsa form:not([class]) header) {
  margin: calc(1.5rem * var(--space-factor, 1)) 0;
  padding: calc(1.5rem * var(--space-factor, 1)) 0;
}
:where(.exsa form:not([class]) label) {
  display: block;
  font-weight: bold;
  margin-bottom: calc(0.2rem * var(--space-factor, 1));
}
:where(.exsa form:not([class]) input),
:where(.exsa form:not([class]) select),
:where(.exsa form:not([class]) textarea) {
  background-color: var(--color-bg);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius);
  display: block;
  font-size: inherit;
  margin-bottom: calc(1rem * var(--space-factor, 1));
  max-width: var(--width-card-wide);
  padding: calc(0.4rem * var(--space-factor, 1)) calc(0.8rem * var(--space-factor, 1));
}
:where(.exsa form:not([class]) input[type=checkbox]),
:where(.exsa form:not([class]) input[type=radio]) {
  display: inline-block;
}
:where(.exsa form:not([class]) input[type=checkbox] + label),
:where(.exsa form:not([class]) input[type=radio] + label) {
  display: inline-block;
  font-weight: normal;
  position: relative;
  top: 1px;
}
:where(.exsa form:not([class]) input[type=range]) {
  padding: calc(0.4rem * var(--space-factor, 1)) 0;
}
:where(.exsa form:not([class]) input[type=text]),
:where(.exsa form:not([class]) input:not([type])),
:where(.exsa form:not([class]) input[type=password]),
:where(.exsa form:not([class]) input[type=email]),
:where(.exsa form:not([class]) input[type=search]),
:where(.exsa form:not([class]) textarea) {
  width: 100%;
}
:where(.exsa form:not([class]) input[readonly]),
:where(.exsa form:not([class]) textarea[readonly]) {
  background-color: var(--color-bg-secondary);
}
:where(.exsa form:not([class]) input[type=file]) {
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius);
  font-size: inherit;
  max-width: var(--width-card-wide);
  padding: calc(0.3rem * var(--space-factor, 1));
}

/* Fieldset */
:where(.exsa form:not([class]) fieldset) {
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius);
  margin: 0 0 calc(1rem * var(--space-factor, 1));
  padding: var(--gap-lg) var(--gap) var(--gap);
}
:where(.exsa form:not([class]) fieldset legend) {
  font-weight: bold;
  padding: 0 var(--gap-sm);
}

/* Validation states */
:where(.exsa form:not([class]) input:invalid:not(:placeholder-shown)),
:where(.exsa form:not([class]) textarea:invalid:not(:placeholder-shown)) {
  border-color: var(--color-danger);
}
:where(.exsa form:not([class]) input:valid:not(:placeholder-shown)),
:where(.exsa form:not([class]) textarea:valid:not(:placeholder-shown)) {
  border-color: var(--color-success);
}

/* ── Progress & Meter ── */
:where(.exsa progress),
:where(.exsa meter) {
  width: 100%;
  height: .8rem;
  border-radius: var(--border-radius);
  overflow: hidden;
}
:where(.exsa progress)::-webkit-progress-bar,
:where(.exsa meter)::-webkit-meter-bar {
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius);
}
:where(.exsa progress)::-webkit-progress-value {
  background: var(--color-link);
  border-radius: var(--border-radius);
}
:where(.exsa meter)::-webkit-meter-optimum-value {
  background: var(--color-success);
  border-radius: var(--border-radius);
}
:where(.exsa meter)::-webkit-meter-suboptimum-value {
  background: var(--color-warning);
  border-radius: var(--border-radius);
}
:where(.exsa meter)::-webkit-meter-even-less-good-value {
  background: var(--color-danger);
  border-radius: var(--border-radius);
}
:where(.exsa progress)::-moz-progress-bar {
  background: var(--color-link);
  border-radius: var(--border-radius);
}
:where(.exsa meter)::-moz-meter-bar {
  background: var(--color-success);
  border-radius: var(--border-radius);
}

/* ── Blockquote ── */
:where(.exsa blockquote:not([class])) {
  border-inline-start: var(--blockquote-border, 4px solid var(--color-secondary));
  display: block;
  font-size: x-large;
  line-height: var(--line-height);
  margin: calc(1rem * var(--space-factor, 1)) auto;
  max-width: var(--width-card-medium);
  padding: calc(1rem * var(--space-factor, 1)) calc(1.5rem * var(--space-factor, 1));
  text-align: var(--justify-heading);
}
:where(.exsa blockquote:not([class]) footer) {
  color: var(--color-text-secondary);
  display: block;
  font-size: small;
  line-height: var(--line-height);
  padding: calc(1.5rem * var(--space-factor, 1)) 0;
}

/* ── Dialog ── */
:where(.exsa dialog:not([class])) {
  max-width: 90%;
  max-height: 85dvh;
  margin: auto;
  padding-block: 0;
  padding-inline: calc(20px * var(--space-factor, 1));
  border: 1px solid var(--color-border);
  border-radius: .5rem;
  overscroll-behavior: contain;
  scroll-behavior: smooth;
  animation: dialog-enter .25s ease-in-out forwards;
}
:where(.exsa dialog:not([class]))::backdrop {
  background-color: var(--color-overlay);
}
@keyframes dialog-enter {
  from {
    opacity: 0;
    transform: translateY(10%);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
:where(.exsa dialog:not([class]) hr) {
  margin-block: calc(1rem * var(--space-factor, 1));
}

/* ── Button ── */
:where(.exsa button:not([class])) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(6px * var(--space-factor, 1));
  font-family: inherit;
  font-size: var(--font-size-base);
  font-weight: 600;
  line-height: 1;
  padding: calc(10px * var(--space-factor, 1)) calc(20px * var(--space-factor, 1));
  border-radius: var(--border-radius);
  border: 2px solid var(--color-border);
  background: var(--color-bg);
  color: var(--color-button-text-inverse);
  cursor: pointer;
  transition: background .15s, border-color .15s, transform .1s;
  text-decoration: none;
  white-space: nowrap;
  user-select: none;
}
:where(.exsa button:not([class]):hover) {
  background: var(--color-bg-secondary);
  border-color: var(--color-text-secondary);
}
:where(.exsa button:not([class]):active) {
  transform: scale(.97);
}
:where(.exsa button:not([class]):disabled) {
  cursor: not-allowed;
  opacity: .5;
  transform: none;
}

/* ── Guarded Structural Detection ── */
/* Card grid — 3+ articles in a section */
:where(.exsa section:not([class]):has(> article:not([class]):nth-child(3))) {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--gap);
}
:where(.exsa section:not([class]):has(> article:not([class]):nth-child(3)) > article:not([class])) {
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius);
  box-shadow: var(--box-shadow) var(--color-shadow);
  padding: var(--gap-lg);
  margin: 0;
}

/* Gallery — 2+ figures in a section (exclude sections with articles/asides) */
:where(.exsa section:not([class]):has(> figure:nth-child(2))):not(:has(> aside)):not(:has(> article)) {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--gap-sm);
}
:where(.exsa section:not([class]):has(> figure:nth-child(2))):not(:has(> aside)):not(:has(> article)) > figure {
  margin: 0;
}

/* Sidebar — aside as first child of main */
:where(.exsa main:not([class]):has(> aside:first-child)) {
  display: grid;
  grid-template-columns: clamp(220px, 25%, 300px) 1fr;
  gap: var(--gap-lg);
  align-items: start;
}

/* Hero split — header inside <main> that contains an image/figure/svg/video */
:where(.exsa main header:not([class]):has(> img, > figure, > svg, > video)) {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap-xl);
  align-items: center;
  max-width: none;
}

/* Full-width header — header outside <main> (direct child of body) */
:where(body.exsa > header:not([class])) {
  max-width: none;
}

/* Nav flush with hero — when nav is directly followed by header */
:where(.exsa nav:has(+ header:not([class]))) {
  margin-bottom: 0;
}

/* Stats row — 3+ sibling paragraphs in a section */
:where(.exsa section:not([class]):has(> p:nth-child(3))):not(:has(> aside)):not(:has(> article)) {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--gap);
  text-align: center;
}
:where(.exsa section:not([class]):has(> p:nth-child(3))):not(:has(> aside)):not(:has(> article)) > p {
  border: 1px solid var(--color-border);
  border-radius: var(--border-radius);
  padding: var(--gap-lg) var(--gap);
  margin: 0;
}

} /* elements */

@layer exsa.overrides {

/* ── Override utilities — force-win: u-* always beats components/layouts.
   Unlayered user CSS still beats everything here. ── */

.u-text-start{text-align:start}
.u-text-center{text-align:center}
.u-text-end{text-align:end}
.u-block{display:block}
.u-flex{display:flex}
.u-inline-flex{display:inline-flex}
.u-none{display:none}
.u-w-full{width:100%}
.u-w-auto{width:auto}
.u-m-0{margin:0}
.u-p-0{padding:0}
.u-mx-auto{margin-inline:auto}
.u-gap-0{gap:0}
.u-gap-sm{gap:var(--gap-sm)}
.u-gap{gap:var(--gap)}
.u-gap-lg{gap:var(--gap-lg)}
.u-radius-0{border-radius:0}
.u-radius-full{border-radius:9999px}
/* Typography escape hatches (re-homed from exsa.utilities — the unprefixed
   versions lost to elements/components, these always win) */
.u-text-xs{font-size:var(--font-size-xs)}.u-text-sm{font-size:var(--font-size-sm)}.u-text-base{font-size:var(--font-size-base)}.u-text-md{font-size:var(--font-size-md)}.u-text-lg{font-size:var(--font-size-lg)}.u-text-xl{font-size:var(--font-size-xl)}.u-text-2xl{font-size:var(--font-size-2xl)}
.u-fw-normal{font-weight:var(--font-weight-normal)}.u-fw-bold{font-weight:var(--font-weight-bold)}.u-fw-heavy{font-weight:var(--font-weight-heavy)}
.u-font-sans{font-family:var(--font-family)}.u-font-mono{font-family:var(--font-family-mono)}.u-font-heading{font-family:var(--font-family-heading)}
.u-italic{font-style:italic}.u-uppercase{text-transform:uppercase}.u-capitalize{text-transform:capitalize}.u-text-muted{color:var(--color-text-secondary)}
.u-text-left{text-align:left}.u-text-right{text-align:right}
.u-fluid-type{--font-size-base:clamp(.85rem,.8rem + .25vw,1rem);--font-size-xl:clamp(1.2rem,1.1rem + .5vw,1.5rem);--font-size-2xl:clamp(1.6rem,1.4rem + 1vw,2.2rem)}

/* Crash-prevention: reduced-motion users never get backdrop blur, whatever
   skin is active (overrides beats skins layer 3). */
@media (prefers-reduced-motion: reduce) {
  :root { --surface-backdrop: none; }
}

} /* overrides */

/* --- accordion.css --- */
@layer exsa.components {

/* ============================================================
   Component: Accordion
   Two APIs — use either, both work:

   1. <details>/<summary> (RECOMMENDED — native a11y, zero JS)
      <details class="accordion__item">
        <summary class="accordion__label">Title</summary>
        <div class="accordion__panel"><div class="accordion__panel-inner">...</div></div>
      </details>

   2. Checkbox hack (legacy — needs JS for aria-expanded sync)
      <div class="accordion__item">
        <input type="checkbox" id="a1" class="accordion__trigger">
        <label for="a1" class="accordion__label">Title</label>
        <div class="accordion__panel"><div class="accordion__panel-inner">...</div></div>
      </div>

   ARIA: <details> handles aria-expanded natively. For checkbox hack,
   js/accordion.js syncs aria-expanded on checkbox change.
   ============================================================ */

.accordion{border:var(--surface-border);border-radius:var(--surface-radius);overflow:hidden}
.accordion__item{border-bottom:1px solid var(--color-bg-secondary)}
.accordion__item:last-child{border-bottom:none}

/* ── <details>/<summary> — recommended ── */
.accordion details.accordion__item summary::-webkit-details-marker{display:none}
.accordion details.accordion__item summary{list-style:none}
.accordion details.accordion__item[open] > .accordion__label{color:var(--color-link)}
.accordion details.accordion__item[open] > .accordion__label::after{transform:rotate(45deg)}
.accordion details.accordion__item > .accordion__panel{max-height:0;overflow:hidden;transition:max-height .35s ease,padding .35s ease}
.accordion details.accordion__item[open] > .accordion__panel{max-height:2000px}

/* ── Checkbox hack — legacy ── */
.accordion__trigger{display:none}
.accordion__label{display:flex;align-items:center;justify-content:space-between;padding: calc(14px * var(--space-factor, 1)) calc(18px * var(--space-factor, 1));font-size:.9rem;font-weight:600;color:var(--color-text);cursor:pointer;user-select:none;transition:background .15s,color .15s;gap: calc(12px * var(--space-factor, 1))}
.accordion__label:hover{background:var(--color-bg-secondary)}
.accordion__label::after{content:'+';font-size:1.2rem;font-weight:400;color:var(--color-text-secondary);transition:transform .25s;flex-shrink:0}
.accordion__trigger:checked + .accordion__label,
.accordion__label[aria-expanded="true"]{color:var(--color-link)}
.accordion__trigger:checked + .accordion__label::after,
.accordion__label[aria-expanded="true"]::after{transform:rotate(45deg)}
.accordion__panel{max-height:0;overflow:hidden;transition:max-height .35s ease,padding .35s ease}
.accordion__panel-inner{padding: 0 calc(18px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));font-size:.84rem;color:var(--color-text-secondary);line-height:1.7}
.accordion__trigger:checked ~ .accordion__panel,
.accordion__label[aria-expanded="true"] ~ .accordion__panel{max-height:2000px}

/* Compact variant */
.accordion--sm .accordion__label{padding: calc(10px * var(--space-factor, 1)) calc(14px * var(--space-factor, 1));font-size:.82rem}
.accordion--sm .accordion__panel-inner{padding: 0 calc(14px * var(--space-factor, 1)) calc(12px * var(--space-factor, 1));font-size:.78rem}

}

/* --- drawer.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: aria-expanded on toggle, role=dialog + aria-modal on panel
   Component: Drawer
   ============================================================ */

/* --- C2: DRAWER --- */
.drawer__toggle{display:none}
.drawer__backdrop{position:fixed;inset:0;z-index:var(--z-drawer);background:var(--color-overlay);opacity:0;visibility:hidden;transition:opacity .25s,visibility .25s}
.drawer__toggle:checked ~ .drawer__backdrop{opacity:1;visibility:visible}
.drawer__panel{position:fixed;top:0;inset-inline-end:0;z-index:var(--z-drawer-panel);width:360px;max-width:88vw;height:100%;background:var(--surface-bg);box-shadow:var(--surface-shadow-side);transform:translateX(100%);transition:transform .3s cubic-bezier(.4,0,.2,1);display:flex;flex-direction:column;overflow-y:auto}
.drawer__toggle:checked ~ .drawer__panel{transform:translateX(0)}
.drawer__head{display:flex;align-items:center;justify-content:space-between;padding: calc(16px * var(--space-factor, 1)) calc(20px * var(--space-factor, 1));border-bottom:1px solid var(--color-bg-secondary);flex-shrink:0}
.drawer__title{font-size:1rem;font-weight:700;color:var(--color-text);margin:0}
.drawer__close{width:32px;height:32px;border-radius:50%;border:none;background:transparent;color:var(--color-text-secondary);font-size:1.2rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s,color .15s;padding:0;margin:0}
.drawer__close:hover{background:var(--color-bg-secondary);color:var(--color-text)}
.drawer__body{padding: calc(20px * var(--space-factor, 1));flex:1;font-size:.88rem;color:var(--color-text);line-height:1.65}
.drawer__body p{margin: calc(0.5rem * var(--space-factor, 1)) 0;width:auto}

/* Left variant */
.drawer--left .drawer__panel{inset-inline-end:auto;inset-inline-start:0;transform:translateX(-100%)}
.drawer--left .drawer__toggle:checked ~ .drawer__panel{transform:translateX(0)}

/* RTL: flip slide direction (translateX is physical, must override) */
[dir="rtl"] .drawer__panel{transform:translateX(-100%)}
[dir="rtl"] .drawer--left .drawer__panel{transform:translateX(100%)}
[dir="rtl"] .drawer__toggle:checked ~ .drawer__panel{transform:translateX(0)}

}

/* --- footer.css --- */
@layer exsa.components {

/* ============================================================
   Footer
   Multi-column site footer with brand, links, and copyright.
   Token-driven — uses --color-bg, --color-bg-secondary.
   ============================================================ */

.footer {
  background: var(--color-bg-secondary);
  border-top: 1px solid var(--color-bg-secondary);
  padding: calc(3rem * var(--space-factor, 1)) 0 0;
  margin-top: calc(3rem * var(--space-factor, 1));
  font-size: 0.88rem;
  color: var(--color-text-secondary);
}

.footer__inner {
  max-width: var(--width-content);
  margin: 0 auto;
  padding: 0 var(--gap);
}

.footer__grid {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap-lg);
  padding-bottom: calc(2rem * var(--space-factor, 1));
}

/* ── Brand column ── */
.footer__brand {
  flex: 1 1 240px;
  min-width: 200px;
}
.footer__logo {
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--color-text);
  margin-bottom: calc(0.5rem * var(--space-factor, 1));
}
.footer__logo span { color: var(--color-link); }
.footer__tagline {
  font-size: 0.82rem;
  color: var(--color-text-secondary);
  line-height: 1.6;
  max-width: 280px;
}

/* ── Link columns ── */
.footer__links {
  flex: 1 1 160px;
  min-width: 140px;
}
.footer__links-title {
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text);
  margin-bottom: calc(0.8rem * var(--space-factor, 1));
}
.footer__links a {
  display: block;
  color: var(--color-text-secondary);
  text-decoration: none;
  font-weight: 400;
  padding: calc(0.25rem * var(--space-factor, 1)) 0;
  font-size: 0.84rem;
  transition: color 0.15s;
}
.footer__links a:hover {
  color: var(--color-link);
}

/* ── Bottom bar ── */
.footer__bottom {
  border-top: 1px solid var(--color-bg);
  padding: calc(1.2rem * var(--space-factor, 1)) 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: calc(0.5rem * var(--space-factor, 1));
  font-size: 0.78rem;
}
.footer__bottom a {
  color: var(--color-text-secondary);
  text-decoration: none;
  font-weight: 400;
}
.footer__bottom a:hover { color: var(--color-link); }

/* ── Mobile ── */
@media (max-width: 600px) {
  .footer { padding-top: calc(2rem * var(--space-factor, 1)); }
  .footer__grid { gap: var(--gap); flex-direction: column; }
  .footer__brand { flex: 1 1 auto; }
  .footer__links { flex: 1 1 auto; }
  .footer__bottom { flex-direction: column; text-align: center; }
}

}

/* --- modal.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: role=dialog + aria-modal + aria-labelledby on .modal
   Component: Modal
   ============================================================ */

/* --- C3: MODAL WINDOW --- */
.modal{position:fixed;inset:0;z-index:var(--z-modal);background:var(--color-overlay);display:flex;align-items:center;justify-content:center;opacity:0;visibility:hidden;transition:opacity .22s,visibility .22s}
.modal--open{opacity:1;visibility:visible}
.modal__dialog{position:relative;width:90%;max-width:520px;max-height:85vh;background:var(--surface-bg);border-radius:var(--surface-radius);box-shadow:var(--surface-shadow-lg);transform:translateY(16px);transition:transform .28s cubic-bezier(.4,0,.2,1);overflow:hidden;display:flex;flex-direction:column}
.modal--open .modal__dialog{transform:translateY(0)}
.modal__header{display:flex;align-items:center;justify-content:space-between;padding: calc(16px * var(--space-factor, 1)) calc(20px * var(--space-factor, 1));border-bottom:1px solid var(--color-bg-secondary);flex-shrink:0}
.modal__title{font-size:1rem;font-weight:700;color:var(--color-text);margin:0}
.modal__close{width:32px;height:32px;border-radius:50%;border:none;background:transparent;color:var(--color-text-secondary);font-size:1.1rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s,color .15s;padding:0;line-height:1;margin:0}
.modal__close:hover{background:var(--color-bg-secondary);color:var(--color-text)}
.modal__body{padding: calc(20px * var(--space-factor, 1));overflow-y:auto;flex:1;font-size:.88rem;color:var(--color-text);line-height:1.65}
.modal__footer{display:flex;justify-content:flex-end;gap: calc(10px * var(--space-factor, 1));padding: calc(14px * var(--space-factor, 1)) calc(20px * var(--space-factor, 1));border-top:1px solid var(--color-bg-secondary);flex-shrink:0}
.modal__btn{padding: calc(8px * var(--space-factor, 1)) calc(18px * var(--space-factor, 1));border-radius:var(--surface-radius);font-size:.82rem;font-weight:600;cursor:pointer;border:var(--surface-border-control);background:var(--surface-bg);color:var(--color-text);transition:background .15s,color .15s,border-color .15s;font-family:inherit;margin:0}
.modal__btn:hover{background:var(--color-bg-secondary)}
.modal__btn--primary{background:var(--color-link);color:var(--color-button-text);border-color:var(--color-link)}
.modal__btn--primary:hover{opacity:.88;filter:none}
.modal__btn--danger{color:var(--color-danger);border-color:var(--color-danger)}
.modal__btn--danger:hover{background:var(--color-danger);color:var(--color-button-text);filter:none}

}

/* --- pricing-table.css --- */
@layer exsa.components {

/* ============================================================
   Component: Pricing Table
   ============================================================ */

/* --- C4: PRICING TABLE --- */
.pricing{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap: calc(20px * var(--space-factor, 1));align-items:start}
.pricing__card{background:var(--surface-bg);border:var(--surface-border);border-radius:var(--surface-radius);padding: calc(20px * var(--space-factor, 1)) calc(20px * var(--space-factor, 1));text-align:center;transition:box-shadow .25s,transform .25s;position:relative;}
.pricing__card:hover{box-shadow:var(--surface-shadow-sm)}
.pricing__card--featured{border-color:var(--color-link);box-shadow:0 0 0 1px var(--color-link),var(--surface-shadow-sm);transform:scale(1.03);z-index:1}
.pricing__card--featured:hover{transform:scale(1.04)}
.pricing__badge{position:absolute;top:-11px;left:50%;transform:translateX(-50%);background:var(--color-link);color:var(--color-button-text);font-size:.66rem;font-weight:700;letter-spacing:.06em;text-transform:uppercase;padding: calc(3px * var(--space-factor, 1)) calc(14px * var(--space-factor, 1));border-radius:99px;white-space:nowrap}
.pricing__name{font-size:.75rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--color-text-secondary);margin-bottom: calc(8px * var(--space-factor, 1))}
.pricing__price{font-size:2.2rem;font-weight:var(--font-weight-heavy);color:var(--color-text);line-height:1;margin-bottom: calc(2px * var(--space-factor, 1))}
.pricing__price sup{font-size:1rem;font-weight:600;vertical-align:super;background:transparent;color:var(--color-text);padding:0;margin:0;border-radius:0;position:static;top:auto}
.pricing__period{font-size:.72rem;color:var(--color-text-secondary);margin-bottom: calc(14px * var(--space-factor, 1))}
.pricing__features{list-style:none;padding:0;margin: 0 0 calc(18px * var(--space-factor, 1));text-align: start}
.pricing__features li{padding: calc(5px * var(--space-factor, 1)) 0;font-size:.8rem;color:var(--color-text);border-bottom:1px solid var(--color-bg-secondary)}
.pricing__features li:last-child{border-bottom:none}
.pricing__features li::before{content:'✓ ';color:var(--color-link);font-weight:700;margin-right: calc(4px * var(--space-factor, 1))}
.pricing__features .pricing__feature--na{color:var(--color-text-secondary);text-decoration:line-through}
.pricing__features .pricing__feature--na::before{content:'✕ ';color:var(--color-text-secondary)}
.pricing__btn{display:block;width:100%;padding: calc(8px * var(--space-factor, 1)) 0;border-radius:var(--surface-radius);font-size:.82rem;font-weight:700;cursor:pointer;border:1px solid var(--color-link);background:transparent;color:var(--color-link);transition:background .18s,color .18s;font-family:inherit;text-align:center;margin:0}
.pricing__btn:hover{background:var(--color-link);color:var(--color-button-text);filter:none}
.pricing__card--featured .pricing__btn{background:var(--color-link);color:var(--color-button-text)}
.pricing__card--featured .pricing__btn:hover{opacity:.88;filter:none}

}

/* --- hero.css --- */
@layer exsa.components {

/* ============================================================
   EXSA Hero — video background overlay for full-width headers

   Link AFTER exsa.css + your theme:
   <link rel="stylesheet" href="components/hero.css">

   Detects: <header> outside <main> with <figure> containing
   <img>/<video>/<svg>. Positions media as a full-bleed
   background layer with text centered on top.

   To customize: override --hero-height (default: 60vh),
   --hero-overlay (default: brand-color gradient), or
   add your own gradient/color in your theme.
   ============================================================ */

:root {
  --hero-height: 60vh;
  --hero-overlay: linear-gradient(135deg, rgba(17,139,238,0.5) 0%, rgba(146,13,233,0.45) 100%);
}

/* Video/image background: figure fills entire hero */
:where(body.exsa > header:not([class]):has(> figure)) {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  min-height: var(--hero-height);
  max-width: none;
  padding: 0;
  position: relative;
  overflow: hidden;
}

/* Figure: absolute fill, behind text */
:where(body.exsa > header:not([class]) > figure) {
  position: absolute;
  inset: 0;
  z-index: 0;
  border-radius: 0;
  margin: 0;
}

/* Media fills figure, crops to fit */
:where(body.exsa > header:not([class]) > figure) > img,
:where(body.exsa > header:not([class]) > figure) > video,
:where(body.exsa > header:not([class]) > figure) > svg {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Gradient overlay for text readability — override --hero-overlay to customize */
:where(body.exsa > header:not([class]) > figure)::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--hero-overlay);
  z-index: 1;
}

/* Text content: above video, centered */
:where(body.exsa > header:not([class]) > div),
:where(body.exsa > header:not([class]) > :not(figure):not(div):not(button)) {
  position: relative;
  z-index: 2;
  text-align: center;
  padding: 0 var(--gap);
}

/* Buttons: never stretch, keep their own padding */
:where(body.exsa > header:not([class]) > button) {
  position: relative;
  z-index: 2;
  align-self: center;
}

/* Light text on dark background */
:where(body.exsa > header:not([class])) {
  color: #fff;
}
:where(body.exsa > header:not([class])) h1,
:where(body.exsa > header:not([class])) h2,
:where(body.exsa > header:not([class])) h3,
:where(body.exsa > header:not([class])) p {
  color: #fff;
}

/* Inverted button for visibility */
:where(body.exsa > header:not([class]) button:not([class])) {
  background: #fff;
  color: var(--color-link);
  border-color: #fff;
}

}

/* --- sidebar.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: aria-expanded on submenu toggles, role=navigation on .sidebar
   Sidebar Navigation
   Vertical nav with icons, sub-menus, active states.
   Token-driven — uses EXSA tokens, not hardcoded colors.
   Adapted from admin dashboard sidebar pattern.
   ============================================================ */

.sidebar {
  width: 240px;
  height: 100%;
  background: var(--color-bg);
  border-inline-end: 1px solid var(--color-bg-secondary);
  overflow-y: auto;
  overflow-x: hidden;
  font-family: inherit;
  position: relative;
  z-index: 10;
}
.sidebar::-webkit-scrollbar { width: 4px; }
.sidebar::-webkit-scrollbar-track { background: transparent; }
.sidebar::-webkit-scrollbar-thumb { background: var(--color-bg-secondary); border-radius: 2px; }

/* ── Optional header slot (logo, search, theme picker, etc.) ── */
.sidebar__head {
  padding: calc(18px * var(--space-factor, 1));
  border-bottom: 1px solid var(--color-bg-secondary);
  flex-shrink: 0;
}

/* ── Nav list ── */
.sidebar__nav,
.sidebar__nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
}
.sidebar__nav li {
  border-bottom: 1px solid var(--color-bg-secondary);
  padding: 0;
}

/* ── Links ── */
.sidebar__link {
  display: flex;
  align-items: center;
  gap: calc(10px * var(--space-factor, 1));
  padding: calc(14px * var(--space-factor, 1)) calc(20px * var(--space-factor, 1));
  font-size: 0.84rem;
  font-weight: 500;
  color: var(--color-text-secondary);
  text-decoration: none;
  cursor: pointer;
  transition: color 0.2s, background 0.2s;
  border: none;
  background: none;
  width: 100%;
  text-align: start;
  font-family: inherit;
  line-height: 1.4;
  position: relative;
}
.sidebar__link:hover {
  color: var(--color-link);
  background: color-mix(in srgb, var(--color-link) 6%, transparent);
}

/* ── Icon ── */
.sidebar__icon {
  width: 18px; height: 18px;
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.sidebar__icon .ic { width: 16px; height: 16px; }

/* ── Label ── */
.sidebar__label { flex: 1; }

/* ── Arrow (chevron for sub-menus) ── */
.sidebar__arrow {
  width: 14px; height: 14px;
  flex-shrink: 0;
  transition: transform 0.25s;
}
.sidebar__sub--open > .sidebar__link .sidebar__arrow {
  transform: rotate(90deg);
}

/* ── Sub-menus ── */
.sidebar__sub > .sidebar__link { font-weight: 600; }

.sidebar__sub-menu {
  display: none;
  background: var(--color-bg-secondary);
}
.sidebar__sub--open > .sidebar__sub-menu,
.sidebar__sub--open > ul {
  display: block;
}
.sidebar__sub-menu .sidebar__link {
  padding: calc(10px * var(--space-factor, 1)) calc(20px * var(--space-factor, 1)) calc(10px * var(--space-factor, 1)) calc(48px * var(--space-factor, 1));
  font-size: 0.8rem;
  font-weight: 400;
}
.sidebar__sub-menu .sidebar__link:hover {
  background: color-mix(in srgb, var(--color-link) 8%, transparent);
}

/* ── Active states ── */
.sidebar__link--active,
.sidebar__sub-menu .sidebar__link--active {
  color: var(--color-link);
  background: color-mix(in srgb, var(--color-link) 10%, transparent);
  font-weight: 600;
}
.sidebar__sub--open > .sidebar__link {
  color: var(--color-text);
}

/* ── Badge ── */
.sidebar__badge {
  margin-inline-start: auto;
  background: var(--color-link);
  color: var(--color-button-text, #fff);
  font-size: 0.7rem;
  font-weight: 700;
  padding: calc(2px * var(--space-factor, 1)) calc(7px * var(--space-factor, 1));
  border-radius: 99px;
  line-height: 1.3;
}

/* ── Collapsible sidebar toggle ── */
.sidebar--collapsed { width: 56px; }
.sidebar--collapsed .sidebar__label,
.sidebar--collapsed .sidebar__arrow,
.sidebar--collapsed .sidebar__sub-menu { display: none; }
.sidebar--collapsed .sidebar__link { justify-content: center; padding: calc(14px * var(--space-factor, 1)) 0; }

}

/* --- topbar.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: aria-expanded + aria-label on toggle, aria-haspopup + aria-expanded on dropdown triggers
   Topbar / Navbar
   Fixed top bar with brand, nav links, dropdowns, mobile menu.
   ============================================================ */

.topbar,
.exsa .topbar {
  position: fixed;
  top: 0; inset-inline-start: 0; inset-inline-end: 0;
  z-index: var(--z-topbar);
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--topbar-height);
  padding: 0 calc(24px * var(--space-factor, 1));
  margin: 0;
  max-width: none;
  background: var(--surface-bg-elevated);
  border-bottom: var(--surface-border);
  transition: background 0.3s ease, box-shadow 0.3s ease, border-color 0.3s ease;
  font-family: inherit;
  text-align: start;
  gap: calc(16px * var(--space-factor, 1));
}

/* Push page content below the fixed topbar.
   --topbar-height is the single source of truth — both body padding
   and .topbar height read from it. Size variants sync automatically
   via :has() so body padding always matches the actual topbar height. */
body.has-topbar {
  --topbar-height: 56px;
  padding-top: var(--topbar-height);
}

/* Size variants — set on topbar, body syncs via :has() */
body:has(.topbar--sm) { --topbar-height: 48px; }
body:has(.topbar--lg) { --topbar-height: 64px; }
body:has(.topbar--xl) { --topbar-height: 72px; }

/* Scrolled — elevation follows the active skin */
.topbar--scrolled {
  box-shadow: var(--surface-shadow-md);
}

/* Height variants */
.topbar--sm { --topbar-height: 48px; }
.topbar--lg { --topbar-height: 64px; }
.topbar--xl { --topbar-height: 72px; }

/* Transparent — skin-tinted frost, always slightly see-through.
   No backdrop-filter here: the crash rule — a bar toggling over
   animated content must never sample it. Translucent tint reads
   the same. */
.topbar--transparent,
.exsa .topbar--transparent {
  background: color-mix(in srgb, var(--surface-bg) 85%, transparent);
}

/* ── Left / Right sections ── */
.topbar__left,
.topbar__right {
  display: flex;
  align-items: center;
  gap: calc(8px * var(--space-factor, 1));
  flex-shrink: 0;
}
.topbar__left  { margin-inline-end: auto; }
.topbar__right { margin-inline-start: auto; }

/* Brand / Logo */
.topbar__brand {
  display: flex;
  align-items: center;
  gap: calc(6px * var(--space-factor, 1));
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--color-text);
  text-decoration: none;
  letter-spacing: -0.01em;
  white-space: nowrap;
  flex-shrink: 0;
}
.topbar__logo { display: block; flex-shrink: 0; }
.topbar__brand span { color: var(--color-link); }

/* Nav container */
.topbar nav {
  margin: 0;
  font-weight: normal;
  display: flex;
  align-items: center;
}

/* Override .exsa button styles — only for nav links & toggle, not .topbar__btn */
.topbar .topbar__link,
.topbar .topbar__toggle {
  background-color: transparent;
  border: none;
  color: inherit;
  margin: 0;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
  border-radius: var(--border-radius);
}
.topbar__nav {
  display: flex;
  align-items: center;
  gap: calc(2px * var(--space-factor, 1));
  list-style: none;
  margin: 0;
  padding: 0;
}
.topbar__nav > li {
  margin: 0 calc(2px * var(--space-factor, 1));
  padding: 0;
  display: inline-block;
  position: relative;
  text-align: start;
}

/* Nav links */
.topbar__link {
  display: inline-flex;
  align-items: center;
  gap: calc(6px * var(--space-factor, 1));
  padding: calc(8px * var(--space-factor, 1)) calc(14px * var(--space-factor, 1));
  min-height: 44px;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--color-text-secondary);
  text-decoration: none;
  border-radius: var(--border-radius);
  transition: color 0.15s, background 0.15s;
  line-height: 1.4;
  font-family: inherit;
  border: none;
  background: none;
  cursor: pointer;
}
.topbar__link:hover {
  color: var(--color-text);
  background: var(--color-bg-secondary);
}
.topbar__link--active {
  color: var(--color-link);
  background: color-mix(in srgb, var(--color-link) 10%, transparent);
}

/* Action buttons in topbar */
.topbar__btn {
  display: inline-flex;
  align-items: center;
  padding: calc(8px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));
  min-height: 44px;
  font-size: 0.85rem;
  font-weight: 500;
  border-radius: var(--border-radius);
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
  line-height: 1.4;
  text-decoration: none;
  white-space: nowrap;
  border: 1px solid var(--color-bg-secondary);
  background: var(--color-bg);
  color: var(--color-text);
}
.topbar__btn:hover {
  background: var(--color-bg-secondary);
}
.topbar__btn--primary {
  background: var(--color-link);
  color: var(--color-button-text, #fff);
  border-color: var(--color-link);
}
.topbar__btn--primary:hover {
  opacity: 0.9;
}

/* ── Dropdown menus ── */
.topbar__dropdown { position: relative; }
.topbar__dd-trigger { gap: calc(2px * var(--space-factor, 1)); }
.topbar__dd-trigger .ic {
  transition: transform 0.2s;
}
.topbar__dropdown--open > .topbar__dd-trigger .ic {
  transform: rotate(180deg);
}

.topbar__dd-menu {
  position: absolute;
  top: calc(100% + 10px);
  left: 0;
  min-width: 180px;
  background: var(--surface-bg);
  border: var(--surface-border);
  border-radius: var(--surface-radius);
  box-shadow: var(--surface-shadow-md), 0 2px 6px rgba(0,0,0,.06);
  padding: calc(8px * var(--space-factor, 1)) 0;
  list-style: none;
  margin: 0;
  display: none;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity 0.15s, transform 0.15s, visibility 0.15s;
  z-index: var(--z-topbar-dropdown);
}

/* Menu list items — full-width click target */
.topbar__dd-menu li {
  margin: 0;
  padding: 0;
  display: block;
  border-bottom: 0px solid var(--color-bg-secondary);
}
.topbar__dd-menu li:last-child {
  border-bottom: 0;
}

/* Dropdown arrow (triangle) */
.topbar__dd-menu::before {
  content: '';
  position: absolute;
  top: -6px;
  left: 16px;
  width: 12px;
  height: 12px;
  background: var(--color-bg);
  border: 1px solid var(--color-bg-secondary);
  border-right: none;
  border-bottom: none;
  transform: rotate(45deg);
  z-index: -1;
}

.topbar__dropdown--open > .topbar__dd-menu {
  display: block;
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.topbar__dd-item {
  display: flex;
  align-items: center;
  gap: calc(10px * var(--space-factor, 1));
  width: 100%;
  padding: calc(12px * var(--space-factor, 1)) calc(18px * var(--space-factor, 1));
  min-height: 42px;
  font-size: 0.84rem;
  font-weight: 500;
  color: var(--color-text-secondary);
  text-decoration: none;
  background: none;
  border: 0;
  cursor: pointer;
  text-align: start;
  font-family: inherit;
  transition: color 0.2s, background 0.2s;
  line-height: 1.4;
  margin: 0;
  box-sizing: border-box;
}
.topbar__dd-item:hover { 
  color: var(--color-link);
  background: color-mix(in srgb, var(--color-link) 6%, transparent);
  text-decoration: none;
}
.topbar__dd-item--active {
  color: var(--color-link);
  background: color-mix(in srgb, var(--color-link) 12%, transparent);
  font-weight: 600;
}
.topbar__dd-item .ic { flex-shrink: 0; }

.topbar__dd-divider {
  height: 1px;
  background: var(--color-bg-secondary);
  margin: calc(1px * var(--space-factor, 1)) 0;
}

/* ── Hamburger toggle (mobile) ── */
.topbar__toggle {
  display: none;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  border: none;
  background: none;
  cursor: pointer;
  padding: 0;
  margin: 0;
  color: var(--color-text);
  border-radius: var(--border-radius);
  transition: background 0.15s;
  flex-shrink: 0;
}
.topbar__toggle:hover { background: var(--color-bg-secondary); }
.topbar__toggle .ic { width: 22px; height: 22px; }

/* ── Mobile (< 768px) ── */
@media (max-width: 767px) {
  .topbar__toggle { display: inline-flex; }

  .topbar__left,
  .topbar__right { gap: calc(4px * var(--space-factor, 1)); }

  .topbar__nav {
    position: absolute;
    top: 100%;
    inset-inline-start: 0; inset-inline-end: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--color-bg);
    border-bottom: 1px solid var(--color-bg-secondary);
    box-shadow: var(--box-shadow) var(--color-shadow);
    padding: calc(8px * var(--space-factor, 1)) 0;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    transition: opacity 0.2s, transform 0.2s, visibility 0.2s;
  }

  .topbar--open .topbar__nav {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
  }

  .topbar__nav > li { display: block; }

  .topbar__link,
  .topbar__dd-trigger {
    width: 100%;
    padding: calc(10px * var(--space-factor, 1)) calc(24px * var(--space-factor, 1));
    border-radius: 0;
    font-size: 0.9rem;
    justify-content: flex-start;
  }

  .topbar__btn { padding: calc(5px * var(--space-factor, 1)) calc(10px * var(--space-factor, 1)); font-size: 0.78rem; }

  /* Mobile dropdowns — static, no animation */
  .topbar__dd-menu {
    position: static;
    transform: none;
    inset-inline-start: auto;
    box-shadow: none;
    border: none;
    border-top: 1px solid var(--color-bg-secondary);
    border-radius: 0;
    background: var(--color-bg-secondary);
    display: none;
    opacity: 1;
    visibility: visible;
    transition: none;
  }
  .topbar__dd-menu::before { display: none; }
  .topbar__dd-menu li { display: block; padding: 0; margin: 0; border-bottom: 0; }
  .topbar__dropdown--open > .topbar__dd-menu { display: block; }
  .topbar__dd-item { padding-inline-start: calc(40px * var(--space-factor, 1)); }
}

}

/* --- back-top.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: aria-label="Back to top" on #back-top-btn
   Component: Back to Top
   ============================================================ */

/* --- C5: BACK TO TOP --- */
.back-top{position:fixed;bottom:28px;inset-inline-end:28px;z-index:var(--z-back-top);width:44px;height:44px;border-radius:50%;background:var(--color-link);color:var(--color-button-text);border:none;font-size:1.1rem;cursor:pointer;display:flex;align-items:center;justify-content:center;box-shadow:var(--surface-shadow-lg);opacity:0;visibility:hidden;transform:translateY(10px);transition:opacity .25s,visibility .25s,transform .25s,background .15s;padding:0;margin:0;line-height:1}
.back-top--visible{opacity:1;visibility:visible;transform:translateY(0)}
.back-top:hover{opacity:.85;filter:none}
.back-top::after{content:'';display:block;width:20px;height:20px;background:currentColor;mask:url(components/icons/arrow-up.svg) center/contain no-repeat;-webkit-mask:url(components/icons/arrow-up.svg) center/contain no-repeat}

}

/* --- breadcrumbs.css --- */
@layer exsa.components {

/* ============================================================
   Component: Breadcrumbs
   ARIA: <nav aria-label="Breadcrumb"> wrapper;
         aria-current="page" on .breadcrumbs__current
   ============================================================ */
   
/* --- C6: BREADCRUMBS --- */
.breadcrumbs{display:flex;align-items:center;gap: calc(6px * var(--space-factor, 1));list-style:none;padding:0;margin:0;flex-wrap:wrap}.breadcrumbs li{display:flex;align-items:center;gap: calc(6px * var(--space-factor, 1));padding:0}.breadcrumbs a{font-size:.82rem;color:var(--color-link);text-decoration:none;font-weight:500;display:inline}.breadcrumbs a:hover{text-decoration:underline}.breadcrumbs__sep{font-size:.75rem;color:var(--color-text-secondary);user-select:none}.breadcrumbs__current{font-size:.82rem;color:var(--color-text-secondary);font-weight:500}

}

/* --- pagination.css --- */
@layer exsa.components {

/* ============================================================
   Component: Pagination
   ARIA: <nav aria-label="Pagination"> wrapper;
         aria-current="page" on the current .pagination__link
   ============================================================ */

/* --- C7: PAGINATION --- */
.pagination{display:flex;align-items:center;gap: calc(4px * var(--space-factor, 1));flex-wrap:wrap;list-style:none;padding:0;margin:0;font-weight:normal;justify-content:flex-start}
.pagination__item{display:inline-flex}
.pagination__link{display:inline-flex;align-items:center;justify-content:center;min-width:36px;height:36px;padding: 0 calc(10px * var(--space-factor, 1));border-radius:var(--surface-radius);font-size:.82rem;font-weight:600;color:var(--color-button-text-inverse);text-decoration:none;border:1px solid var(--color-border);background:var(--surface-bg);transition:background .15s,color .15s,border-color .15s;cursor:pointer}
.pagination__link:hover{background:var(--color-bg-secondary);border-color:var(--color-bg-secondary);filter:none}
.pagination__link:visited{color:var(--color-text)}
.pagination__link--active{background:var(--color-link);color:var(--color-button-text);border-color:var(--color-link)}
.pagination__link--active:hover{background:var(--color-link);filter:none}
.pagination__link--disabled{opacity:.4;pointer-events:none;cursor:default}
.pagination__ellipsis{display:inline-flex;align-items:center;justify-content:center;min-width:36px;height:36px;font-size:.82rem;color:var(--color-text-secondary);letter-spacing:.08em}

/* Compact */
.pagination--sm .pagination__link{min-width:30px;height:30px;font-size:.74rem}
.pagination--sm .pagination__ellipsis{min-width:30px;height:30px;font-size:.74rem}

}

/* --- stepper.css --- */
@layer exsa.components {

/* ============================================================
   Component: Stepper
   ARIA: aria-current="step" on the active .stepper__step
   ============================================================ */

/* --- C8: STEPPER --- */
.stepper{display:flex;align-items:flex-start;gap:0}
.stepper__step{flex:1;text-align:center;position:relative}
.stepper__step::after{content:'';position:absolute;top:16px;inset-inline-start:calc(50% + 20px);width:calc(100% - 40px);height:2px;background:var(--color-bg-secondary)}
.stepper__step:last-child::after{display:none}
.stepper__dot{width:32px;height:32px;border-radius:50%;background:var(--color-bg-secondary);color:var(--color-button-text-inverse);display:inline-flex;align-items:center;justify-content:center;font-size:.78rem;font-weight:700;position:relative;z-index:1;transition:background .2s,color .2s}
.stepper__label{display:block;margin-top: calc(10px * var(--space-factor, 1));font-size:.76rem;font-weight:600;color:var(--color-text-secondary)}
.stepper__step--active .stepper__dot{background:var(--color-link);color:var(--color-button-text)}
.stepper__step--active .stepper__label{color:var(--color-text)}
.stepper__step--done .stepper__dot{background:var(--color-link);color:var(--color-button-text)}
.stepper__step--done::after{background:var(--color-link)}

/* Vertical */
.stepper--vertical{flex-direction:column;gap:0}
.stepper--vertical .stepper__step{display:flex;align-items:flex-start;gap: calc(14px * var(--space-factor, 1));text-align:left;padding-bottom: calc(28px * var(--space-factor, 1))}
.stepper--vertical .stepper__step::after{top:32px;inset-inline-start:15px;width:2px;height:calc(100% - 32px)}
.stepper--vertical .stepper__label{margin-top: calc(4px * var(--space-factor, 1))}
.stepper--vertical .stepper__step:last-child{padding-bottom:0}

}

/* --- timeline.css --- */
@layer exsa.components {

/* ============================================================
   Component: Timeline
   ============================================================ */

/* --- C9: TIMELINE --- */
.timeline{position:relative;padding-inline-start: calc(28px * var(--space-factor, 1))}
.timeline::before{content:'';position:absolute;inset-inline-start:11px;top:4px;bottom:4px;width:2px;background:var(--color-bg-secondary);border-radius:1px}
.timeline__item{position:relative;padding-bottom: calc(28px * var(--space-factor, 1))}
.timeline__item:last-child{padding-bottom:0}
.timeline__dot{position:absolute;inset-inline-start:-25px;top:6px;width:18px;height:18px;border-radius:50%;background:var(--color-bg);border:2px solid var(--color-link);z-index:1}
.timeline__item--active .timeline__dot{background:var(--color-link);box-shadow:0 0 0 4px rgba(0,0,0,.06)}
.timeline__content{background:var(--surface-bg);border:var(--surface-border);border-radius:var(--surface-radius);padding: calc(14px * var(--space-factor, 1)) calc(18px * var(--space-factor, 1))}
.timeline__title{font-size:.88rem;font-weight:700;color:var(--color-text);margin: 0 0 calc(4px * var(--space-factor, 1))}
.timeline__time{font-size:.7rem;font-weight:600;color:var(--color-text-secondary);letter-spacing:.04em;text-transform:uppercase;margin-bottom: calc(6px * var(--space-factor, 1))}
.timeline__desc{font-size:.8rem;color:var(--color-text-secondary);line-height:1.6;margin:0;width:auto}

/* Compact variant */
.timeline--sm{padding-inline-start: calc(22px * var(--space-factor, 1))}
.timeline--sm::before{inset-inline-start:8px}
.timeline--sm .timeline__dot{inset-inline-start:-17px;width:10px;height:10px}
.timeline--sm .timeline__content{padding: calc(10px * var(--space-factor, 1)) calc(14px * var(--space-factor, 1))}
.timeline--sm .timeline__title{font-size:.8rem}
.timeline--sm .timeline__desc{font-size:.72rem}

}

/* --- tooltip.css --- */
@layer exsa.components {

/* ============================================================
   Component: Tooltip
   ARIA: role="tooltip" on .tooltip; for hover/focus-only content also
         expose the tip as aria-label/aria-describedby (::after text
         is not reliably announced by screen readers)
   ============================================================ */
   
/* --- C10: TOOLTIP --- */
.tooltip{position:relative;cursor:help;border-bottom:1px dotted var(--color-text-secondary);display:inline}.tooltip::after{content:attr(data-tip);position:absolute;bottom:calc(100% + 8px);left:50%;transform:translateX(-50%) scale(.8);padding: calc(6px * var(--space-factor, 1)) calc(12px * var(--space-factor, 1));background:var(--color-text);color:var(--color-bg);font-size:.75rem;font-weight:500;border-radius:var(--surface-radius);width:max-content;max-width:min(320px,calc(100vw - 24px));white-space:normal;text-align:center;pointer-events:none;opacity:0;transition:opacity .15s,transform .15s;z-index:var(--z-dropdown);line-height:1.5}.tooltip::before{content:'';position:absolute;bottom:calc(100% + 2px);left:50%;transform:translateX(-50%);border:5px solid transparent;border-top-color:var(--color-text);opacity:0;transition:opacity .15s;pointer-events:none}.tooltip:hover::after,.tooltip:focus-visible::after{opacity:1;transform:translateX(-50%) scale(1)}.tooltip:hover::before,.tooltip:focus-visible::before{opacity:1}

}

/* --- context-menu.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: role=menu on .ctx-menu, role=menuitem on items, aria-haspopup on trigger
   Component: CONTEXT MENU
   Right-click popup. data-ctx-menu on wrapper, data-ctx-trigger
   on the element that opens it (defaults to wrapper).
   Variants: solid (default), soft
   Sizes: sm, default
   ============================================================ */

/* ── Backdrop (closes menu on click outside) ── */
.ctx-backdrop{position:fixed;inset:0;z-index:var(--z-context-backdrop);display:none}
.ctx-backdrop--show{display:block}

/* ── Menu panel ── */
.ctx-menu {
  position: fixed;
  z-index: var(--z-context-menu);
  min-width: 140px;
  max-width: 260px;
  padding: calc(4px * var(--space-factor, 1));
  border-radius: var(--surface-radius);
  background: var(--surface-bg);
  border: var(--surface-border);
  box-shadow: var(--surface-shadow-md), 0 0 0 1px var(--color-bg-secondary);
  opacity: 0;
  transform: scale(0.96) translateY(-4px);
  transform-origin: var(--ctx-origin, top left);
  pointer-events: none;
  transition: opacity 0.12s ease, transform 0.12s ease;
}
.ctx-menu--open{opacity:1;transform:scale(1) translateY(0);pointer-events:all}

/* ── Soft variant ── */
.ctx-menu--soft{background:var(--color-bg-secondary);border-color:transparent;box-shadow:0 2px 10px color-mix(in srgb,#000 6%,transparent)}

/* ── Size: small ── */
.ctx-menu--sm{min-width:120px;padding: calc(3px * var(--space-factor, 1))}
.ctx-menu--sm .ctx-menu__item{padding: calc(5px * var(--space-factor, 1)) calc(8px * var(--space-factor, 1));font-size:.78rem;gap: calc(8px * var(--space-factor, 1))}

/* ── Items ── */
.ctx-menu__item {
  display: flex;
  align-items: center;
  gap: calc(8px * var(--space-factor, 1));
  width: 100%;
  padding: calc(6px * var(--space-factor, 1)) calc(8px * var(--space-factor, 1));
  font-size: .82rem;
  font-family: inherit;
  color: var(--color-text);
  background: none;
  border: none;
  border-radius: calc(var(--border-radius) * 0.6);
  cursor: pointer;
  text-align: start;
  line-height: 1;
  transition: background .06s, color .06s;
  white-space: nowrap;
}
.ctx-menu__item:hover{background:color-mix(in srgb,var(--color-text-secondary)12%,transparent)}
.ctx-menu__item:focus-visible{outline:2px solid var(--color-link);outline-offset:-2px}

/* ── Danger item ── */
.ctx-menu__item--danger{color:var(--color-danger)}
.ctx-menu__item--danger:hover{background:color-mix(in srgb,var(--color-danger)14%,transparent)}

/* ── Separator ── */
.ctx-menu__sep{height:1px;margin: calc(3px * var(--space-factor, 1)) calc(6px * var(--space-factor, 1));background:var(--color-bg-secondary);border:none}

/* ── Shortcut hint ── */
.ctx-menu__shortcut{margin-inline-start:auto;font-size:.7rem;color:var(--color-text-secondary);letter-spacing:.02em;margin-inline-end: calc(2px * var(--space-factor, 1))}

/* ── Label (non-interactive header) ── */
.ctx-menu__label{padding: calc(4px * var(--space-factor, 1)) calc(8px * var(--space-factor, 1)) calc(2px * var(--space-factor, 1));font-size:.68rem;font-weight:600;color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:.06em}

/* ── Submenu indicator ── */
.ctx-menu__sub-arrow{margin-inline-start:auto;opacity:.5;font-size:.7rem}
}

/* --- avatar.css --- */
@layer exsa.components {

/* ============================================================
   Component: Avatar — squircle mask + proportional status dot

   Link AFTER exsa.css + your theme.

   Sizes (fluid — vw-clamped, shrink on small screens):
     --xs clamp(24px,6vw,40px) · default clamp(32px,8vw,56px) · --sm clamp(40px,11vw,80px)
     --lg clamp(64px,20vw,160px) · --xl clamp(96px,34vw,320px)
   Status: --online · --away · --busy · --offline (20% of size, min 8px, bg-colored ring)
   Colors: --primary · --success · --danger · --warning (fallback)
   ARIA: role="img" + aria-label on the avatar; the status dot is decorative (aria-hidden)
   Group:  .avatar-group overlaps with a background ring
   ============================================================ */

.avatar{
  --avatar-mask:url("data:image/svg+xml,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg' fill-rule='evenodd' clip-rule='evenodd' stroke-linejoin='round' stroke-miterlimit='2'%3E%3Cpath d='M49.677.001L50 0c27.596 0 50 22.404 50 50l-.002.443v.046l-.001.029a29.83 29.83 0 01-.006.423v.036l-.001.046-.011.432v.009l-.001.027-.007.233-.007.184-.001.042-.001.021-.019.423-.001.041-.003.042c-.006.141-.014.282-.022.423l-.001.018-.002.04-.012.191-.014.221-.002.03-.001.012c-.009.142-.02.283-.031.425l-.003.044-.003.036-.034.418-.002.026-.004.044-.014.159-.026.277-.043.431-.005.045-.003.029-.046.414-.004.032-.005.044c-.016.142-.033.283-.051.424l-.034.266-.023.172-.005.042-.003.022-.058.41-.005.04-.007.043-.061.41-.003.017-.006.04-.03.191-.032.199-.006.039-.003.016-.068.403-.008.049-.008.042-.063.353A49.459 49.459 0 0197.707 65h-.002a5.3 5.3 0 01-6.5 3.473v.002a17.893 17.893 0 00-2.853-.683l-.098-.015-.077-.011-.097-.014-.079-.011-.095-.012-.082-.011-.093-.011-.084-.01-.091-.01-.086-.009-.09-.009-.088-.009-.089-.008-.09-.007-.087-.008-.092-.007-.086-.006-.094-.006-.084-.005-.096-.006-.083-.004-.099-.005-.081-.003-.102-.004-.077-.002-.108-.003-.073-.002-.12-.002h-.061l-.181-.001-.228.001-.076.002-.152.002-.091.003-.137.004-.096.005-.13.005-.1.006-.126.007-.102.007-.123.009-.103.008-.121.01-.104.009-.12.012-.104.011-.118.012-.105.013-.117.014-.105.013-.117.016-.104.015-.116.017-.104.016-.115.018-.104.017-.115.02-.103.018-.115.022-.102.019-.115.023-.101.021-.115.024-.101.022-.114.025-.1.023-.115.028-.099.023-.114.029-.098.025-.115.031-.096.025-.117.033-.094.026-.118.034-.091.027-.121.037-.087.027-.127.04-.08.026-.14.046-.066.022-.205.071-.205.073-.049.019-.154.057-.07.027-.131.051-.079.032-.122.048-.082.035-.117.048-.084.036-.114.049-.086.038-.111.05-.086.039-.11.05-.086.041-.108.051-.086.042-.107.052-.086.043-.106.054-.085.044-.106.054-.085.045-.104.056-.084.046-.104.057-.083.047-.104.059-.082.047-.104.06-.081.048-.103.062-.08.048-.103.064-.078.049-.104.065-.076.049-.105.068-.074.048-.106.071-.071.048-.108.074-.068.046-.11.078-.064.045-.115.083-.058.042-.124.091-.047.035-.142.108-.027.02-.169.132-.17.134-.166.136-.021.017-.142.119-.038.033-.124.106-.046.04-.114.1-.051.045-.107.097-.054.049-.103.095-.055.051-.1.095-.056.053-.097.094-.057.055-.095.095-.056.056-.094.095-.056.058-.092.095-.056.058-.091.097-.055.059-.09.098-.054.059-.089.1-.053.059-.088.101-.052.059-.088.104-.05.058-.088.106-.048.058-.089.108-.045.057-.089.112-.044.055-.09.116-.04.052-.092.121-.037.049-.095.128-.031.043-.1.139-.025.034-.108.155-.014.02c-.205.296-.402.598-.589.906l-.11.184-.016.026-.092.159-.022.038-.084.148-.026.046-.078.142-.028.051-.073.138-.029.056-.07.134-.03.059-.068.133-.03.062-.065.132-.03.063-.062.131-.031.065-.06.131-.03.066-.058.131-.029.067-.057.132-.029.067-.055.133-.028.068-.053.133-.027.068-.052.135-.026.068-.051.137-.025.066-.05.14-.023.065-.049.142-.022.064-.049.146-.019.06-.049.152-.017.056-.049.16-.015.049-.05.172-.011.038-.054.195-.005.016c-.077.285-.147.572-.21.862l-.008.036-.038.179-.011.059-.032.158-.013.07-.027.147-.014.079-.024.138-.014.086-.021.133-.013.091-.019.129-.013.094-.017.126-.012.098-.015.123-.012.101-.013.121-.01.104-.011.118-.01.107-.009.116-.009.11-.008.113-.007.113a17.978 17.978 0 00.861 6.717h-.002a5.3 5.3 0 01-3.473 6.5v.002c-1.208.38-2.436.715-3.682 1.004l-.364.083-.02.005-.071.015-.229.051-.098.021-.062.013-.068.014-.115.025-.205.042-.074.015-.027.006-.415.082-.021.004-.067.013-.226.043-.109.02-.062.012-.063.011-.112.021-.225.04-.066.012-.022.003c-.14.025-.281.048-.422.071l-.024.005-.068.01-.218.036-.118.018-.065.01-.06.009-.107.017-.243.036-.06.009-.018.002a31.15 31.15 0 01-.426.06l-.028.004-.072.009-.207.028-.126.015-.068.009-.058.007-.101.013-.26.031-.056.006-.014.002-.429.047-.032.004-.076.008-.196.02-.134.013-.072.007-.056.006-.094.009-.279.025-.049.004-.011.001a68.06 68.06 0 01-.431.035l-.038.003-.078.006-.186.014-.142.01-.075.005-.055.003-.087.006-.301.019-.039.002-.008.001c-.144.008-.289.016-.434.022l-.041.003-.081.003-.176.008-.15.006-.078.004-.052.001-.081.004-.357.011-.437.011-.046.001-.08.001-.168.003-.16.002-.08.001h-.049L50 100C22.404 100 0 77.596 0 50a49.738 49.738 0 015.473-22.754l.139-.269a50.144 50.144 0 015.812-8.774l.191-.231a50.32 50.32 0 018.237-7.853l.097-.072a48.756 48.756 0 012.02-1.446l.084-.057.201-.135c.183-.123.368-.244.552-.364l.253-.163.028-.018a49.87 49.87 0 017.739-4.05l.282-.116a49.03 49.03 0 012.877-1.074 50.373 50.373 0 013.525-1.049l.3-.076A50.11 50.11 0 0145.206.227l.316-.029.316-.027.317-.025.318-.023.318-.021.319-.02a51.837 51.837 0 012.098-.076l.146-.002.323-.003z' /%3E%3C/svg%3E");
  --avatar-bg:var(--color-text-secondary);
  position:relative;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;
  width:clamp(32px,8vw,56px);height:clamp(32px,8vw,56px);
  background:transparent;color:var(--color-bg);font-weight:700;font-size:clamp(.72rem,3vw,1rem);
}

/* Fallback (no image): squircle background layer — container stays unmasked so the dot always shows */
.avatar:not(:has(img[src]))::before{
  content:'';position:absolute;inset:0;z-index:0;
  border-radius:var(--surface-radius);
  background:var(--avatar-bg);
  -webkit-mask-image:var(--avatar-mask);mask-image:var(--avatar-mask);
  -webkit-mask-size:100% 100%;mask-size:100% 100%;
}
.avatar img{
  position:relative;z-index:0;width:100%;height:100%;object-fit:cover;display:block;
  -webkit-mask-image:var(--avatar-mask);mask-image:var(--avatar-mask);
  -webkit-mask-size:100% 100%;mask-size:100% 100%;
}
.avatar img:not([src]),.avatar img[src='']{display:none}
.avatar__fallback{line-height:1;position:relative;z-index:1;color:var(--color-bg)}

/* Sizes — fluid: desktop values unchanged, mobile scales down */
.avatar--xs{width:clamp(24px,6vw,40px);height:clamp(24px,6vw,40px);font-size:clamp(.55rem,2.2vw,.78rem)}
.avatar--sm{width:clamp(40px,11vw,80px);height:clamp(40px,11vw,80px);font-size:clamp(.9rem,4.4vw,1.3rem)}
.avatar--lg{width:clamp(64px,20vw,160px);height:clamp(64px,20vw,160px);font-size:clamp(1.3rem,7vw,2.4rem)}
.avatar--xl{width:clamp(96px,34vw,320px);height:clamp(96px,34vw,320px);font-size:clamp(1.9rem,10vw,4.6rem)}

/* Color variants (fallback backgrounds) */
.avatar--primary{--avatar-bg:var(--color-link)}
.avatar--success{--avatar-bg:var(--color-success)}
.avatar--danger{--avatar-bg:var(--color-danger)}
.avatar--warning{--avatar-bg:var(--color-warning)}
.avatar--primary .avatar__fallback,
.avatar--success .avatar__fallback,
.avatar--danger .avatar__fallback,
.avatar--warning .avatar__fallback{color:var(--color-button-text)}

/* Status dot — 20% of avatar (min 8px), bottom-inline-end, bg ring so it reads on any photo */
.avatar__status{
  position:absolute;width:20%;min-width:8px;aspect-ratio:1/1;border-radius:50%;
  inset-inline-end:4%;bottom:4%;z-index:2;
  box-shadow:0 0 0 calc(2px * var(--space-factor, 1)) var(--color-bg);
}
.avatar__status--online{background:var(--color-success)}
.avatar__status--away{background:var(--color-warning)}
.avatar__status--busy{background:var(--color-danger)}
.avatar__status--offline{background:var(--color-text-secondary)}

/* Group — overlapping squircle (drop-shadow follows the masked shape) */
.avatar-group{display:flex}
.avatar-group .avatar{margin-inline-start: calc(-14px * var(--space-factor, 1));filter:drop-shadow(0 0 0 3px var(--color-bg))}
.avatar-group .avatar:first-child{margin-inline-start:0}

}

/* --- badge.css --- */
@layer exsa.components {

/* ============================================================
   Component: Badge
   ============================================================ */

/* --- C12: BADGE --- */
.badge{display:inline-flex;align-items:center;padding: calc(2px * var(--space-factor, 1)) calc(10px * var(--space-factor, 1));border-radius:99px;font-size:.7rem;font-weight:700;letter-spacing:.03em;line-height:1.5;white-space:nowrap;box-shadow:var(--surface-inset)}
.badge--default{background:var(--color-bg-secondary);color:var(--color-text-secondary)}
.badge--primary{background:color-mix(in srgb,var(--color-link)14%,transparent);color:var(--color-link)}
.badge--success{background:color-mix(in srgb, var(--color-success) 14%, transparent);color:var(--color-success-hover)}
.badge--warning{background:color-mix(in srgb, var(--color-warning) 14%, transparent);color:var(--color-warning-hover)}
.badge--danger{background:color-mix(in srgb, var(--color-danger) 12%, transparent);color:var(--color-danger-hover)}

/* Dot badge */
.badge--dot{padding:0;width:8px;height:8px;min-width:8px;border-radius:50%}
.badge--dot.badge--success{background:var(--color-success)}
.badge--dot.badge--warning{background:var(--color-warning)}
.badge--dot.badge--danger{background:var(--color-danger)}

/* Pill count */
.badge--count{padding: calc(1px * var(--space-factor, 1)) calc(7px * var(--space-factor, 1));font-size:.66rem;min-width:18px;text-align:center}

}

/* --- card.css --- */
@layer exsa.components {

/* ============================================================
   Card Component
   ── Semantic component classes for card layouts.
   Vertical by default. Add --horizontal for side-by-side,
   --horizontal-reverse to flip which side the image is on,
   --glass / --glass-dark for frosted translucent cards.
   Container-query driven — adapts to its own width, not the viewport.
   Surface recipes consume the --surface-* tokens — restyle globally
   with a skin (dist/skins/) or override locally.
   ============================================================ */

/* ── Base card ── */
.card {
  display: flex;
  flex-direction: column;
  width: 100%;
  container-type: inline-size;
  container-name: card;
  background: var(--surface-bg-elevated);
  border: var(--surface-border);
  border-radius: var(--surface-radius);
  overflow: hidden;
  transition: box-shadow .25s, transform .25s;
}

/* ── Hoverable ── */
.card--hoverable:hover {
  box-shadow: var(--surface-shadow-sm);
  transform: translateY(-2px);
}

/* ── Glass — frosted translucent variant (for use above backgrounds) ── */
.card--glass {
  background: color-mix(in srgb, var(--color-bg) 55%, transparent);
  border-color: color-mix(in srgb, #fff 25%, transparent);
  backdrop-filter: blur(12px) saturate(1.4);
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  box-shadow: 0 8px 32px rgba(0,0,0,.12);
}
.card--glass-dark {
  background: color-mix(in srgb, #0f172a 45%, transparent);
  border-color: rgba(255,255,255,.18);
  color: #fff;
}

/* ── Card image (vertical/default layout) ── */
.card__image {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  background: var(--color-bg-secondary);
}

/* ── Card body ── */
.card__body {
  flex: 1;
  padding: calc(20px * var(--space-factor, 1));
}

/* ── Card title ── */
.card__title {
  font-size: .95rem;
  font-weight: 700;
  color: var(--color-text);
  margin: 0 0 calc(6px * var(--space-factor, 1));
  line-height: 1.35;
}

/* ── Card text ── */
.card__text {
  font-size: .82rem;
  color: var(--color-text-secondary);
  line-height: 1.65;
  margin: 0;
}

/* ── Card footer ── */
.card__footer {
  padding: calc(14px * var(--space-factor, 1)) calc(20px * var(--space-factor, 1));
  border-top: 1px solid var(--color-bg-secondary);
  display: flex;
  align-items: center;
  gap: calc(12px * var(--space-factor, 1));
}

/* ── Card head row — title, badge, rating in one compact line ── */
.card__head-row {
  display: flex;
  align-items: center;
  gap: calc(6px * var(--space-factor, 1));
  flex-wrap: nowrap;
}
.card__head-row .card__title {
  margin: 0;
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Card rating — star display ── */
.card__rating {
  font-size: .82rem;
  color: var(--color-warning);
  letter-spacing: 1px;
  white-space: nowrap;
  user-select: none;
}

/* ── Card divider — thin line inside body ── */
.card__divider {
  border: none;
  border-top: 1px solid var(--color-bg-secondary);
  margin: calc(8px * var(--space-factor, 1)) 0;
  width: 100%;
}

/* ═══════════════════════════════════════════
   Horizontal card — vertical by default (mobile-first).
   At 640px+ the image moves beside the content.
   Footer stays under the body, not under the image.
   ═══════════════════════════════════════════ */

@media (min-width: 640px) {
  .card--horizontal {
    display: grid;
    grid-template-columns: 200px 1fr;
    grid-template-rows: 1fr auto;
    min-height: 180px;
  }

  .card--horizontal-reverse {
    display: grid;
    grid-template-columns: 1fr 200px;
    min-height: 180px;
  }

  /* Image spans both rows (full card height) */
  .card--horizontal .card__image {
    grid-column: 1;
    grid-row: 1 / 3;
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
    object-fit: cover;
  }

  .card--horizontal-reverse .card__image {
    grid-column: 2;
    grid-row: 1 / 3;
    width: 100%;
    height: 100%;
    aspect-ratio: auto;
    object-fit: cover;
  }

  /* Body: top cell of the content column — clips overflow text */
  .card--horizontal .card__body {
    grid-column: 2;
    grid-row: 1;
    flex: none;
    padding: calc(12px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));
    display: flex;
    flex-direction: column;
    justify-content: center;
    overflow: hidden;
    min-height: 0;
  }

  .card--horizontal-reverse .card__body {
    grid-column: 1;
    grid-row: 1;
    flex: none;
    padding: calc(12px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));
    display: flex;
    flex-direction: column;
    justify-content: center;
    overflow: hidden;
    min-height: 0;
  }

  /* Truncate long text to 4 lines */
  .card--horizontal .card__text,
  .card--horizontal-reverse .card__text {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    line-clamp: 4;
    overflow: hidden;
  }

  /* Footer: bottom cell of the content column — stays under the body */
  .card--horizontal .card__footer {
    grid-column: 2;
    grid-row: 2;
    padding: calc(10px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));
    border-color: transparent;
  }

  .card--horizontal-reverse .card__footer {
    grid-column: 1;
    grid-row: 2;
    padding: calc(10px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));
    border-color: transparent;
  }
}
}

/* --- table.css --- */
@layer exsa.components {

/* ============================================================
   Component: TABLE
   .tbl for component mode — striping, hover, responsive, badges.
   Classless baseline (bare borders, header bg) is in exsa.css.
   Variants: striped, bordered, sm, responsive, status badges
   ============================================================ */

/* ── Wrapper ── */
.table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch;background:var(--surface-bg);border:var(--surface-border);border-radius:var(--surface-radius);box-shadow:var(--surface-shadow-md)}
.table-wrap::-webkit-scrollbar{height:5px}
.table-wrap::-webkit-scrollbar-thumb{background:var(--color-bg-secondary);border-radius:3px}

/* ── Component table ── */
.tbl{width:100%;border-collapse:collapse;font-size:.84rem;color:var(--color-text);white-space:nowrap} /* .84rem deliberate — between --font-size-sm and --font-size-base */
.tbl thead{border-bottom:var(--surface-border)}
.tbl th{padding: calc(12px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));text-align:start;font-size:.72rem;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--color-text-secondary);background:color-mix(in srgb,var(--surface-bg) 96%,var(--color-text))} /* header = rows but a little darker, derived from the active surface */
.tbl td{padding: calc(11px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));border-bottom:var(--surface-border)}
.tbl tbody tr{transition:background .12s}
.tbl tbody tr:hover{background:var(--color-bg-secondary)}
.tbl tbody tr:last-child td{border-bottom:none}

/* Striped */
.tbl--striped tbody tr:nth-child(even){background:color-mix(in srgb,var(--color-bg-secondary)40%,transparent)}
.tbl--striped tbody tr:nth-child(even):hover{background:var(--color-bg-secondary)}

/* Bordered */
.tbl--bordered td,.tbl--bordered th{border:var(--surface-border)}
.tbl--bordered thead{border-bottom-width:1px}

/* Compact */
.tbl--sm th,.tbl--sm td{padding: calc(7px * var(--space-factor, 1)) calc(12px * var(--space-factor, 1));font-size:.76rem}

/* Status badges */
.tbl .tbl-badge{display:inline-block;padding: calc(2px * var(--space-factor, 1)) calc(10px * var(--space-factor, 1));border-radius:99px;font-size:.68rem;font-weight:700;letter-spacing:.03em}
.tbl-badge--success{background:color-mix(in srgb,var(--color-success)14%,transparent);color:var(--color-success)}
.tbl-badge--warning{background:color-mix(in srgb,var(--color-warning)14%,transparent);color:var(--color-warning)}
.tbl-badge--danger{background:color-mix(in srgb,var(--color-danger)12%,transparent);color:var(--color-danger);white-space:nowrap}

/* Responsive card fallback */
@media(max-width:640px){
  .tbl--responsive thead{display:none}
  .tbl--responsive,.tbl--responsive tbody,.tbl--responsive tr,.tbl--responsive td{display:block;white-space:normal}
  .tbl--responsive tr{border:var(--surface-border);border-radius:var(--surface-radius);margin-bottom: calc(10px * var(--space-factor, 1));padding: calc(8px * var(--space-factor, 1)) 0;background:var(--surface-bg)}
  .tbl--responsive td{border:none;padding: calc(6px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));display:flex;justify-content:space-between;align-items:center;gap: calc(8px * var(--space-factor, 1))}
  .tbl--responsive td::before{content:attr(data-label);font-size:.68rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:var(--color-text-secondary);flex-shrink:0}
}

/* ── Sortable (js/table.js — .tbl--sortable with th[data-sort]) ── */
.tbl--sortable th[data-sort]{cursor:pointer;user-select:none}
.tbl--sortable th[data-sort]::after{
  content:'';display:inline-block;width:6px;height:6px;margin-inline-start: calc(6px * var(--space-factor, 1));
  border-inline-end:2px solid var(--color-text-secondary);border-bottom:2px solid var(--color-text-secondary);
  transform:rotate(45deg) translateY(-2px);vertical-align:middle;opacity:.4;transition:opacity .15s;
}
.tbl--sortable th[data-sort]:hover::after{opacity:.9}
.tbl--sortable th[aria-sort="ascending"]::after{transform:rotate(-135deg) translateY(-2px);border-color:var(--color-link);opacity:1}
.tbl--sortable th[aria-sort="descending"]::after{transform:rotate(45deg) translateY(-2px);border-color:var(--color-link);opacity:1}
.tbl--sortable th[data-sort]:focus-visible{outline:2px solid var(--color-link);outline-offset:-2px}

/* ── Filter input (js/table.js — .table-search[data-table]) ── */
.table-search{padding: calc(7px * var(--space-factor, 1)) calc(12px * var(--space-factor, 1));font-size:.82rem;font-family:inherit;border:var(--surface-border-control);border-radius:var(--surface-radius);background:var(--surface-bg);box-shadow:var(--surface-inset);color:var(--color-text);min-width:200px;transition:border-color .15s,box-shadow .15s}
.table-search:focus{outline:none;border-color:var(--color-link);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-link)20%,transparent)}

/* ── Empty row (js/table.js — .table-empty, hidden attr toggled) ── */
.table-empty td{padding: calc(20px * var(--space-factor, 1));text-align:center;color:var(--color-text-secondary);font-style:italic}

/* ── Selectable rows (js/table.js — .tbl--selectable + .tbl__check) ── */
.tbl__check,.tbl__check--all{width:14px;height:14px;margin:0;accent-color:var(--color-link);cursor:pointer;vertical-align:middle}
.tbl--selectable tbody tr.tbl__row--selected{background:color-mix(in srgb,var(--color-link)8%,transparent)}
.tbl--selectable tbody tr.tbl__row--selected:hover{background:color-mix(in srgb,var(--color-link)14%,transparent)}
.tbl--selectable th:first-child,.tbl--selectable td:first-child{width: calc(28px * var(--space-factor, 1));text-align:center;padding-inline-end: calc(4px * var(--space-factor, 1))}

}

/* --- data-list.css --- */
@layer exsa.components {

/* ============================================================
   Component: DATA LIST
   Key-value metadata display using <dl>/<dt>/<dd>.
   Orientation: horizontal (default) or vertical.
   Sizes: sm, default, lg
   ============================================================ */

/* ── Root ── */
.data-list{margin:0;display:grid;grid-template-columns:auto 1fr;gap:0;font-size:.88rem;color:var(--color-text)}
.data-list--vertical{grid-template-columns:1fr;gap: calc(2px * var(--space-factor, 1))}

/* ── Item ── */
.data-list__item{display:grid;grid-template-columns:subgrid;grid-column:1/-1;padding: calc(10px * var(--space-factor, 1)) calc(14px * var(--space-factor, 1));border-bottom:1px solid var(--color-bg-secondary);align-items:baseline}
.data-list__item:last-child{border-bottom:none}
.data-list--vertical .data-list__item{grid-template-columns:1fr;padding: calc(8px * var(--space-factor, 1)) calc(14px * var(--space-factor, 1));gap: calc(2px * var(--space-factor, 1))}

/* ── Label ── */
.data-list__label{font-size:.75rem;font-weight:600;color:var(--color-text-secondary);letter-spacing:.02em;text-transform:uppercase;padding-inline-end: calc(16px * var(--space-factor, 1))}
.data-list--vertical .data-list__label{padding-inline-end:0}

/* ── Value ── */
.data-list__value{margin:0;display:flex;align-items:center;gap: calc(8px * var(--space-factor, 1));flex-wrap:wrap}

/* ── Sizes ── */
.data-list--sm{font-size:.78rem}
.data-list--sm .data-list__item{padding: calc(6px * var(--space-factor, 1)) calc(10px * var(--space-factor, 1))}
.data-list--sm .data-list__label{font-size:.68rem}
.data-list--lg{font-size:.95rem}
.data-list--lg .data-list__item{padding: calc(14px * var(--space-factor, 1)) calc(18px * var(--space-factor, 1))}
.data-list--lg .data-list__label{font-size:.8rem}

/* ── Bordered variant ── */
.data-list--bordered{border:var(--surface-border);border-radius:var(--surface-radius)}
.data-list--bordered .data-list__item:last-child{border-bottom:none}

/* ── Striped variant ── */
.data-list--striped .data-list__item:nth-child(even){background:color-mix(in srgb,var(--color-bg-secondary)40%,transparent)}

/* ── Label color variants ── */
.data-list__label--primary{color:var(--color-link)}
.data-list__label--success{color:var(--color-success)}
.data-list__label--danger{color:var(--color-danger)}
.data-list__label--warning{color:var(--color-warning)}
}

/* --- separator.css --- */
@layer exsa.components {

/* ============================================================
   Component: SEPARATOR
   Horizontal or vertical divider. Uses --color-text at low
   opacity so it remains visible on any background.
   ============================================================ */

.sep{width:100%;height:1px;background:var(--color-text);opacity:.12;border:none;margin: calc(1rem * var(--space-factor, 1)) 0}
.sep--vertical{display:inline-block;width:1px;height:100%;margin: 0 calc(1rem * var(--space-factor, 1));align-self:stretch}
.sep--sm{margin: calc(0.5rem * var(--space-factor, 1)) 0}.sep--sm.sep--vertical{margin: 0 calc(0.5rem * var(--space-factor, 1))}
.sep--lg{margin: calc(1.5rem * var(--space-factor, 1)) 0}.sep--lg.sep--vertical{margin: 0 calc(1.5rem * var(--space-factor, 1))}
}

/* --- code-block.css --- */
@layer exsa.components {

/* ============================================================
   Component: CODE BLOCK
   Sizes: default, sm
   Features: header bar with language label, copy-to-clipboard
             button with "Copied!" feedback state.
   Tokens:  --color-bg, --color-bg-secondary, --color-text,
            --color-text-secondary, --color-link, --color-success,
            --border-radius
   ============================================================ */

/* ── Base wrapper ── */
.code-block {
  position: relative;
  background: var(--color-bg-secondary);
  border-radius: var(--border-radius);
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--color-bg-secondary) 70%, var(--color-text));
}

/* ── Header bar ── */
.code-block__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(6px * var(--space-factor, 1)) calc(12px * var(--space-factor, 1));
  background: color-mix(in srgb, var(--color-bg) 50%, var(--color-bg-secondary));
  border-bottom: 1px solid var(--color-bg-secondary);
  font-size: .78rem;
}

.code-block__lang {
  font-weight: 600;
  color: var(--color-text-secondary);
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: .7rem;
}

/* ── Code body ── */
.code-block__body {
  margin: 0;
  padding: calc(14px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));
  overflow-x: auto;
  font-family: var(--font-family-mono);
  font-size: .82rem;
  line-height: 1.6;
  color: var(--color-text);
  background: transparent;
  tab-size: 2;
  white-space: pre;
}

.code-block__body code {
  font-family: inherit;
  font-size: inherit;
  background: none;
  padding: 0;
  color: inherit;
}

/* ── Syntax highlighting (reuses .hl-* classes from demo.css) ── */
.code-block__body .hl-tag   { color: var(--color-link); }
.code-block__body .hl-attr  { color: var(--color-secondary); }
.code-block__body .hl-val   { color: var(--color-warning); }
.code-block__body .hl-cmt   { color: var(--color-text-secondary); opacity: 0.6; font-style: italic; }

/* ── Copy button ── */
.code-block__copy {
  display: inline-flex;
  align-items: center;
  gap: calc(4px * var(--space-factor, 1));
  padding: calc(4px * var(--space-factor, 1)) calc(8px * var(--space-factor, 1));
  font-size: .72rem;
  font-weight: 600;
  font-family: inherit;
  color: var(--color-text-secondary);
  background: var(--color-bg);
  border: 1px solid var(--color-bg-secondary);
  border-radius: calc(var(--border-radius) * .75);
  cursor: pointer;
  transition: color .15s, border-color .15s;
  line-height: 1.2;
}

.code-block__copy:hover {
  color: var(--color-link);
  border-color: var(--color-link);
}

.code-block__copy .ic-copy {
  width: 13px;
  height: 13px;
  opacity: .7;
  transition: opacity .15s;
}

.code-block__copy:hover .ic-copy {
  opacity: 1;
}

/* ── Copied feedback state ── */
.code-block__copy--copied {
  color: var(--color-success);
  border-color: var(--color-success);
  pointer-events: none;
}

.code-block__copy--copied .ic-copy {
  background-color: var(--color-success);
  opacity: 1;
  -webkit-mask-image: url(components/icons/check.svg);
          mask-image: url(components/icons/check.svg);
}

/* ── Headerless variant — copy overlays code area ── */
.code-block--no-header .code-block__copy {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 1;
}

/* ── Compact size ── */
.code-block--sm .code-block__header {
  padding: calc(4px * var(--space-factor, 1)) calc(10px * var(--space-factor, 1));
  font-size: .7rem;
}

.code-block--sm .code-block__body {
  padding: calc(10px * var(--space-factor, 1)) calc(12px * var(--space-factor, 1));
  font-size: .75rem;
}

.code-block--sm .code-block__copy {
  padding: calc(3px * var(--space-factor, 1)) calc(6px * var(--space-factor, 1));
  font-size: .68rem;
}

}

/* --- lightbox.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: role=dialog + aria-modal + aria-label on .lightbox-gallery__overlay
   Component: Lightbox
   ============================================================ */

/* --- C15: LIGHTBOX GALLERY --- */
.lightbox-gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap: calc(12px * var(--space-factor, 1))}
.lightbox-gallery__thumb{position:relative;aspect-ratio:4/3;border-radius:var(--surface-radius);overflow:hidden;cursor:pointer;border:2px solid transparent;transition:border-color .2s,transform .2s}
.lightbox-gallery__thumb:hover{border-color:var(--color-link);transform:scale(1.03)}
.lightbox-gallery__thumb img{width:100%;height:100%;object-fit:cover;display:block}
.lightbox-gallery__thumb::after{content:'';position:absolute;inset:0;background:rgba(0,0,0,.25);opacity:0;transition:opacity .2s}
.lightbox-gallery__thumb:hover::after{opacity:1}

/* Lightbox overlay */
.lightbox{position:fixed;inset:0;z-index:var(--z-lightbox);background:rgba(0,0,0,.88);display:flex;align-items:center;justify-content:center;opacity:0;visibility:hidden;transition:opacity .22s,visibility .22s}
.lightbox--open{opacity:1;visibility:visible}
.lightbox__img{max-width:90vw;max-height:85vh;border-radius:var(--border-radius);box-shadow:0 8px 40px rgba(0,0,0,.5);transform:scale(.94);transition:transform .28s cubic-bezier(.4,0,.2,1);object-fit:contain}
.lightbox--open .lightbox__img{transform:scale(1)}
.lightbox__close,
.lightbox__prev,
.lightbox__next{position:absolute;z-index:2;background:rgba(255,255,255,.12);color:#fff;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s;padding:0;margin:0}
.lightbox__close:hover,
.lightbox__prev:hover,
.lightbox__next:hover{background:rgba(255,255,255,.25);filter:none}
.lightbox__close{top:16px;inset-inline-end:16px;width:40px;height:40px;border-radius:50%;font-size:1.2rem}
.lightbox__prev,.lightbox__next{top:50%;transform:translateY(-50%);width:44px;height:44px;border-radius:50%;font-size:1rem}
.lightbox__prev{inset-inline-start:16px}
.lightbox__next{inset-inline-end:16px}
.lightbox__counter{position:absolute;bottom:20px;left:50%;transform:translateX(-50%);color:rgba(255,255,255,.65);font-size:.78rem;font-family:var(--font-family-mono);pointer-events:none}

}

/* --- music.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: aria-label on play/pause button, aria-pressed toggled by JS
   Component: Music Player
   ============================================================ */

/* --- C16: MUSIC PLAYER --- */
.media-display{position:relative;height:180px;background-size:cover;background-position:center}.media-display__play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:42px;height:42px;border-radius:50%;border:2px solid #fff;background:rgba(0,0,0,.2);color:#fff;font-size:1rem;display:flex;align-items:center;justify-content:center;cursor:pointer;padding: 0 0 0 calc(3px * var(--space-factor, 1));transition:border-color .15s,background .15s;box-shadow:none;filter:none;margin:0}.media-display__play:hover{border-color:var(--color-link);background:rgba(0,0,0,.4);filter:none}
.media-bar{display:flex;align-items:center;padding: calc(8px * var(--space-factor, 1)) calc(14px * var(--space-factor, 1));gap: calc(10px * var(--space-factor, 1))}.media-bar__btn{font-size:17px;color:var(--color-text-secondary);cursor:pointer;background:none;border:none;padding: calc(3px * var(--space-factor, 1));line-height:1;transition:color .15s;font-family:inherit;box-shadow:none;filter:none;margin:0;display:inline-flex;align-items:center}.media-bar__btn:hover{color:var(--color-link);filter:none}.media-bar__time{font-size:.75rem;color:var(--color-text);font-family:var(--font-family-mono);flex-shrink:0}.media-bar__sep{color:var(--color-text-secondary);margin: 0 calc(2px * var(--space-factor, 1))}.media-bar__spacer{flex:1}

}

/* --- video-gallery.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: role=dialog + aria-modal on .video-modal, aria-label on close
   Component: Video Gallery
   ============================================================ */

/* --- C18: VIDEO GALLERY --- */
.video-gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap: calc(20px * var(--space-factor, 1))}
.video-gallery__card{position:relative;border-radius:var(--surface-radius);overflow:hidden;background:var(--surface-bg);border:var(--surface-border);transition:box-shadow .25s,transform .25s;cursor:pointer}
.video-gallery__card:hover{box-shadow:var(--surface-shadow-sm);transform:translateY(-2px)}
.video-gallery__thumb{position:relative;aspect-ratio:16/9;overflow:hidden;background:var(--color-bg-secondary)}
.video-gallery__thumb img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .35s}
.video-gallery__card:hover .video-gallery__thumb img{transform:scale(1.04)}
.video-gallery__play{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:54px;height:54px;border-radius:50%;background:rgba(0,0,0,.6);border:2px solid rgba(255,255,255,.85);display:flex;align-items:center;justify-content:center;transition:background .2s,transform .2s;pointer-events:none}
.video-gallery__play::after{content:'';display:block;width:0;height:0;border-style:solid;border-width:9px 0 9px 16px;border-color:transparent transparent transparent #fff;margin-left: calc(3px * var(--space-factor, 1))}
.video-gallery__card:hover .video-gallery__play{background:var(--color-link);border-color:var(--color-link);transform:translate(-50%,-50%) scale(1.12)}
.video-gallery__duration{position:absolute;bottom:10px;inset-inline-end:10px;background:rgba(0,0,0,.72);color:#fff;font-size:.68rem;font-weight:600;padding: calc(3px * var(--space-factor, 1)) calc(8px * var(--space-factor, 1));border-radius:4px;font-family:var(--font-family-mono);letter-spacing:.02em;pointer-events:none}
.video-gallery__info{padding: calc(14px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1))}
.video-gallery__title{font-size:.88rem;font-weight:600;color:var(--color-text);margin:0;line-height:1.35}
.video-gallery__meta{font-size:.72rem;color:var(--color-text-secondary);margin-top: calc(4px * var(--space-factor, 1))}

/* Modal overlay */
.video-modal{position:fixed;inset:0;z-index:var(--z-modal);background:rgba(0,0,0,.78);display:flex;align-items:center;justify-content:center;opacity:0;visibility:hidden;transition:opacity .25s,visibility .25s}
.video-modal--open{opacity:1;visibility:visible}
.video-modal__inner{position:relative;width:90%;max-width:860px;background:#000;border-radius:var(--border-radius);overflow:hidden;box-shadow:0 12px 40px rgba(0,0,0,.5);transform:translateY(20px);transition:transform .3s}
.video-modal--open .video-modal__inner{transform:translateY(0)}
.video-modal__close{position:absolute;top:12px;inset-inline-end:14px;z-index:2;width:36px;height:36px;border-radius:50%;background:rgba(0,0,0,.55);color:#fff;border:none;font-size:1.1rem;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .15s;padding:0;margin:0}
.video-modal__close:hover{background:rgba(255,255,255,.25)}
.video-modal__iframe-wrap{position:relative;padding-top:56.25%}
.video-modal__iframe-wrap iframe{position:absolute;top:0;left:0;width:100%;height:100%;border:none}

}

/* --- slideshow.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: aria-live=polite on track, aria-roledescription=carousel, aria-label on dots
   Component: Slideshow
   ============================================================ */

/* --- C17: SLIDESHOW --- */
.slideshow{position:relative;overflow:hidden;user-select:none;-webkit-user-select:none}.slideshow__track{display:flex;transition:transform .4s cubic-bezier(.4,0,.2,1)}.slideshow__slide{flex:0 0 100%;min-width:0;position:relative}.slideshow__slide img{width:100%;aspect-ratio:16/9;object-fit:cover;display:block}.slideshow__slide figcaption{position:absolute;bottom:0;inset-inline:0;padding: calc(14px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));background:linear-gradient(transparent,rgba(0,0,0,.6));color:#fff;font-size:.8rem;font-weight:500}
.slideshow__arrow{position:absolute;top:50%;transform:translateY(-50%);z-index:2;width:32px;height:32px;border-radius:50%;background:var(--surface-bg);color:var(--color-text);border:var(--surface-border-control);font-size:.8rem;display:flex;align-items:center;justify-content:center;cursor:pointer;opacity:0;transition:opacity .15s,background .15s;padding:0;box-shadow:var(--box-shadow);filter:none;font-family:inherit;margin:0}.slideshow:hover .slideshow__arrow,.slideshow:focus-within .slideshow__arrow{opacity:1}.slideshow__arrow:hover{background:var(--color-bg-secondary);filter:none}.slideshow__arrow--prev{inset-inline-start:10px}.slideshow__arrow--next{inset-inline-end:10px}@media(hover:none){.slideshow__arrow{opacity:1}}
.slideshow__dots{position:absolute;bottom:10px;inset-inline-start:50%;transform:translateX(-50%);display:flex;gap: calc(7px * var(--space-factor, 1));z-index:2}.slideshow__dot{width:8px;height:8px;border-radius:50%;background:var(--color-bg-secondary);border:2px solid transparent;cursor:pointer;padding:0;transition:background .15s,transform .15s}.slideshow__dot:hover{background:var(--color-text-secondary)}.slideshow__dot--active{background:var(--color-link);border-color:var(--color-bg);transform:scale(1.35)}

/* RTL: keep slides horizontal (track direction is always LTR) */
[dir=rtl] .slideshow__track{direction:ltr}


}

/* --- carousel.css --- */
@layer exsa.components {

/* ============================================================
   Carousel Web Component — <exsa-carousel>
   ── CSS Grid layout (Shoelace-inspired). Scroll-snap engine.
   Link with exsa.css + a theme. Requires carousel.js.

   ARIA: aria-roledescription="carousel" + aria-live="polite" on the slides
         region; carousel.js manages aria-disabled on nav buttons and
         aria-hidden on off-screen items.

   Usage:
     <exsa-carousel pagination navigation autoplay loop>
       <exsa-carousel-item><img src="..." alt=""></exsa-carousel-item>
     </exsa-carousel>

   Attributes: pagination navigation autoplay loop mouse-dragging
               slides-per-page=N slides-per-move=N orientation=vertical
               autoplay-interval=N (ms)
   CSS custom properties: --aspect-ratio  --slide-gap  --scroll-hint
   ============================================================ */

exsa-carousel {
  --slide-gap: calc(0px * var(--space-factor, 1));
  --aspect-ratio: 16 / 9;
  --scroll-hint: 0px;
  display: block;
}

.carousel {
  position: relative;
  width: 100%;
}

.carousel__slides {
  display: grid;
  overflow: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  border-radius: var(--border-radius);
  cursor: default;
  /* default slide width for pure-CSS use; carousel.js overwrites this inline
     with calc((100% - gap * (perPage - 1)) / perPage) when slides-per-page > 1 */
  --slide-size: 100%;
}
.carousel__slides::-webkit-scrollbar { display: none; }

.carousel__slides--horizontal {
  grid-auto-flow: column;
  grid-auto-columns: var(--slide-size);
  grid-auto-rows: 100%;
  column-gap: var(--slide-gap);
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--scroll-hint);
  padding-inline: var(--scroll-hint);
  overflow-y: hidden;
  aspect-ratio: calc(var(--aspect-ratio) * var(--slides-per-page, 1));
}

.carousel__slides--vertical {
  grid-auto-flow: row;
  grid-auto-rows: var(--slide-size);
  grid-auto-columns: 100%;
  row-gap: var(--slide-gap);
  scroll-snap-type: y mandatory;
  scroll-padding-block: var(--scroll-hint);
  padding-block: var(--scroll-hint);
  overflow-x: hidden;
}

exsa-carousel[orientation="vertical"] .carousel {
  display: flex;
  flex-direction: column;
  height: 100%;
}
exsa-carousel[orientation="vertical"] .carousel__slides--vertical {
  aspect-ratio: auto;
  flex: 1;
  min-height: 0;
}
exsa-carousel[orientation="vertical"] .carousel__nav-btn {
  display: none;
}

exsa-carousel[mouse-dragging] .carousel__slides {
  cursor: grab; user-select: none;
}
exsa-carousel[mouse-dragging] .carousel__slides:active {
  cursor: grabbing;
}

exsa-carousel-item {
  display: block;
  position: relative;
  scroll-snap-align: start;
  overflow: hidden;
  cursor: default;
}
exsa-carousel-item img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}

/* ── Navigation ── */
.carousel__navigation {
  display: contents;
}

.carousel__nav-btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: var(--z-floating);
  display: flex; align-items: center; justify-content: center;
  background: none; color: var(--color-text);
  border: none;
  width: 32px; height: 48px; cursor: pointer; padding: 0;
  font-size: 2.4rem; font-family: inherit; font-weight: 600;
  transition: color .15s, opacity .15s;
  opacity: 0.6;
  pointer-events: auto;
  text-shadow: 1px 1px 16px rgba(0,0,0,.3);
}
.carousel__nav-btn:hover {
  color: var(--color-link);
  opacity: 1;
}
.carousel__nav-btn--prev { inset-inline-start: 8px; }
.carousel__nav-btn--next { inset-inline-end: 8px; }

.carousel__nav-btn[aria-disabled="true"] {
  opacity: .4; cursor: not-allowed; pointer-events: none;
}

exsa-carousel[orientation="vertical"] .carousel__nav-btn {
  margin: calc(6px * var(--space-factor, 1)) 0;
}

/* ── Pagination ── */
.carousel__pagination {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: calc(0.5rem * var(--space-factor, 1)); padding: calc(0.5rem * var(--space-factor, 1)) 0 0;
  min-height: 20px; min-width: 0;
}

.carousel__pagination-item {
  width: 9px; height: 9px; background: var(--color-bg-secondary);
  border: none; border-radius: 50%; cursor: pointer; padding: 0;
  transition: background .2s, transform .2s;
}
.carousel__pagination-item:hover { background: var(--color-text-secondary); }
.carousel__pagination-item--active {
  background: var(--color-link); transform: scale(1.35);
}

/* ── RTL ── */
[dir=rtl] .carousel__slides--horizontal { direction: ltr; }

@media (prefers-reduced-motion: reduce) {
  .carousel__slides { scroll-behavior: auto; }
}

}

/* --- donut.css --- */
@layer exsa.components {

/* ============================================================
   Component: Donut Chart
   ============================================================ */
   
/* --- C19: CHARTS (DONUT + BAR) --- */
.donut{position:relative;width:200px;height:200px;margin: 0 auto calc(1rem * var(--space-factor, 1));border-radius:50%}.donut__slice{position:absolute;width:100%;height:100%;border-radius:50%;clip:rect(0px,200px,200px,100px)}.donut__slice .fill{position:absolute;width:100%;height:100%;border-radius:50%;clip:rect(0px,100px,200px,0px)}.donut__slice--1{transform:rotate(0deg)}.donut__slice--1 .fill{background:var(--color-link);transform:rotate(var(--s1,76deg))}.donut__slice--2{transform:rotate(var(--s1,76deg))}.donut__slice--2 .fill{background:var(--color-secondary);transform:rotate(var(--s2,96deg))}.donut__slice--3{transform:rotate(calc(var(--s1,76deg) + var(--s2,96deg)))}.donut__slice--3 .fill{background:var(--color-bg-secondary);transform:rotate(var(--s3,120deg))}.donut__slice--4{transform:rotate(calc(var(--s1,76deg) + var(--s2,96deg) + var(--s3,120deg)))}.donut__slice--4 .fill{background:var(--color-text-secondary);transform:rotate(var(--s4,68deg))}.donut__center{position:absolute;top:0;left:0;bottom:0;right:0;margin:auto;width:128px;height:128px;border-radius:50%;background:var(--dash-card-bg,var(--color-bg));display:flex;flex-direction:column;align-items:center;justify-content:center}.donut__center-val{font-size:26px;font-weight:700;color:var(--color-text);font-family:var(--font-family-mono);line-height:1}.donut__center-label{font-size:13px;color:var(--color-text-secondary);margin-top: calc(2px * var(--space-factor, 1))}.donut-legend{display:flex}.donut-legend__item{flex:1;text-align:center;padding: calc(10px * var(--space-factor, 1)) 0 calc(12px * var(--space-factor, 1));border-left:1px solid color-mix(in srgb, var(--color-text) 7%, transparent)}.donut-legend__item:first-child{border-left:none}.donut-legend__item p{margin:0;width:auto}.donut-legend__label{font-size:11px;color:var(--color-text-secondary);margin-bottom: calc(4px * var(--space-factor, 1));padding-top: calc(8px * var(--space-factor, 1));border-top:4px solid var(--lbl-clr,var(--color-link))}.donut-legend__pct{font-size:17px;font-weight:700;color:var(--color-text);font-family:var(--font-family-mono);margin:0}.donut-legend__pct sup{font-size:inherit;vertical-align:baseline;top:auto}
.bar-row{display:flex;align-items:center;margin-bottom: calc(12px * var(--space-factor, 1));gap: calc(10px * var(--space-factor, 1))}.bar-row:last-child{margin-bottom:0}.bar-row__label{width:38px;font-size:.72rem;color:var(--color-text);font-weight:500;flex-shrink:0}.bar-row__track{flex:1;height:19px;background:var(--dash-bar-track,color-mix(in srgb,var(--color-bg-secondary)60%,transparent));border-radius:var(--surface-radius);overflow:hidden}.bar-row__fill{height:100%;border-radius:var(--surface-radius);width:var(--bar-w,50%);transition:width .6s cubic-bezier(.4,0,.2,1)}.bar-row__val{width:34px;font-size:.72rem;font-weight:600;color:var(--color-text-secondary);font-family:var(--font-family-mono);text-align:right;flex-shrink:0}

}

/* --- dashboard.css --- */
@layer exsa.components {

/* ============================================================
   Component: Dashboard Primitives — reusable app pieces
   Extracted from layouts/dashboard.css so they work in any shell.
   Tokens (optional, set on <body> by layouts/dashboard.css):
     --dash-gap, --dash-col-min, --dash-toolbar-z
   Fallbacks keep the component functional without the layout.
   ============================================================ */

/* Panel card */
.dash-card {
  background: var(--color-bg);
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  padding: calc(16px * var(--space-factor, 1));
  margin-bottom: var(--dash-gap, var(--gap));
}
.dash-card:last-child { margin-bottom: 0; }
.dash-card--sm { padding: calc(12px * var(--space-factor, 1)); }
.dash-card--lg { padding: calc(24px * var(--space-factor, 1)); }

.dash-card__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--dash-gap, var(--gap));
  flex-wrap: wrap;
  margin-bottom: calc(12px * var(--space-factor, 1));
}
.dash-card__title {
  margin: 0;
  font-size: calc(.95rem * var(--font-factor, 1));
  font-weight: 700;
}
.dash-card__sub {
  margin: calc(2px * var(--space-factor, 1)) 0 0;
  font-size: calc(.74rem * var(--font-factor, 1));
  color: var(--color-text-secondary);
}

/* Auto-fit grid — KPI rows, card groups. Override --dash-col-min per grid. */
.dash-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--dash-col-min, 180px), 100%), 1fr));
  gap: var(--dash-gap, var(--gap));
  margin-bottom: var(--dash-gap, var(--gap));
}
.dash-grid:last-child { margin-bottom: 0; }

/* Stat / KPI card */
.dash-stat { display: flex; flex-direction: column; gap: calc(2px * var(--space-factor, 1)); }
.dash-stat__label {
  font-size: calc(.68rem * var(--font-factor, 1));
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
}
.dash-stat__value {
  font-size: calc(1.25rem * var(--font-factor, 1));
  font-weight: 800;
  margin: calc(2px * var(--space-factor, 1)) 0;
}
.dash-stat__value--num {
  font-family: var(--font-family-mono);
  font-variant-numeric: tabular-nums;
  text-align: end;
}
.dash-stat__delta { font-size: calc(.72rem * var(--font-factor, 1)); }
.dash-stat__delta--up   { color: var(--color-success); }
.dash-stat__delta--down { color: var(--color-danger); }

/* Sticky toolbar — filter bar above tables; sits just below the topbar */
.dash__toolbar {
  position: sticky;
  top: var(--topbar-height, 0);
  z-index: var(--dash-toolbar-z, 89);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--dash-gap, var(--gap));
  flex-wrap: wrap;
  background: var(--color-bg);
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  padding: calc(10px * var(--space-factor, 1)) calc(14px * var(--space-factor, 1));
  margin-bottom: var(--dash-gap, var(--gap));
}

}

/* --- progress.css --- */
@layer exsa.components {

/* ============================================================
   Component: Progress Bar
   ARIA: role="progressbar" + aria-valuenow/min/max on .progress-item__fill
         (or use the native <progress> element — styled by exsa.css)
   ============================================================ */

/* --- C20: PROGRESS BARS --- */
.progress-item{margin-bottom: calc(14px * var(--space-factor, 1))}.progress-item:last-child{margin-bottom:0}.progress-item__head{display:flex;align-items:center;gap: calc(9px * var(--space-factor, 1));margin-bottom: calc(5px * var(--space-factor, 1))}.progress-item__icon{font-size:15px;color:var(--color-text-secondary)}.progress-item__label{flex:1;font-size:.8rem;color:var(--color-text)}.progress-item__pct{font-size:.78rem;font-weight:600;color:var(--color-text-secondary);font-family:var(--font-family-mono)}
.progress-item__track{width:100%;height:18px;border-radius:var(--surface-radius);overflow:hidden;background:var(--dash-bar-track,color-mix(in srgb,var(--color-bg-secondary)60%,transparent))}
.progress-item__fill{height:100%;border-radius:var(--surface-radius);width:var(--fill-pct,50%);background:linear-gradient(to right,var(--fill-clr,var(--color-link)),color-mix(in srgb,var(--fill-clr,var(--color-link))78%,#000))}
/* Self-heal: fill placed directly under the item (missing track) still renders */
.progress-item > .progress-item__fill{min-height:18px}

}

/* --- range-slider.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: aria-describedby linking input to value display
   Component: Range Slider
   ============================================================ */

/* --- C21: RANGE SLIDER --- */
.range{display:flex;align-items:center;gap: calc(12px * var(--space-factor, 1))}
.range__input{-webkit-appearance:none;appearance:none;flex:1;height:6px;border-radius:3px;background:var(--color-bg-secondary);outline:none;cursor:pointer}
.range__input::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:20px;height:20px;border-radius:50%;background:var(--color-link);border:2px solid #fff;box-shadow:0 1px 4px rgba(0,0,0,.2);cursor:pointer;transition:transform .12s}
.range__input::-webkit-slider-thumb:hover{transform:scale(1.2)}
.range__input::-moz-range-thumb{width:20px;height:20px;border-radius:50%;background:var(--color-link);border:2px solid #fff;box-shadow:0 1px 4px rgba(0,0,0,.2);cursor:pointer;box-sizing:border-box}
.range__input::-moz-range-track{height:6px;border-radius:3px;background:var(--color-bg-secondary)}
.range__val{min-width:42px;text-align:center;font-size:.82rem;font-weight:700;color:var(--color-text);font-family:var(--font-family-mono)}

/* Sizes */
.range--sm .range__input{height:4px}
.range--sm .range__input::-webkit-slider-thumb{width:16px;height:16px}
.range--sm .range__input::-moz-range-thumb{width:16px;height:16px}

}

/* --- checkbox.css --- */
@layer exsa.components {

/* ============================================================
   Component: Checkbox
   ============================================================ */
   
/* --- C22: CHECKBOX --- */
.checkbox{display:inline-flex;align-items:center;gap: calc(9px * var(--space-factor, 1));cursor:pointer;margin-bottom: calc(10px * var(--space-factor, 1))}.checkbox input{display:none}.checkbox__box{width:20px;height:20px;border-radius:var(--surface-radius);border:2px solid var(--color-bg-secondary);background:var(--color-bg);flex-shrink:0;position:relative;transition:border-color .18s,background .18s}.checkbox__box::after{content:'';position:absolute;top:2px;left:5px;width:6px;height:11px;border:solid var(--color-link);border-width:0 2px 2px 0;transform:rotate(45deg) scale(0);transition:transform .18s cubic-bezier(.4,0,.2,1)}.checkbox input:checked+.checkbox__box{border-color:var(--color-link);background:var(--color-link)}.checkbox input:checked+.checkbox__box::after{border-color:var(--color-button-text);transform:rotate(45deg) scale(1)}.checkbox__label{font-size:.9rem;color:var(--color-text);user-select:none}

}

/* --- color-picker.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: aria-label on color input, aria-describedby linking swatch to value display
   Color Picker
   Styled native <input type="color"> with swatch preview.
   Input sits transparently over swatch — click anywhere to open.
   ============================================================ */

.color-picker {
  display: inline-flex;
  align-items: center;
  gap: calc(10px * var(--space-factor, 1));
  position: relative;
}

/* ── Swatch (visible color circle) ── */
.color-picker__swatch {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 2px solid var(--color-bg-secondary);
  flex-shrink: 0;
  background: var(--cp-color, var(--color-link));
  position: relative;
}
.color-picker__swatch:hover {
  border-color: var(--color-link);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-link) 20%, transparent);
}

/* ── Native input — transparent overlay on swatch ── */
.color-picker__input {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 100%;
  opacity: 0;
  cursor: pointer;
  border: none;
  padding: 0;
}

/* ── Label ── */
.color-picker__label {
  font-size: 0.85rem;
  color: var(--color-text);
  cursor: pointer;
}

/* ── Hex/value display ── */
.color-picker__value {
  font-size: 0.8rem;
  font-family: monospace;
  color: var(--color-text-secondary);
  padding: calc(4px * var(--space-factor, 1)) calc(8px * var(--space-factor, 1));
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  background: var(--color-bg);
  min-width: 70px;
  text-align: center;
}

/* ── Sizes ── */
.color-picker--sm .color-picker__swatch { width: 26px; height: 26px; }
.color-picker--lg .color-picker__swatch { width: 48px; height: 48px; }

}

/* --- advanced-color-picker.css --- */
@layer exsa.components {

/* EXSA Color Picker — HSL + Alpha custom picker */
/* ARIA: role=dialog + aria-label on the drop panel; aria-label +
   aria-valuetext on the HS canvas and alpha slider; aria-expanded
   + aria-haspopup on the trigger */
/* Uses EXSA tokens with fallbacks for standalone use */
.ex-cp{display:inline-block;position:relative;font-family:var(--font-family,system-ui,sans-serif)}
.ex-cp__trigger{width:28px;height:28px;border-radius:50%;cursor:pointer;border:1.5px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.08),0 1px 6px rgba(0,0,0,.1);background-color:var(--color-link,#3B82F6);background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:6px 6px;background-position:0 0,0 3px,3px -3px,-3px 0}
.ex-cp__drop{position:absolute;left:0;z-index:var(--z-dropdown);background:var(--color-bg,#fff);border-radius:var(--border-radius,8px);box-shadow:var(--box-shadow,0 2px 10px) var(--color-shadow,rgba(0,0,0,.1));padding: calc(8px * var(--space-factor, 1));display:none;width:176px}
.ex-cp__drop.is-open{display:block}
.ex-cp__drop.is-up{bottom:100%;top:auto;margin-bottom: calc(6px * var(--space-factor, 1))}
.ex-cp__drop.is-down{top:100%;bottom:auto;margin-top: calc(6px * var(--space-factor, 1))}
.ex-cp__canvas-wrap{position:relative;width:160px;height:160px}
.ex-cp__dot{position:absolute;width:8px;height:8px;border-radius:50%;border:1.5px solid #fff;box-shadow:0 0 0 1px rgba(0,0,0,.3);transform:translate(-50%,-50%);pointer-events:none}
.ex-cp__sliders{margin-top: calc(4px * var(--space-factor, 1));display:flex;flex-direction:column;gap: calc(2px * var(--space-factor, 1))}
.ex-cp__sliders input{width:100%;height:14px;-webkit-appearance:none;appearance:none;background:transparent;cursor:pointer;margin:0;border-radius:2px}
.ex-cp__sliders input::-webkit-slider-runnable-track{height:3px;border-radius:1.5px;background:var(--color-bg-secondary,#e2e8f0)}
.ex-cp__slider--hue::-webkit-slider-runnable-track{background:linear-gradient(to right,#f00,#ff0,#0f0,#0ff,#00f,#f0f,#f00)}
.ex-cp__slider--alpha::-webkit-slider-runnable-track{background:repeating-conic-gradient(#ccc 0% 25%,transparent 0% 50%) 0 0/6px 6px,linear-gradient(to right,var(--ex-cp-accent,var(--color-link,#3B82F6)),transparent)}
.ex-cp__sliders input::-webkit-slider-thumb{-webkit-appearance:none;width:10px;height:10px;border-radius:50%;background:var(--color-bg,#fff);border:1.5px solid var(--color-link,#3b82f6);box-shadow:0 0 0 1px rgba(0,0,0,.12);margin-top: calc(-3.5px * var(--space-factor, 1))}
.ex-cp__sliders input::-moz-range-thumb{width:10px;height:10px;border-radius:50%;background:var(--color-bg,#fff);border:1.5px solid var(--color-link,#3b82f6);box-shadow:0 0 0 1px rgba(0,0,0,.12)}
.ex-cp__sliders label{font-size:.5rem;font-weight:600;text-transform:uppercase;color:var(--color-text-secondary,#94a3b8)}
.ex-cp__hex{display:flex;align-items:center;gap: calc(4px * var(--space-factor, 1));margin-top: calc(4px * var(--space-factor, 1));font-size:.62rem;font-family:var(--font-family-mono,SF Mono,Fira Code,monospace);color:var(--color-text,#1e293b)}
.ex-cp__eyedrop{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;color:var(--color-text-secondary,#94a3b8);cursor:pointer;border-radius:3px;flex-shrink:0}
.ex-cp__eyedrop:hover{color:var(--color-link,#3b82f6);background:var(--color-bg-secondary,#f8fafc)}
.ex-cp__eyedrop svg{width:12px;height:12px;fill:currentColor}
.ex-cp__hex-swatch{--swatch-color:var(--color-link,#3B82F6);width:75px;height:16px;border-radius:3px;border:1px solid var(--color-border,rgba(0,0,0,.06));background:linear-gradient(var(--swatch-color),var(--swatch-color)),repeating-conic-gradient(#ccc 0% 25%,transparent 0% 50%) 0 0/6px 6px}
.ex-cp__hex-input{flex:1;border:none;background:transparent;font:inherit;color:inherit;outline:none;padding: calc(2px * var(--space-factor, 1)) calc(4px * var(--space-factor, 1));min-width:0}
.ex-cp__hex-input:focus{background:var(--color-bg-secondary,#f8fafc);border-radius:3px}
.ex-cp__canvas{display:block;width:160px;height:160px;border-radius:calc(var(--border-radius,8px)*1.2);cursor:crosshair;touch-action:none}

}

/* --- date-picker.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: aria-label on day buttons, role=dialog on calendar
   Date Picker / Calendar
   Token-driven, zero-dependency. Adapted from GeeksForGeeks.
   ============================================================ */

.date-picker {
  display: inline-block;
  width: 100%;
  max-width: 320px;
  background: var(--surface-bg);
  border: var(--surface-border-control);
  border-radius: var(--surface-radius);
  box-shadow: var(--surface-shadow-md);
  font-family: inherit;
  user-select: none;
  overflow: hidden;
}

/* ── Header: month/year + nav arrows ── */
.date-picker__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: calc(12px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));
  background: var(--color-bg-secondary);
  font-weight: 600;
  font-size: 0.95rem;
  color: var(--color-text);
}

.date-picker__nav {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 30px; height: 30px;
  border: none;
  background: none;
  cursor: pointer;
  color: var(--color-text-secondary);
  border-radius: var(--border-radius);
  transition: background 0.15s, color 0.15s;
}
.date-picker__nav:hover { background: var(--color-bg); color: var(--color-text); }
.date-picker__nav .ic { width: 16px; height: 16px; }

/* ── Weekday row ── */
.date-picker__weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  padding: calc(8px * var(--space-factor, 1)) calc(12px * var(--space-factor, 1)) 0;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-secondary);
  text-align: center;
}

/* ── Date grid ── */
.date-picker__dates {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  padding: calc(4px * var(--space-factor, 1)) calc(12px * var(--space-factor, 1)) calc(12px * var(--space-factor, 1));
  gap: calc(2px * var(--space-factor, 1));
}
.date-picker__day {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  font-size: 0.84rem;
  color: var(--color-text);
  border-radius: 50%;
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
  border: none;
  background: none;
  font-family: inherit;
  padding: 0;
}
.date-picker__day:hover { background: var(--color-bg-secondary); }
.date-picker__day--outside { color: var(--color-text-secondary); opacity: 0.4; }

/* ── Today ── */
.date-picker__day--today {
  background: var(--color-link);
  color: var(--color-button-text, #fff);
  font-weight: 700;
}

/* ── Selected ── */
.date-picker__day--selected {
  background: color-mix(in srgb, var(--color-link) 15%, transparent);
  color: var(--color-link);
  font-weight: 700;
  box-shadow: inset 0 0 0 2px var(--color-link);
}
.date-picker__day--today.date-picker__day--selected {
  background: var(--color-link);
  color: var(--color-button-text, #fff);
  box-shadow: inset 0 0 0 2px var(--color-button-text, #fff);
}

/* ── Inline input trigger variant ── */
.date-picker__input {
  width: 100%;
  padding: calc(0.55rem * var(--space-factor, 1)) calc(0.8rem * var(--space-factor, 1));
  font-size: 0.9rem;
  font-family: inherit;
  color: var(--color-text);
  background: var(--color-bg);
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  cursor: pointer;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.date-picker__input:focus {
  border-color: var(--color-link);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-link) 20%, transparent);
}

.date-picker__wrapper { position: relative; display: inline-block; }
.date-picker__wrapper .date-picker {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: var(--z-dropdown);
  display: none;
}
.date-picker__wrapper--open .date-picker { display: block; }

}

/* --- dropdown.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: role=menu on .dropdown__menu, role=menuitem on items, aria-haspopup/aria-expanded on trigger
   Component: DROPDOWN MENU
   Click-triggered popup with items, separators, shortcuts.
   Variants: solid (default), soft
   Sizes: sm, default
   ============================================================ */

/* ── Container ── */
.dropdown{position:relative;display:inline-block}

/* ── Trigger ── */
.dropdown__trigger{display:inline-flex;align-items:center;gap: calc(6px * var(--space-factor, 1));padding: calc(8px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));border-radius:var(--surface-radius);border:var(--surface-border-control);background:var(--surface-bg);color:var(--color-text);font-size:.88rem;font-weight:500;cursor:pointer;font-family:inherit;transition:background .15s,border-color .15s,box-shadow .15s;line-height:1.4;white-space:nowrap}
.dropdown__trigger:hover{background:var(--color-bg-secondary);border-color:color-mix(in srgb,var(--color-text-secondary)30%,transparent)}
.dropdown__trigger:focus-visible{outline:2px solid var(--color-link);outline-offset:2px}
.dropdown__arrow{font-size:1rem;transition:transform .18s;opacity:.5}
.dropdown--open .dropdown__arrow{transform:rotate(180deg)}

/* ── Menu panel ── */
.dropdown__menu{position:absolute;top:calc(100% + 4px);inset-inline-start:0;min-width:160px;background:var(--surface-bg);border:var(--surface-border);border-radius:var(--surface-radius);box-shadow:var(--surface-shadow-md),0 0 0 1px color-mix(in srgb,var(--color-bg-secondary)60%,transparent);padding: calc(4px * var(--space-factor, 1));z-index:var(--z-dropdown);opacity:0;transform:scale(.95) translateY(-4px);transform-origin:top left;pointer-events:none;transition:opacity .12s,transform .12s}
.dropdown--open .dropdown__menu{opacity:1;transform:scale(1) translateY(0);pointer-events:all}

/* ── Soft variant ── */
.dropdown--soft .dropdown__menu{background:var(--color-bg-secondary);border-color:transparent;box-shadow:0 4px 12px color-mix(in srgb,#000 6%,transparent)}

/* ── Size: small ── */
.dropdown--sm .dropdown__trigger{padding: calc(5px * var(--space-factor, 1)) calc(12px * var(--space-factor, 1));font-size:.8rem}
.dropdown--sm .dropdown__menu{min-width:130px;padding: calc(3px * var(--space-factor, 1))}
.dropdown--sm .dropdown__item{padding: calc(5px * var(--space-factor, 1)) calc(8px * var(--space-factor, 1));font-size:.78rem}

/* ── Items ── */
.dropdown__item{display:flex;align-items:center;gap: calc(8px * var(--space-factor, 1));width:100%;padding: calc(6px * var(--space-factor, 1)) calc(8px * var(--space-factor, 1));font-size:.84rem;color:var(--color-text);background:none;border:none;border-radius:calc(var(--border-radius)*.6);cursor:pointer;text-align:start;font-family:inherit;line-height:1;transition:background .06s}
.dropdown__item:hover{background:color-mix(in srgb,var(--color-text-secondary)10%,transparent)}
.dropdown__item:focus-visible{outline:2px solid var(--color-link);outline-offset:-2px}

/* ── Danger item ── */
.dropdown__item--danger{color:var(--color-danger)}
.dropdown__item--danger:hover{background:color-mix(in srgb,var(--color-danger)12%,transparent)}

/* ── Shortcut hint ── */
.dropdown__shortcut{margin-inline-start:auto;font-size:.68rem;color:var(--color-text-secondary);letter-spacing:.02em}

/* ── Separator ── */
.dropdown__divider{height:1px;background:var(--color-bg-secondary);margin: calc(3px * var(--space-factor, 1)) calc(6px * var(--space-factor, 1))}

/* ── Label (non-interactive header) ── */
.dropdown__label{padding: calc(6px * var(--space-factor, 1)) calc(8px * var(--space-factor, 1)) calc(2px * var(--space-factor, 1));font-size:.68rem;font-weight:600;color:var(--color-text-secondary);text-transform:uppercase;letter-spacing:.06em}

}

/* --- form-validation.css --- */
@layer exsa.components {

/* ============================================================
   Form Validation States
   .input--error | .input--success | .form-helper
   Token-driven — uses semantic color variables.
   ============================================================ */

/* ── Semantic Colors (form-specific backgrounds) ── */
/* ── Input / Textarea / Select states ── */
.input--error,
.textarea--error,
select.select--error {
  border-color: var(--color-danger);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-danger) 15%, transparent);
}
.input--success,
.textarea--success,
select.select--success {
  border-color: var(--color-success);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-success) 15%, transparent);
}

/* ── Form helper text ── */
.form-helper {
  display: flex;
  align-items: center;
  gap: calc(6px * var(--space-factor, 1));
  font-size: 0.8rem;
  margin-top: calc(-0.6rem * var(--space-factor, 1));
  margin-bottom: calc(0.8rem * var(--space-factor, 1));
  line-height: 1.4;
  color: var(--color-text-secondary);
}
.form-helper::before {
  content: "";
  display: inline-block;
  width: 14px; height: 14px;
  flex-shrink: 0;
  background-color: currentColor;
  -webkit-mask: url(components/icons/info.svg) center/contain no-repeat;
          mask: url(components/icons/info.svg) center/contain no-repeat;
}

.form-helper--error {
  color: var(--color-danger);
}
.form-helper--error::before {
  -webkit-mask-image: url(components/icons/x-circle.svg);
          mask-image: url(components/icons/x-circle.svg);
}

.form-helper--success {
  color: var(--color-success);
}
.form-helper--success::before {
  -webkit-mask-image: url(components/icons/check.svg);
          mask-image: url(components/icons/check.svg);
}

/* ── Inline feedback inside input groups ── */
.input-group .form-helper {
  margin-top: calc(4px * var(--space-factor, 1));
  margin-bottom: 0;
}

}

/* --- input-group.css --- */
@layer exsa.components {

/* ============================================================
   Component: Input Group
   ============================================================ */
   
/* --- C25: INPUT GROUP --- */
.input-group{display:flex;flex-direction:column;gap: calc(5px * var(--space-factor, 1))}.input-group__label{font-size:.82rem;font-weight:600;color:var(--color-text)}.input-group__wrap{display:flex;align-items:center;border:var(--surface-border-control);border-radius:var(--surface-radius);background:var(--surface-bg);box-shadow:var(--surface-inset);overflow:hidden;transition:border-color .18s}.input-group__wrap:focus-within{border-color:var(--color-link);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-link)15%,transparent)}.input-group__icon{padding: 0 calc(12px * var(--space-factor, 1));font-size:1rem;color:var(--color-text-secondary);flex-shrink:0}.input-group__input{flex:1;border:none;outline:none;padding: calc(9px * var(--space-factor, 1)) calc(12px * var(--space-factor, 1)) calc(9px * var(--space-factor, 1)) 0;font-size:.88rem;font-family:inherit;color:var(--color-text);background:transparent;margin:0;box-shadow:none;border-radius:0;min-width:0}.input-group__input::placeholder{color:var(--color-text-secondary)}.input-group__addon{padding: 0 calc(12px * var(--space-factor, 1));font-size:.82rem;color:var(--color-text-secondary);background:var(--color-bg-secondary);line-height:38px;flex-shrink:0}

}

/* --- password-input.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: aria-pressed toggled by JS, aria-label on toggle
   Component: Password Input
   ============================================================ */

/* --- C27: PASSWORD INPUT --- */
.password-input{position:relative;display:inline-block;width:100%;max-width:320px}
.password-input__field{width:100%;padding: calc(10px * var(--space-factor, 1)) calc(42px * var(--space-factor, 1)) calc(10px * var(--space-factor, 1)) calc(14px * var(--space-factor, 1));border:var(--surface-border-control);border-radius:var(--surface-radius);font-size:.86rem;font-family:inherit;color:var(--color-text);background:var(--surface-bg);box-shadow:var(--surface-inset);outline:none;transition:border-color .18s,box-shadow .18s;margin:0}
.password-input__field:focus{border-color:var(--color-link);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-link)18%,transparent)}
.password-input__toggle{position:absolute;inset-inline-end:28px;top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;background:none;background-color:transparent;border:none;color:var(--color-text-secondary);cursor:pointer;padding:0;margin:0;line-height:1;font-size:1rem;border-radius:4px;transition:color .15s,background .15s}
.password-input__toggle:hover{color:var(--color-link);background:var(--color-bg-secondary)}
.password-input__toggle svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}

}

/* --- popover.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: role=dialog on .popover__content, aria-expanded on trigger, aria-haspopup on trigger
   Component: POPOVER
   Click-triggered floating card for rich content (forms, text).
   Sizes: sm, default, lg, xl
   ============================================================ */

/* ── Trigger ── */
.popover{position:relative;display:inline-block}

/* ── Content panel ── */
.popover__content{position:absolute;z-index:var(--z-popover);top:calc(100% + 8px);inset-inline-start:50%;transform:translateX(-50%);width:320px;max-width:calc(100vw - 32px);background:var(--surface-bg);border:var(--surface-border);border-radius:var(--surface-radius);box-shadow:var(--surface-shadow-md),0 0 0 1px color-mix(in srgb,var(--color-bg-secondary)50%,transparent);padding: calc(16px * var(--space-factor, 1));opacity:0;transform:translateX(-50%) scale(.95) translateY(-4px);transform-origin:top center;pointer-events:none;transition:opacity .15s,transform .15s}
.popover--open .popover__content{opacity:1;transform:translateX(-50%) scale(1) translateY(0);pointer-events:all}

/* ── Arrow ── */
.popover__arrow{position:absolute;top:-6px;inset-inline-start:50%;transform:translateX(-50%);width:12px;height:6px;overflow:hidden}
.popover__arrow::before{content:'';display:block;width:8px;height:8px;background:var(--surface-bg);border:var(--surface-border);transform:rotate(45deg);margin: calc(2px * var(--space-factor, 1)) auto calc(-6px * var(--space-factor, 1))}

/* ── Sizes ── */
.popover--sm .popover__content{width:240px;padding: calc(12px * var(--space-factor, 1))}
.popover--lg .popover__content{width:400px;padding: calc(20px * var(--space-factor, 1))}
.popover--xl .popover__content{width:520px;padding: calc(24px * var(--space-factor, 1))}

/* ── Align: start (left) ── */
.popover--align-start .popover__content{inset-inline-start:0;transform:translateX(0) scale(.95) translateY(-4px);transform-origin:top left}
.popover--align-start.popover--open .popover__content{transform:translateX(0) scale(1) translateY(0)}
.popover--align-start .popover__arrow{inset-inline-start:20px;transform:none}

/* ── Align: end (right) ── */
.popover--align-end .popover__content{inset-inline-start:auto;inset-inline-end:0;transform:translateX(0) scale(.95) translateY(-4px);transform-origin:top right}
.popover--align-end.popover--open .popover__content{transform:translateX(0) scale(1) translateY(0)}
.popover--align-end .popover__arrow{inset-inline-start:auto;inset-inline-end:20px;transform:none}

/* ── Backdrop ── */
.popover__backdrop{position:fixed;inset:0;z-index:var(--z-popover-backdrop);display:none}
.popover--open .popover__backdrop{display:block}
}

/* --- radio.css --- */
@layer exsa.components {

/* ============================================================
   Component: Radio Button
   ============================================================ */
   
/* --- C28: RADIO BUTTON --- */
.radio{display:inline-flex;align-items:center;gap: calc(9px * var(--space-factor, 1));cursor:pointer;margin-bottom: calc(10px * var(--space-factor, 1))}.radio input{display:none}.radio__circle{width:20px;height:20px;border-radius:50%;border:2px solid var(--color-bg-secondary);background:var(--color-bg);flex-shrink:0;position:relative;transition:border-color .18s,background .18s}.radio__circle::after{content:'';position:absolute;top:3px;left:3px;width:10px;height:10px;border-radius:50%;background:var(--color-link);transform:scale(0);transition:transform .18s cubic-bezier(.4,0,.2,1)}.radio input:checked+.radio__circle{border-color:var(--color-link)}.radio input:checked+.radio__circle::after{transform:scale(1)}.radio__label{font-size:.9rem;color:var(--color-text);user-select:none}

}

/* --- rating.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: role=radiogroup on .rating, role=radio on stars, aria-checked toggled by JS
   Component: Rating
   ============================================================ */
   
/* --- C29: RATING STARS --- */
.rating{display:inline-flex;gap: calc(4px * var(--space-factor, 1));direction:rtl}.rating input{display:none}.rating__star{font-size:1.5rem;color:var(--color-bg-secondary);cursor:pointer;transition:color .15s,transform .12s;user-select:none;line-height:1}.rating__star:hover{transform:scale(1.15)}.rating__star:hover,.rating__star:hover~.rating__star{color:var(--color-warning)}.rating__star--active{color:var(--color-warning)}.rating--readonly .rating__star{cursor:default;pointer-events:none}.rating__value{font-size:.82rem;color:var(--color-text-secondary);margin-inline-start: calc(8px * var(--space-factor, 1));font-family:var(--font-family-mono)}

/* RTL: undo the direction:rtl star-rating hack so it doesn't double-flip */
[dir=rtl] .rating{direction:ltr}

}

/* --- select.css --- */
@layer exsa.components {

/* ============================================================
   Styled Select
   Custom <select> wrapper with chevron icon, focus ring, sizes.
   Token-driven — uses --color-link, --border-radius, --color-bg.
   ============================================================ */

.select {
  position: relative;
  display: inline-block;
  width: 100%;
  max-width: var(--width-card-wide);
}

.select__field {
  appearance: none;
  -webkit-appearance: none;
  width: 100%;
  padding: calc(0.55rem * var(--space-factor, 1)) calc(2.5rem * var(--space-factor, 1)) calc(0.55rem * var(--space-factor, 1)) calc(0.8rem * var(--space-factor, 1));
  font-size: 0.9rem;
  font-family: inherit;
  line-height: var(--line-height);
  color: var(--color-text);
  background: var(--surface-bg);
  border: var(--surface-border-control);
  border-radius: var(--surface-radius);
  box-shadow: var(--surface-inset);
  cursor: pointer;
  transition: border-color 0.15s, box-shadow 0.15s;
  outline: none;
}
.select__field:focus {
  border-color: var(--color-link);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-link) 20%, transparent);
}

/* ── Chevron arrow ── */
.select::after {
  content: "";
  position: absolute;
  inset-inline-end: 10px;
  top: 50%;
  transform: translateY(-50%);
  width: 16px; height: 16px;
  pointer-events: none;
  background-color: var(--color-text-secondary);
  -webkit-mask: url(components/icons/chevron-down.svg) center/contain no-repeat;
          mask: url(components/icons/chevron-down.svg) center/contain no-repeat;
  transition: background-color 0.15s;
}
.select:hover::after { background-color: var(--color-text); }

/* ── Sizes ── */
.select--sm .select__field { padding: calc(0.35rem * var(--space-factor, 1)) calc(2rem * var(--space-factor, 1)) calc(0.35rem * var(--space-factor, 1)) calc(0.6rem * var(--space-factor, 1)); font-size: 0.8rem; }
.select--sm::after { width: 14px; height: 14px; inset-inline-end: 8px; }
.select--lg .select__field { padding: calc(0.7rem * var(--space-factor, 1)) calc(3rem * var(--space-factor, 1)) calc(0.7rem * var(--space-factor, 1)) calc(1rem * var(--space-factor, 1)); font-size: 1rem; }
.select--lg::after { width: 18px; height: 18px; inset-inline-end: 12px; }

/* ── Error state (uses form-validation.css tokens if loaded) ── */
.select--error .select__field {
  border-color: var(--color-danger);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-danger) 15%, transparent);
}

/* ── Disabled ── */
.select__field:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  background: var(--color-bg-secondary);
}

}

/* --- tabs.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: role=tablist on .tabs, role=tab + aria-selected on tabs, role=tabpanel on panels
   Component: Tabs
   ============================================================ */
   
/* --- C30: TABS --- */
.tabs{display:flex;border-bottom:2px solid var(--color-bg-secondary)}.tabs__tab{padding: calc(10px * var(--space-factor, 1)) calc(18px * var(--space-factor, 1));font-size:.82rem;font-weight:600;color:var(--color-text-secondary);cursor:pointer;border:none;background:none;font-family:inherit;border-bottom:2px solid transparent;margin-bottom: calc(-2px * var(--space-factor, 1));transition:color .15s,border-color .15s;white-space:nowrap;box-shadow:none;filter:none}.tabs__tab:hover{color:var(--color-text);filter:none}.tabs__tab--active{color:var(--color-link);border-bottom-color:var(--color-link)}.tabs__panel{display:none;padding: calc(16px * var(--space-factor, 1)) 0 calc(4px * var(--space-factor, 1))}.tabs__panel--active{display:block}

}

/* --- toggle.css --- */
@layer exsa.components {

/* ============================================================
   Component: Toggle
   ARIA: js/toggle.js adds role="switch" + aria-checked on the hidden input
   ============================================================ */
   
/* --- C31: TOGGLE SWITCH --- */
.toggle{display:inline-flex;align-items:center;gap: calc(10px * var(--space-factor, 1));cursor:pointer;margin-bottom: calc(10px * var(--space-factor, 1))}.toggle input{display:none}.toggle__track{position:relative;width:44px;height:24px;background:var(--color-bg-secondary);border-radius:12px;border:1px solid var(--color-bg-secondary);transition:background .2s,border-color .2s;flex-shrink:0}.toggle__track::after{content:'';position:absolute;top:2px;left:2px;width:18px;height:18px;border-radius:50%;background:var(--color-bg);box-shadow:0 1px 3px rgba(0,0,0,.15);transition:transform .2s cubic-bezier(.4,0,.2,1)}.toggle input:checked+.toggle__track{background:var(--color-link);border-color:var(--color-link)}.toggle input:checked+.toggle__track::after{transform:translateX(20px)}.toggle__label{font-size:.85rem;color:var(--color-text);user-select:none}.toggle--sm .toggle__track{width:32px;height:18px;border-radius:9px}.toggle--sm .toggle__track::after{width:12px;height:12px;top:2px;left:2px}.toggle--sm input:checked+.toggle__track::after{transform:translateX(14px)}.toggle--sm .toggle__label{font-size:.75rem}

}

/* --- alert.css --- */
@layer exsa.components {

/* ============================================================
   Component: ALERT / CALLOUT
   Variants: info, success, warning, danger
   Styles: soft (default), outline, surface
   Sizes: sm, default, lg
   ARIA: role="alert" on dynamically inserted alerts (static banners need none)
   ============================================================ */

/* ── Base ── */
.alert{padding: calc(14px * var(--space-factor, 1)) calc(18px * var(--space-factor, 1));border-radius:var(--surface-radius);font-size:.84rem;line-height:1.6;display:flex;align-items:flex-start;gap: calc(12px * var(--space-factor, 1));border:1px solid transparent}
.alert__icon{flex-shrink:0;font-size:1rem;line-height:1.4}
.alert__body{flex:1;min-width:0}
.alert__title{font-weight:700;margin: 0 0 calc(2px * var(--space-factor, 1));font-size:.88rem}
.alert__msg{margin:0;opacity:.85}
.alert__close{flex-shrink:0;background:none;border:none;font-size:1rem;cursor:pointer;opacity:.5;padding: 0 calc(2px * var(--space-factor, 1));line-height:1.4;transition:opacity .15s;margin:0}
.alert__close:hover{opacity:1}

/* ── Soft variants (default) ── */
.alert--info{background:color-mix(in srgb,var(--color-link)10%,transparent);border-color:color-mix(in srgb,var(--color-link)25%,transparent);color:var(--color-link)}
.alert--success{background:color-mix(in srgb,var(--color-success)10%,transparent);border-color:color-mix(in srgb,var(--color-success)28%,transparent);color:var(--color-success-hover)}
.alert--warning{background:color-mix(in srgb,var(--color-warning)10%,transparent);border-color:color-mix(in srgb,var(--color-warning)28%,transparent);color:var(--color-warning-hover)}
.alert--danger{background:color-mix(in srgb,var(--color-danger)8%,transparent);border-color:color-mix(in srgb,var(--color-danger)22%,transparent);color:var(--color-danger-hover)}

/* ── Outline variants ── */
.alert--outline.alert--info{background:transparent;border-color:var(--color-link);color:var(--color-link)}
.alert--outline.alert--success{background:transparent;border-color:var(--color-success);color:var(--color-success)}
.alert--outline.alert--warning{background:transparent;border-color:var(--color-warning);color:var(--color-warning)}
.alert--outline.alert--danger{background:transparent;border-color:var(--color-danger);color:var(--color-danger)}

/* ── Surface variant ── */
.alert--surface{background:var(--surface-bg);border:var(--surface-border);box-shadow:var(--surface-shadow-md);color:var(--color-text)}
.alert--surface .alert__icon{color:var(--color-link)}

/* ── Sizes ── */
.alert--sm{padding: calc(8px * var(--space-factor, 1)) calc(14px * var(--space-factor, 1));font-size:.78rem;gap: calc(8px * var(--space-factor, 1));border-radius:calc(var(--surface-radius)*.75)}
.alert--sm .alert__icon{font-size:.85rem}
.alert--sm .alert__title{font-size:.8rem}
.alert--lg{padding: calc(18px * var(--space-factor, 1)) calc(24px * var(--space-factor, 1));font-size:.92rem;gap: calc(16px * var(--space-factor, 1))}
.alert--lg .alert__title{font-size:.95rem}

}

/* --- consent-bar.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: role=alert on .cookie-bar
   Component: Cookie Bar
   ============================================================ */

/* --- C33: COOKIE BAR --- */
.cookie-bar{position:fixed;bottom:0;left:0;right:0;z-index:var(--z-cookiebar);background:var(--surface-bg);border-top:var(--surface-border);box-shadow:var(--surface-shadow-md);padding: calc(16px * var(--space-factor, 1)) calc(24px * var(--space-factor, 1));display:flex;align-items:center;justify-content:center;gap: calc(16px * var(--space-factor, 1));flex-wrap:wrap;transform:translateY(100%);transition:transform .35s cubic-bezier(.4,0,.2,1)}
.cookie-bar--visible{transform:translateY(0)}
.cookie-bar__text{font-size:.82rem;color:var(--color-text-secondary);line-height:1.6;max-width:600px;margin:0}
.cookie-bar__text a{color:var(--color-link);font-weight:600;text-decoration:underline}
.cookie-bar__actions{display:flex;gap: calc(8px * var(--space-factor, 1));flex-shrink:0}
.cookie-bar__btn{padding: calc(8px * var(--space-factor, 1)) calc(18px * var(--space-factor, 1));border-radius:var(--surface-radius);font-size:.8rem;font-weight:700;cursor:pointer;font-family:inherit;border:var(--surface-border-control);background:var(--surface-bg);color:var(--color-text);transition:background .15s,color .15s;margin:0}
.cookie-bar__btn:hover{background:var(--color-bg-secondary)}
.cookie-bar__btn--accept{background:var(--color-link);color:var(--color-button-text);border-color:var(--color-link)}
.cookie-bar__btn--accept:hover{opacity:.88;filter:none}

}

/* --- skeleton.css --- */
@layer exsa.components {

/* ============================================================
   Component: Skeleton
   ARIA: aria-busy="true" on the loading region; the skeleton itself is aria-hidden
   ============================================================ */
   
/* --- C34: SKELETON LOADER --- */
.skeleton{display:flex;flex-direction:column;gap: calc(12px * var(--space-factor, 1))}.skeleton__line{height:14px;border-radius:var(--surface-radius);background:linear-gradient(90deg,var(--color-bg-secondary) 25%,color-mix(in srgb,var(--color-bg-secondary)60%,var(--color-text))50%,var(--color-bg-secondary)75%);background-size:200% 100%;animation:shimmer 1.6s ease-in-out infinite;width:100%}.skeleton__line--short{width:60%}.skeleton__line--medium{width:85%}.skeleton__line--circle{width:44px;height:44px;border-radius:50%;flex-shrink:0}.skeleton__line--h2{height:22px;width:50%}.skeleton__line--btn{height:36px;width:120px}.skeleton__row{display:flex;gap: calc(14px * var(--space-factor, 1));align-items:center}.skeleton__row .skeleton__line{flex:1}@keyframes shimmer{from{background-position:200% 0}to{background-position:-200% 0}}

}

/* --- spinner.css --- */
@layer exsa.components {

/* ============================================================
   Component: Spinner
   ARIA: role="status" + aria-live="polite" on the loading region;
         the .spinner itself is decorative (aria-hidden)
   ============================================================ */
   
/* --- C35: SPINNER --- */
.spinner{width:36px;height:36px;border-radius:50%;border:4px solid var(--color-bg-secondary);border-top-color:var(--color-link);animation:spin .7s linear infinite;display:inline-block}.spinner--sm{width:20px;height:20px;border-width:2px}.spinner--lg{width:52px;height:52px;border-width:5px}@keyframes spin{to{transform:rotate(360deg)}}.spinner-wrap{display:flex;align-items:center;justify-content:center;gap: calc(12px * var(--space-factor, 1));padding: calc(20px * var(--space-factor, 1));flex-direction:column}.spinner-wrap__label{font-size:.82rem;color:var(--color-text-secondary)}

}

/* --- toast.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: role=status + aria-live=polite on container, role=alert on toasts
   Component: Toast
   ============================================================ */
   
/* --- C36: TOAST NOTIFICATIONS --- */
.toast-container{position:fixed;bottom:20px;inset-inline-end:20px;z-index:var(--z-toast);display:flex;flex-direction:column-reverse;gap: calc(10px * var(--space-factor, 1))}.toast{display:flex;align-items:center;gap: calc(10px * var(--space-factor, 1));min-width:280px;max-width:380px;padding: calc(12px * var(--space-factor, 1)) calc(16px * var(--space-factor, 1));border-radius:var(--surface-radius);background:var(--surface-bg);color:var(--color-text);border:var(--surface-border);box-shadow:var(--surface-shadow-md);font-size:.85rem;animation:toast-in .3s cubic-bezier(.4,0,.2,1);pointer-events:all;line-height:1.4}.toast--leaving{animation:toast-out .25s cubic-bezier(.4,0,1,1) forwards}.toast__icon{font-size:1.1rem;flex-shrink:0}.toast__msg{flex:1}.toast__close{cursor:pointer;opacity:.5;font-size:.9rem;padding: calc(2px * var(--space-factor, 1));background:none;border:none;color:inherit;flex-shrink:0;box-shadow:none;filter:none;margin:0;line-height:1}.toast__close:hover{opacity:1;filter:none}.toast--success{border-left:3px solid var(--color-success)}.toast--error{border-left:3px solid var(--color-danger)}.toast--info{border-left:3px solid var(--color-link)}@keyframes toast-in{from{opacity:0;transform:translateX(40px) scale(.95)}}@keyframes toast-out{to{opacity:0;transform:translateX(60px) scale(.9)}}

}

/* --- form-required.css --- */
@layer exsa.components {

/* ============================================================
   Form Required & Validation Helpers
   Auto-detects :user-invalid forms + required-field asterisks.
   Base form/input styles are in exsa.css (@layer exsa.elements).
   Visual error/success states: form-validation.css
   ============================================================ */

/* ── Auto validation feedback ── */
:where(.exsa form:has(:user-invalid)){border-color:var(--color-danger)}
:where(.exsa label:has(+:required))::after{content:" *";color:var(--color-danger)}
}

/* --- buttons.css --- */
@layer exsa.components {

/* ============================================================
   Component: BUTTONS
   Variants: primary, success, danger, warning, neutral,
             outline, ghost, soft, surface
   Sizes: xs, sm, default, lg
   Mods: high-contrast, radius-full, radius-none, loading, block
   Theme-ready: uses --color-link, --color-bg, etc.
   ARIA: aria-pressed on toggle buttons; aria-label on icon-only buttons;
         aria-busy="true" on the button while a loading state is active
   ============================================================ */

/* ── Base button reset ── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: calc(6px * var(--space-factor, 1));
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  line-height: 1;           /* tight: height = padding×2 + font-size */
  padding: calc(10px * var(--space-factor, 1)) calc(20px * var(--space-factor, 1));
  border-radius: var(--surface-radius);
  border: 2px solid transparent;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s, box-shadow 0.15s, transform 0.1s;
  text-decoration: none;
  white-space: nowrap;
  user-select: none;
  vertical-align: middle;
}
.btn:active { transform: scale(0.97); }
.btn:disabled,
.btn--disabled {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Solid variants ── */

/* Primary (link color) */
.btn--primary {
  background: var(--color-link);
  border-color: var(--color-link);
  color: var(--color-button-text, #fff);
}
.btn--primary:hover { filter: brightness(1.1); }

/* Success (green) */
.btn--success {
  background: var(--color-success);
  border-color: var(--color-success);
  color: var(--color-button-text);
}
.btn--success:hover { background: var(--color-success-hover); border-color: var(--color-success-hover); }

/* Danger (red) */
.btn--danger {
  background: var(--color-danger);
  border-color: var(--color-danger);
  color: var(--color-button-text);
}
.btn--danger:hover { background: var(--color-danger-hover); border-color: var(--color-danger-hover); }

/* Warning (amber) */
.btn--warning {
  background: var(--color-warning);
  border-color: var(--color-warning);
  color: var(--color-button-text);
}
.btn--warning:hover { background: var(--color-warning-hover); border-color: var(--color-warning-hover); }

/* Neutral (grey, theme-aware) */
.btn--neutral {
  background: var(--color-bg-secondary);
  border-color: var(--color-bg-secondary);
  color: var(--color-button-text-inverse);
}
.btn--neutral:hover { filter: brightness(0.95); }

/* Solid buttons pick up the skin's inset (clay's pressed highlight) — default no-op */
.btn--primary,
.btn--success,
.btn--danger,
.btn--warning,
.btn--neutral { box-shadow: var(--surface-inset); }

/* ── Subtle variants ── */

/* Outline */
.btn--outline {
  background: transparent;
  border-color: var(--color-link);
  color: var(--color-link);
}
.btn--outline:hover { background: var(--color-link); color: var(--color-button-text, #fff); }

/* Ghost */
.btn--ghost {
  background: transparent;
  border-color: transparent;
  color: var(--color-button-text-inverse);
}
.btn--ghost:hover { background: var(--color-bg-secondary); }

/* Soft — subtle tint, no border, inherits link hue */
.btn--soft {
  background: color-mix(in srgb, var(--color-link) 12%, transparent);
  border-color: transparent;
  color: var(--color-link);
}
.btn--soft:hover { background: color-mix(in srgb, var(--color-link) 20%, transparent); }

/* Surface — card-like, raised */
.btn--surface {
  background: var(--surface-bg);
  border-color: var(--color-border);
  color: var(--color-button-text-inverse);
  box-shadow: 0 1px 3px color-mix(in srgb, var(--color-text-secondary) 12%, transparent), var(--surface-inset);
}
.btn--surface:hover { background: var(--color-bg-secondary); border-color: color-mix(in srgb, var(--color-text-secondary) 30%, transparent); }

/* ── High Contrast Modifier ── */
.btn--high-contrast.btn--outline,
.btn--high-contrast.btn--ghost,
.btn--high-contrast.btn--soft,
.btn--high-contrast.btn--surface {
  background: var(--color-link);
  border-color: var(--color-link);
  color: var(--color-button-text, #fff);
}
.btn--high-contrast.btn--outline:hover,
.btn--high-contrast.btn--ghost:hover,
.btn--high-contrast.btn--soft:hover,
.btn--high-contrast.btn--surface:hover { filter: brightness(1.1); }

/* ── Sizes ── */

.btn--xs {
  font-size: 0.7rem;
  padding: calc(4px * var(--space-factor, 1)) calc(10px * var(--space-factor, 1));
  border-radius: calc(var(--border-radius) * 0.6);
  gap: calc(4px * var(--space-factor, 1));
}

.btn--sm {
  font-size: 0.78rem;
  padding: calc(6px * var(--space-factor, 1)) calc(14px * var(--space-factor, 1));
  border-radius: calc(var(--border-radius) * 0.75);
  gap: calc(5px * var(--space-factor, 1));
}

.btn--lg {
  font-size: 1rem;
  padding: calc(13px * var(--space-factor, 1)) calc(26px * var(--space-factor, 1));
  border-radius: calc(var(--border-radius) * 1.25);
  gap: calc(8px * var(--space-factor, 1));
}

/* ── Icon-only button ── */
.btn--icon {
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: 50%;
}
.btn--icon.btn--xs { width: 26px; height: 26px; }
.btn--icon.btn--sm { width: 32px; height: 32px; }
.btn--icon.btn--lg { width: 50px; height: 50px; }

/* ── Block (full width) ── */
.btn--block { display: flex; width: 100%; }

/* ── Radius variants ── */
.btn--radius-full { border-radius: 9999px; }
.btn--radius-none  { border-radius: 0; }

/* ── Loading state ── */
.btn--loading {
  position: relative;
  color: transparent;
  pointer-events: none;
}
.btn--loading::after {
  content: '';
  position: absolute;
  inset: 0;
  margin: auto;
  width: 18px; height: 18px;
  border: 2px solid rgba(255,255,255,0.3);
  border-top-color: var(--color-button-text);
  border-radius: 50%;
  animation: btn-spin 0.6s linear infinite;
}
/* Spinner color for light-background variants */
.btn--loading.btn--outline::after,
.btn--loading.btn--ghost::after,
.btn--loading.btn--soft::after,
.btn--loading.btn--surface::after,
.btn--loading.btn--neutral::after {
  border-color: color-mix(in srgb, var(--color-link) 25%, transparent);
  border-top-color: var(--color-link);
}
@keyframes btn-spin { to { transform: rotate(360deg); } }

}

/* --- resizer.css --- */
@layer exsa.components {

/* ============================================================
   ARIA: aria-valuenow/aria-valuemin/aria-valuemax on handle, role=separator
   Component: RESIZER
   Horizontal drag handle for resizable panels.
   Requires resizer.js for drag interaction.
   Theme-ready: uses --color-bg-secondary, --border-radius.
   ============================================================ */

.resizer {
  position: absolute;
  top: 0;
  inset-inline-end: 0;
  bottom: 0;
  width: 1.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  color: var(--color-text-secondary);
  background: color-mix(in srgb, var(--color-text) 7%, transparent);
  border-inline-start: 1px solid var(--color-bg-secondary);
  border-start-end-radius: var(--border-radius);
  border-end-end-radius: var(--border-radius);
  cursor: ew-resize;
  user-select: none;
  z-index: 5;
  transition: color 0.15s, background 0.15s;
}
.resizer:hover,
.resizer--active {
  color: var(--color-text);
  background: var(--color-bg-secondary);
}

/* Grip icon (three vertical dots) */
.resizer::before {
  content: '⋮';
  line-height: 1;
  pointer-events: none;
}

/* Left-edge variant */
.resizer--left {
  inset-inline-end: auto;
  inset-inline-start: 0;
  border-inline-start: none;
  border-inline-end: 1px solid var(--color-bg-secondary);
  border-start-end-radius: 0;
  border-end-end-radius: 0;
  border-start-start-radius: var(--border-radius);
  border-end-start-radius: var(--border-radius);
}

/* RTL: flip cursor direction */
[dir=rtl] .resizer { cursor: ew-resize; }

/* Bottom-edge variant (vertical resize) */
.resizer--bottom {
  top: auto;
  right: 0;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 1.75rem;
  border-inline-start: none;
  border-top: 1px solid var(--color-bg-secondary);
  border-radius: 0 0 var(--border-radius) var(--border-radius);
  cursor: ns-resize;
}
.resizer--bottom::before { content: '⋯'; }

/* ── Resize target ── */
.resizer__target {
  overflow: hidden;
  position: relative;
}

}

/* --- background.css --- */
@layer exsa.components {

/* ============================================================
   EXSA Background — image backgrounds for pages & sections
   Link after exsa.css + your theme.

   Base: add class="bg-page" to any element (usually <body> or a
   <section> with height) and set --bg-image. Everything else is
   optional and driven by tokens or modifier classes.

   Tokens:
     --bg-image        url(components/...) — comma-separate for layers
     --bg-color        color behind the image (loading fallback)
     --bg-size         cover | contain | auto | <length>
     --bg-position     center | top | bottom | left | right
     --bg-repeat       no-repeat | repeat | repeat-x | repeat-y
     --bg-attachment   scroll | fixed (parallax) | local
     --bg-overlay      veil color/gradient above the image
     --bg-blend        normal | multiply | screen | overlay | soft-light
     --bg-filter       optional image filter (grayscale, sepia, blur…)

   Classes:
     .bg-page          activates the background
     .bg-cover / .bg-contain / .bg-auto
     .bg-center / .bg-top / .bg-bottom / .bg-left / .bg-right
     .bg-repeat / .bg-repeat-x / .bg-repeat-y / .bg-no-repeat
     .bg-fixed / .bg-scroll / .bg-local
     .bg-veil--dark / .bg-veil--light / .bg-veil--gradient / .bg-veil--color
     .bg-blend--multiply / .bg-blend--screen / .bg-blend--overlay / .bg-blend--soft
     .bg-blur           backdrop blur only (apply to your own panels)
     .glass             frosted glass panel — bg + blur + border + shadow
                        modifiers: .glass--strong, .glass--dark
     .bg-grayscale / .bg-sepia    filters (image only, never content)
     .bg-pattern        tiled SVG dot-grid (override --bg-pattern-image / -size)
     .bg-none           remove any background

   A11y: bg-fixed falls back to scroll under prefers-reduced-motion.
   ============================================================ */

:root {
  --bg-image: none;
  --bg-color: var(--color-bg);
  --bg-size: cover;
  --bg-position: center;
  --bg-repeat: no-repeat;
  --bg-attachment: scroll;
  --bg-overlay: transparent;
  --bg-blend: normal;
  --bg-filter: none;
  --bg-pattern-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M0 23.5h24M23.5 0v24' stroke='%23118bee' stroke-opacity='.18' fill='none'/%3E%3C/svg%3E");
  --bg-pattern-size: 24px 24px;
}

/* ── Base — image + veil live on pseudo-layers so content & filters stay clean ── */
.bg-page {
  position: relative;
  isolation: isolate;
  background-color: var(--bg-color);
}

.bg-page::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -2;
  background-image: var(--bg-image);
  background-size: var(--bg-size);
  background-position: var(--bg-position);
  background-repeat: var(--bg-repeat);
  background-attachment: var(--bg-attachment);
  background-blend-mode: var(--bg-blend);
  filter: var(--bg-filter);
}

.bg-page::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--bg-overlay);
}

/* ── Size ── */
.bg-cover   { --bg-size: cover; }
.bg-contain { --bg-size: contain; }
.bg-auto    { --bg-size: auto; }

/* ── Position ── */
.bg-center { --bg-position: center; }
.bg-top    { --bg-position: top; }
.bg-bottom { --bg-position: bottom; }
.bg-left   { --bg-position: left; }
.bg-right  { --bg-position: right; }

/* ── Repeat ── */
.bg-repeat    { --bg-repeat: repeat; }
.bg-repeat-x  { --bg-repeat: repeat-x; }
.bg-repeat-y  { --bg-repeat: repeat-y; }
.bg-no-repeat { --bg-repeat: no-repeat; }

/* ── Attachment (parallax) ── */
.bg-fixed  { --bg-attachment: fixed; }
.bg-scroll { --bg-attachment: scroll; }
.bg-local  { --bg-attachment: local; }
@media (prefers-reduced-motion: reduce) {
  .bg-fixed { --bg-attachment: scroll; }
}

/* ── Readability veils ── */
.bg-veil--dark     { --bg-overlay: rgba(0,0,0,.45); }
.bg-veil--light    { --bg-overlay: rgba(255,255,255,.45); }
.bg-veil--gradient { --bg-overlay: linear-gradient(to bottom, rgba(0,0,0,.08), rgba(0,0,0,.65)); }
.bg-veil--color    { --bg-overlay: color-mix(in srgb, var(--color-link) 28%, transparent); }

/* ── Blend modes ── */
.bg-blend--multiply { --bg-blend: multiply; }
.bg-blend--screen   { --bg-blend: screen; }
.bg-blend--overlay  { --bg-blend: overlay; }
.bg-blend--soft     { --bg-blend: soft-light; }

/* ── Effects ── */
.bg-blur {
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}
.bg-grayscale { --bg-filter: grayscale(1); }
.bg-sepia     { --bg-filter: sepia(.65); }

/* ── Glass panels — frosted cards for use above a background ── */
.glass {
  background: color-mix(in srgb, var(--color-bg) 55%, transparent);
  border: 1px solid color-mix(in srgb, #fff 25%, transparent);
  border-radius: var(--border-radius);
  backdrop-filter: blur(12px) saturate(1.4);
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  box-shadow: 0 8px 32px rgba(0,0,0,.12);
}
.glass--strong {
  background: color-mix(in srgb, var(--color-bg) 78%, transparent);
  backdrop-filter: blur(18px) saturate(1.5);
  -webkit-backdrop-filter: blur(18px) saturate(1.5);
}
.glass--dark {
  background: color-mix(in srgb, #0f172a 45%, transparent);
  border-color: rgba(255,255,255,.18);
  color: #fff;
}

/* ── Pattern tile ── */
.bg-pattern {
  --bg-image: var(--bg-pattern-image);
  --bg-size: var(--bg-pattern-size);
  --bg-repeat: repeat;
}

/* ── Kill switch ── */
.bg-none { --bg-image: none; }

}

/* --- transitions.css --- */
@layer exsa.components {

/* ============================================================
   EXSA Page Transitions — one-click animated page navigation
   Link once per site (after exsa.css). Uses the cross-document
   View Transitions API — no JS, no fallback markup. Browsers
   without support simply navigate instantly.

   Tokens:
     --vt-duration  .35s
     --vt-ease      cubic-bezier(.22, .9, .28, 1)

   Chrome defaults (applied automatically when the elements exist
   on both pages):
     .topbar__brand / .topbar__logo — crossfade between pages

   Opt-in morph utilities — put the SAME class on the matching
   element of each page (one element per name per page):
     .vt-brand   brand crossfade
     .vt-title   heading rises in
     .vt-card    card slides in
     .vt-panel   generic panel slides in
     .vt-hero    hero media crossfades

   Custom art direction: override the ::view-transition-*()
   animations and @keyframes in your own CSS.
   ============================================================ */

:root {
  --vt-duration: .35s;
  --vt-ease: cubic-bezier(.22, .9, .28, 1);
}

/* Site-wide switch — linking this file enables transitions */
@view-transition { navigation: auto; }

/* ── EXSA chrome (same elements on every page) ── */
.topbar__brand { view-transition-name: exsa-brand; }
.topbar__logo { view-transition-name: exsa-brand-logo; }

/* ── Opt-in morph utilities ── */
.vt-brand { view-transition-name: vt-brand; }
.vt-title { view-transition-name: vt-title; }
.vt-card  { view-transition-name: vt-card; }
.vt-panel { view-transition-name: vt-panel; }
.vt-hero  { view-transition-name: vt-hero; }

/* ── Default animations ── */
::view-transition-old(exsa-brand),
::view-transition-new(exsa-brand),
::view-transition-old(exsa-brand-logo),
::view-transition-new(exsa-brand-logo) {
  animation: exsa-vt-fade calc(var(--vt-duration) * .8) ease both;
}
::view-transition-old(vt-brand) { animation: exsa-vt-fade calc(var(--vt-duration) * .8) ease both; }
::view-transition-new(vt-brand) { animation: exsa-vt-fade var(--vt-duration) var(--vt-ease) both; }
::view-transition-old(vt-title) { animation: exsa-vt-up-out var(--vt-duration) ease both; }
::view-transition-new(vt-title) { animation: exsa-vt-up-in var(--vt-duration) var(--vt-ease) both; }
::view-transition-old(vt-card),
::view-transition-old(vt-panel) { animation: exsa-vt-side-out calc(var(--vt-duration) * .8) ease both; }
::view-transition-new(vt-card),
::view-transition-new(vt-panel) { animation: exsa-vt-side-in var(--vt-duration) var(--vt-ease) both; }
::view-transition-old(vt-hero)  { animation: exsa-vt-fade calc(var(--vt-duration) * 1.2) ease both; }
::view-transition-new(vt-hero)  { animation: exsa-vt-fade calc(var(--vt-duration) * 1.6) var(--vt-ease) both; }

@keyframes exsa-vt-fade     { to { opacity: 0; } }
@keyframes exsa-vt-up-out   { to { opacity: 0; transform: translateY(-20px); } }
@keyframes exsa-vt-up-in    { from { opacity: 0; transform: translateY(28px); } }
@keyframes exsa-vt-side-out { to { opacity: 0; transform: translateX(-36px); } }
@keyframes exsa-vt-side-in  { from { opacity: 0; transform: translateX(44px); } }

/* A11y — instant navigation for reduced-motion users */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}

}

/* --- activity.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Activity — grouped timeline feed (today / yesterday)
   Link after exsa.css + your theme. avatar.css optional.

   Markup:
     <div class="activity">
       <div class="activity__group">
         <div class="activity__header">Today</div>
         <div class="activity__list">
           <div class="activity__item">
             <div class="activity__body">
               <div class="activity__title">Invoice #1042 paid</div>
               <div class="activity__text">by Acme Corp · $1,240</div>
             </div>
             <span class="activity__time">09:41</span>
           </div>
           …
         </div>
       </div>
     </div>

   Dot colors: --success (default), --danger, --warning,
               --muted (no color, just track).
   ============================================================ */

/* ── Root ── */
.activity { display: block; }

/* ── Group ── */
.activity__group { margin-bottom: 22px; }
.activity__group:last-child { margin-bottom: 0; }

/* ── Day header with connecting rule ── */
.activity__header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 12px;
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
  white-space: nowrap;
}
.activity__header::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--color-bg-secondary);
}

/* ── Track + items ── */
.activity__list {
  position: relative;
  padding-inline-start: 20px;
  margin-inline-start: 5px;
}
.activity__list::before {
  content: '';
  position: absolute;
  inset-inline-start: 0;
  top: 6px;
  bottom: 6px;
  width: 2px;
  border-radius: 2px;
  background: var(--color-bg-secondary);
}

.activity__item {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding: 7px 0;
}
.activity__item::before {
  content: '';
  position: absolute;
  inset-inline-start: -24px;
  top: 13px;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--activity-dot, var(--color-success));
  border: 2px solid var(--color-bg);
}

/* ── Dot color variants ── */
.activity__item--danger  { --activity-dot: var(--color-danger); }
.activity__item--warning { --activity-dot: var(--color-warning); }
.activity__item--muted   { --activity-dot: var(--color-text-secondary); }

/* ── Content ── */
.activity__body { flex: 1; min-width: 0; }
.activity__title {
  font-size: .82rem;
  font-weight: 600;
  color: var(--color-text);
  line-height: 1.4;
}
.activity__text {
  font-size: .76rem;
  color: var(--color-text-secondary);
  line-height: 1.5;
  margin-top: 1px;
  word-wrap: break-word;
}
.activity__time {
  font-size: .7rem;
  color: var(--color-text-secondary);
  font-family: var(--font-family-mono);
  white-space: nowrap;
  padding-top: 2px;
}
}

/* --- calendar.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Calendar — month grid + event chips
   Link after exsa.css + your theme. js/calendar.js renders
   the grid from data attributes; CSS only styles it.

   Markup:
     <div class="calendar"
          data-calendar-date="2026-08-21"
          data-calendar-week-start="0"
          data-calendar-events='[
            {"date":"2026-08-21","title":"Release v1.0","type":"primary"},
            {"date":"2026-08-24","title":"Sprint review","type":"success"}
          ]'></div>

   Options:
     data-calendar-date       initial visible month (ISO date, default today)
     data-calendar-week-start first weekday 0=Sun (default) | 1=Mon
     data-calendar-events     JSON array {date:"YYYY-MM-DD", title, type}
                              type: primary (default) | success | warning |
                              danger | secondary — event chip color

   Events fired (CustomEvent on the .calendar element):
     exsa:day-select   detail {date:"YYYY-MM-DD", dayEl}
     exsa:event-click  detail {date, title, type, eventEl}
     exsa:month-change detail {year, month}  (month is 1-based)

   Tokens (derive from theme tokens → dark mode adapts automatically):
     --calendar-event-*        chip colors per type
     --calendar-cell-min-h     minimum day-cell height
     --calendar-today          today ring color
     --calendar-outside-op     opacity of days outside the month
   ============================================================ */

:root {
  --calendar-event-primary: var(--color-link);
  --calendar-event-success: var(--color-success);
  --calendar-event-warning: var(--color-warning);
  --calendar-event-danger: var(--color-danger);
  --calendar-event-secondary: var(--color-secondary);
  --calendar-cell-min-h: 72px;
  --calendar-today: var(--color-link);
  --calendar-outside-op: .45;
}

/* ── Shell ── */
.calendar {
  background: var(--color-bg);
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  overflow: hidden;
  font-size: .84rem;
}

/* ── Head: prev / label / next / today ── */
.calendar__head {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--color-bg-secondary);
}
.calendar__label {
  flex: 1;
  font-weight: 700;
  font-size: .95rem;
  color: var(--color-text);
  padding-inline: 4px;
}
.calendar__nav {
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  background: var(--color-bg);
  color: var(--color-text);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
  transition: background .12s, border-color .12s;
}
.calendar__nav:hover { background: var(--color-bg-secondary); }
.calendar__nav:focus-visible { outline: 2px solid var(--color-link); outline-offset: 2px; }
/* RTL — prev/next arrows point the other way */
[dir="rtl"] .calendar__nav { transform: scaleX(-1); }
.calendar__today {
  padding: 6px 14px;
  font-size: .78rem;
  font-weight: 600;
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  background: var(--color-bg);
  color: var(--color-link);
  cursor: pointer;
  font-family: inherit;
}
.calendar__today:hover { background: color-mix(in srgb, var(--color-link) 8%, transparent); }

/* ── Weekday header ── */
.calendar__weekdays {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  border-bottom: 1px solid var(--color-bg-secondary);
}
.calendar__weekday {
  padding: 8px 6px;
  text-align: center;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
}

/* ── Grid ── */
.calendar__grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
}

/* ── Day cell ── */
.calendar__day {
  position: relative;
  min-height: var(--calendar-cell-min-h);
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  padding: 8px;
  border: none;
  border-inline-end: 1px solid var(--color-bg-secondary);
  border-bottom: 1px solid var(--color-bg-secondary);
  background: var(--color-bg);
  color: var(--color-text);
  font-family: inherit;
  text-align: start;
  cursor: pointer;
  transition: background .12s;
}
.calendar__day:nth-child(7n) { border-inline-end: none; }
.calendar__day:hover { background: color-mix(in srgb, var(--color-text-secondary) 7%, transparent); }
.calendar__day:focus-visible { outline: 2px solid var(--color-link); outline-offset: -2px; }

.calendar__day--outside { opacity: var(--calendar-outside-op); }

.calendar__daynum {
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  font-size: .8rem;
  font-weight: 600;
  font-family: var(--font-family-mono);
}
.calendar__day--today .calendar__daynum {
  background: var(--calendar-today);
  color: var(--color-button-text);
}
.calendar__day--selected { background: color-mix(in srgb, var(--color-link) 8%, transparent); }
.calendar__day--selected:hover { background: color-mix(in srgb, var(--color-link) 14%, transparent); }

/* ── Event chips ── */
.calendar__events {
  display: flex;
  flex-direction: column;
  gap: 3px;
  width: 100%;
  overflow: hidden;
}
.calendar__event {
  display: block;
  width: 100%;
  padding: 2px 7px;
  border: none;
  border-radius: 4px;
  font-size: .68rem;
  font-weight: 600;
  line-height: 1.5;
  text-align: start;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  font-family: inherit;
  background: var(--calendar-event-bg, color-mix(in srgb, var(--color-link) 14%, transparent));
  color: var(--calendar-event, var(--color-link));
  transition: filter .12s;
}
.calendar__event:hover { filter: brightness(1.1); }
.calendar__event:focus-visible { outline: 2px solid var(--color-link); outline-offset: 1px; }
.calendar__event--primary   { --calendar-event: var(--calendar-event-primary);   --calendar-event-bg: color-mix(in srgb, var(--calendar-event-primary) 14%, transparent); }
.calendar__event--success   { --calendar-event: var(--calendar-event-success);   --calendar-event-bg: color-mix(in srgb, var(--calendar-event-success) 14%, transparent); }
.calendar__event--warning   { --calendar-event: var(--calendar-event-warning);   --calendar-event-bg: color-mix(in srgb, var(--calendar-event-warning) 14%, transparent); }
.calendar__event--danger    { --calendar-event: var(--calendar-event-danger);    --calendar-event-bg: color-mix(in srgb, var(--calendar-event-danger) 12%, transparent); }
.calendar__event--secondary { --calendar-event: var(--calendar-event-secondary); --calendar-event-bg: color-mix(in srgb, var(--calendar-event-secondary) 12%, transparent); }

/* ── More-indicator ── */
.calendar__more {
  font-size: .66rem;
  font-weight: 600;
  color: var(--color-text-secondary);
  padding-inline-start: 2px;
}

/* ── Compact on narrow screens ── */
@media (max-width: 560px) {
  :root { --calendar-cell-min-h: 56px; }
  .calendar__day { padding: 5px; gap: 2px; }
  .calendar__daynum { width: 20px; height: 20px; font-size: .72rem; }
  .calendar__event { font-size: .62rem; padding: 1px 5px; }
}
}

/* --- chart.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Chart — SVG line / area / bar / sparkline
   Link after exsa.css + your theme.

   Markup: any element with data-chart-values. js/chart.js
   generates the SVG markup from data attributes; CSS only
   styles it. Zero third-party dependencies.

     <div class="chart chart--line"
          data-chart-labels="Mon,Tue,Wed,Thu,Fri"
          data-chart-values="12,28,19,33,24"
          aria-label="Weekly sales"></div>

   Types (class or data-chart-type): line, area, bar, sparkline.
   Second series: data-chart-values-2 (renders with --chart-2 tokens).

   Sizing: width-driven — full charts render at 600×240 (2.5:1),
   sparklines at 300×60 (5:1). Set the container width; height follows
   automatically, so keep any explicit height at width × 0.4 (full)
   or width × 0.2 (sparkline) or the chart letterboxes inside the box.

   Tokens (all derive from theme tokens, so dark mode + custom
   themes adapt automatically — override any of them to rebrand):
     --chart-line     series stroke       (default --color-link)
     --chart-2        second series       (default --color-secondary)
     --chart-fill     area fill           (12% color-mix of line)
     --chart-bar      bar fill            (default --color-link)
     --chart-grid     gridline stroke
     --chart-axis     axis label color
     --chart-point    point fill          (default --color-bg)

   A11y: container carries aria-label (role=img); bars/points are
   keyboard-focusable via the generated SVG when tabindex is set.
   ============================================================ */

:root {
  --chart-line: var(--color-link);
  --chart-2: var(--color-secondary);
  --chart-fill: color-mix(in srgb, var(--color-link) 12%, transparent);
  --chart-fill-2: color-mix(in srgb, var(--color-secondary) 12%, transparent);
  --chart-bar: var(--color-link);
  --chart-grid: color-mix(in srgb, var(--color-text) 9%, transparent);
  --chart-axis: var(--color-text-secondary);
  --chart-point: var(--color-bg);
}

/* ── Container ── */
.chart { position: relative; width: 100%; }
.chart svg { display: block; width: 100%; height: auto; overflow: visible; }
.chart--sparkline svg { width: 100%; max-width: 180px; }

/* ── Grid ── */
.chart__grid line { stroke: var(--chart-grid); stroke-width: 1; shape-rendering: crispEdges; }

/* ── Axis labels ── */
.chart__axis text {
  fill: var(--chart-axis);
  font-size: 11px;
  font-family: var(--font-family-mono);
}

/* ── Line series ── */
.chart__line {
  fill: none;
  stroke: var(--chart-line);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.chart__series--2 .chart__line { stroke: var(--chart-2); }

/* ── Area series ── */
.chart__area { stroke: none; }
.chart__area--1 { fill: var(--chart-fill); }
.chart__area--2 { fill: var(--chart-fill-2); }

/* ── Points ── */
.chart__point {
  fill: var(--chart-point);
  stroke: var(--chart-line);
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
}
.chart__series--2 .chart__point { stroke: var(--chart-2); }
.chart__point:hover, .chart__point:focus { r: 5; outline: none; }

/* ── Bars ── */
.chart__bar { fill: var(--chart-bar); transition: opacity .15s; }
.chart__bar:hover, .chart__bar:focus { opacity: .75; outline: none; }

/* ── Bar value labels ── */
.chart__bar-label {
  fill: var(--chart-axis);
  font-size: 10px;
  font-family: var(--font-family-mono);
  text-anchor: middle;
}

/* ── Sparkline — no axes, no grid ── */
.chart--sparkline .chart__grid,
.chart--sparkline .chart__axis,
.chart--sparkline .chart__point { display: none; }

/* ── Intro animation (skipped for reduced motion) ── */
@media (prefers-reduced-motion: no-preference) {
  .chart__line, .chart__area { animation: chart-in .5s ease-out both; }
  .chart__bar { animation: chart-bar-in .4s ease-out both; transform-origin: bottom; }
  @keyframes chart-in { from { opacity: 0; } to { opacity: 1; } }
  @keyframes chart-bar-in { from { opacity: 0; transform: scaleY(.6); } to { opacity: 1; transform: scaleY(1); } }
}
}

/* --- command-palette.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Command Palette — Ctrl+K modal search
   Link after exsa.css + your theme + modal.css (overlay shell
   is reused from .modal). Behavior from js/command-palette.js.

   Markup:
     <div class="modal command-palette" role="dialog" aria-modal="true" aria-label="Command palette">
       <div class="modal__dialog command-palette__dialog">
         <div class="command-palette__input-wrap">
           <span class="command-palette__icon"><span class="ic ic-search"></span></span>
           <input class="command-palette__input" type="text" placeholder="Type a command or search…">
           <kbd class="command-palette__kbd">esc</kbd>
         </div>
         <div class="command-palette__list" role="listbox">
           <div class="command-palette__group">
             <div class="command-palette__group-title">Navigate</div>
             <button type="button" class="command-palette__item" data-command="dashboard" role="option">
               <span class="command-palette__item-icon"><span class="ic ic-home"></span></span>
               <span class="command-palette__item-body">
                 <span class="command-palette__item-label">Go to Dashboard</span>
                 <span class="command-palette__item-desc">Overview and KPIs</span>
               </span>
             </button>
           </div>
         </div>
         <div class="command-palette__empty" hidden>No results</div>
         <div class="command-palette__foot">
           <span><kbd class="command-palette__kbd">↑↓</kbd> navigate</span>
           <span><kbd class="command-palette__kbd">↵</kbd> select</span>
           <span><kbd class="command-palette__kbd">esc</kbd> close</span>
         </div>
       </div>
     </div>

   Behavior (js/command-palette.js, vanilla):
     - Ctrl+K / Cmd+K toggles (also [data-command-open] buttons)
     - type-to-filter across commands, labels, descriptions and
       group names; groups with no matches hide; empty state shows
     - ↑/↓ navigate, Enter selects, Escape closes, click backdrop closes
     - events: exsa:command-open / -close / -select {command, label, item}
   ============================================================ */

/* ── Overlay — reuse .modal, park the dialog near the top ── */
.command-palette {
  align-items: flex-start;
  padding-top: 16vh;
  background: rgba(0, 0, 0, .38);
}
.command-palette__dialog { max-width: 560px; }

/* ── Input row ── */
.command-palette__input-wrap {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--color-bg-secondary);
  flex-shrink: 0;
}
.command-palette__icon {
  color: var(--color-text-secondary);
  font-size: 1rem;
  display: inline-flex;
  flex-shrink: 0;
}
.command-palette__input {
  flex: 1;
  min-width: 0;
  border: none;
  background: none;
  padding: 2px 0;
  font-size: .92rem;
  font-family: inherit;
  color: var(--color-text);
}
.command-palette__input:focus { outline: none; }
.command-palette__input::placeholder { color: var(--color-text-secondary); }

/* ── kbd hint chips ── */
.command-palette__kbd {
  font-family: var(--font-family-mono);
  font-size: .64rem;
  color: var(--color-text-secondary);
  border: 1px solid var(--color-bg-secondary);
  border-bottom-width: 2px;
  border-radius: 4px;
  padding: 2px 6px;
  white-space: nowrap;
}

/* ── Results list ── */
.command-palette__list {
  max-height: 320px;
  overflow-y: auto;
  padding: 6px;
}
.command-palette__group { margin-bottom: 4px; }
.command-palette__group[hidden] { display: none; }
.command-palette__group-title {
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
  padding: 8px 10px 4px;
}

/* ── Item ── */
.command-palette__item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border: none;
  border-radius: var(--border-radius);
  background: none;
  color: var(--color-text);
  font-family: inherit;
  font-size: .86rem;
  text-align: start;
  cursor: pointer;
}
.command-palette__item[hidden] { display: none; }
.command-palette__item:hover,
.command-palette__item--active {
  background: color-mix(in srgb, var(--color-link) 10%, transparent);
}
.command-palette__item-icon {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--border-radius);
  background: var(--color-bg-secondary);
  color: var(--color-text-secondary);
  font-size: .9rem;
  flex-shrink: 0;
}
.command-palette__item--active .command-palette__item-icon {
  background: var(--color-link);
  color: var(--color-button-text);
}
.command-palette__item-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.command-palette__item-label {
  font-weight: 600;
  color: var(--color-text);
}
.command-palette__item-desc {
  font-size: .72rem;
  color: var(--color-text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Empty state ── */
.command-palette__empty {
  padding: 28px 16px;
  text-align: center;
  font-size: .82rem;
  color: var(--color-text-secondary);
}

/* ── Footer hints ── */
.command-palette__foot {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 10px 16px;
  border-top: 1px solid var(--color-bg-secondary);
  font-size: .68rem;
  color: var(--color-text-secondary);
  flex-shrink: 0;
}
.command-palette__foot span {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
}

/* --- empty-state.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Empty State — icon + title + CTA for blank lists/tables
   Link after exsa.css + your theme. icons.css optional.

   Markup:
     <div class="empty-state empty-state--bordered">
       <span class="empty-state__icon"><span class="ic ic-inbox"></span></span>
       <h3 class="empty-state__title">No projects yet</h3>
       <p class="empty-state__text">Create your first project to get started.</p>
       <div class="empty-state__actions">
         <button class="btn btn--primary">New project</button>
         <button class="btn btn--outline">Import</button>
       </div>
     </div>

   Variants: --sm (compact), --bordered (dashed drop-zone look),
             --dark (for use on colored panels).
   ============================================================ */

.empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 5px;
  padding: 48px 24px;
}

.empty-state__icon {
  width: 56px;
  height: 56px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--color-bg-secondary);
  color: var(--color-text-secondary);
  font-size: 24px;
  margin-bottom: 10px;
}

.empty-state__title {
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-text);
  margin: 0;
}

.empty-state__text {
  font-size: .82rem;
  line-height: 1.6;
  color: var(--color-text-secondary);
  max-width: 340px;
  margin: 0;
}

.empty-state__actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 14px;
}

/* ── Compact ── */
.empty-state--sm { padding: 24px 16px; gap: 3px; }
.empty-state--sm .empty-state__icon { width: 40px; height: 40px; font-size: 18px; margin-bottom: 6px; }
.empty-state--sm .empty-state__actions { margin-top: 10px; }

/* ── Bordered (drop-zone / upload placeholder) ── */
.empty-state--bordered {
  border: 2px dashed var(--color-bg-secondary);
  border-radius: var(--border-radius);
}
.empty-state--bordered:hover { border-color: var(--color-link); }

/* ── On dark/colored panels ── */
.empty-state--dark .empty-state__title { color: #fff; }
.empty-state--dark .empty-state__text { color: rgba(255,255,255,.75); }
.empty-state--dark .empty-state__icon {
  background: rgba(255,255,255,.15);
  color: #fff;
}
}

/* --- kanban.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Kanban — drag-and-drop board with columns and cards
   Link after exsa.css + your theme. badge.css / avatar.css
   optional (used inside cards). Behavior comes from js/kanban.js.

   Markup:
     <div class="kanban">
       <div class="kanban__col" data-col-id="todo">
         <div class="kanban__col-head">
           <span class="kanban__col-title">To Do</span>
           <span class="kanban__col-count badge badge--default">2</span>
         </div>
         <div class="kanban__cards">
           <article class="kanban__card" data-card-id="c1" tabindex="0">
             <div class="kanban__card-title">Card title</div>
             <div class="kanban__card-text">Optional body text</div>
             <div class="kanban__card-tags"><span class="badge badge--primary">tag</span></div>
             <div class="kanban__card-foot">
               <span class="kanban__card-date">Aug 21</span>
             </div>
           </article>
         </div>
         <button class="kanban__add" type="button">+ Add card</button>
       </div>
     </div>

   Behavior (js/kanban.js, pointer-based — mouse AND touch):
     - drag cards between columns or reorder inside a column
       (vertical page scroll on touch stays intact: touch-action pan-y)
     - .kanban__add inserts a card with an editable title
     - column count badges (.kanban__col-count) update automatically
     - events: exsa:kanban-drop {cardId, fromColId, toColId, afterId}
               exsa:kanban-add  {card, colId}

   Tokens (theme-derived → dark mode adapts automatically):
     --kanban-col-w   column width
     --kanban-gap     board gap
     --kanban-col-bg  column background
     --kanban-over    drop-target highlight
   ============================================================ */

:root {
  --kanban-col-w: 280px;
  --kanban-gap: 16px;
  --kanban-col-bg: color-mix(in srgb, var(--color-bg-secondary) 45%, transparent);
  --kanban-over: color-mix(in srgb, var(--color-link) 10%, transparent);
}

/* ── Board — horizontal columns, scrolls on narrow screens ── */
.kanban {
  display: flex;
  align-items: flex-start;
  gap: var(--kanban-gap);
  overflow-x: auto;
  padding: 2px 2px 10px;
}

/* ── Column ── */
.kanban__col {
  flex: 0 0 var(--kanban-col-w);
  max-width: var(--kanban-col-w);
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px;
  background: var(--kanban-col-bg);
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
}
.kanban__col--over {
  background: var(--kanban-over);
  border-color: var(--color-link);
}

/* ── Column head ── */
.kanban__col-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.kanban__col-title {
  font-size: .82rem;
  font-weight: 700;
  letter-spacing: .03em;
  text-transform: uppercase;
  color: var(--color-text);
}
.kanban__col-count { flex-shrink: 0; }

/* ── Cards stack ── */
.kanban__cards {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 48px;
  flex: 1;
}

/* ── Card ── */
.kanban__card {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 12px;
  background: var(--color-bg);
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  cursor: grab;
  touch-action: pan-y; /* vertical scroll on touch; horizontal move = drag */
  box-shadow: 0 1px 2px color-mix(in srgb, #000 6%, transparent);
  transition: border-color .15s, box-shadow .15s;
}
.kanban__card:hover {
  border-color: color-mix(in srgb, var(--color-text-secondary) 35%, transparent);
  box-shadow: var(--surface-shadow-md);
}
.kanban__card:focus-visible { outline: 2px solid var(--color-link); outline-offset: 2px; }

.kanban__card--ghost { opacity: .35; }

/* Dragging clone */
.kanban__card--dragging {
  position: fixed;
  left: 0;
  top: 0;
  margin: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: .96;
  cursor: grabbing;
  transform-origin: top left;
  box-shadow: var(--surface-shadow-lg);
}
body.kanban-dragging,
body.kanban-dragging .kanban__card { user-select: none; }

/* ── Card parts ── */
.kanban__card-title {
  font-size: .84rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--color-text);
  word-wrap: break-word;
}
.kanban__card-title[contenteditable="true"]:focus { outline: 1px dashed var(--color-link); outline-offset: 2px; }
.kanban__card-text {
  font-size: .76rem;
  line-height: 1.5;
  color: var(--color-text-secondary);
  word-wrap: break-word;
}
.kanban__card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
}
.kanban__card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.kanban__card-date {
  font-size: .7rem;
  color: var(--color-text-secondary);
  font-family: var(--font-family-mono);
}

/* ── Add button ── */
.kanban__add {
  width: 100%;
  padding: 8px;
  border: 1px dashed var(--color-bg-secondary);
  border-radius: var(--border-radius);
  background: none;
  color: var(--color-text-secondary);
  font-size: .78rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: color .12s, border-color .12s;
}
.kanban__add:hover { color: var(--color-link); border-color: var(--color-link); }
.kanban__add:focus-visible { outline: 2px solid var(--color-link); outline-offset: 2px; }

/* ── Empty column hint ── */
.kanban__empty {
  padding: 14px 10px;
  text-align: center;
  font-size: .76rem;
  color: var(--color-text-secondary);
  border: 1px dashed var(--color-bg-secondary);
  border-radius: var(--border-radius);
}
}

/* --- kpi.css --- */
@layer exsa.components {
/* ============================================================
   EXSA KPI Card — big number + delta + sparkline
   Link after exsa.css + your theme. Standalone (works with or
   without card.css / layouts/dashboard.css).

   Markup:
     <div class="kpi">
       <div class="kpi__head">
         <span class="kpi__label">Revenue</span>
         <span class="kpi__icon"><span class="ic ic-chart"></span></span>
       </div>
       <div class="kpi__value">$48,290</div>
       <div class="kpi__foot">
         <span class="kpi__delta kpi__delta--up">12.4%</span>
         <span class="kpi__delta-note">vs last month</span>
       </div>
     </div>

   Sparkline slot (needs js/chart.js):
     <span class="kpi__spark" data-chart-values="12,18,15,24,29"></span>

   Variants: --success / --warning / --danger (accent + icon tint),
             --sm (compact), --pill (delta badge).
   Grid: wrap cards in .kpi-grid.
   Tokens: --kpi-pad, --kpi-value-size, --kpi-accent, --kpi-icon-bg,
           --kpi-delta-up, --kpi-delta-down.
   ============================================================ */

:root {
  --kpi-pad: 20px;
  --kpi-value-size: 1.75rem;
  --kpi-accent: var(--color-link);
  --kpi-icon-bg: color-mix(in srgb, var(--color-link) 12%, transparent);
  --kpi-delta-up: var(--color-success);
  --kpi-delta-down: var(--color-danger);
}

/* ── Card ── */
.kpi {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: var(--kpi-pad);
  background: var(--surface-bg);
  border: var(--surface-border);
  border-inline-start: 3px solid var(--kpi-accent);
  border-radius: var(--surface-radius);
  box-shadow: var(--surface-shadow-md); /* elevated card — follows the skin's elevation */
  position: relative;
  min-width: 0;
}

/* ── Head row: label + icon ── */
.kpi__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.kpi__label {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
}
.kpi__icon {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--surface-radius);
  background: var(--kpi-icon-bg);
  color: var(--kpi-accent);
  font-size: 1rem;
  flex-shrink: 0;
}

/* ── Value ── */
.kpi__value {
  font-size: var(--kpi-value-size);
  font-weight: 800;
  line-height: 1.1;
  color: var(--color-text);
  font-family: var(--font-family-mono);
  letter-spacing: -.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Foot: delta + note ── */
.kpi__foot {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.kpi__delta {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: .74rem;
  font-weight: 700;
  font-family: var(--font-family-mono);
}
.kpi__delta--up { color: var(--kpi-delta-up); }
.kpi__delta--up::before { content: '↑'; }
.kpi__delta--down { color: var(--kpi-delta-down); }
.kpi__delta--down::before { content: '↓'; }
.kpi__delta--pill {
  padding: 2px 9px;
  border-radius: 99px;
}
.kpi__delta--up.kpi__delta--pill {
  background: color-mix(in srgb, var(--kpi-delta-up) 14%, transparent);
}
.kpi__delta--down.kpi__delta--pill {
  background: color-mix(in srgb, var(--kpi-delta-down) 12%, transparent);
}
.kpi__delta-note {
  font-size: .72rem;
  color: var(--color-text-secondary);
}

/* ── Sparkline slot ── */
.kpi__spark { display: block; margin-top: 2px; }

/* ── Progress slot — slim bars (progress.css) inside the card ── */
.kpi__progress {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin-top: 2px;
  padding-top: 10px;
  border-top: var(--surface-border);
}

/* ── Color variants ── */
.kpi--success { --kpi-accent: var(--color-success); --kpi-icon-bg: color-mix(in srgb, var(--color-success) 12%, transparent); }
.kpi--warning { --kpi-accent: var(--color-warning); --kpi-icon-bg: color-mix(in srgb, var(--color-warning) 14%, transparent); }
.kpi--danger  { --kpi-accent: var(--color-danger);  --kpi-icon-bg: color-mix(in srgb, var(--color-danger) 12%, transparent); }
.kpi--secondary { --kpi-accent: var(--color-secondary); --kpi-icon-bg: color-mix(in srgb, var(--color-secondary) 12%, transparent); }

/* ── Compact ── */
.kpi--sm { --kpi-pad: 14px; --kpi-value-size: 1.35rem; gap: 6px; }
.kpi--sm .kpi__icon { width: 28px; height: 28px; font-size: .8rem; }

/* ── Grid ── */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
}
}

/* --- notifications.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Notifications — bell dropdown built on dropdown.css
   Link after exsa.css + your theme + dropdown.css (+ badge.css,
   avatar.css optional). Toggle behavior comes from js/dropdown.js
   (class .dropdown--open) — no new JS needed.

   Markup:
     <div class="dropdown notifications">
       <button class="dropdown__trigger notifications__trigger"
               aria-haspopup="true" aria-expanded="false" aria-label="Notifications">
         <span class="ic ic-bell"></span>
         <span class="badge badge--danger badge--count">3</span>
       </button>
       <div class="dropdown__menu notifications__menu" role="menu">
         <div class="notifications__head">
           <span class="notifications__title">Notifications</span>
           <button class="notifications__mark" type="button">Mark all read</button>
         </div>
         <div class="notifications__list">
           <div class="notifications__item notifications__item--unread">
             <span class="avatar avatar--xs">JD</span>
             <div class="notifications__body">
               <div class="notifications__text"><b>Jane</b> assigned you a task</div>
               <span class="notifications__time">2 min ago</span>
             </div>
           </div>
           …
         </div>
         <a class="notifications__foot" href="#">View all</a>
       </div>
     </div>

   States: --unread (dot + tint), --error/--success (dot color).
   ============================================================ */

/* ── Trigger — round icon button with floating count badge ── */
.notifications__trigger {
  width: 40px;
  height: 40px;
  padding: 0;
  justify-content: center;
  border-radius: 50%;
  position: relative;
}
.notifications__trigger .badge {
  position: absolute;
  top: -4px;
  inset-inline-end: -4px;
  border: 2px solid var(--color-bg);
}

/* ── Menu panel ── */
.notifications .dropdown__menu {
  min-width: 320px;
  max-width: calc(100vw - 24px);
  padding: 0;
  overflow: hidden;
  inset-inline-start: auto;
  inset-inline-end: 0;
  transform-origin: top right;
}
[dir="rtl"] .notifications .dropdown__menu { transform-origin: top left; }

/* ── Head ── */
.notifications__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--color-bg-secondary);
}
.notifications__title {
  font-size: .8rem;
  font-weight: 700;
  color: var(--color-text);
}
.notifications__mark {
  font-size: .72rem;
  font-weight: 600;
  color: var(--color-link);
  background: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
  padding: 0;
}
.notifications__mark:hover { text-decoration: underline; }

/* ── List ── */
.notifications__list {
  max-height: 340px;
  overflow-y: auto;
  padding: 4px 0;
}

/* ── Item ──
   UA-neutral like .dropdown__item — items may be <div> (docs) or
   <button role="menuitem"> (interactive), so button chrome must not leak. */
.notifications__item {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 10px 16px;
  position: relative;
  width: 100%;
  background: none;
  border: none;
  color: var(--color-text);
  font-family: inherit;
  text-align: start;
  transition: background .12s;
}
.notifications__item:hover {
  background: color-mix(in srgb, var(--color-text-secondary) 8%, transparent);
}
.notifications__item--unread {
  background: color-mix(in srgb, var(--color-link) 7%, transparent);
}
.notifications__item--unread::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--color-link);
  flex-shrink: 0;
  margin-top: 7px;
}
.notifications__item--success::before { background: var(--color-success); }
.notifications__item--danger::before  { background: var(--color-danger); }

.notifications__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.notifications__text {
  font-size: .8rem;
  line-height: 1.45;
  color: var(--color-text);
  word-wrap: break-word;
}
.notifications__text b { font-weight: 700; }
.notifications__time {
  font-size: .68rem;
  color: var(--color-text-secondary);
}
.notifications__time--unread { color: var(--color-link); }

/* ── Footer ── */
.notifications__foot {
  display: block;
  text-align: center;
  padding: 11px;
  font-size: .78rem;
  font-weight: 600;
  color: var(--color-link);
  border-top: 1px solid var(--color-bg-secondary);
  text-decoration: none;
}
.notifications__foot:hover {
  background: color-mix(in srgb, var(--color-link) 6%, transparent);
}

/* ── Empty state ── */
.notifications__empty {
  padding: 32px 16px;
  text-align: center;
  font-size: .8rem;
  color: var(--color-text-secondary);
}
}

/* --- product-card.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Product Card — store product tile

   Link after exsa.css. Used inside layouts/store.css .shop__grid.
   Classes (shop__ namespace — store vocabulary):
     .shop__card            tile
     .shop__card-image      square cover image
     .shop__card-badge      corner badge (pair with badge.css colors)
     .shop__card-body       text block
     .shop__card-title      product name
     .shop__card-price      price (+ --old strikethrough)
     .shop__card-rating     star rating line
   ============================================================ */

.shop__card {
  position: relative;
  background: var(--surface-bg);
  border: var(--surface-border);
  border-radius: var(--surface-radius);
  overflow: hidden;
  transition: box-shadow 0.2s, transform 0.15s;
}
.shop__card:hover {
  box-shadow: var(--surface-shadow-md);
  transform: translateY(-2px);
}
.shop__card-image {
  width: 100%;
  aspect-ratio: 1 / 1;
  display: block;
  overflow: hidden;
  background: var(--color-bg-secondary);
}
.shop__card-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
.shop__card-badge {
  position: absolute;
  top: calc(10px * var(--space-factor, 1)); inset-inline-start: calc(10px * var(--space-factor, 1));
  padding: calc(2px * var(--space-factor, 1)) calc(8px * var(--space-factor, 1));
  border-radius: 4px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  z-index: 1;
}
.shop__card-body {
  padding: calc(14px * var(--space-factor, 1));
}
.shop__card-title {
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--color-text);
  margin-bottom: calc(4px * var(--space-factor, 1));
  line-height: 1.3;
}
.shop__card-price {
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-text);
}
.shop__card-price--old {
  font-size: 0.8rem;
  font-weight: 400;
  color: var(--color-text-secondary);
  text-decoration: line-through;
  margin-inline-start: calc(6px * var(--space-factor, 1));
}
.shop__card-rating {
  font-size: 0.78rem;
  color: var(--color-warning, #f59e0b);
  margin-top: calc(4px * var(--space-factor, 1));
}
}

/* --- tags-input.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Tags Input — chips + type-to-add with suggestions
   Link after exsa.css + your theme. Behavior from js/tags-input.js.

   Markup:
     <div class="tags-input"
          data-tags-suggestions='["design","a11y","docs","bug","feature"]'
          data-tags-max="8" data-tags-name="tags">
       <span class="tags-input__chip" data-value="design">
         <span class="tags-input__chip-label">design</span>
         <button type="button" class="tags-input__remove" aria-label="Remove design">&times;</button>
       </span>
       <!-- the text field is added by js/tags-input.js -->
     </div>

   Behavior (vanilla):
     - Enter or comma adds a chip; Backspace on empty removes the last
     - suggestions dropdown filtered as you type (ArrowUp/Down + Enter,
       click to pick, Escape closes)
     - duplicates are ignored; data-tags-max caps the count
     - data-tags-free="false" restricts to suggestions only
     - data-tags-name creates a hidden input with comma-joined values
     - events: exsa:tags-add / exsa:tags-remove / exsa:tags-change

   Tokens (theme-derived → dark mode adapts automatically):
     --tags-chip-bg, --tags-chip-color
   ============================================================ */

:root {
  --tags-chip-bg: color-mix(in srgb, var(--color-link) 12%, transparent);
  --tags-chip-color: var(--color-link);
}

/* ── Container — looks like an input ── */
.tags-input {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  border: var(--surface-border-control);
  border-radius: var(--surface-radius);
  background: var(--surface-bg);
  box-shadow: var(--surface-inset);
  cursor: text;
  transition: border-color .15s, box-shadow .15s;
}
.tags-input:focus-within {
  border-color: var(--color-link);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-link) 18%, transparent);
}

/* ── Chip ── */
.tags-input__chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 99px;
  box-shadow: var(--surface-inset);
  background: var(--tags-chip-bg);
  color: var(--tags-chip-color);
  font-size: .76rem;
  font-weight: 600;
  line-height: 1.5;
  white-space: nowrap;
}
.tags-input__chip--success { --tags-chip-bg: color-mix(in srgb, var(--color-success) 14%, transparent); --tags-chip-color: var(--color-success); }
.tags-input__chip--warning { --tags-chip-bg: color-mix(in srgb, var(--color-warning) 14%, transparent); --tags-chip-color: var(--color-warning); }
.tags-input__chip--danger  { --tags-chip-bg: color-mix(in srgb, var(--color-danger) 12%, transparent);  --tags-chip-color: var(--color-danger); }

.tags-input__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: color-mix(in srgb, var(--tags-chip-color) 25%, transparent);
  color: var(--tags-chip-color);
  font-size: .8rem;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
}
.tags-input__remove:hover { background: var(--tags-chip-color); color: var(--color-button-text); }
.tags-input__remove:focus-visible { outline: 2px solid var(--color-link); outline-offset: 1px; }

/* ── Text field ── */
.tags-input__field {
  flex: 1;
  min-width: 90px;
  border: none;
  background: none;
  padding: 4px 2px;
  font-size: .84rem;
  font-family: inherit;
  color: var(--color-text);
}
.tags-input__field:focus { outline: none; }
.tags-input__field::placeholder { color: var(--color-text-secondary); }

/* ── Suggestions menu ── */
.tags-input__menu {
  position: absolute;
  top: calc(100% + 4px);
  inset-inline-start: 0;
  z-index: var(--z-dropdown);
  min-width: 180px;
  max-height: 220px;
  overflow-y: auto;
  padding: 4px;
  background: var(--surface-bg);
  border: var(--surface-border);
  border-radius: var(--surface-radius);
  box-shadow: var(--surface-shadow-md);
  display: none;
}
.tags-input__menu--open { display: block; }

.tags-input__item {
  padding: 6px 10px;
  font-size: .8rem;
  border-radius: calc(var(--border-radius) * .6);
  cursor: pointer;
  color: var(--color-text);
}
.tags-input__item:hover,
.tags-input__item--active {
  background: color-mix(in srgb, var(--color-text-secondary) 10%, transparent);
}
}

/* --- transfer.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Transfer — two-panel list picker
   Link after exsa.css + your theme. badge.css optional.
   Behavior from js/transfer.js.

   Markup:
     <div class="transfer" data-transfer-name="roles">
       <div class="transfer__panel">
         <div class="transfer__head">
           <span class="transfer__title">Available</span>
           <span class="transfer__count badge badge--default">3</span>
         </div>
         <input class="transfer__search" type="search" placeholder="Filter…" aria-label="Filter available">
         <ul class="transfer__list">
           <li class="transfer__item" data-value="admin" tabindex="0">Admin</li>
           …
         </ul>
       </div>
       <div class="transfer__actions">
         <button class="transfer__btn" type="button" data-action="add" aria-label="Add selected">›</button>
         <button class="transfer__btn" type="button" data-action="remove" aria-label="Remove selected">‹</button>
         <button class="transfer__btn transfer__btn--text" type="button" data-action="add-all">All ›</button>
         <button class="transfer__btn transfer__btn--text" type="button" data-action="remove-all">‹ All</button>
       </div>
       <div class="transfer__panel"> … selected panel … </div>
     </div>

   Behavior (js/transfer.js, vanilla):
     - click item = select (aria-selected), double-click = move
     - Space toggles selection, Enter moves a focused item
     - action buttons move selected / all items
     - per-panel search filters items
     - data-transfer-name syncs a hidden input (comma-joined values)
     - event: exsa:transfer-change {values, added, removed}

   Tokens (theme-derived → dark mode adapts automatically):
     --transfer-gap, --transfer-checked
   ============================================================ */

:root {
  --transfer-gap: 12px;
  --transfer-checked: color-mix(in srgb, var(--color-link) 10%, transparent);
}

/* ── Layout: two panels + central actions ── */
.transfer {
  display: flex;
  align-items: stretch;
  gap: var(--transfer-gap);
  flex-wrap: wrap;
}

/* ── Panel ── */
.transfer__panel {
  flex: 1;
  min-width: 200px;
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  background: var(--color-bg);
  overflow: hidden;
}
.transfer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--color-bg-secondary);
}
.transfer__title {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--color-text-secondary);
}
.transfer__count { flex-shrink: 0; }

/* ── Search ── */
.transfer__search {
  margin: 10px 10px 4px;
  padding: 7px 12px;
  font-size: .8rem;
  font-family: inherit;
  color: var(--color-text);
  background: var(--color-bg);
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  transition: border-color .15s, box-shadow .15s;
}
.transfer__search::placeholder { color: var(--color-text-secondary); }
.transfer__search:focus { outline: none; border-color: var(--color-link); box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-link) 18%, transparent); }

/* ── List ── */
.transfer__list {
  list-style: none;
  margin: 0;
  padding: 6px;
  max-height: 220px;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* ── Item ── */
.transfer__item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: var(--border-radius);
  font-size: .82rem;
  color: var(--color-text);
  cursor: pointer;
  user-select: none;
  transition: background .1s;
}
.transfer__item:hover { background: color-mix(in srgb, var(--color-text-secondary) 8%, transparent); }
.transfer__item:focus-visible { outline: 2px solid var(--color-link); outline-offset: -2px; }
.transfer__item[hidden] { display: none; }

/* Check indicator (pure CSS) */
.transfer__item::before {
  content: '';
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  border: 1.5px solid var(--color-text-secondary);
  border-radius: 4px;
  transition: background .12s, border-color .12s;
}
.transfer__item--checked { background: var(--transfer-checked); }
.transfer__item--checked::before {
  background: var(--color-link);
  border-color: var(--color-link);
  box-shadow: inset 0 0 0 2.5px var(--color-bg);
}

/* ── Action buttons ── */
.transfer__actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
}
.transfer__btn {
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  background: var(--color-bg);
  color: var(--color-text);
  font-size: 1.05rem;
  line-height: 1;
  cursor: pointer;
  font-family: inherit;
  transition: background .12s, border-color .12s, color .12s;
}
.transfer__btn:hover { background: var(--color-bg-secondary); color: var(--color-link); }
.transfer__btn:focus-visible { outline: 2px solid var(--color-link); outline-offset: 2px; }
.transfer__btn--text {
  width: auto;
  padding: 6px 12px;
  font-size: .76rem;
  font-weight: 600;
}

/* RTL — flip directional glyphs */
[dir="rtl"] .transfer__btn:not(.transfer__btn--text),
[dir="rtl"] .transfer__btn--text { transform: scaleX(-1); }

/* ── Narrow screens: actions row between panels ── */
@media (max-width: 560px) {
  .transfer { flex-direction: column; }
  .transfer__actions { flex-direction: row; padding: 2px 0; }
}
}

/* --- tree.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Tree — nested tree / file tree (pure CSS, zero JS)
   Link after exsa.css + your theme. icons.css + badge.css
   optional. Expand/collapse comes free from <details> —
   keyboard accessible and no JavaScript required.

   Markup:
     <ul class="tree tree--lines">
       <li>
         <details class="tree__node" open>
           <summary class="tree__row">
             <span class="tree__icon"><span class="ic ic-folder"></span></span>
             <span class="tree__label">src</span>
             <span class="badge badge--default tree__badge">4</span>
           </summary>
           <ul class="tree">
             <li class="tree__leaf">
               <span class="tree__row">
                 <input type="checkbox" class="tree__check" aria-label="index.php">
                 <span class="tree__icon"><span class="ic ic-file"></span></span>
                 <span class="tree__label">index.php</span>
               </span>
             </li>
           </ul>
         </details>
       </li>
     </ul>

   States: .tree__row--selected (highlight), checkboxes for
   permission/file selection, --lines variant draws connectors.
   Chevron indicator is pure CSS on the summary (no icon file).
   ============================================================ */

.tree,
.tree li {
  list-style: none;
  margin: 0;
  padding: 0;
}
.tree .tree {
  padding-inline-start: 20px;
}

/* ── Node row (summary or leaf row) ── */
.tree__row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-radius: var(--border-radius);
  font-size: .84rem;
  color: var(--color-text);
  cursor: pointer;
  transition: background .12s;
  list-style: none;
  min-width: 0;
}
.tree__row:hover { background: color-mix(in srgb, var(--color-text-secondary) 8%, transparent); }
.tree__row:focus-visible { outline: 2px solid var(--color-link); outline-offset: -2px; }
.tree__row--selected {
  background: color-mix(in srgb, var(--color-link) 8%, transparent);
  color: var(--color-link);
  font-weight: 600;
}

/* Hide the native details marker on summaries; declare the row weight
   explicitly — it previously leaked in from the classless summary rule. */
.tree__node > summary { list-style: none; font-weight: 700; }
.tree__node > summary::-webkit-details-marker { display: none; }

/* ── Chevron (pure CSS, RTL-safe) ── */
.tree__node > summary::before {
  content: '';
  width: 7px;
  height: 7px;
  flex-shrink: 0;
  border-inline-end: 2px solid var(--color-text-secondary);
  border-bottom: 2px solid var(--color-text-secondary);
  transform: rotate(-45deg);
  transition: transform .15s;
}
.tree__node[open] > summary::before { transform: rotate(45deg); }

/* ── Icon slot ── */
.tree__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: .95rem;
  color: var(--color-text-secondary);
  flex-shrink: 0;
}
.tree__row--selected .tree__icon { color: var(--color-link); }

/* ── Label ── */
.tree__label {
  flex: 1;
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Badge slot ── */
.tree__badge { flex-shrink: 0; }

/* ── Checkbox (permission / file selection) ── */
.tree__check {
  width: 15px;
  height: 15px;
  margin: 0;
  accent-color: var(--color-link);
  cursor: pointer;
  flex-shrink: 0;
}

/* ── Guide lines variant ── */
.tree--lines .tree {
  padding-inline-start: 18px;
  margin-inline-start: 9px;
  border-inline-start: 1px solid var(--color-bg-secondary);
}
.tree--lines > li { position: relative; }

/* ── Size variants ── */
.tree--sm .tree__row {
  padding: 3px 8px;
  gap: 6px;
  font-size: .76rem;
}
.tree--sm .tree .tree {
  padding-inline-start: 14px;
}
.tree--sm .tree__icon { font-size: .8rem; }
.tree--sm .tree__check { width: 13px; height: 13px; }
.tree--sm .tree__node > summary::before { width: 6px; height: 6px; }
.tree--sm.tree--lines .tree {
  padding-inline-start: 13px;
  margin-inline-start: 6px;
}
.tree--lg .tree__row {
  padding: 10px 14px;
  gap: 10px;
  font-size: .92rem;
}

/* ── Reduced motion ── */
@media (prefers-reduced-motion: reduce) {
  .tree__node > summary::before { transition: none; }
}
}

/* --- upload.css --- */
@layer exsa.components {
/* ============================================================
   EXSA Upload — dropzone + file list with progress
   Link after exsa.css + your theme. Behavior from js/upload.js.

   Markup:
     <div class="upload" data-upload-url="/api/upload">
       <div class="upload__dropzone" tabindex="0" role="button"
            aria-label="Upload files">
         <span class="upload__icon"><span class="ic ic-upload"></span></span>
         <div class="upload__title">Drop files here or click to browse</div>
         <div class="upload__hint">PDF, DOC up to 10 MB</div>
         <input class="upload__input" type="file" multiple accept=".pdf,.doc" hidden>
       </div>
       <ul class="upload__list"></ul>
     </div>

   Behavior (js/upload.js, vanilla):
     - click / Enter / Space on the dropzone opens the file input
     - drag & drop onto the dropzone (--over highlight)
     - per-file row: extension chip, name, size, progress track, remove
     - data-upload-url: real XHR upload with live progress
       (omit it to simulate progress for demos)
     - states: .upload__item--done / --error
     - events: exsa:upload-add {files}, exsa:upload-done {file, name},
               exsa:upload-error {file, name, message},
               exsa:upload-remove {name}

   Tokens (theme-derived → dark mode adapts automatically):
     --upload-over, --upload-over-bg, --upload-progress,
     --upload-success, --upload-error
   ============================================================ */

:root {
  --upload-over: var(--color-link);
  --upload-over-bg: color-mix(in srgb, var(--color-link) 8%, transparent);
  --upload-progress: var(--color-link);
  --upload-success: var(--color-success);
  --upload-error: var(--color-danger);
}

.upload {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* ── Dropzone ── */
.upload__dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 32px 20px;
  border: 2px dashed var(--color-bg-secondary);
  border-radius: var(--border-radius);
  cursor: pointer;
  text-align: center;
  transition: border-color .15s, background .15s;
}
.upload__dropzone:hover,
.upload__dropzone:focus-visible { border-color: var(--upload-over); }
.upload__dropzone:focus-visible { outline: none; }
.upload__dropzone--over {
  border-color: var(--upload-over);
  background: var(--upload-over-bg);
}

.upload__icon {
  width: 44px;
  height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--color-bg-secondary);
  color: var(--color-text-secondary);
  font-size: 20px;
  margin-bottom: 6px;
}
.upload__title {
  font-size: .88rem;
  font-weight: 600;
  color: var(--color-text);
}
.upload__hint {
  font-size: .74rem;
  color: var(--color-text-secondary);
}

/* ── File list ── */
.upload__list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* ── File item ── */
.upload__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--color-bg-secondary);
  border-radius: var(--border-radius);
  background: var(--color-bg);
}

.upload__item-ext {
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--border-radius);
  background: var(--color-bg-secondary);
  color: var(--color-text-secondary);
  font-size: .6rem;
  font-weight: 800;
  letter-spacing: .03em;
  font-family: var(--font-family-mono);
  flex-shrink: 0;
}

.upload__item-body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.upload__item-name {
  font-size: .82rem;
  font-weight: 600;
  color: var(--color-text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.upload__item-meta {
  font-size: .7rem;
  color: var(--color-text-secondary);
  font-family: var(--font-family-mono);
}
.upload__item-track {
  height: 6px;
  border-radius: 99px;
  background: var(--color-bg-secondary);
  overflow: hidden;
}
.upload__item-fill {
  height: 100%;
  width: var(--upload-pct, 0%);
  border-radius: 99px;
  background: var(--upload-progress);
  transition: width .2s;
}

/* ── States ── */
.upload__item--done .upload__item-fill { background: var(--upload-success); }
.upload__item--error { border-color: color-mix(in srgb, var(--upload-error) 45%, transparent); }
.upload__item--error .upload__item-fill { background: var(--upload-error); }
.upload__item--error .upload__item-meta { color: var(--upload-error); }

/* ── Remove ── */
.upload__item-remove {
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--border-radius);
  background: none;
  color: var(--color-text-secondary);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  flex-shrink: 0;
  font-family: inherit;
}
.upload__item-remove:hover { background: var(--color-bg-secondary); color: var(--upload-error); }
.upload__item-remove:focus-visible { outline: 2px solid var(--color-link); outline-offset: 2px; }
}

/* --- icons.css --- */
@layer exsa.components {

/* ============================================================
   Icons — CSS Mask Library (112 icons)
   ── Link this file to use any .ic-* icon class.
   SVG icons live in components/icons/. All icons are
   stroke-based 24×24, color inherited via currentColor.
   ARIA: decorative icons → aria-hidden="true";
         meaningful icons → aria-label on the element

   ▸ 103 icons adapted from Feather Icons (MIT)
     Copyright (c) 2013-2023 Cole Bemis — github.com/feathericons/feather
   ▸ 9 social/brand icons (github, x-social, linkedin, youtube,
     discord, tiktok, snapchat, instagram, whatsapp) — EXSA additions
     in matching Feather style (24×24, stroke-width:2)
   ============================================================ */

/* ── Base icon class ── */
.ic {
  display: inline-block;
  width: 16px;
  height: 16px;
  vertical-align: middle;
  flex-shrink: 0;
  background-color: currentColor;
  -webkit-mask-size: contain;
  -webkit-mask-position: center;
  -webkit-mask-repeat: no-repeat;
          mask-size: contain;
          mask-position: center;
          mask-repeat: no-repeat;
}

/* ── Icon masks (110) ── */

/* Navigation */
.ic-menu        { -webkit-mask-image: url(components/icons/menu.svg);          mask-image: url(components/icons/menu.svg); }
.ic-home        { -webkit-mask-image: url(components/icons/home.svg);          mask-image: url(components/icons/home.svg); }
.ic-search      { -webkit-mask-image: url(components/icons/search.svg);        mask-image: url(components/icons/search.svg); }
.ic-chevup      { -webkit-mask-image: url(components/icons/chevron-up.svg);    mask-image: url(components/icons/chevron-up.svg); }
.ic-chevdown    { -webkit-mask-image: url(components/icons/chevron-down.svg);  mask-image: url(components/icons/chevron-down.svg); }
.ic-chevleft    { -webkit-mask-image: url(components/icons/chevron-left.svg);  mask-image: url(components/icons/chevron-left.svg); }
.ic-chevright   { -webkit-mask-image: url(components/icons/chevron-right.svg); mask-image: url(components/icons/chevron-right.svg); }
.ic-ext-link    { -webkit-mask-image: url(components/icons/external-link.svg); mask-image: url(components/icons/external-link.svg); }
.ic-arrow-up    { -webkit-mask-image: url(components/icons/arrow-up.svg);     mask-image: url(components/icons/arrow-up.svg); }
.ic-map-pin     { -webkit-mask-image: url(components/icons/map-pin.svg);       mask-image: url(components/icons/map-pin.svg); }

/* Actions */
.ic-plus        { -webkit-mask-image: url(components/icons/plus.svg);          mask-image: url(components/icons/plus.svg); }
.ic-minus       { -webkit-mask-image: url(components/icons/minus.svg);         mask-image: url(components/icons/minus.svg); }
.ic-edit        { -webkit-mask-image: url(components/icons/edit.svg);          mask-image: url(components/icons/edit.svg); }
.ic-copy        { -webkit-mask-image: url(components/icons/copy.svg);          mask-image: url(components/icons/copy.svg); }
.ic-paste       { -webkit-mask-image: url(components/icons/clipboard-paste.svg); mask-image: url(components/icons/clipboard-paste.svg); }
.ic-trash       { -webkit-mask-image: url(components/icons/trash.svg);         mask-image: url(components/icons/trash.svg); }
.ic-download    { -webkit-mask-image: url(components/icons/download.svg);      mask-image: url(components/icons/download.svg); }
.ic-upload      { -webkit-mask-image: url(components/icons/upload.svg);        mask-image: url(components/icons/upload.svg); }
.ic-share       { -webkit-mask-image: url(components/icons/share.svg);         mask-image: url(components/icons/share.svg); }
.ic-settings    { -webkit-mask-image: url(components/icons/settings.svg);      mask-image: url(components/icons/settings.svg); }
.ic-filter      { -webkit-mask-image: url(components/icons/filter.svg);        mask-image: url(components/icons/filter.svg); }
.ic-refresh     { -webkit-mask-image: url(components/icons/refresh.svg);       mask-image: url(components/icons/refresh.svg); }
.ic-sort        { -webkit-mask-image: url(components/icons/sort.svg);          mask-image: url(components/icons/sort.svg); }
.ic-sliders     { -webkit-mask-image: url(components/icons/sliders.svg);       mask-image: url(components/icons/sliders.svg); }
.ic-grip        { -webkit-mask-image: url(components/icons/grip.svg);          mask-image: url(components/icons/grip.svg); }
.ic-crop        { -webkit-mask-image: url(components/icons/crop.svg);          mask-image: url(components/icons/crop.svg); }

/* Text Editing */
.ic-type        { -webkit-mask-image: url(components/icons/type.svg);          mask-image: url(components/icons/type.svg); }
.ic-bold        { -webkit-mask-image: url(components/icons/bold.svg);          mask-image: url(components/icons/bold.svg); }
.ic-italic      { -webkit-mask-image: url(components/icons/italic.svg);        mask-image: url(components/icons/italic.svg); }
.ic-underline   { -webkit-mask-image: url(components/icons/underline.svg);     mask-image: url(components/icons/underline.svg); }
.ic-align-left  { -webkit-mask-image: url(components/icons/align-left.svg);    mask-image: url(components/icons/align-left.svg); }
.ic-align-center { -webkit-mask-image: url(components/icons/align-center.svg); mask-image: url(components/icons/align-center.svg); }
.ic-align-right { -webkit-mask-image: url(components/icons/align-right.svg);   mask-image: url(components/icons/align-right.svg); }
.ic-list        { -webkit-mask-image: url(components/icons/list.svg);          mask-image: url(components/icons/list.svg); }

/* Media */
.ic-image       { -webkit-mask-image: url(components/icons/image.svg);         mask-image: url(components/icons/image.svg); }
.ic-play        { -webkit-mask-image: url(components/icons/play.svg);          mask-image: url(components/icons/play.svg); }
.ic-pause       { -webkit-mask-image: url(components/icons/pause.svg);         mask-image: url(components/icons/pause.svg); }
.ic-video       { -webkit-mask-image: url(components/icons/video.svg);         mask-image: url(components/icons/video.svg); }
.ic-camera      { -webkit-mask-image: url(components/icons/camera.svg);        mask-image: url(components/icons/camera.svg); }
.ic-mic         { -webkit-mask-image: url(components/icons/mic.svg);           mask-image: url(components/icons/mic.svg); }
.ic-volume      { -webkit-mask-image: url(components/icons/volume.svg);        mask-image: url(components/icons/volume.svg); }

/* Account & Security */
.ic-user        { -webkit-mask-image: url(components/icons/user.svg);          mask-image: url(components/icons/user.svg); }
.ic-user-circle { -webkit-mask-image: url(components/icons/user-circle.svg);   mask-image: url(components/icons/user-circle.svg); }
.ic-user-plus   { -webkit-mask-image: url(components/icons/user-plus.svg);     mask-image: url(components/icons/user-plus.svg); }
.ic-user-check  { -webkit-mask-image: url(components/icons/user-check.svg);    mask-image: url(components/icons/user-check.svg); }
.ic-users       { -webkit-mask-image: url(components/icons/users.svg);         mask-image: url(components/icons/users.svg); }
.ic-lock        { -webkit-mask-image: url(components/icons/lock.svg);          mask-image: url(components/icons/lock.svg); }
.ic-unlock      { -webkit-mask-image: url(components/icons/unlock.svg);        mask-image: url(components/icons/unlock.svg); }
.ic-key         { -webkit-mask-image: url(components/icons/key.svg);           mask-image: url(components/icons/key.svg); }
.ic-shield      { -webkit-mask-image: url(components/icons/shield.svg);        mask-image: url(components/icons/shield.svg); }
.ic-shield-check { -webkit-mask-image: url(components/icons/shield-check.svg); mask-image: url(components/icons/shield-check.svg); }
.ic-log-in      { -webkit-mask-image: url(components/icons/log-in.svg);        mask-image: url(components/icons/log-in.svg); }
.ic-log-out     { -webkit-mask-image: url(components/icons/log-out.svg);       mask-image: url(components/icons/log-out.svg); }

/* Commerce */
.ic-cart        { -webkit-mask-image: url(components/icons/cart.svg);          mask-image: url(components/icons/cart.svg); }
.ic-credit-card { -webkit-mask-image: url(components/icons/credit-card.svg);   mask-image: url(components/icons/credit-card.svg); }
.ic-dollar      { -webkit-mask-image: url(components/icons/dollar-sign.svg);   mask-image: url(components/icons/dollar-sign.svg); }
.ic-tag         { -webkit-mask-image: url(components/icons/tag.svg);           mask-image: url(components/icons/tag.svg); }
.ic-gift        { -webkit-mask-image: url(components/icons/gift.svg);          mask-image: url(components/icons/gift.svg); }
.ic-truck       { -webkit-mask-image: url(components/icons/truck.svg);         mask-image: url(components/icons/truck.svg); }
.ic-package     { -webkit-mask-image: url(components/icons/package.svg);       mask-image: url(components/icons/package.svg); }
.ic-briefcase   { -webkit-mask-image: url(components/icons/briefcase.svg);     mask-image: url(components/icons/briefcase.svg); }

/* Developer */
.ic-terminal    { -webkit-mask-image: url(components/icons/terminal.svg);      mask-image: url(components/icons/terminal.svg); }
.ic-database    { -webkit-mask-image: url(components/icons/database.svg);      mask-image: url(components/icons/database.svg); }
.ic-cloud       { -webkit-mask-image: url(components/icons/cloud.svg);         mask-image: url(components/icons/cloud.svg); }
.ic-code        { -webkit-mask-image: url(components/icons/code.svg);          mask-image: url(components/icons/code.svg); }
.ic-layers      { -webkit-mask-image: url(components/icons/layers.svg);        mask-image: url(components/icons/layers.svg); }
.ic-layout      { -webkit-mask-image: url(components/icons/layout.svg);        mask-image: url(components/icons/layout.svg); }
.ic-hash        { -webkit-mask-image: url(components/icons/hash.svg);          mask-image: url(components/icons/hash.svg); }
.ic-wifi        { -webkit-mask-image: url(components/icons/wifi.svg);          mask-image: url(components/icons/wifi.svg); }
.ic-link        { -webkit-mask-image: url(components/icons/link.svg);          mask-image: url(components/icons/link.svg); }

/* Communication */
.ic-mail        { -webkit-mask-image: url(components/icons/mail.svg);          mask-image: url(components/icons/mail.svg); }
.ic-msg         { -webkit-mask-image: url(components/icons/message-circle.svg); mask-image: url(components/icons/message-circle.svg); }
.ic-send        { -webkit-mask-image: url(components/icons/send.svg);          mask-image: url(components/icons/send.svg); }
.ic-phone       { -webkit-mask-image: url(components/icons/phone.svg);         mask-image: url(components/icons/phone.svg); }
.ic-bell        { -webkit-mask-image: url(components/icons/bell.svg);          mask-image: url(components/icons/bell.svg); }
.ic-at-sign     { -webkit-mask-image: url(components/icons/at-sign.svg);       mask-image: url(components/icons/at-sign.svg); }

/* Status */
.ic-check       { -webkit-mask-image: url(components/icons/check.svg);         mask-image: url(components/icons/check.svg); }
.ic-info        { -webkit-mask-image: url(components/icons/info.svg);          mask-image: url(components/icons/info.svg); }
.ic-warn        { -webkit-mask-image: url(components/icons/warning.svg);       mask-image: url(components/icons/warning.svg); }
.ic-error       { -webkit-mask-image: url(components/icons/x-circle.svg);      mask-image: url(components/icons/x-circle.svg); }
.ic-eye         { -webkit-mask-image: url(components/icons/eye.svg);           mask-image: url(components/icons/eye.svg); }
.ic-eye-off     { -webkit-mask-image: url(components/icons/eye-off.svg);       mask-image: url(components/icons/eye-off.svg); }
.ic-help        { -webkit-mask-image: url(components/icons/help-circle.svg);   mask-image: url(components/icons/help-circle.svg); }
.ic-close       { -webkit-mask-image: url(components/icons/x.svg);             mask-image: url(components/icons/x.svg); }

/* Misc */
.ic-star        { -webkit-mask-image: url(components/icons/star.svg);          mask-image: url(components/icons/star.svg); }
.ic-star-f      { -webkit-mask-image: url(components/icons/star-filled.svg);   mask-image: url(components/icons/star-filled.svg); }
.ic-heart       { -webkit-mask-image: url(components/icons/heart.svg);         mask-image: url(components/icons/heart.svg); }
.ic-bookmark    { -webkit-mask-image: url(components/icons/bookmark.svg);      mask-image: url(components/icons/bookmark.svg); }
.ic-clock       { -webkit-mask-image: url(components/icons/clock.svg);         mask-image: url(components/icons/clock.svg); }
.ic-calendar    { -webkit-mask-image: url(components/icons/calendar.svg);      mask-image: url(components/icons/calendar.svg); }
.ic-sun         { -webkit-mask-image: url(components/icons/sun.svg);           mask-image: url(components/icons/sun.svg); }
.ic-moon        { -webkit-mask-image: url(components/icons/moon.svg);          mask-image: url(components/icons/moon.svg); }
.ic-printer     { -webkit-mask-image: url(components/icons/printer.svg);       mask-image: url(components/icons/printer.svg); }
.ic-archive     { -webkit-mask-image: url(components/icons/archive.svg);       mask-image: url(components/icons/archive.svg); }
.ic-flag        { -webkit-mask-image: url(components/icons/flag.svg);          mask-image: url(components/icons/flag.svg); }
.ic-file        { -webkit-mask-image: url(components/icons/file.svg);          mask-image: url(components/icons/file.svg); }
.ic-folder      { -webkit-mask-image: url(components/icons/folder.svg);        mask-image: url(components/icons/folder.svg); }
.ic-inbox       { -webkit-mask-image: url(components/icons/inbox.svg);         mask-image: url(components/icons/inbox.svg); }
.ic-chart       { -webkit-mask-image: url(components/icons/chart.svg);         mask-image: url(components/icons/chart.svg); }
.ic-more-h      { -webkit-mask-image: url(components/icons/more-horizontal.svg); mask-image: url(components/icons/more-horizontal.svg); }
.ic-more-v      { -webkit-mask-image: url(components/icons/more-vertical.svg); mask-image: url(components/icons/more-vertical.svg); }
.ic-dashboard   { -webkit-mask-image: url(components/icons/dashboard.svg);     mask-image: url(components/icons/dashboard.svg); }
.ic-clipboard   { -webkit-mask-image: url(components/icons/clipboard.svg);     mask-image: url(components/icons/clipboard.svg); }

/* ── Social / Brand ── */
.ic-social-github   { -webkit-mask-image: url(components/icons/github.svg);    mask-image: url(components/icons/github.svg); }
.ic-social-x        { -webkit-mask-image: url(components/icons/x-social.svg);   mask-image: url(components/icons/x-social.svg); }
.ic-social-linkedin { -webkit-mask-image: url(components/icons/linkedin.svg);   mask-image: url(components/icons/linkedin.svg); }
.ic-social-youtube  { -webkit-mask-image: url(components/icons/youtube.svg);    mask-image: url(components/icons/youtube.svg); }
.ic-social-discord  { -webkit-mask-image: url(components/icons/discord.svg);    mask-image: url(components/icons/discord.svg); }
.ic-social-tiktok   { -webkit-mask-image: url(components/icons/tiktok.svg);     mask-image: url(components/icons/tiktok.svg); }
.ic-social-snapchat { -webkit-mask-image: url(components/icons/snapchat.svg);   mask-image: url(components/icons/snapchat.svg); }
.ic-social-instagram{ -webkit-mask-image: url(components/icons/instagram.svg);  mask-image: url(components/icons/instagram.svg); }
.ic-social-whatsapp { -webkit-mask-image: url(components/icons/whatsapp.svg);   mask-image: url(components/icons/whatsapp.svg); }

/* ── RTL: flip directional icons ── */
[dir=rtl] .ic-chevleft  { transform: scaleX(-1); }
[dir=rtl] .ic-chevright { transform: scaleX(-1); }

}

/* --- theme: breeze --- */
@layer exsa.themes {

/* ============================================================
   LAYER 2 — THEME: BREEZE
   Clean blue and white by default, deep navy in dark mode.
   Auto-switches via prefers-color-scheme.
   Force mode: <html data-theme-mode="light|dark">
   Self-contained: forced-mode rules included below (also in exsa.css — harmless duplicate).
   ============================================================ */

:root {
  color-scheme: light dark;
  --color-bg: light-dark(#ffffff, #0f172a);
  --color-bg-secondary: light-dark(#e8f0fe, #1e293b);
  --color-text: light-dark(#1a1a2e, #e2e8f0);
  --color-text-secondary: light-dark(#5f6b7a, #94a3b8);
  --color-link: light-dark(#1a73e8, #60a5fa);
  --color-secondary: light-dark(#7c3aed, #a78bfa);
  --color-secondary-accent: light-dark(#7c3aed0d, #a78bfa15);
  --color-accent: light-dark(#1a73e812, #60a5fa14);
  --color-overlay: rgba(0,0,0,.5);
  --color-shadow: light-dark(#c5d8f7, #00000044);
  --color-scrollbar: light-dark(#a8c4f0, #334155);
  --color-success: light-dark(#16a34a, #22c55e);
  --color-success-hover: light-dark(#15803d, #16a34a);
  --color-danger: light-dark(#dc2626, #ef4444);
  --color-danger-hover: light-dark(#b91c1c, #dc2626);
  --color-warning: light-dark(#d97706, #f59e0b);
  --color-warning-hover: light-dark(#b45309, #d97706);
  --color-border: light-dark(#c5d8f7, #334155);
  --color-button-text: light-dark(var(--color-bg), #000618);
  --color-button-text-inverse: light-dark(#1a1a2e, #e2e8f0);
}

/* Forced dark — <html data-theme-mode="dark">, ignores OS preference */
:root[data-theme-mode="dark"] { color-scheme: dark; }

/* Forced light — <html data-theme-mode="light">, ignores OS preference */
:root[data-theme-mode="light"] { color-scheme: light; }

}
