/* ============================================================================
   tokens.css — the whole design system's vocabulary.
   Everything downstream reads from here; components never write a raw hex.

   Per-demo, exactly one input changes: --accent (from spec.brand.accent).
   The rest of the palette is derived from it with color-mix(), so a demo can
   go from teal to oxblood by changing one line and still look deliberate.
   ==========================================================================*/

/* ---- 1. reset ---------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
img, svg, video, canvas { display: block; max-inline-size: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; }
table { border-collapse: collapse; inline-size: 100%; }
:where(a) { color: inherit; text-decoration: none; }

/* ---- 2. scales (theme-independent) ------------------------------------- */
:root {
  /* Type — 1.2 minor third off a 15px base. Two fluid steps at the top only;
     body text never scales, because scaling body text in a dense enterprise
     table is how you get a broken layout on a Galaxy A54. */
  --text-2xs: 0.6875rem;   /* 11px  — micro labels, table meta */
  --text-xs:  0.75rem;     /* 12px  — captions, badges */
  --text-sm:  0.8125rem;   /* 13px  — table body, secondary */
  --text-base:0.9375rem;   /* 15px  — body */
  --text-md:  1.0625rem;   /* 17px  — card titles */
  --text-lg:  1.3125rem;   /* 21px  — screen titles */
  --text-xl:  clamp(1.5rem, 1.2rem + 1.4vw, 2rem);      /* section heroes */
  --text-2xl: clamp(2rem, 1.4rem + 3.2vw, 3.25rem);     /* hero only */

  --leading-tight: 1.4;    /* tighter than this clips Arabic descenders/diacritics */
  --leading-snug:  1.55;
  --leading-body:  1.75;   /* Arabic needs ~1.7–1.8 where Latin wants 1.5 */

  /* Tracking is ZERO by default. Arabic is cursive: any non-zero letter-spacing
     pulls the joins apart and renders words as disconnected fragments. It looks
     like tasteful tracking to a Latin eye and like broken text to an Arabic
     reader, which is why Latin design systems ship this bug constantly.
     The values below are re-enabled for Latin only, at the bottom of this file. */
  --tracking-display: 0;
  --tracking-label: 0;

  --weight-regular: 400;
  --weight-medium:  500;
  --weight-semi:    600;
  --weight-bold:    700;

  --font-sans: 'Cairo', ui-sans-serif, system-ui, 'Segoe UI', sans-serif;
  /* Numbers/IDs/currency: tabular, and a Latin-first stack so digits never
     inherit an Arabic-indic glyph by accident. */
  --font-num: ui-monospace, 'Cairo', 'SF Mono', Menlo, monospace;

  /* Space — 4px base. Only these values exist; a stray 13px reads as an accident. */
  --space-0:  0;
  --space-1:  0.25rem;   /* 4  */
  --space-2:  0.5rem;    /* 8  */
  --space-3:  0.75rem;   /* 12 */
  --space-4:  1rem;      /* 16 */
  --space-5:  1.5rem;    /* 24 */
  --space-6:  2rem;      /* 32 */
  --space-7:  3rem;      /* 48 */
  --space-8:  4rem;      /* 64 */

  /* Radius — one family, set by spec.brand.radius via --radius-base.
     Every other radius is a ratio of it, so "sharp" and "round" demos stay
     internally consistent instead of mixing a 4px input with a 16px card. */
  --radius-base: 12px;
  --radius-xs: calc(var(--radius-base) * 0.34);
  --radius-sm: calc(var(--radius-base) * 0.67);
  --radius-md: var(--radius-base);
  --radius-lg: calc(var(--radius-base) * 1.34);
  --radius-xl: calc(var(--radius-base) * 2);
  --radius-pill: 999px;

  /* Motion. Everything is fast — a 400ms drawer feels like a slow app. */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
  --dur-fast: 120ms;
  --dur-base: 180ms;
  --dur-slow: 280ms;

  --z-sticky: 10;
  --z-scrim: 40;
  --z-drawer: 50;
  --z-toast: 70;

  --shell-rail: 248px;      /* sidebar at desktop */
  --shell-rail-narrow: 76px;
  --shell-max: 1560px;
  --topbar-h: 60px;

  /* The single per-demo input. Overridden inline by renderShell(). */
  --accent: #0f766e;
}

/* ---- 3. semantic colour ------------------------------------------------
   Named by role, not by value: a component asking for --surface-raised keeps
   working when the theme flips. Both themes define the same names.
   ------------------------------------------------------------------------ */
:root, :root[data-theme="dark"] {
  color-scheme: dark;

  --canvas:          #0a0d14;
  --surface:         #10141d;
  --surface-raised:  #161b26;
  --surface-sunken:  #0c1017;
  --surface-hover:   #1b2130;
  /* Tinted overlay used behind accent-owned regions (selected row, active nav). */
  --surface-accent:  color-mix(in oklab, var(--accent) 14%, transparent);

  --border:          #212836;
  --border-soft:     #1a202c;
  --border-strong:   #2e394c;

  --ink:             #e9eef7;
  --ink-muted:       #98a3b8;
  --ink-subtle:      #64708a;
  /* Text that sits ON the accent. Derived, so a pale accent still reads. */
  --ink-on-accent:   #04120f;

  --accent-hover:    color-mix(in oklab, var(--accent) 82%, white);
  --accent-press:    color-mix(in oklab, var(--accent) 84%, black);
  --accent-soft:     color-mix(in oklab, var(--accent) 16%, transparent);
  --accent-ink:      color-mix(in oklab, var(--accent) 76%, white);
  --accent-border:   color-mix(in oklab, var(--accent) 44%, transparent);

  --success:      #3ecf8e;   --success-soft: color-mix(in oklab, #3ecf8e 16%, transparent);
  --warning:      #f0b429;   --warning-soft: color-mix(in oklab, #f0b429 16%, transparent);
  --danger:       #f2645a;   --danger-soft:  color-mix(in oklab, #f2645a 16%, transparent);
  --info:         #7c8cf8;   --info-soft:    color-mix(in oklab, #7c8cf8 16%, transparent);
  --neutral-soft: #1c2331;

  /* Elevation: two stacked shadows (contact + ambient) reads as real depth;
     one big blurry shadow reads as a template. */
  --elev-1: 0 1px 2px rgba(0,0,0,.34);
  --elev-2: 0 1px 2px rgba(0,0,0,.30), 0 4px 12px rgba(0,0,0,.30);
  --elev-3: 0 2px 4px rgba(0,0,0,.32), 0 12px 32px rgba(0,0,0,.40);
  --elev-4: 0 4px 8px rgba(0,0,0,.34), 0 28px 68px rgba(0,0,0,.52);
  --glow-accent: 0 6px 22px color-mix(in oklab, var(--accent) 34%, transparent);

  /* Ambient page wash — keyed to the accent so it never fights the brand. */
  --canvas-wash:
    radial-gradient(1200px 620px at 88% -12%, color-mix(in oklab, var(--accent) 13%, transparent), transparent 62%),
    radial-gradient(900px 520px at -8% 108%, color-mix(in oklab, var(--info) 9%, transparent), transparent 58%);

  --skeleton-base: #171d29;
  --skeleton-shine: #222b3b;
}

