/**
 * sonaloop-design — shared component layer.
 *
 * One CSS file, applied to each stack's OWN markup, so React (website) and the
 * Python-SSR app render identical components without sharing component code:
 *   React:  <button className="sl-btn sl-btn--primary">
 *   Python: h("button", {"class_": "sl-btn sl-btn--primary"}, …)
 *
 * Driven by the canonical --sl-* tokens (emitted into both styles/tokens.css and
 * py/sonaloop_icons/tokens.py), so the components are theme-aware (light / dark) and
 * never drift. Sizing is **em-based**, so the SAME class adapts to each surface's base
 * font-size — dense in the 13px Python-SSR app, airy on the 16px website. Hand-authored.
 * Class prefix `sl-` avoids clashing with either app.
 *
 * SPACING CONTRACT (docs: "Spacing & density" Foundations page; tokens.data.mjs `scales`):
 * px spacing in this file sits on the 4px grid via tokens — --sl-s-1…--sl-s-8 (raw steps),
 * the semantic gaps --sl-gap-tight/item/group/section/region, the row heights
 * --sl-row-dense (32) / --sl-row (40) / --sl-row-h (48, chrome) and --sl-ctl-sm (28).
 * Allowed literals: 1–3px optical hairlines/micro-nudges, chart + calendar-grid geometry
 * (data fidelity, not rhythm), and layout column widths. The em/rem-sized rules (buttons,
 * inputs, cards, ⌘K) are the density-adaptive layer and stay off the px grid on purpose.
 */

/* ── Buttons ─────────────────────────────────────────────────────────────────── */
.sl-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5em;
  font: inherit; font-weight: 550; line-height: 1; white-space: nowrap; cursor: pointer;
  padding: .55em .95em; border-radius: var(--sl-radius-sm); border: 1px solid transparent;
  background: var(--sl-surface); color: var(--sl-ink); border-color: var(--sl-line);
  transition: background .12s, border-color .12s, opacity .12s, filter .12s;
}
.sl-btn:hover { background: var(--sl-hover); }
.sl-btn:focus-visible { outline: none; box-shadow: 0 0 0 2px color-mix(in srgb, var(--sl-accent) 45%, transparent); }
.sl-btn--primary { background: var(--sl-ink); color: var(--sl-bg); border-color: transparent; }
.sl-btn--primary:hover { background: var(--sl-ink); opacity: .88; }
.sl-btn--accent { background: var(--sl-accent); color: var(--sl-accent-ink); border-color: transparent; }
.sl-btn--accent:hover { filter: brightness(1.06); background: var(--sl-accent); opacity: 1; }
.sl-btn--ghost { background: transparent; border-color: transparent; }
.sl-btn--ghost:hover { background: var(--sl-hover); }
.sl-btn--sm { padding: .35em .7em; font-size: .92em; }
.sl-btn--lg { padding: .85em 1.7em; border-radius: var(--sl-radius); }
.sl-btn.is-active { background: var(--sl-sel); border-color: var(--sl-line); }
.sl-btn[disabled], .sl-btn.is-disabled { color: var(--sl-faint); cursor: default; opacity: .65; }
.sl-btn[disabled]:hover, .sl-btn.is-disabled:hover { background: var(--sl-surface); }

/* ── Card ────────────────────────────────────────────────────────────────────── */
.sl-card {
  background: var(--sl-surface); border: 1px solid var(--sl-line);
  border-radius: var(--sl-radius); padding: 1.05em;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--sl-ink) 4%, transparent);
}
.sl-card__title { margin: 0 0 .4em; font-weight: 600; color: var(--sl-ink); }
.sl-card__body { margin: 0; color: var(--sl-muted); line-height: 1.5; }

/* ── Eyebrow (mono label) ────────────────────────────────────────────────────── */
.sl-eyebrow {
  font-family: var(--sl-mono); font-size: .72em; font-weight: 500;
  text-transform: uppercase; letter-spacing: .14em; color: var(--sl-muted);
}

/* ── Badge / Pill / Chip ─────────────────────────────────────────────────────── */
.sl-badge {
  display: inline-flex; align-items: center; gap: .35em;
  padding: .15em .6em; border-radius: var(--sl-radius-full); font-size: .82em; font-weight: 550;
  background: var(--sl-surface-2); color: var(--sl-muted);
}
.sl-badge--accent { background: var(--sl-accent-weak); color: var(--sl-accent); }
.sl-badge--positive { background: color-mix(in srgb, var(--sl-green) 14%, transparent); color: var(--sl-green); }
.sl-badge--warning { background: color-mix(in srgb, var(--sl-amber) 16%, transparent); color: var(--sl-amber); }
.sl-badge--negative { background: color-mix(in srgb, var(--sl-red) 14%, transparent); color: var(--sl-red); }
.sl-badge__dot { width: .5em; height: .5em; border-radius: var(--sl-radius-full); background: currentColor; flex-shrink: 0; opacity: .85; }
.sl-badge--square { border-radius: var(--sl-radius-sm); }   /* a soft rectangular chip rather than a pill */
.sl-pill { display: inline-flex; align-items: center; gap: .45em; padding: .2em .8em;
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius-full); font-size: .9em; color: var(--sl-ink);
  background: var(--sl-surface); }
.sl-chip { display: inline-flex; align-items: center; gap: .45em; padding: .2em .65em;
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius-sm); font-size: .85em;
  color: var(--sl-muted); background: var(--sl-surface); }
.sl-chip::before { content: ""; width: .5em; height: .5em; border-radius: 50%; background: var(--sl-accent); }
/* Tag — a bordered, uppercase mono label (distinct from the filled .sl-badge). Tone tints the
   border + fill; used for verdict tags, plan tiers, blog categories, …. */
.sl-tag {
  display: inline-flex; align-items: center; gap: .35em;
  font-family: var(--sl-mono); font-size: .72em; font-weight: 500;
  text-transform: uppercase; letter-spacing: .14em; padding: .25em .7em;
  border-radius: var(--sl-radius-sm);
  border: 1px solid color-mix(in srgb, var(--sl-accent) 38%, transparent);
  background: color-mix(in srgb, var(--sl-accent) 9%, transparent); color: var(--sl-accent);
}
.sl-tag--neutral { border-color: var(--sl-line); background: var(--sl-surface-2); color: var(--sl-muted); }
.sl-tag--warm { border-color: color-mix(in srgb, var(--sl-violet) 40%, transparent);
  background: color-mix(in srgb, var(--sl-violet) 10%, transparent); color: var(--sl-ink); }

/* ── Input ───────────────────────────────────────────────────────────────────── */
.sl-input {
  font: inherit; width: 100%; padding: .55em .8em; color: var(--sl-ink);
  background: var(--sl-bg); border: 1px solid var(--sl-line); border-radius: var(--sl-radius-sm);
}
.sl-input::placeholder { color: var(--sl-faint); }
.sl-input:hover { border-color: color-mix(in srgb, var(--sl-ink) 18%, var(--sl-line)); }
.sl-input:focus, .sl-input:focus-visible { outline: none; border-color: var(--sl-accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--sl-accent) 25%, transparent); }

/* ── kbd + divider ───────────────────────────────────────────────────────────── */
.sl-kbd { font-family: var(--sl-mono); font-size: .8em; padding: .05em .45em;
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius-sm); background: var(--sl-surface-2); color: var(--sl-ink); }
.sl-divider { height: 1px; border: 0; background: var(--sl-line); margin: 1.1em 0; }

/* ── Arrow-link — a mono uppercase "more →" link whose gap widens on hover. Apply to the
   app's own <a>/<Link>; works on self-hover or inside a Tailwind `group`. ──────────────── */
.sl-arrow-link {
  display: inline-flex; align-items: center; gap: .55em;
  font-family: var(--sl-mono); font-size: .82em; font-weight: 500;
  text-transform: uppercase; letter-spacing: .04em; color: var(--sl-accent);
  text-decoration: none; transition: gap .15s ease;
}
.sl-arrow-link:hover, .group:hover .sl-arrow-link { gap: .85em; }

/* ── Logo — the brand lockup: the loop mark + the "sonaloop" wordmark, where "sona" is set in
   Sona Mono and the trailing "loop" in Sona Pixel (the bitmap accent whose cells echo the loop
   mark). The single source of truth for the logo across stacks — React (website nav/footer) and
   the Python-SSR app (sidebar) apply these classes to their OWN link, so it never drifts. The
   mark is monochrome (--sl-ink) and sits on the baseline like a glyph; the whole lockup is
   static (no hover/animation). Em-based — mark + wordmark track the host font-size.
   Markup: a 24×24 SonaloopIcon SVG in `.sl-logo__mark`, and the wordmark with its final "loop"
   wrapped in `.sl-logo__loop`. The host must load the Sona Mono + Sona Pixel faces
   (styles/fonts.css). Use --sm / --lg to nudge the mark. Product apps append a `.sl-logo__sub`
   (a muted, lowercase product label — "design", "data", "tracker"); the core + marketing site
   keep the bare lockup. ──────────────────────────────────────────────────────────────────── */
.sl-logo {
  display: inline-flex; align-items: baseline; gap: .16em;
  color: var(--sl-ink); text-decoration: none; white-space: nowrap;
}
.sl-logo__mark {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  align-self: baseline; color: var(--sl-ink);
}
/* Two-class specificity so the mark size wins over a host `svg.ic` rule (the Python app). The
   translate compensates for the empty space below the loop in its 24×24 box, so the mark rests
   on the baseline rather than floating; em-based, so it tracks the lockup size. */
.sl-logo .sl-logo__mark svg { width: 1.08em; height: 1.08em; overflow: visible; transform: translateY(.27em); }
.sl-logo__word {
  display: inline-flex; align-items: baseline;
  font-family: var(--sl-mono); font-weight: 500; line-height: 1;
  letter-spacing: .01em; text-transform: lowercase;
}
.sl-logo__loop { font-family: var(--sl-pixel); font-size: 1.05em; letter-spacing: 0; text-transform: none; margin-left: .04em; }
/* Product sub-label — a muted lowercase mono suffix beside the wordmark ("design", "data",
   "tracker"). A sibling of the wordmark; the .sl-logo gap plus a small margin give it a touch
   more breathing room than the mark↔wordmark gap. `text-transform: lowercase` normalises
   whatever case the host passes. */
.sl-logo__sub { align-self: baseline; margin-left: .2em; font-family: var(--sl-mono); font-weight: 500;
  letter-spacing: .01em; text-transform: lowercase; color: var(--sl-muted); }
.sl-logo--sm .sl-logo__mark svg { width: .92em; height: .92em; transform: translateY(.23em); }
.sl-logo--lg .sl-logo__mark svg { width: 1.4em; height: 1.4em; transform: translateY(.35em); }

/* ── Status dot — a small coloured presence/verdict dot ──────────────────────────── */
.sl-dot { display: inline-block; width: .62em; height: .62em; border-radius: 50%; flex: none;
  background: var(--sl-muted); }
.sl-dot--accent { background: var(--sl-accent); }
.sl-dot--positive { background: var(--sl-green); }
.sl-dot--warning { background: var(--sl-amber); }
.sl-dot--negative { background: var(--sl-red); }
.sl-dot--info { background: var(--sl-blue); }
.sl-dot--shift { background: var(--sl-violet); }

/* ── Avatar (+ overlapping group) ────────────────────────────────────────────────── */
.sl-avatar {
  display: inline-flex; align-items: center; justify-content: center; flex: none; overflow: hidden;
  width: 2.4em; height: 2.4em; border-radius: 50%; border: 1px solid var(--sl-line);
  font-weight: 600; font-size: .85em; line-height: 1; color: #fff; background: var(--sl-accent);
  object-fit: cover; /* when the element itself is an <img> portrait */
}
.sl-avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sl-avatar--sm { width: 1.7em; height: 1.7em; font-size: .72em; }
.sl-avatar--lg { width: 3.6em; height: 3.6em; font-size: 1.1em; }
.sl-avatar--blue { background: var(--sl-blue); }
.sl-avatar--violet { background: var(--sl-violet); }
.sl-avatar--green { background: var(--sl-green); }
.sl-avatar--amber { background: var(--sl-amber); }
.sl-avatar-group { display: inline-flex; }
.sl-avatar-group .sl-avatar { margin-left: -.5em; box-shadow: 0 0 0 2px var(--sl-bg); }
.sl-avatar-group .sl-avatar:first-child { margin-left: 0; }

/* ── Segmented control / Tabs (horizontal · --fill stretches · --stacked icon-over-label) ── */
.sl-segmented { display: inline-flex; gap: .15em; padding: .2em; border-radius: var(--sl-radius-sm);
  border: 1px solid var(--sl-line); background: var(--sl-surface-2); }