:root[data-theme="light"] {
  color-scheme: light;

  --canvas:          #f4f6fa;
  --surface:         #ffffff;
  --surface-raised:  #ffffff;
  --surface-sunken:  #f7f9fc;
  --surface-hover:   #f1f4f9;
  --surface-accent:  color-mix(in oklab, var(--accent) 9%, transparent);

  --border:          #e2e7ef;
  --border-soft:     #edf1f6;
  --border-strong:   #cbd4e1;

  --ink:             #131a26;
  --ink-muted:       #5b6779;
  --ink-subtle:      #8b97a9;
  --ink-on-accent:   #ffffff;

  --accent-hover:    color-mix(in oklab, var(--accent) 86%, black);
  --accent-press:    color-mix(in oklab, var(--accent) 74%, black);
  --accent-soft:     color-mix(in oklab, var(--accent) 11%, transparent);
  --accent-ink:      color-mix(in oklab, var(--accent) 88%, black);
  --accent-border:   color-mix(in oklab, var(--accent) 34%, transparent);

  --success:      #12905a;   --success-soft: color-mix(in oklab, #12905a 12%, transparent);
  --warning:      #b06f04;   --warning-soft: color-mix(in oklab, #b06f04 12%, transparent);
  --danger:       #cf3b32;   --danger-soft:  color-mix(in oklab, #cf3b32 11%, transparent);
  --info:         #4f5fd8;   --info-soft:    color-mix(in oklab, #4f5fd8 11%, transparent);
  --neutral-soft: #eef2f7;

  --elev-1: 0 1px 2px rgba(19,26,38,.06);
  --elev-2: 0 1px 2px rgba(19,26,38,.05), 0 4px 12px rgba(19,26,38,.07);
  --elev-3: 0 2px 4px rgba(19,26,38,.06), 0 12px 30px rgba(19,26,38,.10);
  --elev-4: 0 4px 8px rgba(19,26,38,.07), 0 26px 64px rgba(19,26,38,.14);
  --glow-accent: 0 6px 20px color-mix(in oklab, var(--accent) 26%, transparent);

  --canvas-wash:
    radial-gradient(1200px 620px at 88% -12%, color-mix(in oklab, var(--accent) 9%, transparent), transparent 62%),
    radial-gradient(900px 520px at -8% 108%, color-mix(in oklab, var(--info) 7%, transparent), transparent 58%);

  --skeleton-base: #e9eef4;
  --skeleton-shine: #f6f9fc;
}

/* ---- 4. base ----------------------------------------------------------- */
html, body { block-size: 100%; }

body {
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-body);
  color: var(--ink);
  background-color: var(--canvas);
  background-image: var(--canvas-wash);
  background-attachment: fixed;
}

/* Belt and braces on the cursive-join rule: even if a component hardcodes a
   tracking value, Arabic never receives it. Latin runs get their tracking back
   here, which is also what the EN toggle switches to (it sets lang="en"). */
:lang(ar), :lang(ar) * { letter-spacing: normal; }
:lang(en) {
  --tracking-display: -0.02em;
  --tracking-label: 0.06em;
}
/* text-transform: uppercase is a no-op in Arabic — there are no capitals — so
   hierarchy is carried by size, weight and colour throughout, never by caps. */

/* Latin digits everywhere by default — Gulf business software is written with
   them, and mixing 1234 with ١٢٣٤ in one table is the fastest way to look
   unfinished. spec.locale.numerals='arab' flips it on the <html> element. */
:root[data-numerals="latn"] { font-variant-numeric: lining-nums; }

/* Any run that mixes Arabic with Latin/digits gets isolated, or the bidi
   algorithm reorders it: "+966 55 123 4567" renders as "4567 123 55 966+". */
.num, .lat, bdi, [data-num] {
  unicode-bidi: isolate;
  font-variant-numeric: tabular-nums lining-nums;
}
/* No tracking here either: Intl's currency output puts Arabic glyphs inside the
   numeric run ("4,200 ر.س.‏"), so negative tracking would disconnect them. */
.num, [data-num] { font-family: var(--font-num); }

::selection { background: var(--accent-soft); color: var(--ink); }

/* One focus treatment, everywhere, visible in both themes. Never remove it. */
:focus-visible {
  outline: 2px solid var(--accent-ink);
  outline-offset: 2px;
  border-radius: var(--radius-xs);
}
:focus:not(:focus-visible) { outline: none; }

/* Scrollbars: thin and themed, so a scrolling table doesn't punch a
   light-grey Windows scrollbar through a dark UI. */
* { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
*::-webkit-scrollbar { inline-size: 9px; block-size: 9px; }
*::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: var(--radius-pill); }
*::-webkit-scrollbar-track { background: transparent; }

.sr-only {
  position: absolute; inline-size: 1px; block-size: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ============================================================================
   shell.css — the app frame: rail, topbar, screen router, common primitives.
   RTL-first: logical properties only. There is no `left` or `right` in this
   file, so the LTR toggle is free and correct rather than a second stylesheet.
   ==========================================================================*/

.app {
  display: grid;
  grid-template-columns: var(--shell-rail) minmax(0, 1fr);
  min-block-size: 100dvh;
}

/* skip link — first tabbable thing on the page */
.skip {
  position: fixed; inset-block-start: var(--space-2); inset-inline-start: var(--space-2);
  z-index: 99; padding: var(--space-2) var(--space-4);
  background: var(--accent); color: var(--ink-on-accent);
  border-radius: var(--radius-sm); font-weight: var(--weight-semi);
  transform: translateY(-200%);
}
.skip:focus { transform: none; }

/* ---- invite gate --------------------------------------------------------
   Same tokens, font and accent as the app behind it — it is the first thing
   the client sees, so an off-brand gate undersells everything after it.
   ------------------------------------------------------------------------ */
.gate-body { display: grid; place-items: center; min-block-size: 100dvh; padding: var(--space-4); }
.gate-hero {
  position: fixed; inset: 0; z-index: 0;
  block-size: 100dvh; margin: 0; border: 0; border-radius: 0;
  opacity: .55;
}
.gate-card {
  position: relative; z-index: 1;
  inline-size: min(400px, 100%); text-align: center;
  display: flex; flex-direction: column; gap: var(--space-3);
  padding: var(--space-6); border-radius: var(--radius-xl);
  box-shadow: var(--elev-4);
  background: color-mix(in oklab, var(--surface) 88%, transparent);
  backdrop-filter: blur(16px);
}
.gate-card .rail-mark { margin-inline: auto; inline-size: 48px; block-size: 48px; font-size: var(--text-lg); }
.gate-card h1 { font-size: var(--text-lg); font-weight: var(--weight-bold); }
.gate-card > p { color: var(--ink-muted); font-size: var(--text-sm); }
.gate-card form { display: flex; flex-direction: column; gap: var(--space-3); margin-block-start: var(--space-2); text-align: start; }
.gate-card .field > span { font-size: var(--text-xs); font-weight: var(--weight-semi); color: var(--ink-muted); }
.gate-card .btn { min-block-size: 44px; }
/* The code is Latin and fixed-width; tracking is safe here and nowhere else. */
.gate-code { text-align: center; font-family: var(--font-num); letter-spacing: .3em; text-transform: uppercase; }
.gate-err { color: var(--danger); font-size: var(--text-xs); text-align: center; }

/* ---- rail --------------------------------------------------------------- */
.rail {
  position: sticky; inset-block-start: 0; block-size: 100dvh;
  display: flex; flex-direction: column;
  padding: var(--space-4) var(--space-3);
  gap: var(--space-5);
  background: color-mix(in oklab, var(--surface) 72%, transparent);
  backdrop-filter: blur(14px);
  border-inline-end: 1px solid var(--border);
  z-index: var(--z-sticky);
}

.rail-brand { display: flex; align-items: center; gap: var(--space-3); padding-inline: var(--space-2); }
.rail-mark {
  inline-size: 38px; block-size: 38px; flex: none;
  border-radius: var(--radius-md);
  display: grid; place-items: center;
  background: linear-gradient(140deg, var(--accent), color-mix(in oklab, var(--accent) 55%, var(--info)));
  color: var(--ink-on-accent);
  font-weight: var(--weight-bold); font-size: var(--text-md);
  box-shadow: var(--glow-accent);
}
.rail-name { min-inline-size: 0; }
.rail-name b { display: block; font-size: var(--text-md); font-weight: var(--weight-bold); letter-spacing: var(--tracking-display); }
.rail-name small {
  display: block; color: var(--ink-subtle); font-size: var(--text-2xs);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.rail-nav { display: flex; flex-direction: column; gap: 2px; flex: 1; overflow-y: auto; }
.rail-sec {
  font-size: var(--text-2xs); font-weight: var(--weight-bold);
  color: var(--ink-subtle); letter-spacing: var(--tracking-label);
  padding: var(--space-4) var(--space-3) var(--space-2);
}
.nav-item {
  display: flex; align-items: center; gap: var(--space-3);
  padding: var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--ink-muted); font-size: var(--text-sm); font-weight: var(--weight-medium);
  inline-size: 100%; text-align: start;
  transition: background var(--dur-fast), color var(--dur-fast);
  position: relative;
}
.nav-item svg { inline-size: 18px; block-size: 18px; flex: none; }
.nav-item:hover { background: var(--surface-hover); color: var(--ink); }
.nav-item[aria-current="page"] { background: var(--surface-accent); color: var(--accent-ink); font-weight: var(--weight-semi); }
/* Active marker rides the inline-start edge — mirrors correctly by itself. */
.nav-item[aria-current="page"]::before {
  content: ""; position: absolute; inset-inline-start: 0; inset-block: 22%;
  inline-size: 3px; border-radius: var(--radius-pill); background: var(--accent);
}
.nav-item .count {
  margin-inline-start: auto; font-size: var(--text-2xs); font-weight: var(--weight-bold);
  background: var(--neutral-soft); color: var(--ink-muted);
  padding: 1px var(--space-2); border-radius: var(--radius-pill);
}

.rail-foot { display: flex; flex-direction: column; gap: var(--space-2); border-block-start: 1px solid var(--border-soft); padding-block-start: var(--space-3); }

/* ---- stage + topbar ----------------------------------------------------- */
.stage { display: flex; flex-direction: column; min-inline-size: 0; }

.topbar {
  position: sticky; inset-block-start: 0; z-index: var(--z-sticky);
  display: flex; align-items: center; gap: var(--space-4);
  min-block-size: var(--topbar-h);
  padding: var(--space-3) var(--space-5);
  background: color-mix(in oklab, var(--canvas) 82%, transparent);
  backdrop-filter: blur(14px);
  border-block-end: 1px solid var(--border-soft);
}
.topbar-title { min-inline-size: 0; flex: 1; }
.topbar-title h1 { font-size: var(--text-lg); font-weight: var(--weight-bold); letter-spacing: var(--tracking-display); line-height: var(--leading-tight); }
.topbar-title p { font-size: var(--text-xs); color: var(--ink-muted); margin-block-start: 2px; }
.topbar-actions { display: flex; align-items: center; gap: var(--space-2); }

.screens { flex: 1; padding: var(--space-5); max-inline-size: var(--shell-max); inline-size: 100%; margin-inline: auto; }
.screen { display: none; }
.screen.is-active { display: block; animation: screen-in var(--dur-slow) var(--ease-out); }
@keyframes screen-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

.screen-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--space-4); margin-block-end: var(--space-5); flex-wrap: wrap; }
.screen-head h2 { font-size: var(--text-xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-display); }
.screen-head p { color: var(--ink-muted); font-size: var(--text-sm); margin-block-start: var(--space-1); max-inline-size: 62ch; }