.sl-segmented--fill { display: flex; }
.sl-segmented__item {
  display: inline-flex; align-items: center; justify-content: center; gap: .4em;
  border: 0; border-radius: calc(var(--sl-radius-sm) - 1px); background: transparent;
  color: var(--sl-muted); font: inherit; font-weight: 550; line-height: 1; padding: .4em .85em;
  cursor: pointer; text-decoration: none; transition: background .12s, color .12s;
}
.sl-segmented--fill .sl-segmented__item { flex: 1; }
.sl-segmented--stacked .sl-segmented__item { flex-direction: column; gap: .3em; padding: .55em .4em; font-size: .92em; }
.sl-segmented__item:hover { color: var(--sl-ink); }
.sl-segmented__item.is-active { background: var(--sl-surface); color: var(--sl-ink);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--sl-ink) 12%, transparent); }
.sl-segmented__item.is-active :where(svg) { color: var(--sl-accent); }

/* ── Copy button + Snippet (inline command) + Code block ─────────────────────────── */
.sl-copy { display: inline-flex; align-items: center; gap: .4em; border: 1px solid var(--sl-line);
  background: var(--sl-bg); color: var(--sl-muted); border-radius: var(--sl-radius-sm);
  padding: .3em .6em; font: inherit; font-size: .8em; cursor: pointer; transition: color .12s, border-color .12s; }
.sl-copy:hover { color: var(--sl-ink); border-color: color-mix(in srgb, var(--sl-ink) 22%, var(--sl-line)); }
.sl-copy svg { width: 1.05em; height: 1.05em; }
/* Copy confirmation — the clipboard glyph swaps to a green check while `is-copied` is set.
   The visual lives here so the website, inspector and docs all confirm identically; each
   consumer's own JS just adds `.is-copied` for ~1.6s after writing to the clipboard (and a
   single-icon legacy button still turns green as a fallback). */
.sl-copy__check { display: none; }
.sl-copy.is-copied { color: var(--sl-green); border-color: color-mix(in srgb, var(--sl-green) 42%, var(--sl-line)); }
.sl-copy.is-copied .sl-copy__ico { display: none; }
.sl-copy.is-copied .sl-copy__check { display: inline; }
.sl-snippet { display: flex; align-items: center; gap: .75em; border: 1px solid var(--sl-line);
  border-radius: var(--sl-radius-sm); background: var(--sl-surface); padding: .5em .55em .5em .9em; }
.sl-snippet__code { flex: 1; min-width: 0; overflow-x: auto; white-space: pre; font-family: var(--sl-mono);
  font-size: .9em; color: var(--sl-ink); }
.sl-snippet--cmd .sl-snippet__code::before { content: "$ "; color: var(--sl-faint); }
.sl-code { border: 1px solid var(--sl-line); border-radius: var(--sl-radius); background: var(--sl-surface); overflow: hidden; }
.sl-code__head { display: flex; align-items: center; gap: .5em; padding: .45em .5em .45em .9em; border-bottom: 1px solid var(--sl-line); }
.sl-code__lang { flex: 1; font-family: var(--sl-mono); font-size: .72em; text-transform: uppercase; letter-spacing: .1em; color: var(--sl-faint); }
.sl-code pre { margin: 0; padding: 1em; overflow-x: auto; }
.sl-code code { font-family: var(--sl-mono); font-size: .85em; line-height: 1.6; color: var(--sl-ink); white-space: pre; }

/* ── Note / Callout (accent-tinted info block; tones) ────────────────────────────── */
.sl-note { display: flex; gap: .8em; padding: .8em 1em; border: 1px solid var(--sl-line);
  border-left: 3px solid var(--sl-accent); border-radius: var(--sl-radius-sm);
  background: var(--sl-surface); color: var(--sl-muted); line-height: 1.55; }
.sl-note__icon { flex: none; line-height: 0; margin-top: .1em; color: var(--sl-accent); }
.sl-note__body { margin: 0; min-width: 0; }
.sl-note__body b, .sl-note__body strong { color: var(--sl-ink); font-weight: 600; }
.sl-note--positive { border-left-color: var(--sl-green); } .sl-note--positive .sl-note__icon { color: var(--sl-green); }
.sl-note--warning { border-left-color: var(--sl-amber); } .sl-note--warning .sl-note__icon { color: var(--sl-amber); }
.sl-note--negative { border-left-color: var(--sl-red); } .sl-note--negative .sl-note__icon { color: var(--sl-red); }

/* ── Empty state (centred card with a hi-fi glyph) ─────────────────────────────────
   The base card is the FIRST-USE state ("nothing here yet" — inviting, with a primary
   CTA in __actions). Two sibling variants cover the other empty moments: --no-results
   (a search/filter matched nothing — a quieter dashed frame on the page background;
   pair with a "Clear search" action) and --error (something failed — the glyph and
   frame tint negative; pair with a Retry action). --sm is the compact density for
   panels, drawers and table bodies. All additive — existing .sl-empty markup keeps
   rendering exactly as before. */
.sl-empty { display: flex; flex-direction: column; align-items: center; gap: .6em; text-align: center;
  max-width: 26em; padding: 2.3em 2em; border: 1px solid var(--sl-line); border-radius: var(--sl-radius);
  background: var(--sl-surface); }
.sl-empty__icon { color: var(--sl-muted); line-height: 0; }
.sl-empty__title { margin: 0; font-size: 1.15em; font-weight: 600; color: var(--sl-ink); }
.sl-empty__body { margin: 0; max-width: 24em; color: var(--sl-muted); line-height: 1.55; }
/* CTA slot — a Button (first-use), a quiet text action (no-results), a Retry (error). */
.sl-empty__actions { display: flex; align-items: center; justify-content: center; gap: .6em; margin-top: .4em; }
/* no-results — the search context: calmer, recedes onto the page background */
.sl-empty--no-results { border-style: dashed; background: transparent; }
.sl-empty--no-results .sl-empty__icon { color: var(--sl-faint); }
/* error — the retry moment: glyph + frame tinted negative */
.sl-empty--error { border-color: color-mix(in srgb, var(--sl-red) 32%, var(--sl-line)); }
.sl-empty--error .sl-empty__icon { color: var(--sl-red); }
/* sm — compact (panels, drawers, table bodies); the glyph scales down with it */
.sl-empty--sm { padding: 1.4em 1.3em; gap: .45em; max-width: 22em; }
.sl-empty--sm .sl-empty__title { font-size: 1em; }
.sl-empty--sm .sl-empty__body { font-size: .9em; }
.sl-empty--sm .sl-empty__icon svg { width: 2.2em; height: 2.2em; }

/* ── Breadcrumb ──────────────────────────────────────────────────────────────────── */
.sl-breadcrumb { display: flex; align-items: center; gap: .5em; min-width: 0; overflow: hidden; font-size: .9em; }
.sl-breadcrumb__link { color: var(--sl-muted); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sl-breadcrumb__link:hover { color: var(--sl-ink); }
.sl-breadcrumb__current { color: var(--sl-ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The separator GLYPH lives once here, not in each consumer's markup — so the breadcrumb can
   never diverge (app vs website vs docs). Consumers emit an empty <span class="sl-breadcrumb__sep">. */
.sl-breadcrumb__sep { flex: none; color: var(--sl-faint); user-select: none; }
.sl-breadcrumb__sep::after { content: "\203A"; }

/* ── Table ───────────────────────────────────────────────────────────────────────── */
.sl-table { width: 100%; border-collapse: collapse; font-size: .95em; line-height: 1.45; }
.sl-table th, .sl-table td { text-align: left; padding: .6em .8em; border-bottom: 1px solid var(--sl-line); vertical-align: top; }
.sl-table thead th { font-size: .8em; font-weight: 650; text-transform: uppercase; letter-spacing: .04em; color: var(--sl-muted); }
.sl-table td { color: var(--sl-muted); }
.sl-table td:first-child { color: var(--sl-ink); }
.sl-table tbody tr:hover td { background: var(--sl-hover); }
.sl-table--bordered th, .sl-table--bordered td { border: 1px solid var(--sl-line); }
.sl-table--bordered thead th { background: var(--sl-surface-2); }
.sl-table--zebra tbody tr:nth-child(even) td { background: var(--sl-surface-2); }
.sl-table--zebra tbody tr:hover td { background: var(--sl-hover); }

/* ── Progress bar ────────────────────────────────────────────────────────────────── */
.sl-progress { height: .5em; border-radius: var(--sl-radius-full); background: var(--sl-surface-2); overflow: hidden; }
.sl-progress__bar { height: 100%; border-radius: var(--sl-radius-full); background: var(--sl-accent); transition: width .3s var(--sl-ease, ease); }

/* ── Stepper (numbered / checked progress steps) ───────────────────────────────────
   The multi-stage flow indicator (onboarding, council setup, any wizard) — Progress's
   discrete sibling: numbered circular markers joined by hairline connectors, ticking
   off with a check as steps complete. States are classes the host derives from its
   current index — `.is-done` (✓, accent fill) and `.is-current` (accent ring) on a
   step; unmarked steps read as upcoming. Markup: an <ol class="sl-stepper"> of
   <li class="sl-stepper__step"> rows, each a __marker (the step number, or a check
   SVG when done) plus an optional __text (__label over a quiet __desc) — labels can
   be omitted for a marker-only rail. `--vertical` is the compact stacked variant
   (the connector drops below each marker). Em-based: dense in the 13px app, airy on
   the 16px website. */
.sl-stepper { display: flex; align-items: flex-start; margin: 0; padding: 0; list-style: none; }
.sl-stepper__step { display: flex; align-items: center; gap: .55em; min-width: 0; color: var(--sl-muted); }
.sl-stepper__step:not(:last-child) { flex: 1; }
/* the connector — a flexible hairline running to the next step; done segments tint accent */
.sl-stepper__step:not(:last-child)::after { content: ""; flex: 1; height: 1px; min-width: 1.2em;
  background: var(--sl-line); margin: 0 .75em; }
.sl-stepper__step.is-done:not(:last-child)::after { background: color-mix(in srgb, var(--sl-accent) 55%, var(--sl-line)); }
.sl-stepper__marker { display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 1.7em; height: 1.7em; border-radius: 50%; border: 1px solid var(--sl-line);
  background: var(--sl-surface); color: var(--sl-muted); font-size: .85em; font-weight: 600;
  font-variant-numeric: tabular-nums; line-height: 1;
  transition: background .12s, border-color .12s, color .12s, box-shadow .12s; }
.sl-stepper__marker svg { width: .95em; height: .95em; }
.sl-stepper__step.is-current { color: var(--sl-ink); }
.sl-stepper__step.is-current .sl-stepper__marker { border-color: var(--sl-accent); color: var(--sl-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--sl-accent) 18%, transparent); }
.sl-stepper__step.is-done { color: var(--sl-ink); }
.sl-stepper__step.is-done .sl-stepper__marker { background: var(--sl-accent); border-color: var(--sl-accent);
  color: var(--sl-accent-ink); }
.sl-stepper__text { display: flex; flex-direction: column; gap: .1em; min-width: 0; }
.sl-stepper__label { font-weight: 550; font-size: .92em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sl-stepper__step.is-current .sl-stepper__label { font-weight: 600; }
.sl-stepper__desc { font-size: .8em; color: var(--sl-faint);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Compact vertical — the connector becomes a short rail dropping below each marker. */
.sl-stepper--vertical { flex-direction: column; align-items: stretch; }
.sl-stepper--vertical .sl-stepper__step { align-items: flex-start; position: relative; }
.sl-stepper--vertical .sl-stepper__step:not(:last-child) { flex: none; padding-bottom: 1.45em; }
.sl-stepper--vertical .sl-stepper__step:not(:last-child)::after { content: none; }
.sl-stepper--vertical .sl-stepper__step:not(:last-child)::before { content: ""; position: absolute;
  left: calc(1.7em * .85 / 2); top: calc(1.7em * .85 + .25em); bottom: .25em; width: 1px;
  transform: translateX(-50%); background: var(--sl-line); }
.sl-stepper--vertical .sl-stepper__step.is-done:not(:last-child)::before {
  background: color-mix(in srgb, var(--sl-accent) 55%, var(--sl-line)); }
.sl-stepper--vertical .sl-stepper__text { padding-top: .12em; }

/* ── Stat (metric chip + strip) ──────────────────────────────────────────────────── */
.sl-stats { display: flex; flex-wrap: wrap; gap: .55em; }
.sl-stat { display: inline-flex; align-items: baseline; gap: .5em; border: 1px solid var(--sl-line);
  border-radius: var(--sl-radius-sm); background: var(--sl-surface); padding: .5em .8em; }
.sl-stat__value { font-size: 1.35em; font-weight: 700; color: var(--sl-ink); line-height: 1; }
.sl-stat__label { color: var(--sl-muted); font-size: .85em; }

/* ── Textarea ────────────────────────────────────────────────────────────────── */
.sl-textarea {
  font: inherit; width: 100%; padding: .6em .8em; color: var(--sl-ink); line-height: 1.5;
  background: var(--sl-bg); border: 1px solid var(--sl-line); border-radius: var(--sl-radius-sm);
  resize: vertical; min-height: 4.5em;
}
.sl-textarea::placeholder { color: var(--sl-faint); }
.sl-textarea:hover { border-color: color-mix(in srgb, var(--sl-ink) 18%, var(--sl-line)); }
.sl-textarea:focus, .sl-textarea:focus-visible { outline: none; border-color: var(--sl-accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--sl-accent) 25%, transparent); }

/* ── Select (styled native <select> + caret) ─────────────────────────────────── */
.sl-select { position: relative; display: inline-flex; width: 100%; }
.sl-select select {
  font: inherit; width: 100%; padding: .55em 2.2em .55em .8em; color: var(--sl-ink); cursor: pointer;
  appearance: none; -webkit-appearance: none;
  background: var(--sl-bg); border: 1px solid var(--sl-line); border-radius: var(--sl-radius-sm);
}
.sl-select::after { content: ""; position: absolute; right: .9em; top: 50%; width: .45em; height: .45em;
  border-right: 1.5px solid var(--sl-muted); border-bottom: 1.5px solid var(--sl-muted);
  transform: translateY(-65%) rotate(45deg); pointer-events: none; }
.sl-select select:hover { border-color: color-mix(in srgb, var(--sl-ink) 18%, var(--sl-line)); }
.sl-select select:focus, .sl-select select:focus-visible { outline: none; border-color: var(--sl-accent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--sl-accent) 25%, transparent); }
.sl-select select:disabled { color: var(--sl-faint); cursor: default; opacity: .7; }

/* ── Checkbox / Radio (one class, [type] picks the shape) ────────────────────────
   The label wraps the native control so the whole row is clickable; appearance is reset
   so the box/dot is token-driven and theme-aware. */
.sl-check { display: inline-flex; align-items: center; gap: .55em; cursor: pointer;
  color: var(--sl-ink); line-height: 1.4; }
.sl-check input { appearance: none; -webkit-appearance: none; flex: none; margin: 0;
  width: 1.15em; height: 1.15em; background: var(--sl-bg); border: 1px solid var(--sl-line);
  cursor: pointer; transition: background .12s, border-color .12s; }
.sl-check input[type="checkbox"] { border-radius: var(--sl-radius-sm); }
.sl-check input[type="radio"] { border-radius: 50%; }
.sl-check:hover input:not(:checked):not(:disabled) { border-color: color-mix(in srgb, var(--sl-ink) 28%, var(--sl-line)); }
.sl-check input:checked { background: var(--sl-accent); border-color: var(--sl-accent); }
.sl-check input[type="checkbox"]:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E");
  background-size: .9em; background-position: center; background-repeat: no-repeat; }
.sl-check input[type="radio"]:checked { box-shadow: inset 0 0 0 .22em var(--sl-bg); }
.sl-check input:focus-visible { outline: none;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--sl-accent) 35%, transparent); }
.sl-check input[type="radio"]:checked:focus-visible {
  box-shadow: inset 0 0 0 .22em var(--sl-bg), 0 0 0 2px color-mix(in srgb, var(--sl-accent) 35%, transparent); }