/* ---- buttons ------------------------------------------------------------ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-4); min-block-size: 38px;
  border-radius: var(--radius-sm);
  font-size: var(--text-sm); font-weight: var(--weight-semi);
  border: 1px solid transparent;
  transition: background var(--dur-fast), border-color var(--dur-fast), transform var(--dur-fast), box-shadow var(--dur-fast);
  white-space: nowrap;
}
.btn svg { inline-size: 16px; block-size: 16px; }
.btn:active { transform: translateY(1px); }
.btn[disabled], .btn[aria-disabled="true"] { opacity: .5; pointer-events: none; }

.btn-primary { background: var(--accent); color: var(--ink-on-accent); box-shadow: var(--glow-accent); }
.btn-primary:hover { background: var(--accent-hover); }
.btn-primary:active { background: var(--accent-press); }

.btn-secondary { background: var(--surface-raised); color: var(--ink); border-color: var(--border); box-shadow: var(--elev-1); }
.btn-secondary:hover { background: var(--surface-hover); border-color: var(--border-strong); }

.btn-ghost { color: var(--ink-muted); }
.btn-ghost:hover { background: var(--surface-hover); color: var(--ink); }

.btn-danger { background: var(--danger-soft); color: var(--danger); border-color: color-mix(in oklab, var(--danger) 34%, transparent); }
.btn-danger:hover { background: var(--danger); color: #fff; }

.btn-icon { padding: 0; inline-size: 38px; block-size: 38px; }

/* ---- inputs ------------------------------------------------------------- */
.field { display: flex; flex-direction: column; gap: var(--space-2); min-inline-size: 0; }
.field > label { font-size: var(--text-xs); font-weight: var(--weight-semi); color: var(--ink-muted); }
.input, .select, .textarea {
  inline-size: 100%; min-block-size: 38px;
  padding: var(--space-2) var(--space-3);
  background: var(--surface-sunken); color: var(--ink);
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  transition: border-color var(--dur-fast), background var(--dur-fast);
}
.input::placeholder, .textarea::placeholder { color: var(--ink-subtle); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--border-strong); }
.input:focus, .select:focus, .textarea:focus { outline: none; border-color: var(--accent); background: var(--surface); box-shadow: 0 0 0 3px var(--accent-soft); }
.textarea { min-block-size: 92px; resize: vertical; line-height: var(--leading-body); }
/* Native select arrow is on the wrong side in RTL on some engines; the
   browser handles this correctly when the element inherits dir, so we only
   reserve room for it logically. */
.select { padding-inline-end: var(--space-6); }

.search {
  position: relative; flex: 1; max-inline-size: 340px; min-inline-size: 0;
}
.search .input { padding-inline-start: var(--space-7); }
.search svg {
  position: absolute; inset-inline-start: var(--space-3); inset-block-start: 50%;
  transform: translateY(-50%); inline-size: 16px; block-size: 16px; color: var(--ink-subtle); pointer-events: none;
}

/* ---- surfaces ----------------------------------------------------------- */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--elev-2);
  padding: var(--space-5);
}
.card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-block-end: var(--space-4); }
.card-head h3 { font-size: var(--text-md); font-weight: var(--weight-semi); }
.card-head .hint { font-size: var(--text-xs); color: var(--ink-subtle); }
.card-flush { padding: 0; overflow: hidden; }
.card-flush .card-head { padding: var(--space-4) var(--space-5); margin: 0; border-block-end: 1px solid var(--border-soft); }

.grid { display: grid; gap: var(--space-4); }
.grid-kpi { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.split { display: grid; grid-template-columns: minmax(0, 1.9fr) minmax(0, 1fr); gap: var(--space-4); }
@media (max-width: 1080px) { .split { grid-template-columns: minmax(0, 1fr); } }

.badge {
  display: inline-flex; align-items: center; gap: var(--space-1);
  padding: 2px var(--space-2); border-radius: var(--radius-pill);
  font-size: var(--text-2xs); font-weight: var(--weight-bold); white-space: nowrap;
  background: var(--neutral-soft); color: var(--ink-muted);
}
.badge::before { content: ""; inline-size: 5px; block-size: 5px; border-radius: 50%; background: currentColor; }
.badge-success { background: var(--success-soft); color: var(--success); }
.badge-warning { background: var(--warning-soft); color: var(--warning); }
.badge-danger  { background: var(--danger-soft);  color: var(--danger); }
.badge-info    { background: var(--info-soft);    color: var(--info); }
.badge-accent  { background: var(--accent-soft);  color: var(--accent-ink); }
.badge-plain::before { display: none; }

.chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.chip {
  padding: var(--space-1) var(--space-3); border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--surface);
  font-size: var(--text-xs); font-weight: var(--weight-medium); color: var(--ink-muted);
  transition: all var(--dur-fast);
}
.chip:hover { border-color: var(--accent-border); color: var(--accent-ink); }
.chip[aria-pressed="true"] { background: var(--surface-accent); border-color: var(--accent-border); color: var(--accent-ink); font-weight: var(--weight-semi); }

.divider { block-size: 1px; background: var(--border-soft); margin-block: var(--space-4); }

/* Chevrons and other directional glyphs mirror; clocks, logos, media controls
   and the search magnifier must NOT. Only this class flips. */
:root[dir="rtl"] .mirror { transform: scaleX(-1); }

/* ---- responsive: rail becomes a bottom tab bar -------------------------- */
@media (max-width: 1180px) and (min-width: 861px) {
  .app { grid-template-columns: var(--shell-rail-narrow) minmax(0, 1fr); }
  .rail-name, .rail-sec, .nav-item .label, .nav-item .count { display: none; }
  .nav-item { justify-content: center; padding-inline: 0; }
  .rail-brand { justify-content: center; }
}

@media (max-width: 860px) {
  .app { grid-template-columns: minmax(0, 1fr); }
  .rail {
    position: fixed; inset-block-start: auto; inset-block-end: 0; inset-inline: 0;
    block-size: auto; flex-direction: row; align-items: center;
    padding: var(--space-2) var(--space-2) max(var(--space-2), env(safe-area-inset-bottom));
    border-inline-end: 0; border-block-start: 1px solid var(--border);
    gap: 0;
  }
  .rail-brand, .rail-sec, .rail-foot { display: none; }
  .rail-nav { flex-direction: row; justify-content: space-around; inline-size: 100%; overflow: visible; }
  .nav-item { flex-direction: column; gap: 2px; padding: var(--space-2) var(--space-1); font-size: var(--text-2xs); }
  .nav-item .count { display: none; }
  .nav-item[aria-current="page"]::before { inset-inline: 30%; inset-block-start: 0; inset-block-end: auto; block-size: 3px; inline-size: auto; }
  .topbar { padding-inline: var(--space-4); }
  .screens { padding: var(--space-4) var(--space-4) calc(var(--space-8) + var(--space-4)); }
  .screen-head h2 { font-size: var(--text-lg); }
}

/* ============================================================================
   components/data.css — table · kpi-card · skeleton · empty-state · pager
   Grouped into one file on purpose: they are always loaded together and the
   generator concatenates the CSS anyway, so nine files would buy nothing.
   ==========================================================================*/

/* ---- data table --------------------------------------------------------
   Header is sticky; the whole thing scrolls inside its own box so a 12-column
   table never makes the page scroll sideways (the classic RTL demo-killer).
   ------------------------------------------------------------------------ */
.table-wrap { overflow-x: auto; overscroll-behavior-x: contain; }