.sl-check input:disabled { opacity: .55; cursor: default; }
.sl-check:has(input:disabled) { color: var(--sl-faint); cursor: default; }

/* ── Switch (toggle) ─────────────────────────────────────────────────────────── */
.sl-switch { display: inline-flex; align-items: center; gap: .6em; cursor: pointer; color: var(--sl-ink); }
.sl-switch__input { position: absolute; opacity: 0; width: 0; height: 0; }
.sl-switch__track { position: relative; flex: none; width: 2.2em; height: 1.25em;
  border-radius: var(--sl-radius-full); background: var(--sl-surface-2); border: 1px solid var(--sl-line);
  transition: background .15s, border-color .15s; }
.sl-switch__track::after { content: ""; position: absolute; top: 50%; left: .15em; transform: translateY(-50%);
  width: .95em; height: .95em; border-radius: 50%; background: var(--sl-bg);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--sl-ink) 28%, transparent); transition: left .15s; }
.sl-switch__input:checked + .sl-switch__track { background: var(--sl-accent); border-color: var(--sl-accent); }
.sl-switch__input:checked + .sl-switch__track::after { left: calc(100% - 1.1em); }
.sl-switch__input:focus-visible + .sl-switch__track {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--sl-accent) 35%, transparent); }
.sl-switch:has(.sl-switch__input:disabled) { cursor: default; color: var(--sl-faint); }
.sl-switch__input:disabled + .sl-switch__track { opacity: .55; }

/* ── Field (label + hint/error wrapper) · Fieldset (grouped) ─────────────────────
   The composition layer that pairs a label + optional hint/error with any control
   (.sl-input / .sl-textarea / .sl-select / .sl-check …). */
.sl-field { display: flex; flex-direction: column; gap: .4em; }
.sl-field__label { font-size: .9em; font-weight: 550; color: var(--sl-ink); }
.sl-field__req { color: var(--sl-red); margin-left: .15em; }
.sl-field__hint { font-size: .82em; color: var(--sl-muted); line-height: 1.45; }
.sl-field__error { font-size: .82em; color: var(--sl-red); line-height: 1.45; }
.sl-field--invalid :where(.sl-input, .sl-textarea, .sl-select select) { border-color: var(--sl-red); }
.sl-field--invalid :where(.sl-input, .sl-textarea, .sl-select select):focus {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--sl-red) 25%, transparent); }
.sl-fieldset { display: flex; flex-direction: column; gap: .7em; margin: 0;
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius); padding: 1em 1.1em; }
.sl-fieldset__legend { padding: 0 .4em; font-weight: 600; font-size: .9em; color: var(--sl-ink); }

/* ── Entity (a list row: leading visual · title/desc · trailing) ──────────────────
   The shared primitive for council/persona/project/synthesis rows. Use .sl-entity-list to
   stack rows under one hairline frame; --button makes a row interactive. */
.sl-entity { display: flex; align-items: center; gap: .85em; padding: .7em .9em;
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius); background: var(--sl-surface); }
.sl-entity--button { cursor: pointer; transition: background .12s, border-color .12s; }
.sl-entity--button:hover { background: var(--sl-hover); }
.sl-entity--button:focus-visible { outline: 2px solid color-mix(in srgb, var(--sl-accent) 55%, transparent); outline-offset: -1px; }
.sl-entity__visual { flex: none; display: inline-flex; align-items: center; justify-content: center;
  color: var(--sl-muted); line-height: 0; }