.table { font-size: var(--text-sm); inline-size: 100%; }
.table thead th {
  position: sticky; inset-block-start: 0; z-index: 1;
  text-align: start; white-space: nowrap;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-2xs); font-weight: var(--weight-bold);
  color: var(--ink-subtle); letter-spacing: var(--tracking-label);
  background: var(--surface-sunken);
  border-block-end: 1px solid var(--border);
}
.table thead th.sortable { cursor: pointer; user-select: none; }
.table thead th.sortable:hover { color: var(--ink); }
.table thead th .caret { opacity: 0; margin-inline-start: var(--space-1); font-size: 9px; }
.table thead th[aria-sort] { color: var(--accent-ink); }
.table thead th[aria-sort] .caret { opacity: 1; }
.table thead th[aria-sort="descending"] .caret { display: inline-block; transform: rotate(180deg); }

.table tbody td {
  padding: var(--space-3) var(--space-4);
  border-block-end: 1px solid var(--border-soft);
  vertical-align: middle;
}
.table tbody tr { transition: background var(--dur-fast); }
.table tbody tr[data-row] { cursor: pointer; }
.table tbody tr:hover { background: var(--surface-hover); }
.table tbody tr[aria-selected="true"] { background: var(--surface-accent); }
.table tbody tr:last-child td { border-block-end: 0; }

.table .cell-strong { font-weight: var(--weight-semi); color: var(--ink); }
.table .cell-muted { color: var(--ink-muted); font-size: var(--text-xs); }
/* Numeric columns align to the end of the line in both directions and stay
   tabular so digits form a column instead of a ragged edge. */
.table .cell-num { text-align: end; font-family: var(--font-num); font-variant-numeric: tabular-nums; white-space: nowrap; unicode-bidi: isolate; }
.table .cell-actions { text-align: end; white-space: nowrap; }

/* Primary cell: name over a secondary identifier. Carries most demos. */
.cell-lead { display: flex; align-items: center; gap: var(--space-3); min-inline-size: 0; }
.cell-lead .avatar {
  inline-size: 32px; block-size: 32px; flex: none; border-radius: var(--radius-sm);
  display: grid; place-items: center; font-size: var(--text-xs); font-weight: var(--weight-bold);
  background: var(--surface-accent); color: var(--accent-ink);
}
.cell-lead .meta { min-inline-size: 0; }
.cell-lead .meta b { display: block; font-weight: var(--weight-semi); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cell-lead .meta small { display: block; color: var(--ink-subtle); font-size: var(--text-2xs); }

.table-toolbar {
  display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap;
  padding: var(--space-3) var(--space-4);
  border-block-end: 1px solid var(--border-soft);
}
.table-toolbar .spacer { flex: 1; }

.pager {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
  padding: var(--space-3) var(--space-4); border-block-start: 1px solid var(--border-soft);
  font-size: var(--text-xs); color: var(--ink-muted);
}
.pager .pages { display: flex; gap: var(--space-1); }
.pager button {
  min-inline-size: 30px; block-size: 30px; padding-inline: var(--space-2);
  border-radius: var(--radius-xs); color: var(--ink-muted); font-size: var(--text-xs); font-weight: var(--weight-semi);
}
.pager button:hover:not([disabled]) { background: var(--surface-hover); color: var(--ink); }
.pager button[aria-current="true"] { background: var(--surface-accent); color: var(--accent-ink); }
.pager button[disabled] { opacity: .35; cursor: default; }

/* ---- kpi card ----------------------------------------------------------- */
.kpi {
  position: relative; overflow: hidden;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); padding: var(--space-4) var(--space-5);
  box-shadow: var(--elev-2);
}
.kpi::after {
  content: ""; position: absolute; inset-block-start: 0; inset-inline: 0; block-size: 2px;
  background: linear-gradient(to inline-end, var(--accent), transparent);
  opacity: .8;
}
.kpi .label { font-size: var(--text-2xs); font-weight: var(--weight-bold); color: var(--ink-subtle); letter-spacing: var(--tracking-label); }
.kpi .value {
  font-size: 1.75rem; font-weight: var(--weight-bold); letter-spacing: var(--tracking-display);
  margin-block-start: var(--space-2); font-variant-numeric: tabular-nums; unicode-bidi: isolate;
}
.kpi .value .unit { font-size: var(--text-sm); font-weight: var(--weight-semi); color: var(--ink-muted); margin-inline-start: var(--space-1); }
.kpi .delta {
  display: inline-flex; align-items: center; gap: var(--space-1);
  margin-block-start: var(--space-2); padding: 1px var(--space-2);
  border-radius: var(--radius-pill); font-size: var(--text-2xs); font-weight: var(--weight-bold);
  unicode-bidi: isolate;
}
.kpi .delta.up { background: var(--success-soft); color: var(--success); }
.kpi .delta.down { background: var(--danger-soft); color: var(--danger); }
.kpi .delta.flat { background: var(--neutral-soft); color: var(--ink-muted); }
.kpi .spark { position: absolute; inset-inline-end: var(--space-3); inset-block-end: var(--space-3); opacity: .55; pointer-events: none; }
.kpi .spark path { fill: none; stroke: var(--accent); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* ---- skeleton ----------------------------------------------------------
   Skeletons, never spinners: a spinner says "wait", a skeleton says "this is
   the shape of what's arriving" and reads as faster at the same latency.
   ------------------------------------------------------------------------ */
.sk {
  border-radius: var(--radius-xs);
  background: linear-gradient(90deg, var(--skeleton-base) 0%, var(--skeleton-shine) 50%, var(--skeleton-base) 100%);
  background-size: 220% 100%;
  animation: sk-shift 1.25s linear infinite;
}
@keyframes sk-shift { from { background-position: 200% 0; } to { background-position: -20% 0; } }
.sk-text { block-size: 0.75em; margin-block: 0.25em; }
.sk-line-60 { inline-size: 60%; } .sk-line-40 { inline-size: 40%; } .sk-line-80 { inline-size: 80%; }
.sk-avatar { inline-size: 32px; block-size: 32px; border-radius: var(--radius-sm); }
.sk-kpi { block-size: 108px; border-radius: var(--radius-lg); }
.sk-block { block-size: 220px; border-radius: var(--radius-lg); }

/* ---- empty state -------------------------------------------------------
   Every empty state names WHY it is empty and offers the way out. A filter
   that returns nothing with no explanation is scored as a dead end.
   ------------------------------------------------------------------------ */
.empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--space-3); padding: var(--space-8) var(--space-5); text-align: center;
}
.empty .glyph {
  inline-size: 52px; block-size: 52px; border-radius: var(--radius-lg);
  display: grid; place-items: center;
  background: var(--surface-accent); color: var(--accent-ink);
}
.empty .glyph svg { inline-size: 24px; block-size: 24px; }
.empty h4 { font-size: var(--text-md); font-weight: var(--weight-semi); }
.empty p { color: var(--ink-muted); font-size: var(--text-sm); max-inline-size: 44ch; }

/* ---- inline chart bars (dependency-free) -------------------------------- */
.bars { display: flex; flex-direction: column; gap: var(--space-3); }
.bar-row { display: grid; grid-template-columns: minmax(88px, 22%) 1fr auto; align-items: center; gap: var(--space-3); font-size: var(--text-xs); }
.bar-row .k { color: var(--ink-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar-row .track { block-size: 8px; border-radius: var(--radius-pill); background: var(--neutral-soft); overflow: hidden; }
.bar-row .track i { display: block; block-size: 100%; border-radius: var(--radius-pill); background: linear-gradient(to inline-end, var(--accent), color-mix(in oklab, var(--accent) 60%, var(--info))); transition: inline-size var(--dur-slow) var(--ease-out); }
.bar-row .v { font-family: var(--font-num); font-variant-numeric: tabular-nums; color: var(--ink); font-weight: var(--weight-semi); unicode-bidi: isolate; }

/* ============================================================================
   components/overlay.css — drawer · scrim · toast · modal · copilot
   ==========================================================================*/

.scrim {
  position: fixed; inset: 0; z-index: var(--z-scrim);
  background: color-mix(in oklab, var(--canvas) 62%, transparent);
  backdrop-filter: blur(2px);
  opacity: 0; pointer-events: none;
  transition: opacity var(--dur-base);
}
.scrim.is-open { opacity: 1; pointer-events: auto; }

/* Drawer slides in from the inline-end edge — in RTL that is the left of the
   screen, which is correct: it comes from the "away" side either way. */
.drawer {
  position: fixed; inset-block: 0; inset-inline-end: 0; z-index: var(--z-drawer);
  inline-size: min(480px, 100vw);
  display: flex; flex-direction: column;
  background: var(--surface);
  border-inline-start: 1px solid var(--border);
  box-shadow: var(--elev-4);
  transform: translateX(calc(var(--drawer-dir, 1) * 102%));
  transition: transform var(--dur-slow) var(--ease-out);
  visibility: hidden;
}
:root[dir="rtl"] .drawer { --drawer-dir: -1; }
.drawer.is-open { transform: none; visibility: visible; }

.drawer-head {
  display: flex; align-items: flex-start; gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  border-block-end: 1px solid var(--border-soft);
}
.drawer-head .t { flex: 1; min-inline-size: 0; }
.drawer-head h3 { font-size: var(--text-md); font-weight: var(--weight-bold); }
.drawer-head p { font-size: var(--text-xs); color: var(--ink-muted); margin-block-start: 2px; }
.drawer-body { flex: 1; overflow-y: auto; padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-5); }
.drawer-foot { display: flex; gap: var(--space-2); padding: var(--space-4) var(--space-5); border-block-start: 1px solid var(--border-soft); background: var(--surface-sunken); }
.drawer-foot .btn { flex: 1; }

.dl { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--space-3); }
.dl .cell { background: var(--surface-sunken); border: 1px solid var(--border-soft); border-radius: var(--radius-sm); padding: var(--space-3); }
.dl .cell span { display: block; font-size: var(--text-2xs); font-weight: var(--weight-bold); color: var(--ink-subtle); letter-spacing: var(--tracking-label); }
.dl .cell b { display: block; font-size: var(--text-sm); font-weight: var(--weight-semi); margin-block-start: var(--space-1); unicode-bidi: isolate; }

.sec-label { font-size: var(--text-2xs); font-weight: var(--weight-bold); color: var(--ink-subtle); letter-spacing: var(--tracking-label); margin-block-end: var(--space-3); }

/* ---- modal -------------------------------------------------------------- */
.modal-host { position: fixed; inset: 0; z-index: var(--z-drawer); display: grid; place-items: center; padding: var(--space-4); pointer-events: none; }
.modal {
  inline-size: min(560px, 100%); max-block-size: 86dvh; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-xl); box-shadow: var(--elev-4);
  padding: var(--space-5); pointer-events: auto;
  opacity: 0; transform: scale(.97) translateY(8px);
  transition: opacity var(--dur-base), transform var(--dur-base) var(--ease-out);
}
.modal-host.is-open .modal { opacity: 1; transform: none; }

/* ---- toast -------------------------------------------------------------- */
/* Stacks above the copilot FAB on the content side — inline-start would put it
   on top of the rail in RTL, which is where it lands if you forget the rail. */
.toast-host {
  position: fixed; inset-block-end: calc(var(--space-5) + 56px); inset-inline-end: var(--space-5);
  z-index: var(--z-toast); display: flex; flex-direction: column; gap: var(--space-2);
  pointer-events: none;
}
.toast {
  display: flex; align-items: flex-start; gap: var(--space-3);
  min-inline-size: 260px; max-inline-size: min(400px, 92vw);
  padding: var(--space-3) var(--space-4);
  background: var(--surface-raised); border: 1px solid var(--border);
  border-radius: var(--radius-md); box-shadow: var(--elev-3);
  font-size: var(--text-sm); pointer-events: auto;
  animation: toast-in var(--dur-base) var(--ease-out);
}
.toast.is-leaving { animation: toast-out var(--dur-base) var(--ease-in-out) forwards; }
.toast .dot { inline-size: 8px; block-size: 8px; border-radius: 50%; flex: none; margin-block-start: 6px; background: var(--accent); }
.toast.ok .dot { background: var(--success); }
.toast.warn .dot { background: var(--warning); }
.toast.err .dot { background: var(--danger); }
.toast b { display: block; font-weight: var(--weight-semi); }
.toast small { display: block; color: var(--ink-muted); font-size: var(--text-xs); }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px) scale(.97); } to { opacity: 1; transform: none; } }
@keyframes toast-out { to { opacity: 0; transform: translateY(6px) scale(.98); } }

@media (max-width: 860px) {
  .toast-host { inset-block-end: calc(var(--space-8) + var(--space-2)); inset-inline: var(--space-3); }
  .drawer { inline-size: 100vw; }
}

/* ---- copilot ------------------------------------------------------------ */
.fab {
  position: fixed; inset-block-end: var(--space-5); inset-inline-end: var(--space-5);
  z-index: var(--z-sticky);
  display: inline-flex; align-items: center; gap: var(--space-2);
  padding: var(--space-3) var(--space-5); border-radius: var(--radius-pill);
  background: var(--accent); color: var(--ink-on-accent);
  font-size: var(--text-sm); font-weight: var(--weight-bold);
  box-shadow: var(--glow-accent), var(--elev-3);
  transition: transform var(--dur-fast), box-shadow var(--dur-fast);
}
.fab:hover { transform: translateY(-2px); }
@media (max-width: 860px) { .fab { inset-block-end: calc(var(--space-8) + var(--space-2)); padding: var(--space-3); } .fab span { display: none; } }