.sl-entity__content { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: .15em; }
.sl-entity__title { font-weight: 550; color: var(--sl-ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sl-entity__desc { font-size: .85em; color: var(--sl-muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sl-entity__trailing { flex: none; display: inline-flex; align-items: center; gap: .5em; color: var(--sl-muted); }
.sl-entity-list { display: flex; flex-direction: column; overflow: hidden;
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius); background: var(--sl-surface); }
.sl-entity-list .sl-entity { border: 0; border-radius: 0; border-bottom: 1px solid var(--sl-line); }
.sl-entity-list .sl-entity:last-child { border-bottom: 0; }

/* ── Charts (bar · pie/donut · effort·impact quadrant) ────────────────────────────────
   Static, token-driven, print-safe (no hover-only data) so they render identically in the
   app, the website, and headless-Chromium PDF/PPTX export. Markup is emitted by the React
   (src/charts.tsx) and Python (py/sonaloop_icons/charts.py) wrappers; this is the one style
   source. Series colours come from position (--c1..--c7) unless an item sets --c inline. */
.sl-chart { margin: 0; --c1: var(--sl-accent); --c2: var(--sl-violet); --c3: var(--sl-blue);
  --c4: var(--sl-green); --c5: var(--sl-amber); --c6: var(--sl-red); --c7: var(--sl-skep); }
.sl-chart__title { font-size: .8em; font-weight: 650; text-transform: uppercase; letter-spacing: .04em;
  color: var(--sl-muted); margin: 0 0 .8em; }

/* Bar chart — horizontal labelled bars (ranking, counts) */
.sl-bars { display: flex; flex-direction: column; gap: .5em; }
.sl-bar { display: grid; grid-template-columns: minmax(4.5em, 10em) 1fr auto; align-items: center;
  gap: .75em; font-size: .92em; }
.sl-bar__label { color: var(--sl-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-bar__track { display: block; height: .7em; border-radius: var(--sl-radius-full); background: var(--sl-surface-2); overflow: hidden; }
.sl-bar__fill { display: block; height: 100%; width: var(--v, 0%); border-radius: var(--sl-radius-full); background: var(--c, var(--sl-accent)); }
.sl-bar__val { color: var(--sl-muted); font-variant-numeric: tabular-nums; min-width: 2em; text-align: right; font-size: .85em; }
/* Stacked bar — the fill is sized to the bar total (--v); inner --seg-s split it by series value. */
.sl-bar__fill--stack { display: flex; background: none; overflow: hidden; }
.sl-bar__seg { height: 100%; flex-basis: 0; background: var(--c, var(--sl-accent)); }

/* Gauge — radial progress rings (KPI / % complete). `--p` (0..100) is set inline. */
.sl-gauges { display: flex; flex-wrap: wrap; gap: 1.5em; align-items: flex-start; }
.sl-gauge-item { display: flex; flex-direction: column; align-items: center; gap: .55em; text-align: center; }
.sl-gauge { position: relative; width: 7.5em; height: 7.5em; flex: none; border-radius: 50%;
  background: conic-gradient(var(--c, var(--sl-accent)) calc(var(--p, 0) * 1%), var(--sl-surface-2) 0); }
.sl-gauge::after { content: ''; position: absolute; inset: 15%; border-radius: 50%; background: var(--sl-bg); }
.sl-gauge__val { position: absolute; inset: 0; z-index: 1; display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 1.35em; color: var(--sl-ink); font-variant-numeric: tabular-nums; }
.sl-gauge__label { font-size: .85em; color: var(--sl-ink); max-width: 9em; }
.sl-gauge__sub { font-size: .78em; color: var(--sl-muted); font-variant-numeric: tabular-nums; }

/* Diverging bar — net sentiment / for↔against around a centre axis. Two half-tracks meet at the
   zero line; each --v-sized fill grows outward (negative left, positive right). */
.sl-dbars { display: flex; flex-direction: column; gap: .5em; }
.sl-dbar { display: grid; grid-template-columns: minmax(4.5em, 9em) 1fr 1fr auto; align-items: center; gap: .4em; font-size: .92em; }
.sl-dbar__label { color: var(--sl-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-dbar__neg, .sl-dbar__pos { display: flex; height: .7em; background: var(--sl-surface-2); }
.sl-dbar__neg { justify-content: flex-end; border-radius: var(--sl-radius-full) 0 0 var(--sl-radius-full); }
.sl-dbar__pos { justify-content: flex-start; border-radius: 0 var(--sl-radius-full) var(--sl-radius-full) 0; border-left: 1px solid var(--sl-line); }
.sl-dbar__fill { width: var(--v, 0%); height: 100%; background: var(--c, var(--sl-accent)); border-radius: inherit; }
.sl-dbar__val { color: var(--sl-muted); font-variant-numeric: tabular-nums; white-space: nowrap; font-size: .85em; }

/* Heatmap / matrix — option × criteria (or persona × theme); cells tinted by value via color-mix.
   `grid-template-columns` and each cell's tint background are set inline. */
.sl-heat { display: grid; gap: 3px; font-size: .85em; }
.sl-heat__col { font-weight: 600; color: var(--sl-muted); text-align: center; padding: .2em .15em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-heat__row { color: var(--sl-ink); align-self: center; padding-right: .5em; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-heat__cell { display: flex; align-items: center; justify-content: center; min-height: 2em; padding: .25em;
  border-radius: var(--sl-radius-sm); background: var(--sl-surface-2); color: var(--sl-ink); font-variant-numeric: tabular-nums; }

/* Dot / range plot — where N voices land on a scale (spread/disagreement). Dots positioned by --x (%);
   the taller --mean marker is the average. */
.sl-dots { display: flex; flex-direction: column; gap: .5em; }
.sl-dot-row { display: grid; grid-template-columns: minmax(4.5em, 10em) 1fr auto; gap: .75em; align-items: center; font-size: .9em; }
.sl-dot-label { color: var(--sl-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-dot-track { position: relative; height: 1.4em; }
.sl-dot-track::before { content: ''; position: absolute; left: 0; right: 0; top: 50%; border-top: 1px solid var(--sl-line); }
.sl-dot-pt { position: absolute; top: 50%; left: var(--x); transform: translate(-50%, -50%);
  width: .72em; height: .72em; border-radius: 50%; background: var(--c, var(--sl-accent)); opacity: .55; }
.sl-dot-mean { position: absolute; top: 50%; left: var(--x); transform: translate(-50%, -50%);
  width: .26em; height: 1.3em; border-radius: 2px; background: var(--c, var(--sl-accent)); box-shadow: 0 0 0 2px var(--sl-bg); }
.sl-dot-val { color: var(--sl-muted); font-variant-numeric: tabular-nums; min-width: 2em; text-align: right; font-size: .85em; }
.sl-dot-scale { display: grid; grid-template-columns: minmax(4.5em, 10em) 1fr auto; gap: .75em; margin-top: .35em; }
.sl-dot-scale__axis { display: flex; justify-content: space-between; font-size: .75em; color: var(--sl-faint); }

/* Line / trend — a static inline-SVG polyline (the one chart that needs SVG). `--c` carries the
   series colour; non-scaling strokes keep the line crisp at any render size. Quiet quarter-height
   gridlines (`.sl-line__grid`) sit under every SVG chart, Linear-style. */
.sl-line svg { width: 100%; height: auto; display: block; overflow: visible; }
.sl-line__axis { stroke: var(--sl-line); stroke-width: 1; vector-effect: non-scaling-stroke; }
.sl-line__grid { stroke: color-mix(in srgb, var(--sl-line) 55%, transparent); stroke-width: 1;
  vector-effect: non-scaling-stroke; }
.sl-line__path { fill: none; stroke: var(--c, var(--sl-accent)); stroke-width: 1.75;
  vector-effect: non-scaling-stroke; stroke-linejoin: round; stroke-linecap: round; }
.sl-line__dot { fill: var(--c, var(--sl-accent)); }
.sl-line__labels { display: flex; justify-content: space-between; font-size: .75em; color: var(--sl-muted); margin-top: .3em; }

/* Burn-up / progress-over-time — the line SVG plus soft band fills under each series, a dotted
   ideal/target reference line, and a "now" marker with a hatched future region (the Linear
   cycle chart). Stacked area / cumulative flow shares the band classes. */
.sl-line__area { fill: var(--c, var(--sl-accent)); opacity: .10; stroke: none; }
.sl-line__ref { stroke: var(--sl-muted); stroke-width: 1; stroke-dasharray: 3 3; vector-effect: non-scaling-stroke; }
.sl-line__now { stroke: var(--sl-ink); opacity: .4; stroke-width: 1; vector-effect: non-scaling-stroke; }
.sl-burnup__future { fill: var(--sl-ink); opacity: .035; }
.sl-burnup__hatch { stroke: var(--sl-line); stroke-width: 1; vector-effect: non-scaling-stroke; opacity: .7; }
.sl-area__band { fill: var(--c, var(--sl-accent)); opacity: .45; stroke: none; }
.sl-area__edge { fill: none; stroke: var(--c, var(--sl-accent)); stroke-width: 1.25;
  vector-effect: non-scaling-stroke; stroke-linejoin: round; }

/* Pie / donut — proportions (distribution, sentiment). `--slices` is set inline (conic-gradient). */
.sl-pie-wrap { display: flex; align-items: center; gap: 1.3em; flex-wrap: wrap; }
.sl-pie { width: 9.5em; height: 9.5em; flex: none; border-radius: 50%; background: var(--slices, var(--sl-surface-2)); }
.sl-pie--donut { -webkit-mask: radial-gradient(circle, #0000 53%, #000 54%); mask: radial-gradient(circle, #0000 53%, #000 54%); }

/* Legend — shared by pie + quadrant + multi-series bar */
.sl-legend { display: flex; flex-direction: column; gap: .4em; font-size: .85em; min-width: 0; }
.sl-legend--row { flex-direction: row; flex-wrap: wrap; gap: .25em 1.2em; }
.sl-legend__item { display: flex; align-items: baseline; gap: .55em; color: var(--sl-muted); }
.sl-legend__sw { width: .72em; height: .72em; flex: none; border-radius: 3px; background: var(--c, var(--sl-accent)); transform: translateY(.06em); }
.sl-legend__num { width: 1.5em; height: 1.5em; flex: none; border-radius: 50%; display: inline-flex; align-items: center;
  justify-content: center; font-size: .78em; font-weight: 700; color: var(--c, var(--sl-accent));
  border: 1.5px solid var(--c, var(--sl-accent)); transform: translateY(.05em); }
.sl-legend__label { color: var(--sl-ink); }
.sl-legend__val { color: var(--sl-muted); font-variant-numeric: tabular-nums; margin-left: auto; padding-left: .6em; }

/* Effort·impact — a 2×2 scatter. Dots positioned by --x/--y (%); origin bottom-left. */
.sl-quad-wrap { display: grid; grid-template-columns: 1.3em 1fr; grid-template-rows: 1fr 1.3em; gap: .4em;
  max-width: 32em; margin: 0 auto; }
.sl-quad-ylab { grid-column: 1; grid-row: 1; writing-mode: vertical-rl; transform: rotate(180deg);
  text-align: center; align-self: center; font-size: .78em; color: var(--sl-ink); }
.sl-quad-xlab { grid-column: 2; grid-row: 2; text-align: center; font-size: .78em; color: var(--sl-ink); }
.sl-quad { grid-column: 2; grid-row: 1; position: relative; aspect-ratio: 4 / 3;
  border-left: 1px solid var(--sl-line); border-bottom: 1px solid var(--sl-line); }
.sl-quad__gx { position: absolute; top: 0; bottom: 0; left: 50%; border-left: 1px dashed var(--sl-line); }
.sl-quad__gy { position: absolute; left: 0; right: 0; top: 50%; border-top: 1px dashed var(--sl-line); }
.sl-quad__q { position: absolute; font-size: .68em; color: var(--sl-faint); padding: .35em .5em; max-width: 48%; }
.sl-quad__q--tl { top: 0; left: 0; } .sl-quad__q--tr { top: 0; right: 0; text-align: right; }
.sl-quad__q--bl { bottom: 0; left: 0; } .sl-quad__q--br { bottom: 0; right: 0; text-align: right; }
.sl-quad__dot { position: absolute; left: var(--x, 50%); top: var(--y, 50%); transform: translate(-50%, -50%);
  width: 1.9em; height: 1.9em; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  font-size: .8em; font-weight: 700; color: var(--c, var(--sl-accent)); background: var(--sl-bg);
  border: 1.8px solid var(--c, var(--sl-accent)); box-shadow: 0 0 0 3px var(--sl-bg); }

/* Column chart — thin rounded VERTICAL bars over hairline gridlines (the Linear Insights panel),
   optionally segment-stacked, with an optional breakdown table beneath (.sl-chart__table).
   Fills are scaled to 86% of the plot so per-column value labels always fit; y ticks read
   max / half / 0. Gridlines are quiet color-mixed hairlines, the baseline a solid rule. */
.sl-cols-wrap { display: grid; grid-template-columns: auto 1fr; gap: .2em .55em; }
.sl-cols-axis { display: flex; flex-direction: column; justify-content: space-between; text-align: right;
  font-size: .72em; color: var(--sl-faint); font-variant-numeric: tabular-nums; transform: translateY(.35em); }
.sl-cols { display: flex; align-items: flex-end; gap: .55em; height: 9.5em;
  border-bottom: 1px solid var(--sl-line);
  background-image: linear-gradient(color-mix(in srgb, var(--sl-line) 55%, transparent) 1px, transparent 1px);
  background-size: 100% 25%; }
.sl-col { flex: 1; min-width: 0; height: 100%; display: flex; flex-direction: column;
  justify-content: flex-end; align-items: center; gap: .3em; }
.sl-col__val { font-size: .72em; color: var(--sl-muted); font-variant-numeric: tabular-nums; line-height: 1; }
.sl-col__bar { width: min(100%, 2.1em); height: calc(var(--v, 0%) * .86); min-height: 2px;
  border-radius: 3px 3px 0 0; background: var(--c, var(--c1)); }
.sl-col__bar--stack { display: flex; flex-direction: column-reverse; background: none; overflow: hidden; }
.sl-col__seg { flex-basis: 0; background: var(--c, var(--sl-accent)); }
.sl-cols-labels { grid-column: 2; display: flex; gap: .55em; margin-top: .3em; }
.sl-cols-labels span { flex: 1; min-width: 0; text-align: center; font-size: .75em; color: var(--sl-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-chart__table { margin-top: .9em; font-size: .85em; }
.sl-chart__table td { font-variant-numeric: tabular-nums; }

/* KPI stat row — big-number tiles (small label · big value · optional sub/delta): the Linear-style
   stat header above a progress chart, or a standalone headline-metrics row. Swatch only when an
   item sets a colour (a stat header is colour-keyed to its chart; plain KPIs stay quiet). */
.sl-kpis { display: flex; flex-wrap: wrap; gap: 1.1em 2.4em; }
.sl-kpi { display: flex; flex-direction: column; gap: .2em; min-width: 0; }
.sl-kpi__label { display: flex; align-items: center; gap: .45em; font-size: .78em; color: var(--sl-muted); }
.sl-kpi__sw { width: .68em; height: .68em; flex: none; border-radius: 3px; background: var(--c, var(--sl-accent)); }
.sl-kpi__val { font-size: 1.45em; font-weight: 700; color: var(--sl-ink); line-height: 1.15; font-variant-numeric: tabular-nums; }
.sl-kpi__sub { font-size: .75em; color: var(--sl-faint); font-variant-numeric: tabular-nums; }

/* Progress strip — ONE full-width segmented status bar + a count/% legend (composition at a
   glance: finding status, sentiment split). Denser and calmer than a pie for inline report use.
   Segments are flex-grown by value; a hairline of background separates them. */
.sl-pstrip { display: flex; height: .8em; border-radius: var(--sl-radius-full); overflow: hidden; background: var(--sl-surface-2); }
.sl-pstrip__seg { flex-basis: 0; min-width: 2px; background: var(--c, var(--sl-accent)); }
.sl-pstrip__seg + .sl-pstrip__seg { border-left: 2px solid var(--sl-bg); }

/* Micro progress-pie — a tiny inline pie that fills value/max, for list rows and table cells
   (milestone 77%, per-persona completion). Pairs with text like “77% of 15”. */
.sl-mpie { display: inline-block; width: 1em; height: 1em; vertical-align: -.12em; border-radius: 50%;
  background: conic-gradient(var(--c, var(--sl-accent)) calc(var(--p, 0) * 1%),
    color-mix(in srgb, var(--c, var(--sl-accent)) 16%, transparent) 0);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c, var(--sl-accent)) 40%, transparent); }

/* ── Command palette (⌘K) ─────────────────────────────────────────────────────────
   A Linear/Raycast-style global command palette: results grouped under muted section
   headers, a type-coloured leading icon, an optional right-aligned subtitle, and a
   footer hint bar. Shared markup — the React <CommandPalette> (website) and the docs
   site (vanilla JS) render these same classes, so they can never drift. */
.sl-cmdk { position: fixed; inset: 0; z-index: 200; display: flex; align-items: flex-start; justify-content: center; }
.sl-cmdk[hidden] { display: none; }
.sl-cmdk-backdrop { position: absolute; inset: 0; background: color-mix(in srgb, #000 48%, transparent); backdrop-filter: blur(2px); }
.sl-cmdk-panel { position: relative; margin-top: 12vh; width: min(600px, 92vw); max-height: 74vh;
  display: flex; flex-direction: column; background: var(--sl-surface); border: 1px solid var(--sl-line);
  border-radius: var(--sl-radius-lg); box-shadow: 0 24px 70px rgba(0, 0, 0, .30); overflow: hidden; }
/* Inline presentation (docs preview / embedding): no overlay offset, a calmer shadow. */
.sl-cmdk-panel--inline { margin: 0 auto; box-shadow: 0 10px 40px rgba(0, 0, 0, .16); }
.sl-cmdk-head { display: flex; align-items: center; gap: .7rem; padding: .85rem 1rem; border-bottom: 1px solid var(--sl-line); }
.sl-cmdk-head-ico { width: 1.05rem; height: 1.05rem; flex: none; color: var(--sl-faint); }
.sl-cmdk-input { flex: 1; min-width: 0; border: 0; outline: none; background: transparent;
  font: inherit; font-size: .95rem; color: var(--sl-ink); }
.sl-cmdk-input::placeholder { color: var(--sl-faint); }
.sl-cmdk-list { flex: 1; overflow-y: auto; padding: .35rem; margin: 0; list-style: none; }
.sl-cmdk-empty { padding: 1.7rem; text-align: center; color: var(--sl-faint); font-size: .9rem; }
.sl-cmdk-sec { padding: .6rem .65rem .25rem; font-size: .68rem; font-weight: 600; letter-spacing: .04em; color: var(--sl-faint); }
.sl-cmdk-item { display: flex; align-items: center; gap: .65rem; width: 100%; box-sizing: border-box;
  padding: .55rem .65rem; border: 0; border-radius: var(--sl-radius); background: transparent;
  font: inherit; font-size: .9rem; color: var(--sl-ink); text-align: left; text-decoration: none; cursor: pointer; }
.sl-cmdk-item.is-active { background: var(--sl-hover); }
.sl-cmdk-ico { flex: none; width: 1.1rem; height: 1.1rem; display: inline-flex; align-items: center; justify-content: center; color: var(--sl-muted); }
.sl-cmdk-ico svg { width: 1.1rem; height: 1.1rem; }
.sl-cmdk-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-cmdk-sub { flex: none; max-width: 42%; color: var(--sl-muted); font-size: .8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-cmdk-foot { display: flex; gap: 1.15rem; padding: .5rem 1rem; border-top: 1px solid var(--sl-line);
  background: var(--sl-surface-2); color: var(--sl-muted); font-size: .8rem; }
.sl-cmdk-foot .sl-kbd { margin-right: .4rem; }

/* Search trigger — a reusable button that opens the palette (search glyph · label · ⌘K hint). */
.sl-cmdk-trigger { display: inline-flex; align-items: center; gap: .55rem; padding: .4rem .7rem;
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius); background: var(--sl-surface);
  color: var(--sl-muted); font: inherit; font-size: .85rem; cursor: pointer; transition: border-color .12s, background .12s; }
.sl-cmdk-trigger:hover { border-color: color-mix(in srgb, var(--sl-ink) 22%, var(--sl-line)); }
.sl-cmdk-trigger-ico { width: .95rem; height: .95rem; flex: none; }
.sl-cmdk-trigger span { flex: 1; text-align: left; }

/* ── App shell ──────────────────────────────────────────────────────────────────────
   The product chrome: a collapsible + drag-resizable sidebar (brand · nav sections ·
   bottom user menu), a resize handle, and a topbar (sidebar toggle · breadcrumb · actions).
   Shared markup — the React <AppShell> (tsx consumers) and the Python-SSR app render these
   same classes from one source, so the inspector and the tracker can never drift.
   Sidebar width is a scoped custom property the resize JS writes; collapse via .is-collapsed. */
.sl-app-shell { display: flex; height: 100vh; overflow: hidden; --sl-sidebar-w: 248px; }
.sl-sidebar { width: var(--sl-sidebar-w); min-width: var(--sl-sidebar-w); background: var(--sl-sidebar);
  border-right: 1px solid var(--sl-line); display: flex; flex-direction: column; flex-shrink: 0; overflow: hidden;
  transition: width 200ms var(--sl-ease), min-width 200ms var(--sl-ease), border-right-width 200ms; }
.sl-app-shell.is-collapsed .sl-sidebar { width: 0; min-width: 0; border-right-width: 0; }
.sl-brand { height: var(--sl-row-h); flex-shrink: 0; display: flex; align-items: center; padding: 0 var(--sl-s-4);
  font-size: .8125rem; border-bottom: 1px solid var(--sl-line); }
.sl-sb-scroll { overflow: auto; padding: var(--sl-s-2); flex: 1; min-height: 0; }
/* Search slot — pinned under the brand (below its border), above the nav. The trigger fills the width. */
.sl-sb-search { flex-shrink: 0; padding: var(--sl-s-2) var(--sl-s-2) 2px; }
.sl-sb-search .sl-cmdk-trigger { width: 100%; }
.sl-nav { display: flex; flex-direction: column; gap: 1px; }
/* Items render as <a> in the SSR app and <button> in React consumers — both styled here. */
.sl-nav a, .sl-nav button { display: flex; align-items: center; gap: var(--sl-gap-item); width: 100%; padding: var(--sl-s-1) var(--sl-s-2);
  border: 0; background: transparent; border-radius: var(--sl-radius-sm); color: var(--sl-ink); font: inherit;
  font-weight: 500; font-size: .8125rem; text-align: left; position: relative; min-height: var(--sl-row-dense); text-decoration: none; cursor: pointer; }
.sl-nav a svg, .sl-nav button svg { width: 16px; height: 16px; flex: none; color: var(--sl-faint); }
.sl-nav a:hover, .sl-nav button:hover { background: var(--sl-hover); }
.sl-nav a.is-active, .sl-nav button.is-active { background: var(--sl-sel); color: var(--sl-ink); font-weight: 600; }
.sl-nav a.is-active::before, .sl-nav button.is-active::before { content: ''; position: absolute; left: -8px; top: 8px; bottom: 8px;
  width: 2.5px; border-radius: 0 3px 3px 0; background: var(--sl-accent); }
.sl-nav a.is-active svg, .sl-nav button.is-active svg { color: var(--sl-accent); }
.sl-nav-meta { margin-left: auto; font-size: .7rem; color: var(--sl-faint); font-variant-numeric: tabular-nums; }
.sl-navhead { font-size: .6875rem; letter-spacing: .05em; text-transform: uppercase; color: var(--sl-faint);
  margin: var(--sl-s-4) var(--sl-s-2) var(--sl-s-1); font-weight: 650; }
/* Collapsible section variant — the head is a caret toggle; .is-collapsed hides the items. */
.sl-nav-group { display: flex; flex-direction: column; }
button.sl-navhead { display: flex; align-items: center; gap: var(--sl-gap-tight); width: 100%; padding: 0; background: none; border: 0;
  cursor: pointer; text-align: left; font-family: inherit; }
button.sl-navhead:hover { color: var(--sl-muted); }
.sl-navhead__caret { margin-left: auto; display: inline-flex; color: var(--sl-faint); transition: transform .15s var(--sl-ease); }
.sl-nav-group.is-collapsed .sl-navhead__caret { transform: rotate(-90deg); }
.sl-nav-group.is-collapsed .sl-nav { display: none; }
.sl-usermenu { position: relative; flex-shrink: 0; border-top: 1px solid var(--sl-line); padding: var(--sl-s-2); }
.sl-um-trigger { width: 100%; display: flex; align-items: center; gap: var(--sl-gap-item); padding: var(--sl-s-1) var(--sl-s-2); border: 1px solid transparent;
  border-radius: var(--sl-radius); background: transparent; cursor: pointer; color: var(--sl-ink); font: inherit; font-size: .8125rem; font-weight: 500; }
.sl-um-trigger:hover { background: var(--sl-hover); }
.sl-usermenu.is-open .sl-um-trigger { background: var(--sl-hover); }
.sl-um-ava { display: flex; align-items: center; justify-content: center; width: 22px; height: 22px; flex-shrink: 0; color: var(--sl-muted); }
.sl-um-ava svg { width: 18px; height: 18px; }
.sl-um-name { flex: 1; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sl-um-caret { color: var(--sl-muted); display: inline-flex; transition: transform .15s var(--sl-ease); }
.sl-um-caret svg { width: 16px; height: 16px; }
.sl-usermenu.is-open .sl-um-caret { transform: rotate(180deg); }
.sl-um-pop { position: absolute; left: 8px; right: 8px; bottom: calc(100% + var(--sl-s-1)); background: var(--sl-overlay);
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius-lg); box-shadow: 0 16px 44px rgba(0, 0, 0, .22); padding: var(--sl-s-2); z-index: 60; }
.sl-um-pop[hidden] { display: none; }
.sl-um-sec { margin-bottom: var(--sl-gap-item); }
.sl-um-sec:last-child { margin-bottom: 0; }
.sl-um-lbl { font-size: .6875rem; letter-spacing: .02em; color: var(--sl-faint); font-weight: 600; margin: 0 2px var(--sl-s-1); }
.sl-resize { width: 8px; margin: 0 -4px; flex-shrink: 0; cursor: col-resize; position: relative; z-index: 10; }
.sl-app-shell.is-collapsed .sl-resize { display: none; }
.sl-resize::after { content: ''; position: absolute; inset: 0 50%; width: 2px; transform: translateX(-50%);
  background: var(--sl-accent); opacity: 0; transition: opacity 150ms; }
.sl-resize:hover::after { opacity: .4; }
.sl-main { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; }
.sl-topbar { height: var(--sl-row-h); flex-shrink: 0; display: flex; align-items: center; gap: var(--sl-gap-group); padding: 0 var(--sl-s-3);
  border-bottom: 1px solid var(--sl-line); background: var(--sl-surface); }
.sl-iconbtn { border: 1px solid var(--sl-line); background: var(--sl-surface); border-radius: var(--sl-radius-sm);
  width: var(--sl-ctl-sm); height: var(--sl-ctl-sm); cursor: pointer; color: var(--sl-muted); flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; }
.sl-iconbtn:hover { background: var(--sl-hover); color: var(--sl-ink); }
.sl-iconbtn svg { width: 16px; height: 16px; }
/* Ghost: a borderless quiet icon button for inline row actions (edit · delete · close). */
.sl-iconbtn--ghost { border-color: transparent; background: none; }
.sl-iconbtn--ghost:hover { background: var(--sl-hover); }
.sl-iconbtn--danger:hover { color: var(--sl-red); }
.sl-spacer { flex: 1; }
.sl-tb-actions { display: flex; align-items: center; gap: var(--sl-gap-item); }
.sl-shell-body { flex: 1; min-height: 0; overflow: auto; }
@media (max-width: 760px) {
  .sl-sidebar { position: fixed; top: 0; left: 0; height: 100vh; z-index: 100; width: 280px !important; min-width: 280px !important;
    transform: translateX(-100%); transition: transform 220ms var(--sl-ease); }
  .sl-app-shell:not(.is-collapsed) .sl-sidebar { transform: translateX(0); box-shadow: var(--sl-shadow-lg); }
  .sl-resize { display: none; }
}

/* ── Overlays: Drawer · Modal · Popover ───────────────────────────────────────────
   The shared overlay layer. The React wrappers mount on open (no exit animation, like
   .sl-cmdk); an SSR app may keep a persistent root and toggle the `hidden` attribute
   instead (the enter animation replays on un-hide). All sit above the shell, z-index 120 / 60. */
.sl-overlay-close { border: 0; background: none; cursor: pointer; color: var(--sl-muted);
  border-radius: var(--sl-radius-sm); padding: var(--sl-s-1); line-height: 0; display: inline-flex; flex-shrink: 0; }
.sl-overlay-close:hover { background: var(--sl-hover); color: var(--sl-ink); }
.sl-overlay-close svg { width: 18px; height: 18px; }
.sl-drawer[hidden], .sl-modal[hidden] { display: none; }
@keyframes sl-fade-in { from { opacity: 0; } }

/* Drawer (right/left slide-over). A persistent root: when closed it's pointer-events:none with the
   scrim faded and the panel translated off-screen; `.is-open` transitions it in, and removing the
   class transitions it back out (a real exit animation). Both React (toggles the class on a kept-
   mounted element) and the SSR app (toggles it in JS) drive it the same way. */
.sl-drawer { position: fixed; inset: 0; z-index: 120; display: flex; justify-content: flex-end; pointer-events: none; }
.sl-drawer.is-open { pointer-events: auto; }
.sl-drawer--left { justify-content: flex-start; }
.sl-drawer__scrim { position: absolute; inset: 0; background: color-mix(in srgb, #0a0c10 32%, transparent);
  opacity: 0; transition: opacity .2s var(--sl-ease); }
.sl-drawer.is-open .sl-drawer__scrim { opacity: 1; }
.sl-drawer__panel { position: relative; height: 100%; width: min(620px, 94vw); display: flex; flex-direction: column;
  overflow: hidden; background: var(--sl-surface); border-left: 1px solid var(--sl-line);
  box-shadow: var(--sl-shadow-lg); transform: translateX(100%); transition: transform .24s var(--sl-ease); }
.sl-drawer--left .sl-drawer__panel { border-left: 0; border-right: 1px solid var(--sl-line); transform: translateX(-100%); }
/* --wide: the Notion-style slide-over that renders a FULL detail page in sidebar layout
   (not an essence preview) — generous reading width, still leaving the page behind visible. */
.sl-drawer--wide .sl-drawer__panel { width: min(720px, 94vw); }
.sl-drawer.is-open .sl-drawer__panel { transform: none; }
.sl-drawer__head { height: var(--sl-row-h); flex-shrink: 0; display: flex; align-items: center; gap: var(--sl-gap-item);
  padding: 0 var(--sl-s-2) 0 var(--sl-s-4); border-bottom: 1px solid var(--sl-line); }
.sl-drawer__title { font-weight: 600; flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sl-drawer__body { flex: 1; min-height: 0; overflow-y: auto; padding: var(--sl-s-5) var(--sl-gap-section); }
.sl-drawer__foot { flex-shrink: 0; border-top: 1px solid var(--sl-line); padding: var(--sl-s-3) var(--sl-s-4);
  display: flex; justify-content: flex-end; gap: var(--sl-gap-item); }

/* Modal (centered dialog) */
.sl-modal { position: fixed; inset: 0; z-index: 120; display: flex; align-items: center; justify-content: center; padding: var(--sl-s-6); }
.sl-modal__scrim { position: absolute; inset: 0; background: color-mix(in srgb, #0a0c10 38%, transparent);
  animation: sl-fade-in .2s var(--sl-ease); }
.sl-modal__panel { position: relative; width: min(520px, 100%); max-height: calc(100vh - 48px); display: flex;
  flex-direction: column; overflow: hidden; background: var(--sl-surface); border: 1px solid var(--sl-line);
  border-radius: var(--sl-radius-lg); box-shadow: var(--sl-shadow-lg); animation: sl-modal-in .18s var(--sl-ease); }
.sl-modal--sm .sl-modal__panel { width: min(400px, 100%); }
.sl-modal--lg .sl-modal__panel { width: min(720px, 100%); }
@keyframes sl-modal-in { from { opacity: 0; transform: translateY(8px) scale(.98); } }
.sl-modal__head { display: flex; align-items: flex-start; gap: var(--sl-gap-item); padding: var(--sl-s-4) var(--sl-s-4) 0; }
.sl-modal__title { font-weight: 600; font-size: 1.05em; flex: 1; min-width: 0; }
.sl-modal__body { padding: var(--sl-s-2) var(--sl-s-4) var(--sl-s-4); overflow-y: auto; color: var(--sl-muted); }
.sl-modal__foot { flex-shrink: 0; padding: var(--sl-s-3) var(--sl-s-4); border-top: 1px solid var(--sl-line);
  display: flex; justify-content: flex-end; gap: var(--sl-gap-item); }

/* Image lightbox — a full-bleed zoom view (distinct from Modal's chrome'd dialog). */
.sl-lightbox { position: fixed; inset: 0; z-index: 130; display: flex; align-items: center; justify-content: center;
  padding: var(--sl-s-6); background: color-mix(in srgb, #0a0c10 80%, transparent); backdrop-filter: blur(4px);
  animation: sl-fade-in .2s var(--sl-ease); }
.sl-lightbox__fig { display: flex; flex-direction: column; align-items: center; gap: var(--sl-gap-group); max-height: 100%; margin: 0; }
.sl-lightbox__img { max-width: 86vw; max-height: 82vh; object-fit: contain;
  border-radius: var(--sl-radius-lg); box-shadow: var(--sl-shadow-lg); }
.sl-lightbox__cap { font-family: var(--sl-mono); font-size: .8em; color: rgba(255, 255, 255, .72); }
.sl-lightbox__x { position: absolute; top: var(--sl-s-4); right: var(--sl-s-4); padding: .25em .6em; font-family: var(--sl-mono);
  font-size: .8em; color: rgba(255, 255, 255, .8); background: none; border: 1px solid rgba(255, 255, 255, .2);
  border-radius: var(--sl-radius-sm); cursor: pointer; }
.sl-lightbox__x:hover { background: rgba(255, 255, 255, .1); }

/* Popover (anchored) + the menu rows it usually holds */
.sl-popover-wrap { position: relative; display: inline-flex; }
.sl-popover { position: absolute; z-index: 60; min-width: 180px; padding: var(--sl-s-1); background: var(--sl-overlay);
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius-lg); box-shadow: var(--sl-shadow-lg);
  animation: sl-pop-in .12s var(--sl-ease); }
.sl-popover[hidden] { display: none; }
@keyframes sl-pop-in { from { opacity: 0; transform: translateY(-4px); } }
.sl-popover--bottom-start { top: calc(100% + var(--sl-s-2)); left: 0; }
.sl-popover--bottom-end { top: calc(100% + var(--sl-s-2)); right: 0; }
.sl-popover--top-start { bottom: calc(100% + var(--sl-s-2)); left: 0; }
.sl-popover--top-end { bottom: calc(100% + var(--sl-s-2)); right: 0; }
.sl-menu-item { display: flex; align-items: center; gap: var(--sl-gap-item); width: 100%; padding: var(--sl-s-2) var(--sl-s-3); border: 0;
  background: none; border-radius: var(--sl-radius-sm); font: inherit; color: var(--sl-ink); cursor: pointer;
  text-align: left; text-decoration: none; }
.sl-menu-item:hover { background: var(--sl-hover); }
.sl-menu-item > svg { width: 16px; height: 16px; color: var(--sl-muted); flex-shrink: 0; }   /* the leading icon only */
/* Selectable rows (option/filter menus): a leading check column + the label + a trailing count. */
.sl-menu-item__check { width: 1.05em; flex-shrink: 0; display: inline-flex; justify-content: center; }
.sl-menu-item__check svg { width: 13px; height: 13px; color: var(--sl-accent); }
.sl-menu-item__label { flex: 1; min-width: 0; display: inline-flex; align-items: center; gap: var(--sl-gap-item); }
.sl-menu-item__count { flex-shrink: 0; font-family: var(--sl-mono); font-size: .82em; color: var(--sl-faint); }
.sl-menu-sep { height: 1px; background: var(--sl-line); margin: var(--sl-s-1) 0; }
.sl-menu-label { font-size: .6875em; letter-spacing: .02em; color: var(--sl-faint); font-weight: 600; padding: var(--sl-s-1) var(--sl-s-3) 2px; }
/* A labelled control row inside a menu (a Select, a toggle) — Display / settings menus. */
.sl-menu-field { display: flex; align-items: center; justify-content: space-between; gap: var(--sl-gap-group); padding: var(--sl-s-1) var(--sl-s-2); }
.sl-menu-field__label { font-size: .9em; color: var(--sl-muted); }

/* Toolbar button — a quiet bordered pill that triggers a menu (Filter · Display · Views) or
   toggles a mode. Distinct from .sl-btn: smaller, muted, for dense list toolbars. */
.sl-toolbtn { display: inline-flex; align-items: center; gap: .4em; padding: .25em .65em; font: inherit;
  font-size: .92em; color: var(--sl-muted); background: none; border: 1px solid var(--sl-line);
  border-radius: var(--sl-radius-sm); cursor: pointer; white-space: nowrap; transition: background .12s, color .12s; }
.sl-toolbtn:hover { background: var(--sl-hover); color: var(--sl-ink); }
.sl-toolbtn.is-active { color: var(--sl-ink); background: var(--sl-sel); }
.sl-toolbtn svg { width: 15px; height: 15px; }

/* ── Filter bar (faceted list filtering + search) ─────────────────────────────────
   The COMPLETE list-control row: a leading quiet search slot, a "+ Filter" toolbar button
   that opens a two-level facet menu (pick a facet, then its values as selectable
   .sl-menu-item rows), and a removable chip per non-empty facet that reopens its value
   menu. Filter + search always travel together — consumers place the whole bar in the
   scaffold bar INSIDE the content measure and never compose the pieces themselves.
   Chips wrap onto further lines; nothing ever clips. The menu rows reuse .sl-menu-item. */
.sl-filter-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sl-gap-item); }
/* The leading search slot — borderless until focus so it fuses with the button + chips
   into one quiet row; a trailing hairline separates it from the facet controls. */
.sl-filter-search { position: relative; display: inline-flex; align-items: center; flex: 0 1 220px; min-width: 130px; }
.sl-filter-search > svg { position: absolute; left: .55em; width: 14px; height: 14px; color: var(--sl-faint); pointer-events: none; }
.sl-filter-search__input { width: 100%; padding: .28em .5em .28em 2em; border: 1px solid transparent; border-radius: var(--sl-radius-sm);
  background: none; font: inherit; font-size: .92em; color: var(--sl-ink); transition: background .12s, border-color .12s; }
.sl-filter-search__input::placeholder { color: var(--sl-faint); }
.sl-filter-search__input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.sl-filter-search__input:hover { background: var(--sl-hover); }
.sl-filter-search__input:focus, .sl-filter-search__input:focus-visible { outline: none; border-color: var(--sl-accent);
  background: var(--sl-bg); box-shadow: 0 0 0 2px color-mix(in srgb, var(--sl-accent) 22%, transparent); }
.sl-filter-search::after { content: ""; flex: none; width: 1px; height: 1.1em; margin-left: var(--sl-gap-item); background: var(--sl-line); }
.sl-filter-back { display: flex; width: 100%; align-items: center; gap: var(--sl-gap-tight); margin-bottom: 2px;
  padding: var(--sl-s-1) var(--sl-s-3); border: 0; background: none; cursor: pointer; font: inherit; font-size: .72em;
  text-transform: uppercase; letter-spacing: .04em; color: var(--sl-faint); text-align: left;
  border-radius: var(--sl-radius-sm); }
.sl-filter-back:hover { background: var(--sl-hover); color: var(--sl-muted); }
.sl-filter-empty { padding: var(--sl-s-2) var(--sl-s-3); font-size: .85em; color: var(--sl-faint); }
.sl-filter-chip { display: inline-flex; align-items: center; overflow: hidden;
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius-sm); font-size: .85em; }
.sl-filter-chip__body { display: inline-flex; align-items: center; gap: var(--sl-gap-tight); padding: .25em .45em .25em .65em;
  border: 0; background: none; font: inherit; font-size: 1em; color: var(--sl-ink); cursor: pointer; }
.sl-filter-chip__body:hover { background: var(--sl-hover); }
.sl-filter-chip__key { color: var(--sl-muted); }
.sl-filter-chip__op { color: var(--sl-faint); }
.sl-filter-chip__val { max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-filter-chip__x { display: inline-flex; align-items: center; padding: .3em .4em; border: 0;
  border-left: 1px solid var(--sl-line); background: none; color: var(--sl-faint); cursor: pointer; }
.sl-filter-chip__x:hover { background: var(--sl-hover); color: var(--sl-ink); }
.sl-filter-chip__x svg { width: 13px; height: 13px; }
.sl-filter-clear { padding: 0 4px; border: 0; background: none; font: inherit; font-size: .85em;
  color: var(--sl-muted); cursor: pointer; }
.sl-filter-clear:hover { color: var(--sl-ink); text-decoration: underline; }

/* ── Facet bar (always-visible faceted filtering) ─────────────────────────────────
   .sl-filter-bar's open sibling: chip rows per facet group, every option on the page
   with its live count (OR within a group, AND across groups is the host's contract).
   Markup: .sl-facet-bar > .sl-facet-group (a fixed-width uppercase __label + wrapping
   __chips) of .sl-facet-chip buttons (.is-active when selected; a mono __count), plus
   the quiet text actions .sl-facet-more ("+N more" / "less" on overflowing groups) and
   .sl-facet-clear ("Clear filters", only while something is selected). On narrow
   viewports each group stacks its label above the chips. */
.sl-facet-bar { display: flex; flex-direction: column; gap: var(--sl-gap-item); }
.sl-facet-group { display: flex; gap: var(--sl-s-3); align-items: baseline; }
.sl-facet-group__label { flex: none; width: 110px; font-size: .72em; text-transform: uppercase;
  letter-spacing: .05em; color: var(--sl-muted); font-weight: 600; }
.sl-facet-group__chips { display: flex; flex-wrap: wrap; gap: var(--sl-gap-tight); min-width: 0; }
.sl-facet-chip {
  display: inline-flex; align-items: center; gap: var(--sl-gap-tight); padding: 2px var(--sl-s-2);
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius-full);
  background: var(--sl-surface); color: var(--sl-ink); font: inherit; font-size: .85em;
  cursor: pointer;
}
.sl-facet-chip:hover { background: var(--sl-hover); }
.sl-facet-chip.is-active { background: var(--sl-accent-weak); border-color: var(--sl-accent); color: var(--sl-accent); }
.sl-facet-chip__count { font-family: var(--sl-mono); font-size: .82em; color: var(--sl-faint); }
.sl-facet-chip.is-active .sl-facet-chip__count { color: var(--sl-accent); opacity: .75; }
.sl-facet-more, .sl-facet-clear {
  background: none; border: 0; padding: 2px 4px; font: inherit; font-size: .85em;
  color: var(--sl-accent); cursor: pointer;
}
.sl-facet-more:hover, .sl-facet-clear:hover { text-decoration: underline; }
.sl-facet-clear { align-self: flex-start; margin-left: calc(110px + var(--sl-s-3)); }   /* label col + group gap */
@media (max-width: 760px) {
  .sl-facet-group { flex-direction: column; gap: 3px; }
  .sl-facet-clear { margin-left: 0; }
}

/* ── Tabs (underline default · pill segmented) ────────────────────────────────────
   Underline tabs for in-page section switching (docs, detail bodies); the pill variant
   is the compact segmented look for small option sets (calendar ranges). For a settings
   theme/density toggle, prefer .sl-segmented. */
.sl-tabs { display: flex; gap: var(--sl-gap-tight); flex-wrap: wrap; border-bottom: 1px solid var(--sl-line); }
.sl-tab { display: inline-flex; align-items: center; gap: var(--sl-gap-item); padding: .6em .8em; font-size: .92em; font-weight: 500;
  color: var(--sl-muted); background: none; border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px;
  cursor: pointer; text-decoration: none; transition: color .11s, border-color .11s; }
.sl-tab:hover { color: var(--sl-ink); }
.sl-tab.is-active { color: var(--sl-accent); border-bottom-color: var(--sl-accent); font-weight: 600; }
.sl-tab svg { width: 15px; height: 15px; }
.sl-tabs--pill { display: inline-flex; gap: 2px; flex-wrap: nowrap; padding: 2px; border: 1px solid var(--sl-line);
  border-radius: var(--sl-radius); background: var(--sl-surface-2); }
.sl-tabs--pill .sl-tab { border: 0; margin: 0; padding: .35em .8em; border-radius: var(--sl-radius-sm); }
.sl-tabs--pill .sl-tab.is-active { background: var(--sl-surface); color: var(--sl-ink); box-shadow: 0 1px 2px rgba(0, 0, 0, .06); }

/* ── Property list (Linear-style key/value rows) ──────────────────────────────────
   icon · label · value per row; the detail-page Properties/metadata panel. */
.sl-props { display: flex; flex-direction: column; }
.sl-props--card { padding: var(--sl-s-1); background: var(--sl-surface); border: 1px solid var(--sl-line); border-radius: var(--sl-radius); }
.sl-prop { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sl-gap-group); padding: var(--sl-s-2) var(--sl-s-3); font-size: .92em; }
.sl-prop__k { display: inline-flex; align-items: center; gap: var(--sl-gap-item); color: var(--sl-muted); flex-shrink: 0; }
.sl-prop__k svg { width: 14px; height: 14px; color: var(--sl-faint); }
.sl-prop__v { color: var(--sl-ink); font-weight: 500; text-align: right; min-width: 0; overflow-wrap: anywhere; }
/* Left-aligned variant — a fixed label column with the value beside it (Linear's issue rail). */
.sl-props--start .sl-prop { justify-content: flex-start; align-items: center; }
.sl-props--start .sl-prop__k { width: 5.5rem; }
.sl-props--start .sl-prop__v { text-align: left; font-weight: 400; }
/* Frameless quiet variant (Notion-style) — detail pages & slide-overs. No card chrome at
   all: a plain muted label column, regular-weight values (links in accent), and a generous
   row rhythm from the gap tokens instead of row padding. Quiet owns its layout — don't
   combine with --card/--start. */
.sl-props--quiet { gap: var(--sl-gap-group); }
.sl-props--quiet .sl-prop { justify-content: flex-start; align-items: center; padding: 0; gap: var(--sl-gap-group); }
.sl-props--quiet .sl-prop__k { width: 8.5rem; color: var(--sl-muted); font-weight: 400; }
.sl-props--quiet .sl-prop__v { text-align: left; font-weight: 400; }
.sl-props--quiet .sl-prop__v a { color: var(--sl-accent); text-decoration: none; }
.sl-props--quiet .sl-prop__v a:hover { text-decoration: underline; }

/* ── List page (index scaffold: title · count · lead · dense hairline rows) ───────
   The shell every index page shares (projects, personas, councils, …): a header with a
   title + a muted count + an optional lead and trailing actions (a search box), then a
   list of dense, hairline-separated rows. The rows are flatter than the bordered .sl-entity. */
.sl-list-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sl-s-4); }
.sl-list-title { margin: 0 0 var(--sl-gap-tight); font-size: 1.85em; font-weight: 650; letter-spacing: -.02em; line-height: 1.2; }
.sl-list-count { margin-left: .35em; font-size: .55em; font-weight: 500; color: var(--sl-faint); vertical-align: middle; }
.sl-list-lead { margin: 0 0 var(--sl-s-4); max-width: 74ch; color: var(--sl-muted); line-height: 1.5; }
.sl-list { margin-top: var(--sl-gap-item); border-top: 1px solid var(--sl-line); }
.sl-list-row { display: flex; align-items: center; gap: var(--sl-gap-group); width: 100%; min-height: var(--sl-row); padding: var(--sl-s-2) var(--sl-s-3);
  border: 0; border-bottom: 1px solid var(--sl-line); border-radius: var(--sl-radius-sm); background: none;
  font: inherit; color: var(--sl-ink); text-align: left; cursor: pointer; transition: background .11s; }
.sl-list-row:last-child { border-bottom: 0; }
.sl-list-row:hover { background: var(--sl-hover); }
.sl-list-row__title { flex: 1; min-width: 0; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-list-row__trailing { flex-shrink: 0; display: flex; align-items: center; gap: var(--sl-gap-group); color: var(--sl-faint); font-size: .85em; }

/* ── Page header (the detail-page hero: top slot · icon · title · sub · actions) ─── */
.sl-page-header { display: flex; align-items: flex-start; gap: var(--sl-s-4); }
.sl-page-header__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--sl-gap-item); }
.sl-page-header__top { display: flex; align-items: center; gap: var(--sl-gap-item); }
.sl-page-header__title { display: flex; align-items: center; gap: var(--sl-gap-group); margin: 0; font-size: 1.55em; font-weight: 650;
  line-height: 1.2; }
.sl-page-header__title svg { width: 1.05em; height: 1.05em; flex-shrink: 0; color: var(--sl-muted); }
.sl-page-header__sub { margin: 0; color: var(--sl-muted); max-width: 65ch; }
.sl-page-header__actions { flex-shrink: 0; display: flex; align-items: center; gap: var(--sl-gap-item); }

/* ── Detail layout (content column + sticky aside) and the scrollspy page rail ───── */
.sl-detail { display: grid; grid-template-columns: minmax(0, 1fr) 248px; gap: var(--sl-gap-region); align-items: start; }
.sl-detail__main { min-width: 0; display: flex; flex-direction: column; gap: var(--sl-gap-section); }
.sl-detail__aside { display: flex; flex-direction: column; gap: var(--sl-s-5); position: sticky; top: var(--sl-s-4); }
@media (max-width: 900px) {
  .sl-detail { grid-template-columns: 1fr; }
  .sl-detail__aside { position: static; }
}
.sl-rail { display: flex; flex-direction: column; gap: 2px; font-size: .85em; }
.sl-rail__head { font-size: .8em; letter-spacing: .02em; text-transform: uppercase; color: var(--sl-faint);
  font-weight: 600; margin-bottom: var(--sl-gap-tight); }
.sl-rail__item { color: var(--sl-muted); text-decoration: none; padding: 3px 0 3px var(--sl-s-3);
  border-left: 2px solid var(--sl-line); transition: color .12s, border-color .12s; }
.sl-rail__item:hover { color: var(--sl-ink); }
.sl-rail__item.is-active { color: var(--sl-ink); border-left-color: var(--sl-accent); }

/* ── Page scaffold (ONE scroll context per page) ──────────────────────────────────
   The layout contract that replaces every hand-rolled flex/scroll arrangement: a
   column filling its container with fixed `__head` (breadcrumb/title/actions) and
   `__bar` (filters, tabs) slots, and `__body` — THE one scroll container on the
   page. The rule: two nested scroll traps = bug. A child of `__body` must never set
   its own overflow or flex:1 (competing scrollers squeeze content to nothing — the
   inspector's outline-squeeze incident); only STRUCTURE may be sticky inside the
   body (phase headers, the `.sl-detail` rail). React <Scaffold> and the SSR app's
   ui.scaffold() emit this same markup, so the page skeleton can never drift. */
.sl-scaffold { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.sl-scaffold__head { flex: 0 0 auto; }
.sl-scaffold__bar { flex: 0 0 auto; }
.sl-scaffold__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

/* ── Section (quiet content group below the main canvas) ──────────────────────────
   A content-sized block in the page's centered 900px measure for below-content
   groups (decision records, assets, open questions): plain document flow — never
   flexed, never internally scrolled; anchor arrivals clear sticky headers via
   scroll-margin. The h2 stays at body size (a section is part of the page, not a
   new page); `__h` is the uppercase small group label inside a section. */
.sl-section { flex: 0 0 auto; width: 100%; max-width: 900px; margin: 0 auto; padding: 0 var(--sl-s-6); scroll-margin-top: var(--sl-s-2); }
.sl-section h2 { font-size: 1em; margin: 0 0 .45em; }
.sl-section__h { font-size: .92em; font-weight: 600; color: var(--sl-muted); text-transform: uppercase; letter-spacing: .04em; }

/* ── Clamp (dosed long-form text) ─────────────────────────────────────────────────
   Long authored prose in a row/peek context clamps to 5 lines; `.open` reveals the
   full text in place. `.sl-clamp-toggle` is the quiet accent text-button that flips
   it — the host wires the click (React <Clamp> holds state; the SSR app's ui.clamp()
   toggles the class inline). Authored prose is a feature of the DATA, not of the
   list: full text belongs on detail pages (UX contract C6). */
.sl-clamp { display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden; }
.sl-clamp.open { display: block; -webkit-line-clamp: unset; }
.sl-clamp-toggle { background: none; border: 0; padding: 0; margin: .3em 0 0; display: block;
  color: var(--sl-accent); font: inherit; font-size: .92em; cursor: pointer; }
.sl-clamp-toggle:hover { text-decoration: underline; }

/* ── Sparkline (compact inline trend) ─────────────────────────────────────────── */
.sl-spark { display: inline-block; vertical-align: middle; line-height: 0; }
.sl-spark svg { width: 100%; height: 100%; display: block; overflow: visible; }
.sl-spark__line { fill: none; stroke: var(--c); stroke-width: 1.5; vector-effect: non-scaling-stroke; stroke-linejoin: round; stroke-linecap: round; }
.sl-spark__fill { fill: var(--c); opacity: .12; stroke: none; }

/* ── Prose (rendered Markdown / rich text) ────────────────────────────────────────
   The one reading surface for generated long-form content — council findings, syntheses,
   SOUL docs, report bodies. Apply to the wrapper around rendered HTML; em-based, so it
   adapts to the host's base size (set the container's font-size to scale the whole block).
   Tables come from the shared .sl-table; headings/links/code/quotes are token-driven so the
   prose reads identically across the Python-SSR app and the React surfaces. */
.sl-prose { line-height: 1.62; color: var(--sl-ink); overflow-wrap: break-word; }
.sl-prose > :first-child { margin-top: 0; }
.sl-prose > :last-child { margin-bottom: 0; }
.sl-prose p { margin: 0 0 .9em; max-width: 70ch; }
.sl-prose strong { font-weight: 680; }
.sl-prose em { font-style: italic; }
.sl-prose del { color: var(--sl-muted); }
.sl-prose a { color: var(--sl-accent); text-decoration: none; }
.sl-prose a:hover { text-decoration: underline; }
.sl-prose h2 { font-size: 1.18em; font-weight: 680; line-height: 1.3; margin: 1.5em 0 .55em; }
.sl-prose h3 { font-size: 1.05em; font-weight: 680; margin: 1.4em 0 .45em; }
.sl-prose h4 { font-size: 1em; font-weight: 680; margin: 1.25em 0 .4em; }
.sl-prose ul, .sl-prose ol { margin: 0 0 .9em; padding-left: 1.5em; max-width: 70ch; }
.sl-prose li { margin: 0 0 .4em; }
.sl-prose li > ul, .sl-prose li > ol { margin: .4em 0 0; }
.sl-prose blockquote { margin: 0 0 .9em; padding: .55em 1em; max-width: 70ch;
  border-left: 3px solid var(--sl-accent); background: var(--sl-accent-weak);
  border-radius: 0 var(--sl-radius-sm) var(--sl-radius-sm) 0; }
.sl-prose blockquote > :last-child { margin-bottom: 0; }
.sl-prose code { font-family: var(--sl-mono); font-size: .88em; padding: .07em .35em;
  background: var(--sl-surface-2); border: 1px solid var(--sl-line); border-radius: var(--sl-radius-sm); }
.sl-prose pre { margin: 0 0 .9em; padding: .8em 1em; overflow-x: auto; max-width: 100%;
  background: var(--sl-surface-2); border: 1px solid var(--sl-line); border-radius: var(--sl-radius); }
.sl-prose pre code { padding: 0; background: none; border: 0; font-size: .9em; }
.sl-prose img { max-width: 100%; height: auto; }
.sl-prose hr { height: 1px; border: 0; background: var(--sl-line); margin: 1.5em 0; }
.sl-prose .sl-table { display: block; overflow-x: auto; margin: 1.1em 0; }
/* --sm: a denser variant for inline/aside prose (a card body, a drawer). */
.sl-prose--sm { font-size: .92em; line-height: 1.55; }

/* ── Calendar (persona-activity views: week agenda · month grid · year heatmap) ───
   The dense calendar shared by the Python-SSR app and the React data UI. The week/month/year
   switch is .sl-tabs--pill. Structural sizes stay px (the grid); type is em. The host builds the
   grid markup (per language); these classes style it identically. */
:root { --sl-cal-h0: #edeef2; --sl-cal-h1: #d8dcf7; --sl-cal-h2: #b2bbef; --sl-cal-h3: #838ee0; --sl-cal-h4: #5b67d1; }
[data-theme="dark"] { --sl-cal-h0: #1c1d21; --sl-cal-h1: #23284a; --sl-cal-h2: #343c80; --sl-cal-h3: #4a54b8; --sl-cal-h4: #5e6ad2; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --sl-cal-h0: #1c1d21; --sl-cal-h1: #23284a; --sl-cal-h2: #343c80; --sl-cal-h3: #4a54b8; --sl-cal-h4: #5e6ad2; } }
.sl-cal-nav { display: flex; align-items: center; justify-content: space-between; gap: var(--sl-gap-group); flex-wrap: wrap; margin: var(--sl-s-3) 0; }
.sl-cal-nav-l { display: flex; align-items: center; gap: var(--sl-gap-item); }
.sl-cal-arrow { width: var(--sl-ctl-sm); height: var(--sl-ctl-sm); display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius-sm); color: var(--sl-muted); font-size: 17px; line-height: 1; background: var(--sl-surface); }
.sl-cal-arrow:hover { background: var(--sl-hover); color: var(--sl-ink); }
.sl-cal-today { border: 1px solid var(--sl-line); border-radius: var(--sl-radius-sm); padding: var(--sl-s-1) var(--sl-s-3); font-size: .92em; color: var(--sl-ink); background: var(--sl-surface); }
.sl-cal-today:hover { background: var(--sl-hover); }
.sl-cal-title { font-size: 1.15em; font-weight: 600; color: var(--sl-ink); margin-left: var(--sl-s-2); }
/* event chip (week + month) — soft fill, leading type-coloured rule */
.sl-cev { display: flex; align-items: baseline; gap: 6px; border-left: 2.5px solid var(--sl-accent); background: var(--sl-surface-2);
  border-radius: var(--sl-radius-sm); padding: 2px 7px; font-size: .82em; color: var(--sl-ink); line-height: 1.45; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sl-cev .sl-cev-t { color: var(--sl-muted); font-variant-numeric: tabular-nums; flex: none; }
.sl-cev.focus { border-left-color: var(--sl-green); } .sl-cev.admin { border-left-color: var(--sl-amber); }
.sl-cev.interruption { border-left-color: var(--sl-red); } .sl-cev.meeting { border-left-color: var(--sl-accent); }
.sl-cev:hover { background: var(--sl-hover); }
/* WEEK: 7 agenda columns */
.sl-cal-week { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 1px; background: var(--sl-line); border: 1px solid var(--sl-line); border-radius: var(--sl-radius); overflow: hidden; }
.sl-cw-col { background: var(--sl-surface); min-height: 300px; } .sl-cw-col.we { background: var(--sl-surface-2); }
.sl-cw-h { padding: 8px 6px 9px; text-align: center; border-bottom: 1px solid var(--sl-line); position: relative; }
.sl-cw-wd { font-size: .82em; text-transform: uppercase; letter-spacing: .05em; color: var(--sl-muted); font-weight: 600; }
.sl-cw-d { font-size: 1.15em; font-weight: 550; margin-top: 3px; color: var(--sl-ink); }
.sl-cw-h.today .sl-cw-d { background: var(--sl-accent); color: #fff; width: 24px; height: 24px; line-height: 24px; border-radius: 50%; margin: 3px auto 0; }
.sl-cw-mood { position: absolute; top: 9px; right: 9px; width: 7px; height: 7px; border-radius: 50%; background: var(--sl-muted); }
.sl-cw-mood.pos { background: var(--sl-green); } .sl-cw-mood.neg { background: var(--sl-amber); } .sl-cw-mood.neu { background: var(--sl-line-2); }
.sl-cw-body { padding: var(--sl-s-2); display: flex; flex-direction: column; gap: var(--sl-gap-tight); }
.sl-cw-empty { color: var(--sl-faint); font-size: .92em; text-align: center; padding-top: 10px; }
/* MONTH: weekday grid */
.sl-cal-month { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 1px; background: var(--sl-line); border: 1px solid var(--sl-line); border-radius: var(--sl-radius); overflow: hidden; }
.sl-cm-wd { background: var(--sl-surface); padding: 7px 8px; font-size: .82em; text-transform: uppercase; letter-spacing: .05em; color: var(--sl-muted); font-weight: 600; }
.sl-cm-wd.we { color: var(--sl-faint); }
.sl-cm-cell { background: var(--sl-surface); min-height: 108px; padding: 6px 7px 9px; position: relative; display: flex; flex-direction: column; gap: 3px; }
.sl-cm-cell.out { background: var(--sl-bg); } .sl-cm-cell.we { background: var(--sl-surface-2); }
.sl-cm-num { font-size: .92em; font-weight: 500; color: var(--sl-ink); align-self: flex-start; }
.sl-cm-cell.out .sl-cm-num { color: var(--sl-faint); }
.sl-cm-num.today { background: var(--sl-accent); color: #fff; min-width: 21px; height: 21px; line-height: 21px; text-align: center; border-radius: 50%; }
.sl-cm-more { font-size: .82em; color: var(--sl-muted); } .sl-cm-more:hover { color: var(--sl-accent); }
.sl-cm-mood { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--sl-line-2); }
.sl-cm-mood.pos { background: var(--sl-green); } .sl-cm-mood.neg { background: var(--sl-amber); } .sl-cm-mood.neu { background: var(--sl-line-2); }
/* YEAR: activity heatmap */
.sl-cal-year { display: flex; gap: 9px; align-items: flex-start; overflow-x: auto; overflow-y: hidden; padding: 6px 2px 2px; }
.sl-cy-wd { display: grid; grid-template-rows: repeat(7, 11px); gap: 3px; padding-top: 18px; }
.sl-cy-wd span { font-size: 9px; line-height: 11px; height: 11px; color: var(--sl-muted); }
.sl-cy-main { min-width: 0; }
.sl-cy-mons { display: grid; gap: 3px; height: 14px; margin-bottom: 4px; }
.sl-cy-mon { font-size: .82em; color: var(--sl-muted); font-weight: 500; white-space: nowrap; }
.sl-cy-grid { display: grid; grid-template-rows: repeat(7, 11px); grid-auto-flow: column; grid-auto-columns: 11px; gap: 3px; }
.sl-cy-cell { width: 11px; height: 11px; border-radius: 3px; background: var(--sl-cal-h0); display: block; }
a.sl-cy-cell:hover { outline: 1.5px solid var(--sl-accent); outline-offset: 1px; }
.sl-cy-cell.empty { background: transparent; }
.sl-cy-cell.l0 { background: var(--sl-cal-h0); } .sl-cy-cell.l1 { background: var(--sl-cal-h1); } .sl-cy-cell.l2 { background: var(--sl-cal-h2); } .sl-cy-cell.l3 { background: var(--sl-cal-h3); } .sl-cy-cell.l4 { background: var(--sl-cal-h4); }
.sl-cy-cell.today { box-shadow: 0 0 0 1.5px var(--sl-accent); }
.sl-cy-legend { display: flex; justify-content: flex-end; align-items: center; gap: 5px; margin: 12px 2px 0; font-size: .82em; color: var(--sl-muted); }
.sl-cy-swatch { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }
.sl-cy-swatch.l0 { background: var(--sl-cal-h0); } .sl-cy-swatch.l1 { background: var(--sl-cal-h1); } .sl-cy-swatch.l2 { background: var(--sl-cal-h2); } .sl-cy-swatch.l3 { background: var(--sl-cal-h3); } .sl-cy-swatch.l4 { background: var(--sl-cal-h4); }

/* ── File card (file-first asset presentation) ─────────────────────────────────────
   An asset rendered as a FILE, not a generic row: a prominent type identity on a quiet
   stage (an uppercase extension badge derived from the media type — PPTX · PNG · PDF ·
   CSV — or an image thumbnail), the filename WITH its extension as the title, a faint
   size · date meta line, and exactly ONE trailing action slot (a download IconButton —
   never duplicated affordances). .sl-file-grid lays cards out responsively;
   .sl-file--row is the compact list variant for dense lenses. The badge tone follows the
   type family (--red docs that print, --amber decks, --green sheets/data, --blue text,
   --violet images); unknown types stay neutral. */
.sl-file { display: flex; flex-direction: column; min-width: 0; background: var(--sl-surface);
  border: 1px solid var(--sl-line); border-radius: var(--sl-radius); overflow: hidden;
  color: inherit; text-decoration: none; transition: background .12s, border-color .12s; }
a.sl-file:hover, button.sl-file:hover { background: var(--sl-hover); border-color: color-mix(in srgb, var(--sl-ink) 14%, var(--sl-line)); }
.sl-file__stage { display: flex; align-items: center; justify-content: center; height: 84px;
  background: var(--sl-surface-2); border-bottom: 1px solid var(--sl-line-2); overflow: hidden; }
.sl-file__thumb { width: 100%; height: 100%; object-fit: cover; }
.sl-file__ext { font-family: var(--sl-mono); font-size: .72em; font-weight: 650; letter-spacing: .08em; line-height: 1;
  text-transform: uppercase; padding: .5em .75em; border-radius: var(--sl-radius-sm);
  color: var(--sl-muted); background: var(--sl-surface); border: 1px solid var(--sl-line);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--sl-ink) 5%, transparent); }
.sl-file__ext--red    { color: var(--sl-red);    background: color-mix(in srgb, var(--sl-red) 8%, var(--sl-surface));    border-color: color-mix(in srgb, var(--sl-red) 30%, transparent); }
.sl-file__ext--amber  { color: var(--sl-amber);  background: color-mix(in srgb, var(--sl-amber) 8%, var(--sl-surface));  border-color: color-mix(in srgb, var(--sl-amber) 30%, transparent); }
.sl-file__ext--green  { color: var(--sl-green);  background: color-mix(in srgb, var(--sl-green) 8%, var(--sl-surface));  border-color: color-mix(in srgb, var(--sl-green) 30%, transparent); }
.sl-file__ext--blue   { color: var(--sl-blue);   background: color-mix(in srgb, var(--sl-blue) 8%, var(--sl-surface));   border-color: color-mix(in srgb, var(--sl-blue) 30%, transparent); }
.sl-file__ext--violet { color: var(--sl-violet); background: color-mix(in srgb, var(--sl-violet) 8%, var(--sl-surface)); border-color: color-mix(in srgb, var(--sl-violet) 30%, transparent); }
.sl-file__body { display: flex; align-items: center; gap: var(--sl-gap-item); min-height: var(--sl-row); padding: var(--sl-s-2) var(--sl-s-3); }
.sl-file__info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.sl-file__name { font-size: .92em; font-weight: 500; color: var(--sl-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-file__meta { font-size: .8em; color: var(--sl-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sl-file__action { flex: none; display: inline-flex; align-items: center; }
.sl-file-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: var(--sl-gap-group); }
/* Compact row — the dense list/lens variant: a small identity square, then name + meta. */
.sl-file--row { flex-direction: row; align-items: stretch; }
.sl-file--row .sl-file__stage { flex: none; width: 56px; height: auto; border-bottom: 0; border-right: 1px solid var(--sl-line-2); }
.sl-file--row .sl-file__ext { font-size: .62em; padding: .45em .55em; letter-spacing: .06em; }
.sl-file--row .sl-file__body { min-height: var(--sl-row-h); }

/* ── Likelihood (labelled probability: percentage + 40px mini-bar) ─────────────────
   The presentation contract for predicted behaviour ("85 %" beside a fixed mini-bar).
   Pure markup — SSR-friendly; the fill width comes from --p (0–100) set inline. Tone
   shifts at thresholds via the modifier the host applies: --high (≥ 70) green,
   --mid (≥ 40) amber, --low red; unmodified stays accent. */
.sl-likelihood { display: inline-flex; align-items: center; gap: var(--sl-gap-item);
  font-variant-numeric: tabular-nums; --tone: var(--sl-accent); }
.sl-likelihood__val { font-size: .92em; font-weight: 600; color: var(--sl-ink); white-space: nowrap; }
.sl-likelihood__bar { flex: none; width: 40px; height: 4px; border-radius: var(--sl-radius-full);
  background: var(--sl-surface-2); overflow: hidden; }
.sl-likelihood__fill { display: block; height: 100%; width: calc(var(--p, 0) * 1%);
  border-radius: var(--sl-radius-full); background: var(--tone); }
.sl-likelihood--high { --tone: var(--sl-green); }
.sl-likelihood--mid  { --tone: var(--sl-amber); }
.sl-likelihood--low  { --tone: var(--sl-red); }