.chat { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: var(--space-3); }
.msg { max-inline-size: 88%; padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); font-size: var(--text-sm); line-height: var(--leading-body); }
.msg.me { align-self: flex-end; background: var(--accent); color: var(--ink-on-accent); font-weight: var(--weight-medium); border-end-end-radius: var(--radius-xs); }
.msg.ai { align-self: flex-start; background: var(--surface-sunken); border: 1px solid var(--border-soft); border-end-start-radius: var(--radius-xs); }
.msg.ai strong { color: var(--accent-ink); }
.msg.typing { display: flex; gap: 4px; align-items: center; }
.msg.typing i { inline-size: 6px; block-size: 6px; border-radius: 50%; background: var(--accent); animation: blip 1.1s infinite; }
.msg.typing i:nth-child(2) { animation-delay: .18s; }
.msg.typing i:nth-child(3) { animation-delay: .36s; }
@keyframes blip { 0%, 100% { opacity: .25; transform: scale(.8); } 50% { opacity: 1; transform: scale(1.1); } }

.composer { display: flex; gap: var(--space-2); padding-block-start: var(--space-3); border-block-start: 1px solid var(--border-soft); }

/* ============================================================================
   components/flow.css — kanban · wizard · timeline · catalog card
   The pieces that give the non-table archetypes their silhouette.
   ==========================================================================*/

/* ---- kanban ------------------------------------------------------------- */
.board {
  display: grid; gap: var(--space-4);
  grid-auto-flow: column; grid-auto-columns: minmax(276px, 1fr);
  overflow-x: auto; padding-block-end: var(--space-3);
  overscroll-behavior-x: contain;
}
.col {
  display: flex; flex-direction: column; min-block-size: 0;
  background: var(--surface-sunken); border: 1px solid var(--border-soft);
  border-radius: var(--radius-lg);
}
.col-head {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-block-end: 1px solid var(--border-soft);
  font-size: var(--text-sm); font-weight: var(--weight-semi);
}
.col-head .dot { inline-size: 8px; block-size: 8px; border-radius: 50%; background: var(--accent); flex: none; }
.col-head .count { margin-inline-start: auto; font-size: var(--text-2xs); font-weight: var(--weight-bold); color: var(--ink-subtle); background: var(--neutral-soft); padding: 1px var(--space-2); border-radius: var(--radius-pill); }
.col-body { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-3); overflow-y: auto; flex: 1; min-block-size: 120px; }

.tile {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-md); padding: var(--space-3) var(--space-4);
  box-shadow: var(--elev-1); text-align: start; inline-size: 100%;
  transition: transform var(--dur-fast), box-shadow var(--dur-fast), border-color var(--dur-fast);
}
.tile:hover { transform: translateY(-2px); box-shadow: var(--elev-3); border-color: var(--border-strong); }
.tile .th { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-2); }
.tile .th b { font-size: var(--text-sm); font-weight: var(--weight-semi); }
.tile .sub { font-size: var(--text-2xs); color: var(--ink-subtle); margin-block-start: 2px; unicode-bidi: isolate; }
.tile .tf { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); margin-block-start: var(--space-3); padding-block-start: var(--space-3); border-block-start: 1px solid var(--border-soft); }
.tile .amt { font-family: var(--font-num); font-variant-numeric: tabular-nums; font-weight: var(--weight-bold); font-size: var(--text-sm); unicode-bidi: isolate; }
.tile.is-moving { opacity: .5; }
/* An SLA-breached card must be visible from across the room. */
.tile.is-urgent { border-inline-start: 3px solid var(--danger); }

/* ---- wizard ------------------------------------------------------------- */
.steps { display: flex; align-items: center; gap: var(--space-2); margin-block-end: var(--space-6); flex-wrap: wrap; }
.step { display: flex; align-items: center; gap: var(--space-3); }
.step .bullet {
  inline-size: 30px; block-size: 30px; flex: none; border-radius: 50%;
  display: grid; place-items: center;
  font-size: var(--text-xs); font-weight: var(--weight-bold);
  background: var(--neutral-soft); color: var(--ink-subtle);
  border: 1px solid var(--border);
  transition: all var(--dur-base);
}
.step .name { font-size: var(--text-sm); color: var(--ink-subtle); font-weight: var(--weight-medium); }
.step[data-state="active"] .bullet { background: var(--accent); color: var(--ink-on-accent); border-color: var(--accent); box-shadow: var(--glow-accent); }
.step[data-state="active"] .name { color: var(--ink); font-weight: var(--weight-semi); }
.step[data-state="done"] .bullet { background: var(--success-soft); color: var(--success); border-color: color-mix(in oklab, var(--success) 40%, transparent); }
.step[data-state="done"] .name { color: var(--ink-muted); }
.step-link { inline-size: 28px; block-size: 1px; background: var(--border); }
@media (max-width: 700px) { .step .name { display: none; } .step-link { inline-size: 16px; } }

.wizard-panel { display: none; }
.wizard-panel.is-active { display: block; animation: screen-in var(--dur-base) var(--ease-out); }
.wizard-nav { display: flex; gap: var(--space-2); justify-content: space-between; margin-block-start: var(--space-6); padding-block-start: var(--space-4); border-block-start: 1px solid var(--border-soft); }

.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--space-4); }
.form-grid .span-2 { grid-column: 1 / -1; }

/* Radio cards — a real product asks you to pick a plan like this, not with
   a bare <select>. */
.pick { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--space-3); }
.pick label {
  display: block; padding: var(--space-4); cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-md);
  transition: all var(--dur-fast);
}
.pick label:hover { border-color: var(--border-strong); }
.pick input { position: absolute; opacity: 0; pointer-events: none; }
.pick input:checked + .pk { color: var(--accent-ink); }
.pick label:has(input:checked) { border-color: var(--accent); background: var(--surface-accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.pick label:has(input:focus-visible) { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
.pick .pk b { display: block; font-size: var(--text-sm); font-weight: var(--weight-semi); }
.pick .pk small { display: block; color: var(--ink-muted); font-size: var(--text-xs); margin-block-start: var(--space-1); }

/* ---- timeline ----------------------------------------------------------
   The spine sits on the inline-start edge, so it mirrors with direction.
   ------------------------------------------------------------------------ */
.timeline { position: relative; padding-inline-start: var(--space-6); }
.timeline::before {
  content: ""; position: absolute; inset-inline-start: 9px; inset-block: 6px 6px;
  inline-size: 2px; background: var(--border);
}
.tl-item { position: relative; padding-block-end: var(--space-5); }
.tl-item:last-child { padding-block-end: 0; }
.tl-item::before {
  content: ""; position: absolute; inset-inline-start: calc(-1 * var(--space-6) + 4px); inset-block-start: 5px;
  inline-size: 12px; block-size: 12px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--border-strong);
}
.tl-item[data-state="done"]::before { background: var(--success); border-color: var(--success); }
.tl-item[data-state="active"]::before { background: var(--accent); border-color: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.tl-item b { display: block; font-size: var(--text-sm); font-weight: var(--weight-semi); }
.tl-item p { font-size: var(--text-xs); color: var(--ink-muted); margin-block-start: 2px; }
.tl-item time { display: block; font-size: var(--text-2xs); color: var(--ink-subtle); margin-block-start: var(--space-1); font-family: var(--font-num); unicode-bidi: isolate; }

/* ---- catalog card (marketplace) ----------------------------------------- */
.catalog { display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fill, minmax(268px, 1fr)); }
.listing {
  display: flex; flex-direction: column; overflow: hidden; text-align: start;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--elev-1);
  transition: transform var(--dur-base) var(--ease-out), box-shadow var(--dur-base), border-color var(--dur-base);
}
.listing:hover { transform: translateY(-3px); box-shadow: var(--elev-3); border-color: var(--accent-border); }
.listing .thumb {
  aspect-ratio: 16 / 10; position: relative;
  background:
    radial-gradient(120% 90% at 20% 0%, color-mix(in oklab, var(--accent) 34%, transparent), transparent 60%),
    linear-gradient(140deg, var(--surface-raised), var(--surface-sunken));
  display: grid; place-items: center;
}
.listing .thumb .mono { font-size: 2rem; font-weight: var(--weight-bold); color: color-mix(in oklab, var(--accent) 60%, var(--ink)); opacity: .65; letter-spacing: var(--tracking-display); }
.listing .thumb .tag { position: absolute; inset-block-start: var(--space-3); inset-inline-start: var(--space-3); }
.listing .body { padding: var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
.listing .body b { font-size: var(--text-sm); font-weight: var(--weight-semi); }
.listing .body .sub { font-size: var(--text-xs); color: var(--ink-muted); }
.listing .body .row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-2); margin-block-start: auto; padding-block-start: var(--space-3); border-block-start: 1px solid var(--border-soft); }
.listing .price { font-family: var(--font-num); font-variant-numeric: tabular-nums; font-weight: var(--weight-bold); font-size: var(--text-md); unicode-bidi: isolate; }
.listing .price small { font-size: var(--text-2xs); color: var(--ink-muted); font-weight: var(--weight-medium); margin-inline-start: 2px; }

/* hero3d — the box is sized and coloured before any JS runs, so the WebGL
   layer fading in on top causes exactly zero layout shift. */
.hero3d {
  position: relative; overflow: hidden;
  block-size: clamp(200px, 34vh, 340px);
  border-radius: var(--radius-xl);
  margin-block-end: var(--space-5);
  border: 1px solid var(--border);
  isolation: isolate;
}
.hero3d-fallback {
  position: absolute; inset: 0; z-index: 0;
  background:
    radial-gradient(120% 130% at 82% -10%, color-mix(in oklab, var(--accent) 62%, transparent), transparent 60%),
    radial-gradient(90% 120% at 8% 110%, color-mix(in oklab, var(--info) 40%, transparent), transparent 58%),
    linear-gradient(135deg, color-mix(in oklab, var(--accent) 22%, var(--canvas)), var(--surface-sunken));
}
.hero3d-canvas { position: absolute; inset: 0; z-index: 1; inline-size: 100%; block-size: 100%; animation: hero-fade 600ms var(--ease-out); }
@keyframes hero-fade { from { opacity: 0; } to { opacity: 1; } }

.hero3d-copy {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; justify-content: flex-end;
  block-size: 100%; padding: var(--space-6);
  /* Scrim under the text: a shader can drift bright and the headline must
     stay readable in every frame, not just the ones in the screenshot. */
  background: linear-gradient(to top, color-mix(in oklab, var(--canvas) 78%, transparent), transparent 62%);
}
.hero3d-copy h2 { font-size: var(--text-2xl); font-weight: var(--weight-bold); letter-spacing: var(--tracking-display); line-height: var(--leading-tight); color: #fff; text-shadow: 0 2px 20px rgba(0,0,0,.4); }
.hero3d-copy p { color: rgba(255,255,255,.86); font-size: var(--text-base); margin-block-start: var(--space-2); max-inline-size: 54ch; text-shadow: 0 1px 12px rgba(0,0,0,.4); }

@media (prefers-reduced-motion: reduce) { .hero3d-canvas { display: none; } }

/* ops-console — dense command centre. Data runs edge to edge, chrome is thin,
   density is high. Reads as a system an operator lives in all day.
   Silhouette: full-width rail + a table that fills the viewport, detail in a drawer. */

[data-archetype="ops-console"] {
  --radius-base: 10px;
  --topbar-h: 54px;
}
[data-archetype="ops-console"] .screens {
  padding: var(--space-4);
  max-inline-size: none;           /* edge to edge — no reading column here */
}
[data-archetype="ops-console"] .screen-head { margin-block-end: var(--space-4); }
[data-archetype="ops-console"] .screen-head h2 { font-size: var(--text-lg); }

/* The table owns the screen: it gets its own scroll box sized to the viewport
   so the header stays pinned and the page itself never scrolls. */
[data-archetype="ops-console"] .console-table { display: flex; flex-direction: column; max-block-size: calc(100dvh - var(--topbar-h) - 190px); }
[data-archetype="ops-console"] .console-table .table-wrap { overflow: auto; flex: 1; }
[data-archetype="ops-console"] .table tbody td { padding-block: var(--space-2); }
[data-archetype="ops-console"] .table { font-size: var(--text-xs); }
[data-archetype="ops-console"] .cell-lead .avatar { inline-size: 28px; block-size: 28px; }

/* Status strip above the table — the "what needs me now" line. */
[data-archetype="ops-console"] .statline {
  display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap;
  padding: var(--space-3) var(--space-4); margin-block-end: var(--space-4);
  background: var(--surface); border: 1px solid var(--border);
  border-inline-start: 3px solid var(--accent);
  border-radius: var(--radius-md); font-size: var(--text-xs);
}
[data-archetype="ops-console"] .statline .item { display: flex; align-items: center; gap: var(--space-2); color: var(--ink-muted); }
[data-archetype="ops-console"] .statline .item b { color: var(--ink); font-family: var(--font-num); font-variant-numeric: tabular-nums; }
[data-archetype="ops-console"] .kpi { padding: var(--space-3) var(--space-4); }
[data-archetype="ops-console"] .kpi .value { font-size: 1.5rem; }

@media (max-width: 860px) {
  [data-archetype="ops-console"] .console-table { max-block-size: none; }
}

:root{--accent:#0F766E;--radius-base:12px;}
