/* Branding mirrors Levirge Command (assets/css/ui/_ui-theme.css) — "Claude
   Desktop dark" warm clay chrome so Brain reads as one product with Command.

   BASE LAYER ONLY: reset, page grid, header/footer shell, nav, and shared
   primitives. Everything component-specific lives in
   assets/components/<name>/_<name>.css, inlined by the @imports at the end of
   this file (CssBuilder resolves relative @imports at build time).

   Design tokens are NOT defined here — they come from _tokens.css, a copy of
   the canonical design/tokens.css. Do not add a :root block to this file; add
   the token to design/tokens.css and re-copy. See design/STYLE-GUIDE.md. */

/* ─── Levirge canonical design tokens ─────────────────────────────────────────
   Single source of truth for all 5 UIs: app, admin, command, brain, agent-search.
   See design/STYLE-GUIDE.md for the name map, collisions, and adoption steps.

   Derived from app/assets/css/_ui-theme.css (the richest set — only one with a
   light mode, type scale, and dual shadows), with neutrals warmed to hue 48–60
   to match brain / command / agent-search. Values equal brain's hexes where the
   two families already agreed.

   Dark is default. Light via [data-theme="light"] on <html>.
   ponytail: no build step — repos copy this file and @import it. */

:root {
  /* ─── Neutrals — 3 required tiers + sidebar/hover/inset ───────────── */
  --bg-base: hsl(60 2% 12%); /* page canvas */
  --bg-sidebar: hsl(60 3% 10%); /* nav rail — below the canvas */
  --bg-surface: hsl(0 0% 15%); /* cards, panels */
  --bg-raised: hsl(60 3% 17%); /* selected rows, dropdowns */
  --bg-hover: hsl(60 3% 21%); /* one shade above resting */
  --bg-inset: hsl(60 3% 6%); /* tables, inputs, code blocks */

  /* ─── Borders — alpha overlays, so they work on any tier ──────────── */
  --line-1: hsl(0 0% 100% / 0.06); /* hairline, same-tier division */
  --line-2: hsl(0 0% 100% / 0.10); /* default border */
  --line-3: hsl(0 0% 100% / 0.18); /* emphasis / focus ring base */
  --top-highlight: hsl(0 0% 100% / 0.06); /* top edge of raised surfaces */

  /* ─── Foreground — 4 steps ────────────────────────────────────────── */
  --fg-0: hsl(48 12% 92%); /* headings */
  --fg-1: hsl(43 7% 70%); /* body */
  --fg-2: hsl(44 5% 52%); /* secondary / captions */
  --fg-3: hsl(44 4% 36%); /* disabled */

  /* ─── Brand accent — amber ────────────────────────────────────────── */
  --accent: oklch(0.731 0.132 73.9);
  --accent-hi: oklch(0.8 0.132 73.9); /* hover */
  --accent-soft: oklch(0.731 0.132 73.9 / 0.18); /* tinted fill */
  --accent-line: oklch(0.731 0.132 73.9 / 0.42); /* tinted border */
  /* Text/icon ON an accent fill. Tracks the canvas, so it stays readable in both
     modes: near-black on bright amber (dark), white on deep amber (light). */
  --accent-fg: var(--bg-base);
  --link: var(--accent); /* links use the accent everywhere (was blue, hue 250) */

  /* ─── Semantic status ─────────────────────────────────────────────── */
  --ok: oklch(0.74 0.13 150); /* was brain/command `--accent` */
  --warn: oklch(0.78 0.14 75);
  --error: oklch(0.7 0.18 18);
  --idle: hsl(44 4% 38%);
  --status-online: var(--ok);
  --status-degraded: var(--warn);
  --status-error: var(--error);
  --status-offline: var(--idle);
  --status-unknown: transparent;

  /* ─── Environment palette — 6 assignable hues ─────────────────────── */
  --env-slate: oklch(0.72 0.02 270);
  --env-cyan: oklch(0.72 0.13 220);
  --env-mint: oklch(0.78 0.14 160);
  --env-amber: oklch(0.8 0.14 78);
  --env-rose: oklch(0.7 0.18 18);
  --env-iris: oklch(0.74 0.13 290);

  --env-slate-soft: oklch(0.72 0.02 270 / 0.2);
  --env-cyan-soft: oklch(0.72 0.13 220 / 0.22);
  --env-mint-soft: oklch(0.78 0.14 160 / 0.22);
  --env-amber-soft: oklch(0.8 0.14 78 / 0.22);
  --env-rose-soft: oklch(0.7 0.18 18 / 0.22);
  --env-iris-soft: oklch(0.74 0.13 290 / 0.22);

  --env-slate-line: oklch(0.72 0.02 270 / 0.55);
  --env-cyan-line: oklch(0.72 0.13 220 / 0.6);
  --env-mint-line: oklch(0.78 0.14 160 / 0.6);
  --env-amber-line: oklch(0.8 0.14 78 / 0.6);
  --env-rose-line: oklch(0.7 0.18 18 / 0.6);
  --env-iris-line: oklch(0.74 0.13 290 / 0.6);

  /* ─── Syntax highlighting ─────────────────────────────────────────── */
  --syn-keyword: oklch(0.78 0.13 290);
  --syn-string: oklch(0.78 0.1 145);
  --syn-number: oklch(0.8 0.13 75);
  --syn-ident: var(--fg-0);
  --syn-comment: hsl(44 5% 44%);
  --syn-fn: oklch(0.82 0.1 290);

  /* ─── Shadows — always two layers: contact + ambient ──────────────── */
  --shadow-sm: 0 1px 2px hsl(0 0% 0% / 0.4), 0 4px 12px hsl(0 0% 0% / 0.22);
  --shadow-md: 0 1px 3px hsl(0 0% 0% / 0.45), 0 8px 24px hsl(0 0% 0% / 0.28);
  --shadow-lg: 0 2px 4px hsl(0 0% 0% / 0.5), 0 16px 40px hsl(0 0% 0% / 0.34);
  --shadow-inset: inset 0 2px 4px hsl(0 0% 0% / 0.32), inset 0 -1px 1px hsl(0 0% 100% / 0.04);
  --shadow-selected: inset 0 1px 0 hsl(0 0% 100% / 0.06), inset 0 -1px 0 hsl(0 0% 0% / 0.18);

  /* ─── Typography ──────────────────────────────────────────────────── */
  /* system-ui + "Segoe UI" are load-bearing on Windows — brain and
     agent-search both had them; app's stack did not. Superset of all three. */
  --font-sans:
    ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue",
        Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

  /* Size scale — t-N = Npx / 16 rem */
  --t-11: 0.6875rem;
  --t-12: 0.75rem;
  --t-13: 0.8125rem;
  --t-14: 0.875rem; /* default body */
  --t-16: 1rem;
  --t-20: 1.25rem;
  --t-28: 1.75rem;

  /* ─── Radii ───────────────────────────────────────────────────────── */
  --r-2: 0.125rem;
  --r-4: 0.25rem;
  --r-6: 0.375rem;
  --r-8: 0.5rem;
  --r-12: 0.75rem; /* dialogs and large cards — .ui-dialog, onboarding panels */
  --r-pill: 624.9375rem;

  /* ─── Row heights — dense-UI rhythm ───────────────────────────────── */
  --row-tight: 1.5rem;
  --row: 1.75rem;
  --row-loose: 2rem;
}

/* ─── LIGHT MODE — white canvas, warm grey chrome ──────────────────────── */
[data-theme="light"] {
  --bg-base: hsl(0 0% 100%);
  --bg-sidebar: hsl(36 12% 95%);
  --bg-surface: hsl(36 12% 97%);
  --bg-raised: hsl(0 0% 100%);
  --bg-hover: hsl(36 16% 93%);
  --bg-inset: hsl(36 12% 91%);

  --line-1: hsl(30 18% 16% / 0.07);
  --line-2: hsl(30 18% 16% / 0.13);
  --line-3: hsl(30 18% 16% / 0.22);
  --top-highlight: hsl(0 0% 100% / 0.85);

  --fg-0: hsl(30 18% 10%);
  --fg-1: hsl(30 12% 24%);
  --fg-2: hsl(30 8% 40%);
  --fg-3: hsl(30 6% 56%);

  --accent: oklch(0.56 0.132 73.9);
  --accent-hi: oklch(0.48 0.14 73.9);
  --accent-soft: oklch(0.56 0.132 73.9 / 0.14);
  --accent-line: oklch(0.56 0.132 73.9 / 0.42);
  --link: var(--accent);

  --ok: oklch(0.55 0.15 150);
  --warn: oklch(0.62 0.15 68);
  --error: oklch(0.55 0.2 18);
  --idle: hsl(30 6% 60%);

  --env-slate: oklch(0.5 0.02 270);
  --env-cyan: oklch(0.55 0.14 220);
  --env-mint: oklch(0.55 0.15 155);
  --env-amber: oklch(0.62 0.16 72);
  --env-rose: oklch(0.55 0.2 18);
  --env-iris: oklch(0.5 0.16 290);

  --env-slate-soft: oklch(0.5 0.02 270 / 0.14);
  --env-cyan-soft: oklch(0.55 0.14 220 / 0.14);
  --env-mint-soft: oklch(0.55 0.15 155 / 0.14);
  --env-amber-soft: oklch(0.62 0.16 72 / 0.16);
  --env-rose-soft: oklch(0.55 0.2 18 / 0.14);
  --env-iris-soft: oklch(0.5 0.16 290 / 0.14);

  --env-slate-line: oklch(0.5 0.02 270 / 0.55);
  --env-cyan-line: oklch(0.55 0.14 220 / 0.55);
  --env-mint-line: oklch(0.55 0.15 155 / 0.55);
  --env-amber-line: oklch(0.62 0.16 72 / 0.6);
  --env-rose-line: oklch(0.55 0.2 18 / 0.55);
  --env-iris-line: oklch(0.5 0.16 290 / 0.55);

  --syn-keyword: oklch(0.5 0.16 290);
  --syn-string: oklch(0.45 0.13 150);
  --syn-number: oklch(0.55 0.14 60);
  --syn-comment: hsl(30 6% 56%);
  --syn-fn: oklch(0.42 0.18 290);

  --shadow-sm: 0 1px 2px hsl(30 18% 16% / 0.06), 0 6px 18px hsl(30 18% 16% / 0.06);
  --shadow-md: 0 1px 3px hsl(30 18% 16% / 0.08), 0 12px 32px hsl(30 18% 16% / 0.08);
  --shadow-lg: 0 2px 6px hsl(30 18% 16% / 0.1), 0 20px 48px hsl(30 18% 16% / 0.1);
  --shadow-inset: inset 0 2px 4px hsl(30 18% 16% / 0.1), inset 0 -1px 1px hsl(0 0% 100% / 0.5);
  --shadow-selected: inset 0 1px 0 hsl(0 0% 100% / 0.6), inset 0 -1px 0 hsl(30 18% 16% / 0.06);
}

/* ─── Icon filters — theme-aware tint for <img>-based SVG icons ────────── */
:root {
  --icon-filter-0: brightness(0) invert(1);
  --icon-filter-1: brightness(0) invert(1) opacity(0.74);
  --icon-filter-2: brightness(0) invert(1) opacity(0.51);
  --icon-filter-3: brightness(0) invert(1) opacity(0.34);
}
[data-theme="light"] {
  --icon-filter-0: brightness(0);
  --icon-filter-1: brightness(0) opacity(0.7);
  --icon-filter-2: brightness(0) opacity(0.48);
  --icon-filter-3: brightness(0) opacity(0.28);
}

/* ─── LEGACY ALIASES ──────────────────────────────────────────────────────
   Compatibility shims so an existing UI can adopt this file without a
   rewrite. MUST NOT be used in new code. Delete a block once its repo's CSS
   has been sed'd to canonical names.

   Two names could NOT be aliased — they mean different things in the two
   families and must be renamed at the call site on adoption:
     • `--accent`  — amber in app/admin, GREEN in brain/command/agent-search.
                     Green is now `--ok`.
     • `--line-2`  — mid border in app, STRONG border in brain/command/
                     agent-search. Their `--line-2` is now `--line-3`. */
:root {
  /* app */
  --bg-0: var(--bg-base);
  --bg-1: var(--bg-surface);
  --bg-2: var(--bg-raised);
  --bg-3: var(--bg-hover);
  --font-size-xs: var(--t-11);
  --font-size-sm: var(--t-12);
  --font-size-md: var(--t-14);
  --font-size-base: var(--t-16);
  --font-size-lg: var(--t-16);
  --font-size-xl: var(--t-20);
  --font-size-2xl: var(--t-28);
  --radius-xs: var(--r-2);
  --radius-sm: var(--r-4);
  --radius-md: var(--r-6);
  --radius-lg: var(--r-8);
  --radius-pill: var(--r-pill);
  --row-height-tight: var(--row-tight);
  --row-height: var(--row);
  --row-height-loose: var(--row-loose);
  --border-color: var(--line-2);
  --border-width: 0.0625rem;
  --border-radius: var(--r-8);
  --button-border-radius: var(--r-8);
  --icon-filter-primary: var(--icon-filter-0);
  --icon-filter-secondary: var(--icon-filter-1);
  --icon-filter-muted: var(--icon-filter-2);
  --icon-filter-disabled: var(--icon-filter-3);

  /* brain / command / agent-search */
  --bg: var(--bg-base);
  --sidebar: var(--bg-sidebar);
  --panel: var(--bg-surface);
  --panel-2: var(--bg-raised);
  --raised: var(--bg-raised);
  --code-bg: var(--bg-inset);
  --line: var(--line-2);
  --text: var(--fg-0);
  --muted: var(--fg-1);
  --faint: var(--fg-2);
  --brand: var(--accent);
  --clay: var(--accent-hi);
  --clay-soft: var(--accent-soft);
  --stuck: var(--error);
  --question: var(--link);

  /* agent-search — already aliased onto canonical semantics */
  --text-primary: var(--fg-0);
  --text-muted: var(--fg-1);
  --border: var(--line-2);
  --highlight: var(--accent);
}

/* NOT here, deliberately — product-specific semantic palettes stay in their own
   repo, because canonical cannot know how many values must stay mutually
   distinguishable:
     • command `--st-*` (issue statuses) — these render as ADJACENT kanban column
       borders and status buttons, so `planning` and `in_review` must not collapse
       to one hue. Canonical has a single violet (`--env-iris`); command needs two.
     • command `--agent`, brain `--km-*` (knowledge-map hues), admin `--topbar-h` /
       `--nav-w` (layout constants).
   Each lives in its own repo's CSS and may reference canonical tokens. */


*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
html {
  font-size: 16px;
}
body {
  font: 1rem ui-sans-serif, -apple-system, "Segoe UI", system-ui, sans-serif;
  background: var(--bg);
  color: var(--text);
  display: grid;
  grid-template-columns: 20rem 1fr;
  grid-template-rows: auto 1fr auto auto;
  grid-template-areas:
    "header  header"
    "sidebar main"
    "drawer  main"
    "footer  footer";
  gap: 0.5rem;
  padding: 0.5rem;
  height: 100vh;
  overflow: hidden;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
.app-header {
  grid-area: header;
  display: grid;
  grid-template-columns: subgrid;
  align-items: center;
  gap: 0.45rem;
  padding: 0.2rem 0.5rem;
  /* Column 1 of the header subgrid (sidebar width): logo left, the Help and
     Settings icons right-aligned at its edge. */
  .brand-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
  }
  .brand-actions {
    display: grid;
    grid-auto-flow: column;
    align-items: center;
    gap: 0.15rem;

    a {
      display: grid;
      place-items: center;
      padding: 0.3rem;
      border-radius: 0.375rem;
      color: var(--muted);
      opacity: 0.5;
      transition: opacity 0.15s, color 0.15s, background 0.15s;

      &:hover {
        opacity: 1;
        color: var(--text);
        background: var(--raised);
      }
      &.active {
        opacity: 1;
        color: var(--text);
      }
    }

    .icon {
      display: block;
      width: 1.2rem;
      height: 1.2rem;
      background: currentColor;
      mask: no-repeat center / contain;
      &.icon-help {
        mask-image: url("/img/help.svg");
      }
      &.icon-settings {
        mask-image: url("/img/settings.svg");
      }
      &.icon-add {
        mask-image: url("/img/add.svg");
      }
    }
  }
  .brand {
    text-decoration: none;
    display: grid;
    align-items: center;
    /* Logo and the "Dashboard" label share one cell; hover or keyboard focus
       swaps them, so the logo reads as the link home. */
    & > * {
      grid-area: 1 / 1;
      transition: opacity 150ms ease;
    }
    .brand-home {
      display: grid;
      grid-auto-flow: column;
      justify-content: start;
      align-items: center;
      gap: 0.4rem;
      color: var(--text);
      font-size: 0.95rem;
      font-weight: 600;
      opacity: 0;
    }
    .icon-home {
      display: block;
      width: 1.2rem;
      height: 1.2rem;
      background: currentColor;
      mask: url("/img/home.svg") no-repeat center / contain;
    }
    &:hover,
    &:focus-visible {
      .brand-logo { opacity: 0; }
      .brand-home { opacity: 1; }
    }
    @media (prefers-reduced-motion: reduce) {
      & > * { transition: none; }
    }
  }
  & > section {
    display: grid;
    grid-template-columns: 1fr auto;
    justify-content: space-between;
    align-items: center;
    gap: 2rem;
  }
  /* Page title shares the Ask bar's cell; only one is visible at a time. */
  & > section > .header-title,
  & > section > #query-form { grid-area: 1 / 1; }
  .header-title {
    display: none;
    /* #main's 2rem side padding, so the title lines up with the page content. */
    padding-inline-start: 2rem;
    font-size: 1.15rem;
    font-weight: 650;
    color: var(--text);
  }
}
html[data-onboarding] .app-header .header-title { display: block; }
.app-header .header-title-page { display: block; }
/* Wizard position at the start of a title (Step 2.3 of 5), in the accent. */
.app-header .header-step { color: var(--accent-hi); }
.app-header .header-actions[hidden],
.app-header .header-actions [hidden] { display: none; }
/* Secondary header action (setup Back): outlined, so the accent Next reads as the way on. */
.app-header .header-btn.header-btn-ghost {
  background: none;
  border-color: var(--line-3);
  color: var(--text);
}
/* Context beside a page title (e.g. the plan) — lighter so the title reads first. */
.app-header .header-title-sub {
  color: var(--muted);
  font-weight: 500;

  /* Breadcrumb step (Settings > Users > name) — same muted text, underline on hover. */
  a {
    color: inherit;
    text-decoration: none;
    &:hover { color: var(--text); text-decoration: underline; }
  }
}
/* Settings header actions (_header.eta): Overview's health icons + Manage
   Billing, Users' + Add User, Vaults' + Add Vault, Ingest's Retry all failed — in the app header's right column where #page-nav sits elsewhere. */
.app-header {
  .header-actions {
    display: flex;
    align-items: center;
    gap: 1rem;
  }
  /* Ingest filters: label text inline with its control so the header stays
     one row. */
  .inbox-filters {
    display: flex;
    align-items: center;
    gap: 0.75rem;

    label {
      display: flex;
      align-items: center;
      gap: 0.4rem;
      color: var(--muted);
      font-size: 0.75rem;
    }
    input,
    select {
      box-sizing: border-box;
      height: 2rem;
      background: var(--bg);
      color: var(--text);
      border: 1px solid var(--line);
      border-radius: 0.3rem;
      padding: 0 0.45rem;
      font: inherit;
      font-size: 0.82rem;
    }
    input { width: 5rem; }
  }
  /* Solid accent action in the header (Manage Billing, + Add User). */
  /* <a> and <button> inherit different line-heights (1.5 vs normal), so the
     height is pinned — every header control is 2rem tall. */
  .header-btn {
    display: inline-flex;
    align-items: center;
    box-sizing: border-box;
    height: 2rem;
    line-height: 1;
    font-family: inherit;
    cursor: pointer;
    padding: 0 0.75rem;
    border: 1px solid var(--accent);
    border-radius: 0.4rem;
    background: var(--accent);
    color: var(--accent-fg);
    font-size: 0.85rem;
    font-weight: 600;
    text-decoration: none;
    transition: filter 0.15s;

    &[hidden] { display: none; }
    &:hover:not(:disabled) {
      filter: brightness(1.08);
    }
    &:disabled {
      opacity: 0.6;
      cursor: default;
    }
    &:focus-visible {
      outline: 0.125rem solid var(--brand);
      outline-offset: 0.125rem;
    }
  }

  .settings-health {
    display: flex;
    align-items: center;
    gap: 0.6rem;
  }

  /* Masked glyph tinted by state — colour IS the signal, the tooltip carries
     the words. Focusable so keyboard users can reach the tooltip too. */
  .health-dot {
    width: 1.15rem;
    height: 1.15rem;
    background: currentColor;
    mask: no-repeat center / contain;
    cursor: help;

    &.health-docs { mask-image: url("/img/docs.svg"); }
    &.health-hub { mask-image: url("/img/hub.svg"); }
    &.health-search { mask-image: url("/img/search.svg"); }

    &[data-state="ok"] { color: var(--ok); }
    &[data-state="bad"] { color: var(--stuck); }
    &[data-state="unknown"] { color: var(--faint); }

    &:focus-visible {
      outline: 0.125rem solid var(--brand);
      outline-offset: 0.125rem;
    }
  }
}

/* Levirge Brain wordmark (icon + name in one SVG, ~6.4:1). */
.app-header .brand-logo {
  display: block;
  height: 1.75rem;
  width: auto;
}
.app-footer {
  grid-area: footer;
  /* auto columns + space-between: children stay content-sized (a 1fr track
     would stretch ui-conn-status and spread its dot from its label). */
  display: grid;
  grid-auto-flow: column;
  justify-content: space-between;
  align-items: center;
  padding: 0.1rem 0.75rem;
  font-size: 0.72rem;
  color: var(--faint);
  .footer-link {
    color: var(--faint);
    text-decoration: none;
    &:hover {
      color: var(--clay);
    }
  }
}
::-webkit-scrollbar {
  width: 6px;
}
::-webkit-scrollbar-track {
  background: transparent;
}
::-webkit-scrollbar-thumb {
  background: var(--line-3);
  border-radius: 3px;
}
#sidebar {
  grid-area: sidebar;
  min-width: 16px;
  background: var(--panel);
  border: 1px solid var(--line);
  /* bottom is closed by the flush ui-account-drawer below it */
  border-bottom: none;
  border-radius: 0.5rem 0.5rem 0 0;
  overflow: hidden;
  /* Stacked rows; the LAST child fills so its list scrolls internally. Sidebars
     hold 1–3 children (a component, or header + nav + component), hence the
     ladder — grid can't say "last row gets 1fr" without knowing the count. */
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  &:has(> :nth-child(2)) {
    grid-template-rows: auto minmax(0, 1fr);
  }
  &:has(> :nth-child(3)) {
    grid-template-rows: auto auto minmax(0, 1fr);
  }
}
#main {
  grid-area: main;
  overflow-y: auto;
  padding: 1.5rem 2rem;
}
/* Table pages (Settings → Users/Vaults/Ingest): the table's header row lines up with
   the sidebar section header ("SETTINGS"), so less top padding — and its footer (the
   count) lines up with the bottom of the sidebar/account drawer, so none at the bottom
   (the body's 0.5rem gap is the only space left before the app footer). */
#main.table-page {
  padding-top: 0.6rem;
  padding-bottom: 0;
}
/* Avatar tile — vault detail, user detail, Profile (lib/_avatar.ts). One
   control: a label wrapping the hidden file input, so the whole tile is the
   click target for upload/replace. Both children share one grid cell; exactly
   one is unhidden once the image loads or 404s. */
.avatar-field {
  display: grid;
  width: 3.5rem;
  height: 3.5rem;
  cursor: pointer;
  position: relative;

  .avatar-preview,
  .avatar-none {
    grid-area: 1 / 1;
    width: 3.5rem;
    height: 3.5rem;
    border-radius: 0.5rem;
  }
  .avatar-preview {
    object-fit: contain;
    border: 1px solid var(--line);
    background: var(--bg);
  }
  .avatar-none {
    border: 1px dashed var(--line);
    display: grid;
    place-items: center;
    text-align: center;
    color: var(--faint);
    font-size: 0.62rem;
  }
  /* After .avatar-none on purpose: equal specificity, the later display wins, and
     the UA [hidden] rule loses to any class' display — without this the
     placeholder (text + dashed border) shows over the loaded image. */
  .avatar-preview[hidden],
  .avatar-none[hidden] {
    display: none;
  }
  /* Hover affordance — the tile is the button, so it must say so. */
  &::after {
    content: "";
    grid-area: 1 / 1;
    border-radius: 0.5rem;
    background: hsl(0 0% 0% / 0.45);
    opacity: 0;
    transition: opacity 0.15s;
  }
  &:hover::after,
  &:focus-within::after {
    opacity: 1;
  }
  &:focus-within {
    outline: 2px solid var(--brand);
    outline-offset: 2px;
    border-radius: 0.5rem;
  }
  &[data-busy="true"] {
    cursor: progress;
    opacity: 0.6;
  }
}
/* Busy button — disabled with an inline spinner while its request is in
   flight. JS sets disabled + aria-busy="true" and clears both when done. */
button[aria-busy="true"] {
  cursor: progress;
  &::after {
    content: "";
    display: inline-block;
    inline-size: 0.8em;
    block-size: 0.8em;
    margin-inline-start: 0.5em;
    vertical-align: -0.1em;
    border: 0.15em solid currentColor;
    border-inline-end-color: transparent;
    border-radius: 50%;
    animation: btn-spin 0.7s linear infinite;
  }
  @media (prefers-reduced-motion: reduce) {
    &::after { animation-duration: 2s; }
  }
}
@keyframes btn-spin {
  to { rotate: 360deg; }
}
/* Shared primitives — any component may render these states. */
.loading {
  color: var(--faint);
  font-size: 0.85rem;
  padding: 2rem 0;
}
.error {
  color: var(--stuck);
  font-size: 0.85rem;
  padding: 1rem 0;
}
/* Sidebar placeholder for pages with no list (Metrics, Ask) — page templates
   render this directly; no component owns it. */
.sidebar-empty {
  padding: 1rem;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--faint);
}
/* Settings page wrapper — lives on <main> in the _page-settings-* templates.
   Left-aligned (not centred) and wider than before, but still capped: long
   measure hurts the link-card and metrics grids more than the extra room
   helps. */
.settings-page {
  max-width: 84rem;
  margin: 0;
  padding: 1.5rem;
  display: grid;
  gap: 1.5rem;
}
/* Sign-in page — standalone SSR template (templates/login.eta), no app chrome.
   The .brand styles above are scoped to .app-header, so the card carries its
   own sizing for the same marks. */
#login-page {
  min-height: 100vh;
  display: grid;
  /* The base `body` rule is the app-shell grid (20rem sidebar + named areas);
     this page has no chrome, so reset all three template axes or the card
     lands in the sidebar column. */
  grid-template-columns: 1fr;
  grid-template-rows: 1fr auto;
  grid-template-areas: none;
  place-items: center;
  background: var(--bg);

  .login-card {
    display: grid;
    justify-items: center;
    gap: 0.75rem;
    width: 24rem;
    max-width: 92vw;
    padding: 2.5rem 2rem 2rem;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 0.75rem;
  }
  /* Levirge Brain wordmark (~6.4:1) — same asset as the app header. */
  .login-logo {
    height: 2.5rem;
    width: auto;
    max-width: 100%;
    margin-bottom: 0.35rem;
  }

  h1 {
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--text);
  }
  .login-providers {
    display: grid;
    gap: 0.6rem;
    width: 100%;
  }
  .login-provider {
    display: grid;
    grid-auto-flow: column;
    justify-content: center;
    align-items: center;
    gap: 0.6rem;
    padding: 0.65rem 1rem;
    border: 1px solid var(--line-2);
    border-radius: 0.45rem;
    background: var(--raised);
    color: var(--text);
    font-size: 0.9rem;
    font-weight: 600;
    text-decoration: none;
    transition: border-color 0.15s ease, background 0.15s ease;

    &:hover {
      border-color: var(--brand);
      background: var(--panel);
    }
    .provider-logo {
      height: 1.15rem;
      width: 1.15rem;
    }
  }

  .login-error {
    width: 100%;
    padding: 0.6rem 0.8rem;
    border: 1px solid var(--error);
    border-radius: 0.45rem;
    color: var(--error);
    font-size: 0.85rem;
    text-align: center;
  }

  .login-foot {
    font-size: 0.85rem;
    color: var(--muted);
    a {
      color: var(--brand);
      text-decoration: underline dotted;
      &:hover {
        text-decoration: underline;
      }
    }
  }

  /* Mirrors the Levirge Search sign-in footer: product + version left, © right. */
  .login-footer {
    justify-self: stretch;
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    padding: 0.5rem 1rem;
    font-size: 0.8rem;
    color: var(--muted);
    a {
      color: var(--muted);
      text-decoration: none;
      &:hover {
        color: var(--brand);
      }
    }
  }
}

/* Section sidebar navs — SSR partials (_settings-nav.eta, _profile-nav.eta, _help-nav.eta),
   mirroring the main sidebar list look. */
#settings-nav-header,
#profile-nav-header,
#help-nav-header {
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding: 1rem 1rem 0.5rem;
  color: var(--faint);
}
#settings-nav,
#profile-nav,
#help-nav {
  display: grid;
  align-content: start;
  padding: 0.25rem 0;
  a {
    padding: 0.45rem 1rem;
    border-left: 3px solid transparent;
    font-size: 0.875rem;
    color: var(--muted);
    text-decoration: none;
    transition: all 0.15s ease;
    &:hover {
      background: var(--raised);
      color: var(--text);
    }
    &.active {
      background: var(--raised);
      border-left-color: var(--brand);
      color: var(--text);
    }
    /* Right-aligned chip on an entry (Settings → Billing "Stripe Portal"). */
    &:has(.nav-chip) {
      display: flex;
      align-items: center;
      justify-content: space-between;
      gap: 0.5rem;
    }
    .nav-chip {
      padding: 0.05rem 0.45rem;
      border: 1px solid var(--line);
      border-radius: 999rem;
      background: var(--raised);
      color: var(--faint);
      font-size: 0.68rem;
      font-weight: 600;
      line-height: 1.4;
    }
    /* Nested nav entries (e.g. per-agent MCP pages under "MCP Setup"). */
    &.sub {
      padding-left: 2rem;
      font-size: 0.82rem;
      color: var(--faint);
      &:hover,
      &.active {
        color: var(--text);
      }
    }
  }
}
/* Help nav extras — vendor logo on agent links + the "Connect your agent" group
   label. Logos are CSS masks over currentColor so they follow hover/active. */
#help-nav {
  overflow-y: auto;
  a.sub {
    display: grid;
    grid-template-columns: 1rem 1fr;
    align-items: center;
    column-gap: 0.5rem;
  }
  .nav-logo {
    width: 1rem;
    height: 1rem;
    background: currentColor;
    mask: no-repeat center / contain;
    opacity: 0.85;
  }
  .help-nav-group {
    padding: 0.6rem 1rem 0.2rem;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--faint);
  }
}
/* Vendor logo masks — shared by the nav links and the overview agent cards. */
#help-nav a[data-vendor="claude"] .nav-logo,
.agent-card[data-vendor="claude"] .agent-logo::after {
  mask-image: url("/img/vendors/claude.svg");
}
#help-nav a[data-vendor="openai"] .nav-logo,
.agent-card[data-vendor="openai"] .agent-logo::after {
  mask-image: url("/img/vendors/openai.svg");
}
#help-nav a[data-vendor="cursor"] .nav-logo,
.agent-card[data-vendor="cursor"] .agent-logo::after {
  mask-image: url("/img/vendors/cursor.svg");
}
#help-nav a[data-vendor="opencode"] .nav-logo,
.agent-card[data-vendor="opencode"] .agent-logo::after {
  mask-image: url("/img/vendors/opencode.svg");
}
#help-nav a[data-vendor="pi"] .nav-logo,
.agent-card[data-vendor="pi"] .agent-logo::after {
  mask-image: url("/img/vendors/pi.svg");
}
#help-nav a[data-vendor="vscode"] .nav-logo,
.agent-card[data-vendor="vscode"] .agent-logo::after {
  mask-image: url("/img/vendors/vscode.svg");
}
#help-nav a[data-vendor="googlegemini"] .nav-logo,
.agent-card[data-vendor="googlegemini"] .agent-logo::after {
  mask-image: url("/img/vendors/googlegemini.svg");
}
#help-nav a[data-vendor="antigravity"] .nav-logo,
.agent-card[data-vendor="antigravity"] .agent-logo::after {
  mask-image: url("/img/vendors/antigravity.svg");
}
#help-nav a[data-vendor="windsurf"] .nav-logo,
.agent-card[data-vendor="windsurf"] .agent-logo::after {
  mask-image: url("/img/vendors/windsurf.svg");
}
#help-nav a[data-vendor="cline"] .nav-logo,
.agent-card[data-vendor="cline"] .agent-logo::after {
  mask-image: url("/img/vendors/cline.svg");
}
#help-nav a[data-vendor="terminal"] .nav-logo,
.agent-card[data-vendor="terminal"] .agent-logo::after {
  mask-image: url("/img/vendors/terminal.svg");
}
/* Help pages — ported from Levirge Search's /docs (agent-search assets/css/ui.css)
   so both products' help reads the same. Static SSR, no JS. */
#main.docs {
  line-height: 1.6;
  overflow-x: hidden;
  /* Cap the reading column, not the scroll container — the scrollbar stays at
     the frame's right edge. */
  > * {
    max-width: 52rem;
  }
  a {
    color: var(--link);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15rem;
    &:hover {
      color: var(--text);
    }
  }
  code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.85em;
    background: var(--panel);
    color: var(--clay);
    padding: 0.1rem 0.35rem;
    border-radius: 0.25rem;
    border: 1px solid var(--line);
    overflow-wrap: anywhere;
  }
  pre {
    background: var(--code-bg);
    border: 1px solid var(--line);
    border-radius: 0.5rem;
    padding: 0.85rem 1rem;
    margin: 0.5rem 0 0.9rem;
    overflow-x: auto;
    box-shadow: inset 0 1px 3px hsl(0 0% 0% / 0.3);
    code {
      background: none;
      border: none;
      padding: 0;
      color: var(--text);
      font-size: var(--font-size-md);
      line-height: 1.55;
      white-space: pre;
    }
  }
  ol,
  ul:not(.agent-grid, .docs-options) {
    margin: 0 0 0.9rem 1.4rem;
    li {
      margin-bottom: 0.4rem;
    }
  }
}
.docs-section {
  margin-bottom: 2.25rem;
  h1 {
    font-size: 1.35rem;
    font-weight: 600;
    margin-bottom: 0.75rem;
  }
  h2 {
    font-size: 1.125rem;
    font-weight: 600;
    margin: 1.5rem 0 0.6rem;
    padding-bottom: 0.35rem;
    border-bottom: 1px solid var(--line);
  }
  h3 {
    font-size: var(--font-size-base);
    font-weight: 600;
    color: var(--muted);
    margin: 1.1rem 0 0.5rem;
  }
  p,
  li {
    color: var(--text);
    font-size: var(--font-size-base);
    margin-bottom: 0.75rem;
  }
  strong {
    color: var(--text);
    font-weight: 600;
  }
}
.docs-step {
  color: var(--brand);
}
.docs-lede {
  color: var(--muted);
}
/* Numbered step heading: a round badge + the instruction, screenshot follows. */
.docs-section .docs-stepline {
  display: grid;
  grid-template-columns: 1.6rem 1fr;
  column-gap: 0.6rem;
  align-items: baseline;
  font-size: var(--font-size-base);
  font-weight: 500;
  border-bottom: none;
  margin: 1.4rem 0 0.5rem;
  padding: 0;
  .docs-step {
    display: inline-grid;
    place-items: center;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 50%;
    background: var(--accent-soft);
    border: 1px solid var(--accent-line);
    font-size: var(--font-size-md);
    font-weight: 700;
  }
}
.docs-section .docs-note {
  color: var(--muted);
  border-left: 0.2rem solid var(--brand);
  padding: 0.5rem 0.85rem;
  background: var(--raised);
  border-radius: 0 0.375rem 0.375rem 0;
}
.docs-table-wrap {
  overflow-x: auto;
  margin-bottom: 0.9rem;
}
.docs-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--font-size-base);
  th,
  td {
    text-align: left;
    vertical-align: top;
    padding: 0.5rem 0.7rem;
    border-bottom: 1px solid var(--line);
    color: var(--text);
  }
  th {
    color: var(--muted);
    font-weight: 600;
    font-size: var(--font-size-md);
  }
}
/* The screenshot SVGs draw their own stroked, rounded frame — no CSS border,
   or the corners show two outlines. The radius only shapes the shadow. */
.docs-shot {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 1rem;
  margin: 0.75rem 0 1.1rem;
  box-shadow: 0 1px 2px hsl(0 0% 0% / 0.3), 0 8px 24px hsl(0 0% 0% / 0.25);
}
#main.docs .docs-foot {
  margin: 0 0 2rem;
  a {
    display: inline-block;
    background: var(--raised);
    color: var(--brand);
    border: 1px solid var(--line-3);
    border-radius: 0.375rem;
    padding: 0.3rem 0.75rem;
    font-size: var(--font-size-md);
    font-weight: 600;
    text-decoration: none;
    &:hover {
      background: var(--panel);
    }
  }
}
/* Overview agent cards and per-page option cards. */
#main.docs :is(.agent-grid, .docs-options) {
  list-style: none;
  margin: 0.75rem 0 1rem;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.75rem;
  li {
    margin: 0;
  }
}
#main.docs :is(a.agent-card, a.docs-option) {
  display: grid;
  row-gap: 0.35rem;
  align-content: start;
  height: 100%;
  padding: 0.85rem 0.95rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 0.6rem;
  color: var(--text);
  text-decoration: none;
  box-shadow: 0 1px 2px hsl(0 0% 0% / 0.25), 0 6px 16px hsl(0 0% 0% / 0.18);
  &:hover {
    background: var(--raised);
    border-color: var(--accent-line);
    color: var(--text);
  }
}
#main.docs a.agent-card {
  grid-template-columns: 2.25rem minmax(0, 1fr);
  grid-template-rows: auto 1fr auto;
  column-gap: 0.75rem;
}
.agent-logo {
  grid-row: 1 / span 3;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 0.5rem;
  background: var(--bg-inset);
  border: 1px solid var(--line);
  position: relative;
  &::after {
    content: "";
    position: absolute;
    inset: 0.5rem;
    background: currentColor;
    mask: no-repeat center / contain;
  }
}
.agent-name,
.opt-title {
  font-size: var(--font-size-base);
  font-weight: 600;
}
.agent-desc,
.opt-desc {
  font-size: var(--font-size-md);
  color: var(--muted);
  line-height: 1.4;
}
.agent-tags {
  display: flex;
  gap: 0.35rem;
  flex-wrap: wrap;
}
/* Tags: icon mask + label. Setup style neutral; sign-in (preferred) amber,
   token (fallback) muted. */
#main.docs .tag {
  display: inline-grid;
  grid-auto-flow: column;
  align-items: center;
  gap: 0.3rem;
  font-size: var(--font-size-sm);
  font-weight: 600;
  line-height: 1.4;
  padding: 0.1rem 0.5rem 0.1rem 0.4rem;
  border-radius: 999rem;
  background: var(--raised);
  color: var(--muted);
  border: 1px solid var(--line);
  white-space: nowrap;
  vertical-align: middle;
  &::before {
    content: "";
    width: 0.8rem;
    height: 0.8rem;
    background: currentColor;
    mask: no-repeat center / contain;
  }
  &.tag-plain::before {
    display: none;
  }
  &.tag-gui::before {
    mask-image: url("/img/tags/gui.svg");
  }
  &.tag-cli::before {
    mask-image: url("/img/tags/terminal.svg");
  }
  &.tag-token::before {
    mask-image: url("/img/tags/token.svg");
  }
  &:is(.tag-signin, .tag-either) {
    background: var(--accent-soft);
    color: var(--brand);
    border-color: var(--accent-line);
    &::before {
      mask-image: url("/img/tags/signin.svg");
    }
  }
}
.docs-legend {
  font-size: var(--font-size-md);
  color: var(--muted);
  line-height: 1.9;
}
/* Troubleshooting accordion — native <details>, no JS. */
#main.docs .faq {
  border: 1px solid var(--line);
  border-radius: 0.5rem;
  background: var(--panel);
  margin-bottom: 0.5rem;
  summary {
    cursor: pointer;
    list-style: none;
    display: grid;
    grid-template-columns: 1fr 1rem;
    align-items: center;
    gap: 0.5rem;
    padding: 0.7rem 0.9rem;
    font-size: var(--font-size-base);
    font-weight: 600;
    color: var(--text);
    &::-webkit-details-marker {
      display: none;
    }
    &::after {
      content: "";
      width: 0.8rem;
      height: 0.8rem;
      background: currentColor;
      mask: url("/img/expand-more.svg") no-repeat center / contain;
      color: var(--faint);
      transition: transform 0.15s;
    }
    &:hover {
      background: var(--raised);
      border-radius: 0.5rem;
    }
  }
  &[open] summary {
    border-bottom: 1px solid var(--line);
    border-radius: 0.5rem 0.5rem 0 0;
    &::after {
      transform: rotate(180deg);
    }
  }
  p {
    color: var(--muted);
    margin: 0.6rem 0.9rem;
  }
}
@media (max-width: 640px) {
  #main.docs :is(.agent-grid, .docs-options) {
    grid-template-columns: minmax(0, 1fr);
  }
  #main.docs .tag {
    white-space: normal;
  }
}
/* Tablet: beside the four nav links (~18rem + 2rem gap) the search bar's text
   input needs column 2 ≥ ~46rem, i.e. a viewport ≥ ~1090px (measured: 921px
   left the input 30px wide, 768px left the vault control 1px). Below that,
   stack: search bar gets the full column, nav drops to its own row. */
@media (max-width: 1100px) {
  .app-header > section {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.35rem;
  }
}
/* Touch: header links/icons to the 2.75rem (44px) minimum target. */
@media (pointer: coarse) {
  .app-header .brand-actions a {
    display: grid;
    place-items: center;
    min-height: 2.75rem;
    min-width: 2.75rem;
  }
}
@media (max-width: 640px) {
  body {
    grid-template-columns: 180px 1fr;
  }
  #sidebar {
    width: auto;
    min-width: 0;
  }
  #main {
    padding: 1rem;
  }
}

/* Shared primitive: YAML frontmatter block emitted by renderMarkdown()
   (assets/js/lib/_markdown.ts) — appears wherever markdown renders (docs,
   skills, entities, ask answers), so it lives in the base layer. Inset like
   code blocks: bg-base tier + inset shadow, no outer elevation. */
.md-frontmatter {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.125rem 0.75rem;
  margin: 0 0 1rem;
  padding: 0.6rem 0.8rem;
  background: var(--code-bg);
  border: 1px solid var(--line);
  border-radius: 0.375rem;
  box-shadow: inset 0 1px 3px hsl(0 0% 0% / 0.25);
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 0.78rem;
  line-height: 1.5;
}
.md-frontmatter .fm-key {
  color: var(--brand);
  white-space: nowrap;
}
.md-frontmatter .fm-val {
  color: var(--muted);
  overflow-wrap: anywhere;
}
.md-frontmatter .fm-raw {
  grid-column: 1 / -1;
  color: var(--muted);
  white-space: pre-wrap;
}

/* Home landing hero (placeholder main; sidebar is the vault-nav rail). */
.home-hero {
  max-width: 48rem;
  margin: 0 auto;
  padding-top: 2rem;
}
.home-hero h1 {
  font-size: 1.6rem;
  font-weight: 650;
}
.home-hero p {
  color: var(--muted);
  font-size: 0.95rem;
  margin-top: 0.5rem;
  line-height: 1.6;
}

/* ── Toast — transient action feedback (js/lib/_toast.ts) ──────────────
   Fixed overlay: appearing/disappearing never shifts page layout. Top right,
   just under the app header row so it never covers the account controls. */
.toast {
  position: fixed;
  inset-block-start: 3.5rem;
  inset-inline-end: 1.5rem;
  z-index: 1000;
  max-inline-size: min(24rem, calc(100vw - 3rem));
  padding: 0.625rem 1rem;
  border: 1px solid var(--line-2);
  border-inline-start: 0.25rem solid var(--ok);
  border-radius: 0.5rem;
  background: var(--bg-raised);
  color: var(--fg-0);
  font-size: 0.875rem;
  box-shadow: var(--shadow-md);
  opacity: 0;
  translate: 0 -0.5rem;
  pointer-events: none;
  transition: opacity 150ms ease, translate 150ms ease;

  &[data-open] {
    opacity: 1;
    translate: 0;
    pointer-events: auto;
    cursor: pointer;
  }
  &[data-error="true"] {
    border-inline-start-color: var(--error);
  }
  @media (prefers-reduced-motion: reduce) {
    transition: none;
  }
}

/* ── Components (inlined by CssBuilder at build time) ─────────────────── */

/* ui-table — shared results-table pattern, ported from the app repo's
   ui-table component (app/assets/components/ui-table). CSS-only: consumers
   put class="ui-table" on a container, declare grid-template-columns ONCE on
   it, and use this structure:

     <div class="ui-table">
       <header class="ui-table-header"><div class="row"><span class="cell">…</span></div></header>
       <main class="ui-table-body [rows-zebra]"> …<div class="row"><span class="cell">…</span></div> </main>
       <footer class="ui-table-footer">…</footer>   (optional)
     </div>

   Columns flow to every row via subgrid, so header and body can never drift.
   The table is a rows grid (auto 1fr auto): it fills its container and ONLY
   the body scrolls. */

.ui-table {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr) auto;
    min-height: 0;
    overflow: hidden;

    .ui-table-header,
    .ui-table-body,
    .ui-table-footer,
    .row {
        display: grid;
        grid-column: 1 / -1;
        grid-template-columns: subgrid;
    }

    .ui-table-header {
        color: var(--faint);
        font-weight: 500;
        border-bottom: 1px solid var(--line);
    }

    /* Footer: one full-width line (counts, totals) under the scrolling body. */
    .ui-table-footer {
        border-top: 1px solid var(--line);
        color: var(--faint);
        font-size: 0.8rem;

        > .cell {
            grid-column: 1 / -1;
            padding: 0.4rem 0.5rem;
        }
    }

    .ui-table-body {
        align-content: start;
        overflow-y: auto;
        min-height: 0;

        .row {
            border-bottom: 1px solid var(--line);
        }
        &.rows-zebra .row:nth-child(even) {
            background: hsl(0 0% 100% / 0.03);
        }
    }

    .row {
        align-items: center;

        .cell {
            padding: 0.4rem 0.5rem;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;

            &.num {
                text-align: right;
                font-variant-numeric: tabular-nums;
            }
            &.actions {
                text-align: right;
            }
        }
    }
}



/* Header query bar. Customized built-in (<form is="ui-search-bar">) — scoped
   under form[is=…] per the component convention. The form IS the single bordered
   element: [mode | input | vault | submit] read as one control, divided by
   internal hairlines rather than four separate outlines. */

form[is="ui-search-bar"] {
    display: grid;
    /* mode | input | ⌘K hint | vault | submit */
    grid-template-columns: auto minmax(0, 1fr) auto auto auto;
    align-items: stretch;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 0.375rem;
    overflow: hidden; /* clips child corners to the shared radius */

    &:focus-within {
        border-color: var(--brand);
    }

    /* Segments: no own border/radius/background — the form owns those. */
    input[type="text"],
    select {
        min-width: 0;
        background: transparent;
        color: var(--text);
        border: none;
        border-radius: 0;
        font-family: inherit;

        &:focus {
            outline: none;
        }
    }

    input[type="text"] {
        padding: 0.5rem 0.9rem;
        font-size: 1rem;
        border-left: 1px solid var(--line); /* divider: mode | input */
    }

    select {
        padding: 0.5rem 0.6rem;
        font-size: 0.85rem;
        cursor: pointer;
    }

    /* ⌘K affordance. Hidden once the bar has focus — you are already here, and
       it would sit under the caret on a long query. */
    .query-hint {
        align-self: center;
        margin-right: 0.4rem;
        padding: 0.1rem 0.35rem;
        border: 1px solid var(--line);
        border-radius: 0.25rem;
        color: var(--faint);
        background: var(--bg);
        font-family: inherit;
        font-size: 0.68rem;
        white-space: nowrap;
        pointer-events: none;
    }

    &:focus-within .query-hint {
        visibility: hidden;
    }

    /* Mode picker — customizable <select> (Chromium `appearance: base-select`,
       verified in Chrome 148; Brain is a Chromium internal tool). Options carry
       an icon + label; the closed button clones only the icon via
       <selectedcontent>, so it reads icon-only shut, icon + label open. */
    .query-mode {
        padding: 0;

        /* Label is for the open list only — the closed button shows the icon. */
        selectedcontent .mode-label { display: none; }

        option {
            display: grid;
            grid-template-columns: auto minmax(0, 1fr);
            align-items: center;
            gap: 0.5rem;
            padding: 0.4rem 0.5rem;
            border-radius: 0.3rem;
            color: var(--muted);
            font-size: 0.85rem;

            &:hover, &:checked { background: var(--raised); color: var(--text); }

            /* Native checkmark column — the icon is the affordance here. */
            &::checkmark { display: none; }
        }

        .icon {
            display: block; /* inline spans ignore width/height */
            width: 1.1rem;
            height: 1.1rem;
            background: currentColor;
            mask: no-repeat center / contain;

            &.icon-chat { mask-image: url("/img/chat-bubble.svg"); }
            &.icon-search { mask-image: url("/img/search.svg"); }
        }
    }

    /* Vault segment — ui-vault-picker's trigger, flattened into the bar.
       Long vault names truncate rather than widen the bar. */
    .vault-trigger {
        max-width: 10rem;
        padding: 0.5rem 0.5rem 0.5rem 0.7rem;
        background: transparent;
        color: var(--muted);
        border: none;
        border-left: 1px solid var(--line); /* divider: input | vault */
        border-radius: 0;

        &:hover { color: var(--text); }
        &:focus-visible { outline: none; color: var(--text); }
    }

    /* ── Chevrons ─────────────────────────────────────────────────────────
       The mode select runs `appearance: base-select` so the UA arrow becomes a styleable
       ::picker-icon, which we replace with the same masked expand_more used by
       the account drawer caret. Muted at half opacity, full on hover. */
    .query-mode {
        appearance: base-select;
        display: grid;
        grid-auto-flow: column;
        justify-content: start;
        align-items: center;

        &::picker(select) {
            appearance: base-select;
            margin-top: 0.25rem;
            padding: 0.25rem;
            border: 1px solid var(--line-2);
            border-radius: 0.45rem;
            background: var(--panel);
        }

        &::picker-icon {
            content: "";
            align-self: center;
            width: 1rem;
            height: 1rem;
            margin-right: 0.5rem;
            background: var(--muted);
            mask: url("/img/expand-more.svg") no-repeat center / contain;
            opacity: 0.5;
            transition: opacity 0.15s, background 0.15s;
        }

        &:hover::picker-icon { opacity: 1; background: var(--text); }

        & > button {
            display: grid;
            grid-auto-flow: column;
            justify-content: start;
            align-items: center;
            min-width: 0;
            padding: 0.5rem 0.35rem 0.5rem 0.7rem;
            border: none;
            background: transparent;
            color: var(--muted);
            font-size: 0.85rem;
            font-family: inherit;
            cursor: pointer;

            &:hover { color: var(--text); }
        }
    }

    /* Right cap: brand fill is its own visual divider — no hairline needed. */
    button[type="submit"] {
        background: var(--brand);
        color: var(--bg-base);
        border: none;
        border-radius: 0;
        padding: 0.4rem 1.1rem;
        font-size: 0.85rem;
        font-weight: 600;
        cursor: pointer;
        transition: opacity 0.15s;

        &:hover {
            opacity: 0.9;
        }

        &:disabled {
            opacity: 0.5;
            cursor: default;
        }
    }
}

/* Hidden until onboarding is complete (html[data-onboarding], lib/_onboarding.ts).
   visibility, not display: the header keeps its layout. */
html[data-onboarding] #query-form { visibility: hidden; }



ui-vault-nav {
    display: grid;
    align-content: start;
    overflow-y: auto;

    header {
        padding: 1rem 1rem 0.5rem;

        h2 {
            font-size: 0.8rem;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.08em;
            color: var(--faint);
        }

        span {
            display: block;
            color: var(--faint);
            font-size: 0.76rem;
            text-transform: none;
            letter-spacing: normal;
        }
    }

    ul {
        display: grid;
        align-content: start;
        padding: 0.25rem 0;
    }

    a {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr) auto;
        align-items: center;
        gap: 0.5rem;
        padding: 0.45rem 1rem;
        border-left: 3px solid transparent;
        font-size: 0.875rem;
        color: var(--muted);
        text-decoration: none;
        transition: all 0.15s ease;

        span {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        &:hover {
            background: var(--raised);
            color: var(--text);
        }
    }

    .vault-nav-avatar,
    .vault-nav-ph {
        width: 1.2rem;
        height: 1.2rem;
        border-radius: 0.25rem;
        flex-shrink: 0;
    }

    .vault-nav-avatar { object-fit: contain; }

    .vault-nav-ph {
        display: grid;
        place-items: center;
        background: var(--raised);
        color: var(--faint);
        font-size: 0.6rem;
        font-weight: 650;
    }

    /* class display: grid beats the UA [hidden] rule — restore it so the
       placeholder never shows alongside a real avatar. */
    .vault-nav-avatar[hidden],
    .vault-nav-ph[hidden] { display: none; }

    .vault-nav-label {
        min-width: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .vault-nav-count {
        flex-shrink: 0;
        color: var(--faint);
        font-size: 0.68rem;
        font-variant-numeric: tabular-nums;
    }

    .vault-nav-empty {
        padding: 0.45rem 1rem;
        color: var(--faint);
        font-size: 0.8rem;
    }

    .vault-nav-onboard {
        display: grid;
        align-content: start;
        border-bottom: 1px solid var(--line);
        padding-bottom: 0.5rem;

        /* class display: grid beats the UA [hidden] rule. */
        &[hidden],
        li[hidden] { display: none; }

        li[data-viewing] a { background: var(--bg-hover); }

        /* Getting started replaces the vault list until the viewer hides it. */
        &:not([hidden]) ~ .vault-nav-vaults,
        &:not([hidden]) ~ .vault-nav-links { display: none; }

        header {
            display: grid;
            grid-template-columns: 1fr auto;
            align-items: center;
        }

        header button {
            background: none;
            border: 0;
            padding: 0;
            color: var(--faint);
            font-size: 0.75rem;
            cursor: pointer;

            &:hover { color: var(--text); }
            &:focus-visible { outline: 0.125rem solid var(--brand); }
        }

        ol {
            display: grid;
            align-content: start;
            padding: 0.25rem 0;
            list-style: none;
        }

        /* Outline button under the steps, full width of the step rows (1rem side inset). */
        .vault-nav-skip {
            justify-self: stretch;
            text-align: center;
            margin: 0.25rem 1rem 0.5rem;
            padding: 0.35rem 0.8rem;
            background: none;
            border: 1px solid var(--line-3);
            border-radius: 0.4rem;
            color: var(--muted);
            font: inherit;
            font-size: 0.8rem;
            cursor: pointer;

            &:hover { border-color: var(--accent); color: var(--text); }
            &:focus-visible { outline: 0.125rem solid var(--brand); outline-offset: 0.125rem; }
        }

        /* Two-line row: marker left, title over hint. */
        a {
            grid-template-columns: auto minmax(0, 1fr);
            grid-template-rows: auto auto;
            column-gap: 0.6rem;
            row-gap: 0.1rem;
            align-items: start;
            padding: 0.5rem 1rem;
        }

        a:focus-visible {
            outline: 0.125rem solid var(--brand);
            outline-offset: -0.125rem;
        }
    }

    /* Stepper markers, same as the Levirge signup: numbered grey circle →
       current step in accent outline → done as a solid accent tick. The
       number is a CSS counter, so a hidden step (invite) doesn't count. */
    .vault-nav-onboard ol { counter-reset: onboard-step; }
    .vault-nav-onboard li:not([hidden]) { counter-increment: onboard-step; }

    .vault-nav-mark {
        grid-row: 1 / span 2;
        display: grid;
        place-items: center;
        width: 1.35rem;
        height: 1.35rem;
        border: 1px solid var(--line-3);
        border-radius: 50%;
        color: var(--faint);
        font-size: 0.72rem;
        font-weight: 600;
        line-height: 1;

        &::before { content: counter(onboard-step); }
    }

    li[data-current] .vault-nav-mark {
        border-color: var(--accent);
        color: var(--accent);
    }

    .vault-nav-mark[data-state="done"] {
        border-color: var(--accent);
        background: var(--accent);
        color: var(--accent-fg);

        &::before { content: "\2713"; }
    }

    .vault-nav-step {
        white-space: normal;
        color: var(--text);
        font-weight: 550;
    }

    li:has([data-state="done"]) .vault-nav-step { color: var(--muted); }


    .vault-nav-onboard .vault-nav-hint {
        grid-column: 2;
        color: var(--faint);
        font-size: 0.76rem;
        white-space: normal;
    }

    /* Skills — under the vault list. Same row treatment as the vault sidebar's
       Entities / Docs / Map links (ui-vault-metrics .vm-nav). */
    .vault-nav-links {
        display: grid;
        padding: 0.25rem 0;
        border-top: 1px solid var(--line);

        a {
            display: grid;
            grid-template-columns: auto minmax(0, 1fr);
            align-items: center;
            gap: 0.6rem;
            padding: 0.45rem 1rem;
            border-left: 3px solid transparent;
            color: var(--muted);
            font-size: 0.82rem;
            text-decoration: none;
            transition: all 0.15s ease;

            &:hover {
                background: var(--raised);
                border-left-color: var(--brand);
                color: var(--text);
            }
        }
        .icon {
            width: 1.1rem;
            height: 1.1rem;
            flex-shrink: 0;
            background: currentColor;
            mask: no-repeat center / contain;

            &.icon-skills { mask-image: url("/img/psychology.svg"); }
        }
    }
}



ui-home {
    display: grid;
    gap: 1rem;
    max-width: 72rem;
    margin: 0 auto;

    .panel {
        border: 1px solid var(--line);
        background: var(--panel);
        border-radius: 0.45rem;
        padding: 0.9rem;
    }

    /* ── View switch ──
       data-first-run (ui-home.ts, from the overview) absent → loading line.
       Getting started showing (html/ui-home[data-onboarding]) → the welcome + step card only.
       Otherwise → the dashboard, even for an empty workspace: once Getting started is done or
       skipped there is no step left to show. html[data-onboarding] is set at bundle load, so
       a new account never flashes zero tiles before its checklist publishes. */
    .home-loading {
        color: var(--faint);
        font-size: 0.85rem;
    }
    &[data-first-run] .home-loading { display: none; }

    .home-dashboard {
        display: none;
        gap: 1rem;
    }
    &[data-first-run] .home-dashboard { display: grid; }
    html[data-onboarding] & .home-dashboard { display: none; }

    /* ── Getting started (empty workspace) ───────────────────────────────── */
    .home-welcome {
        display: none;
        /* No chrome: sits on the page. Top padding matches the sidebar
           header (1rem) so the title lines up with "Getting started". */
        gap: 1.25rem;
        padding: 1rem 0;

        /* One column width so header, card and link share both edges. */
        > * { max-width: 44rem; }

        h1 {
            font-size: 1.6rem;
            font-weight: 650;
            line-height: 1.25;
            color: var(--text);
        }
    }
    /* Sidebar checklist showing → welcome + next step, never the dashboard. */
    &[data-onboarding] .home-welcome { display: grid; }
    /* Getting started is left-aligned with the header title, as the /setup/agent pages are. */
    &[data-onboarding] { margin: 0; }
    /* The step number is in the header (ui-home.ts); past Step 1 so is its title. */
    &[data-onboarding] .home-next-label,
    &[data-step-header] .home-next > strong,
    &[data-step-header] .home-next-hint { display: none; }
    &[data-onboarding] .home-dashboard,
    &[data-onboarding] .home-loading { display: none; }

    .home-next {
        display: grid;
        gap: 0.75rem;
        padding: 1.25rem 0;
        border: none; /* no visible box (Steve); flush with the header title */
        border-radius: 0.45rem;
        color: var(--muted);
        text-decoration: none;
        transition: border-color 0.15s;

        strong {
            color: var(--text);
            font-size: 1.1rem;
            font-weight: 600;
        }
        &:focus-visible { outline: 1px solid var(--accent); outline-offset: 0.15rem; }
    }
    /* Title block (label/title/hint) sits tight; the form fields below keep the card gap. */
    .home-next-label + strong { margin-top: -0.5rem; }
    strong + .home-next-hint { margin-top: -0.5rem; }

    /* Back / Done under a step only the viewer can tick (ui-home.ts). */
    .home-step-nav {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 0.75rem;
        margin-top: 0.5rem;

        &[hidden], [hidden] { display: none; }
        a, button {
            border: 1px solid var(--line-3);
            border-radius: 0.4rem;
            background: none;
            color: var(--text);
            font: inherit;
            font-size: 0.8rem;
            padding: 0.3rem 0.8rem;
            text-decoration: none;
            cursor: pointer;
            &:hover { border-color: var(--accent); }
        }
        .home-step-done {
            margin-left: auto;
            background: var(--accent);
            border-color: var(--accent);
            color: var(--bg);
            font-weight: 600;
        }
    }

    /* Only the viewed step's body shows. */
    .home-step-body { display: none; }
    &[data-view-step="vault"] [data-step-body="vault"],
    &[data-view-step="connect"] [data-step-body="connect"],
    &[data-view-step="identity"] [data-step-body="identity"],
    &[data-view-step="first-doc"] [data-step-body="first-doc"],
    &[data-view-step="handoff"] [data-step-body="handoff"],
    &[data-view-step="invite"] [data-step-body="invite"] { display: block; }
    .home-step-body > :first-child { margin-top: 0; }
    /* Suggested prompt, styled like a chat composer with a copy button (ui-home.ts). */
    .prompt-box {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: end;
        gap: 0.75rem;
        margin: 0.25rem 0 1rem;
        padding: 0.85rem 0.85rem 0.85rem 1.1rem;
        background: var(--bg-surface);
        border: 1px solid var(--line-2);
        border-radius: 1.1rem;
        box-shadow: 0 1px 2px hsl(0 0% 0% / 0.3), 0 6px 18px hsl(0 0% 0% / 0.2);
    }
    /* Label above a prompt box, and a small aside under one (Step 5's handoff prompts). */
    .prompt-label { margin: 0.75rem 0 0.4rem; color: var(--text); font-weight: 600; }
    .prompt-note { margin: -0.5rem 0 0.75rem; color: var(--faint); font-size: 0.85rem; }
    .prompt-text {
        margin: 0;
        color: var(--text);
        font-size: 0.95rem;
        line-height: 1.5;
        user-select: all; /* one click selects it all, if the clipboard is blocked */
    }
    /* A command rather than a sentence (Step 3's /brain:start). */
    .prompt-cmd { font-family: var(--font-mono); font-size: 0.9rem; }
    .prompt-copy {
        display: grid;
        place-items: center;
        width: 2rem;
        height: 2rem;
        padding: 0;
        border: 1px solid var(--line-3);
        border-radius: 50%;
        background: var(--bg-raised);
        color: var(--muted);
        cursor: pointer;

        &:hover { color: var(--text); border-color: var(--accent); }
        &:focus-visible { outline: 0.125rem solid var(--brand); outline-offset: 0.125rem; }
        &[data-state="copied"] { color: var(--accent); border-color: var(--accent); }
        &[data-state="failed"] { color: var(--error); }
    }
    .prompt-copy-icon {
        width: 1rem;
        height: 1rem;
        background: currentColor;
        mask: url("/img/copy.svg") no-repeat center / contain;
    }
    .prompt-copy[data-state="copied"] .prompt-copy-icon { mask-image: url("/img/check.svg"); }

    /* Copyable prompts and commands wrap in the card instead of scrolling sideways. */
    .home-step-body pre { white-space: pre-wrap; overflow-wrap: anywhere; }

    .home-vault-form {
        display: grid;
        gap: 0.75rem;
        label {
            display: grid;
            gap: 0.35rem;
            color: var(--muted);
            font-size: 0.85rem;
        }
        input {
            padding: 0.5rem 0.65rem;
            border: 1px solid var(--line-3);
            border-radius: 0.35rem;
            background: var(--panel);
            color: var(--text);
            font: inherit;
        }
        .error {
            color: var(--error);
            font-size: 0.85rem;
            &:empty { display: none; }
        }
        button {
            justify-self: start;
            padding: 0.5rem 1.1rem;
            border: 0;
            border-radius: 0.35rem;
            background: var(--accent);
            color: var(--accent-fg);
            font-weight: 600;
            cursor: pointer;
            &:disabled { opacity: 0.6; cursor: progress; }
        }
    }
    .home-next-label {
        color: var(--accent);
        font-size: 0.75rem;
        font-weight: 600;
        letter-spacing: 0.08em;
        text-transform: uppercase;
    }

    .home-head {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: baseline;
        margin-bottom: 0.7rem;

        h2 { font-size: 0.9rem; font-weight: 650; }
        span { color: var(--faint); font-size: 0.78rem; font-variant-numeric: tabular-nums; }
    }

    .home-heatmap {
        display: grid;
        grid-auto-flow: column;
        grid-template-rows: repeat(7, 1fr);
        grid-auto-columns: 1fr;
        gap: 0.1875rem;
        width: 100%;
        height: 7rem;
    }

    .heat-cell {
        border-radius: 0.125rem;
        background: var(--raised);

        &[data-level="1"] { background: color-mix(in srgb, var(--brand) 30%, var(--raised)); }
        &[data-level="2"] { background: color-mix(in srgb, var(--brand) 55%, var(--raised)); }
        &[data-level="3"] { background: color-mix(in srgb, var(--brand) 78%, var(--raised)); }
        &[data-level="4"] { background: var(--brand); }
    }

    .home-empty { color: var(--faint); font-size: 0.85rem; }

    .home-metrics {
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: 0.75rem;

        article {
            border: 1px solid var(--line);
            background: var(--panel);
            border-radius: 0.45rem;
            padding: 0.7rem 0.85rem;
            display: grid;
            gap: 0.1rem;
        }

        span {
            font-size: 1.5rem;
            font-weight: 650;
            font-variant-numeric: tabular-nums;
        }

        label {
            color: var(--faint);
            font-size: 0.68rem;
            text-transform: uppercase;
            letter-spacing: 0.05em;
        }
    }

    .home-cols {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 1rem;
        align-items: start;
    }

    @media (max-width: 760px) {
        .home-metrics { grid-template-columns: repeat(2, 1fr); }
        .home-cols { grid-template-columns: 1fr; }
    }

    .home-list {
        list-style: none;
        display: grid;
        gap: 0.4rem;

        li {
            display: grid;
            grid-template-columns: auto minmax(0, 1fr) auto;
            gap: 0.5rem;
            align-items: baseline;
            font-size: 0.82rem;
            color: var(--muted);
        }

        .home-item-text {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .home-item-meta {
            color: var(--faint);
            font-size: 0.68rem;
            text-transform: uppercase;
            letter-spacing: 0.04em;
        }
    }

    /* Two-line todo row: [status] [title …… priority] / (under title) [vault …… due] */
    .home-list li.todo-row {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        gap: 0.5rem;
        align-items: start;
    }

    .todo-body {
        display: grid;
        gap: 0.15rem;
        min-width: 0;
    }

    .todo-l1,
    .todo-l2 {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: baseline;
        gap: 0.6rem;
        min-width: 0;
    }

    .todo-title {
        color: var(--text);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        /* flex items default to min-width:auto — without this the nowrap
           title refuses to shrink and overflows instead of ellipsing. */
        min-width: 0;
    }

    .todo-pri {
        flex-shrink: 0;
        font-size: 0.62rem;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        color: var(--faint);

        &[data-pri="high"] { color: var(--stuck); }
        &[data-pri="normal"] { color: var(--clay, var(--brand)); }
    }

    .todo-vault {
        color: var(--link);
        font-size: 0.74rem;
        text-decoration: none;

        &:hover { text-decoration: underline; }
    }

    .todo-due {
        flex-shrink: 0;
        color: var(--faint);
        font-size: 0.72rem;
    }

    .home-badge {
        font-size: 0.62rem;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        color: var(--faint);
        background: var(--raised);
        border: 1px solid var(--line);
        border-radius: 0.3rem;
        padding: 0.05rem 0.35rem;
        white-space: nowrap;
    }

    @media (max-width: 760px) {
        .home-cols { grid-template-columns: 1fr; }
    }
}

/* Home's first panel top-aligns with the sidebar card (#main's shared 1.5rem top padding would push it down). */
#main:has(> ui-home) { padding-top: 0; }



ui-todos {
    display: grid;
    gap: 1rem;
    max-width: 60rem;
    margin: 0 auto;

    .todos-head {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: end;
        gap: 1rem;
        border-bottom: 1px solid var(--line);
        padding-bottom: 0.9rem;

        h1 { font-size: 1.45rem; font-weight: 650; }
        .back-link { color: var(--link); font-size: 0.78rem; text-decoration: none; display: block; }
    }

    .todos-tabs {
        display: grid;
        grid-auto-flow: column;
        justify-content: start;
        gap: 0.25rem;

        button {
            border: 1px solid var(--line);
            background: var(--bg);
            color: var(--muted);
            font-size: 0.78rem;
            padding: 0.3rem 0.7rem;
            cursor: pointer;

            &:first-child { border-radius: 0.35rem 0 0 0.35rem; }
            &:last-child { border-radius: 0 0.35rem 0.35rem 0; }
            &.active { background: var(--raised); color: var(--text); border-color: var(--line-3); }
        }
    }

    .loading { color: var(--faint); font-size: 0.86rem; }
    .todos-empty { color: var(--faint); font-size: 0.86rem; }

    &[data-state="loading"] .todos-empty,
    &[data-state="loading"] .todos-list { display: none; }
    &[data-state="ready"] .loading { display: none; }

    .todos-list {
        list-style: none;
        display: grid;
        gap: 0.5rem;
    }

    .todos-list li {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 0.7rem;
        align-items: center;
        border: 1px solid var(--line);
        background: var(--panel);
        border-radius: 0.4rem;
        padding: 0.55rem 0.8rem;
    }

    .todo-body {
        display: grid;
        gap: 0.15rem;
        min-width: 0;
    }

    .todo-l1 {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: center;
        gap: 0.5rem;
    }

    .todo-title {
        min-width: 0;
        color: var(--text);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .todo-l2 {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: baseline;
        gap: 0.5rem;
    }

    .todo-vault {
        color: var(--link);
        font-size: 0.74rem;
        text-decoration: none;

        &:hover { text-decoration: underline; }
    }

    .todo-due {
        color: var(--faint);
        font-size: 0.72rem;
    }

    .todo-pri-sel {
        background: var(--bg);
        color: var(--muted);
        border: 1px solid var(--line);
        border-radius: 0.3rem;
        font-size: 0.72rem;
        padding: 0.2rem 0.3rem;
        cursor: pointer;

        &[data-pri="high"] { color: var(--stuck); }
        &[data-pri="normal"] { color: var(--clay, var(--brand)); }
    }

    /* Done control: empty circle → faint tick on hover → filled green tick done. */
    .todo-toggle {
        width: 1.35rem;
        height: 1.35rem;
        padding: 0;
        border: 1.5px solid var(--line-2);
        border-radius: 50%;
        background: transparent;
        color: transparent;
        display: grid;
        place-items: center;
        cursor: pointer;
        transition: color 0.12s, background 0.12s, border-color 0.12s;

        &::after {
            content: "✓";
            font-size: 0.8rem;
            line-height: 1;
        }

        &:hover {
            border-color: var(--accent);
            color: var(--faint);
        }

        &[data-done="true"] {
            background: var(--accent);
            border-color: var(--accent);
            color: var(--bg);
        }
    }

}



/* Footer live connection indicator — rules moved from assets/css/ui.css
   (#conn-status), re-scoped under the component element. The dot is a
   ::before on the component root; colour is driven by [data-state]. */

ui-conn-status {
    display: grid;
    grid-auto-flow: column;
    align-items: center;
    gap: 0.4rem;
    color: var(--muted);

    &::before {
        content: "";
        width: 0.7em;
        height: 0.7em;
        border-radius: 50%;
        background: currentColor;
    }

    &[data-state="online"] {
        color: var(--ok);
    }

    &[data-state="offline"] {
        color: var(--stuck);
    }
}



/* Account drawer — the bottom of the left sidebar panel (shell owns one instance;
   grid-area "drawer" in ui.css places it flush under #sidebar so the two read as
   one panel). The menu is a native [popover]: zero-JS toggle + light-dismiss,
   CSS-anchored above the trigger. Mirrors the admin ui-account-drawer. */

ui-account-drawer {
  grid-area: drawer;
  display: block;
  margin-top: -0.5rem; /* eat the grid row-gap so it merges with #sidebar */
  padding: 0.4rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-top: none;
  border-radius: 0 0 0.5rem 0.5rem;
}

.account-avatar {
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 0.4rem;
  border: 1px solid var(--line-3);
  background: var(--raised);
  display: grid;
  place-items: center;
  overflow: hidden;

  img {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* Placeholder when no avatar is set. */
  .icon-person {
    width: 1.4rem;
    height: 1.4rem;
    background: var(--faint);
    mask: url("/img/person.svg") no-repeat center / contain;
  }

  /* `display: grid` would otherwise beat the UA [hidden] rule. */
  [hidden] { display: none; }
}

.account-trigger {
  anchor-name: --account-trigger;
  width: 100%;
  display: grid;
  /* [avatar] [name ......] [caret] — avatar and caret span both rows, the
     email sits under the name in row 2. */
  grid-template-columns: 2.2rem minmax(0, 1fr) auto;
  grid-template-rows: auto auto;
  column-gap: 0.6rem;
  align-items: center;
  padding: 0.4rem;
  border: none;
  border-radius: 0.4rem;
  background: transparent;
  color: var(--text);
  text-align: left;
  cursor: pointer;

  /* Explicit placement: with 3 columns, auto-flow would drop the email into
     column 3 row 1 instead of under the name. */
  .account-avatar { grid-column: 1; grid-row: span 2; }
  .account-caret { grid-column: 3; grid-row: span 2; }
  strong { grid-column: 2; grid-row: 1; font-size: 0.85rem; font-weight: 600; }
  small { grid-column: 2; grid-row: 2; color: var(--faint); font-size: 0.72rem; }
  strong, small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  &:hover { background: var(--raised); }
}

/* Caret affordance — same expand_more glyph and half-opacity treatment as the
   search-bar select chevrons, so every dropdown on the page reads alike. */
.account-caret {
  width: 1rem;
  height: 1rem;
  background: var(--muted);
  mask: url("/img/expand-more.svg") no-repeat center / contain;
  opacity: 0.5;
  transition: opacity 0.15s, background 0.15s;
}

.account-trigger:hover .account-caret { opacity: 1; background: var(--text); }

/* ── Popover menu ──────────────────────────────────────────────────────
   Grows upward from the trigger: the menu's bottom edge sits on the anchor's
   bottom edge, left/right flush with it (native CSS anchor positioning).
   ponytail: no fallback — Brain is a Chromium internal tool. */
.account-menu {
  position: fixed;
  position-anchor: --account-trigger;
  margin: 0;
  inset: auto;
  bottom: anchor(bottom);
  left: anchor(left);
  right: anchor(right);
  width: auto; /* beat the UA [popover] { width: fit-content } so it stretches */
  padding: 0.4rem;
  border: 1px solid var(--line-3);
  border-radius: 0.6rem;
  background: var(--panel);
  color: var(--text);
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.45);
}

.account-menu-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.4rem 0.6rem;
  border-bottom: 1px solid var(--line);

  strong { display: block; font-size: 0.85rem; }
  small { display: block; color: var(--faint); font-size: 0.72rem; }
  .account-menu-id { overflow: hidden; }
  strong, small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ── Usage gauges (Search's ui-quota look) ─────────────────────────────── */
.account-usage {
  display: grid;
  gap: 0.55rem;
  padding: 0.6rem 0.4rem;
  border-bottom: 1px solid var(--line);

  h3 {
    margin: 0;
    color: var(--faint);
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }
  /* The rows are grids — beat the UA [hidden] rule. */
  [hidden] { display: none; }
}

.usage-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.15rem 0.75rem;
  font-size: 0.78rem;
}
.usage-label { color: var(--faint); }
.usage-value { text-align: right; font-variant-numeric: tabular-nums; }

/* Sunken track, raised fill — reads as "capacity". */
.usage-meter {
  grid-column: 1 / -1;
  height: 0.3rem;
  border-radius: 0.15rem;
  background: var(--raised);
  box-shadow: inset 0 1px 2px hsl(0 0% 0% / 0.35);
  overflow: hidden;
}
.usage-fill {
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: var(--brand);
  transition: width 0.25s;

  /* Bands, not a gradient: the question is "am I near the limit". */
  &[data-level="warn"] { background: var(--warn); }
  &[data-level="full"] { background: var(--stuck); }
  /* No limit / unreadable — empty track rather than implying 0%. */
  &[data-level="none"] { width: 0 !important; }
}

.account-menu-items {
  display: grid;
  padding-top: 0.3rem;
}

.account-item {
  /* [icon] [label / description] — icon spans both rows. Logout has no
     description, so its single child just sits in row 1. */
  display: grid;
  grid-template-columns: 1.1rem minmax(0, 1fr);
  align-items: center;
  column-gap: 0.6rem;
  width: 100%;
  padding: 0.5rem 0.5rem;
  border: none;
  border-radius: 0.4rem;
  background: transparent;
  color: var(--text);
  font-size: 0.85rem;
  text-align: left;
  text-decoration: none;
  cursor: pointer;

  &:hover { background: var(--raised); }
  &:disabled { color: var(--faint); cursor: not-allowed; background: transparent; }
  &.account-item--danger { color: var(--stuck); }

  strong { grid-column: 2; font-size: 0.85rem; font-weight: 600; }
  small {
    grid-column: 2;
    color: var(--faint);
    font-size: 0.72rem;
    line-height: 1.3;
  }
  strong, small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

  /* Icons inherit the row's colour (incl. the danger + disabled states). */
  .icon {
    grid-column: 1;
    grid-row: 1 / -1;
    width: 1.1rem;
    height: 1.1rem;
    background: currentColor;
    mask: no-repeat center / contain;

    &.icon-person { mask-image: url("/img/person.svg"); }
    &.icon-settings { mask-image: url("/img/settings.svg"); }
    &.icon-help { mask-image: url("/img/help.svg"); }
    &.icon-swap { mask-image: url("/img/swap-horiz.svg"); }
    &.icon-logout { mask-image: url("/img/logout.svg"); }
  }

  /* Workspace avatar stands in for the swap icon: same column/row span. */
  .account-ws-avatar {
    grid-column: 1;
    grid-row: 1 / -1;
    width: 1.1rem;
    height: 1.1rem;
    border-radius: 0.2rem;
    object-fit: cover;
  }
}



/* Skills sidebar — rules copied from assets/css/ui.css (#skills-header,
   #skill-list, .add-btn, .error), re-scoped under the component. The
   surrounding <aside id="sidebar"> flex column stays in ui.css; the component
   fills it and owns the header/list split. */

ui-skill-sidebar {
    min-height: 0;
    display: grid;
    grid-template-rows: auto 1fr;
    overflow: hidden;

    #skills-header {
        font-size: 0.8rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.08em;
        padding: 1rem 1rem 0.5rem;
        color: var(--faint);
        cursor: pointer;
        transition: color 0.15s;
        user-select: none;
        display: grid;
        grid-template-columns: 1fr auto;
        align-items: center;

        &:hover {
            color: var(--muted);
        }

        /* psychology.svg (Material Symbols), masked so it takes the header colour. */
        .skills-title {
            display: inline-grid;
            grid-auto-flow: column;
            justify-content: start;
            align-items: center;
            gap: 0.4rem;
        }

        .icon-skills {
            width: 1rem;
            height: 1rem;
            background: currentColor;
            mask: url("/img/psychology.svg") no-repeat center / contain;
        }
    }

    .add-btn {
        background: var(--clay-soft);
        color: var(--clay);
        border: 1px solid var(--line);
        border-radius: 0.3rem;
        padding: 0.2rem 0.5rem;
        font-size: 0.68rem;
        font-weight: 600;
        text-transform: none;
        letter-spacing: normal;
        cursor: pointer;
        transition: background 0.15s, color 0.15s;

        &:hover {
            background: var(--brand);
            color: var(--bg);
        }
    }

    #skill-list {
        list-style: none;
        overflow-y: auto;
        min-height: 0;
        padding: 0.25rem 0;

        li {
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto auto;
            gap: 0.5rem;
            align-items: center;
            padding: 0.45rem 1rem;
            cursor: pointer;
            border-left: 3px solid transparent;
            font-size: 0.875rem;
            color: var(--muted);
            transition: all 0.15s ease;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;

            [data-field="name"] {
                overflow: hidden;
                text-overflow: ellipsis;
            }

            /* Load count (skill get); hover for file reads + last use. */
            .uses {
                color: var(--faint);
                font-size: 0.65rem;
                font-variant-numeric: tabular-nums;
            }

            .status {
                display: none;
                color: var(--faint);
                font-size: 0.65rem;
                font-weight: 600;
            }

            &.disabled {
                color: var(--faint);
            }

            &.disabled .status {
                display: inline;
            }

            &:hover {
                background: var(--raised);
                color: var(--text);
            }

            &.active {
                background: var(--raised);
                border-left-color: var(--brand);
                color: var(--text);
            }

            &.error {
                color: var(--stuck);
                font-size: 0.85rem;
                cursor: default;
                white-space: normal;
            }

            &.group {
                display: block;
                cursor: default;
                padding: 0.8rem 1rem 0.25rem;
                border-left-color: transparent;
                color: var(--faint);
                font-size: 0.68rem;
                font-weight: 700;
                text-transform: uppercase;
                letter-spacing: 0.08em;
            }

            &.group:hover {
                background: transparent;
                color: var(--faint);
            }
        }
    }
}



/* Skill detail pane — rules copied from assets/css/ui.css (.skill-header,
   #skill-body typography, #bundled-files, .file-list, #file-preview, .loading,
   .error), re-scoped under the component. Pane switching (readme ↔ skill),
   bundled-files presence, file-preview visibility, and loading/error states
   are all CSS-driven off data-* attributes on the component root — no
   style.display or classList toggling in JS. */

ui-skill-detail {
    display: block;

    /* ── Pane switching: empty prompt vs skill view ────────────────────────── */

    > .detail-empty {
        margin: 0;
        padding: 2rem 0;
        color: var(--muted);
        font-size: 0.9rem;
    }

    &[data-view="skill"] > .detail-empty {
        display: none;
    }

    &[data-view="readme"] #skill-detail {
        display: none;
    }

    /* ── Loading / error states (replace the old innerHTML swaps) ──────────── */

    #skill-detail .loading {
        display: none;
        color: var(--faint);
        font-size: 0.85rem;
        padding: 2rem 0;
    }

    &[data-state="loading"] #skill-detail .loading {
        display: block;
    }

    #skill-detail .skill-error {
        display: none;
        color: var(--stuck);
        font-size: 0.85rem;
        padding: 1rem 0;
    }

    &[data-state="error"] #skill-detail .skill-error {
        display: block;
    }

    &[data-state="loading"] #skill-body,
    &[data-state="error"] #skill-body {
        display: none;
    }

    /* ── Header ────────────────────────────────────────────────────────────── */

    .skill-header {
        margin-bottom: 1.5rem;
        padding-bottom: 1rem;
        border-bottom: 1px solid var(--line);

        .skill-title-row {
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto;
            align-items: center;
            gap: 1rem;
        }

        .skill-actions {
            display: grid;
            grid-auto-flow: column;
            justify-content: start;
            align-items: center;
            gap: 0.75rem;
        }

        .enable-toggle {
            display: inline-grid;
            grid-auto-flow: column;
            align-items: center;
            gap: 0.35rem;
            color: var(--muted);
            font-size: 0.75rem;
            font-weight: 500;
            cursor: pointer;
        }

        .enable-toggle input {
            width: 0.9rem;
            height: 0.9rem;
            accent-color: var(--brand);
        }

        h2 {
            font-size: 1.4rem;
            font-weight: 600;
            color: var(--text);
        }

        .danger-btn {
            border: 1px solid color-mix(in srgb, var(--stuck) 45%, transparent);
            background: transparent;
            color: var(--stuck);
            border-radius: 0.25rem;
            padding: 0.25rem 0.55rem;
            font-size: 0.75rem;
            cursor: pointer;
        }

        .danger-btn:hover {
            background: color-mix(in srgb, var(--stuck) 10%, transparent);
        }

        .danger-btn:disabled {
            opacity: 0.55;
            cursor: wait;
        }

        .version {
            font-size: 0.75rem;
            font-weight: 500;
            color: var(--faint);
            background: var(--raised);
            padding: 0.15rem 0.5rem;
            border-radius: 0.25rem;
            display: inline-block;
            margin-top: 0.25rem;
        }

        .description {
            font-size: 0.9rem;
            color: var(--muted);
            margin-top: 0.5rem;
            line-height: 1.6;
        }
    }

    /* ── Markdown body typography (from the shared #skill-body block) ──────── */

    #skill-body {
        max-width: 720px;

        h1 {
            font-size: 1.3rem;
            font-weight: 600;
            margin: 1.5rem 0 0.75rem;
            color: var(--text);
        }

        h2 {
            font-size: 1.1rem;
            font-weight: 600;
            margin: 1.25rem 0 0.5rem;
            color: var(--text);
        }

        h3 {
            font-size: 1rem;
            font-weight: 600;
            margin: 1rem 0 0.5rem;
            color: var(--text);
        }

        p {
            margin: 0 0 0.75rem;
            color: var(--text);
        }

        ul,
        ol {
            margin: 0 0 0.75rem 1.25rem;
        }

        li {
            margin-bottom: 0.25rem;
            color: var(--text);
        }

        code {
            background: var(--raised);
            padding: 0.1em 0.35em;
            border-radius: 0.1875rem;
            font-size: 0.85em;
            font-family: "SF Mono", "Fira Code", "Fira Mono", monospace;
            color: var(--clay);
        }

        pre {
            background: var(--code-bg);
            border: 1px solid var(--line);
            border-radius: 0.375rem;
            padding: 0.75rem 1rem;
            overflow-x: auto;
            margin: 0 0 0.75rem;
            font-size: 0.82rem;
            line-height: 1.5;
        }

        pre code {
            background: none;
            padding: 0;
            color: var(--text);
        }

        table {
            border-collapse: collapse;
            margin: 0 0 0.75rem;
            width: 100%;
            font-size: 0.85rem;
        }

        th,
        td {
            border: 1px solid var(--line);
            padding: 0.4rem 0.6rem;
            text-align: left;
        }

        th {
            background: var(--panel);
            color: var(--text);
            font-weight: 600;
        }

        td {
            color: var(--muted);
        }

        a {
            color: var(--link);
            text-decoration: none;

            &:hover {
                text-decoration: underline;
            }
        }

        hr {
            border: none;
            border-top: 1px solid var(--line);
            margin: 1rem 0;
        }

        blockquote {
            border-left: 0.1875rem solid var(--line-3);
            padding-left: 0.75rem;
            margin: 0 0 0.75rem;
            color: var(--muted);
        }
    }

    /* ── Bundled files (hidden until a skill with files loads) ─────────────── */

    #bundled-files {
        margin-top: 2rem;
        padding-top: 1rem;
        border-top: 1px solid var(--line);
    }

    &:not([data-has-files]) #bundled-files {
        display: none;
    }

    #bundled-files h3 {
        font-size: 0.85rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        color: var(--faint);
        margin-bottom: 0.5rem;
    }

    .file-list {
        list-style: none;

        li {
            padding: 0.3rem 0;
        }

        a {
            font-size: 0.85rem;
            font-family: "SF Mono", "Fira Code", monospace;
            color: var(--link);
            cursor: pointer;
            transition: color 0.15s;

            &:hover {
                text-decoration: underline;
            }
        }
    }

    /* ── File preview (was #file-preview.visible class toggling) ───────────── */

    #file-preview {
        margin-top: 1rem;
        display: none;
    }

    &[data-preview] #file-preview {
        display: block;
    }

    #file-preview .file-header {
        display: grid;
        grid-auto-flow: column;
        justify-content: start;
        align-items: center;
        gap: 0.5rem;
        margin-bottom: 0.5rem;

        h4 {
            font-size: 0.8rem;
            font-weight: 500;
            color: var(--muted);
            font-family: "SF Mono", monospace;
        }
    }

    #file-preview .close-btn {
        background: none;
        border: 1px solid var(--line-3);
        color: var(--muted);
        border-radius: 0.25rem;
        padding: 0.1rem 0.4rem;
        font-size: 0.7rem;
        cursor: pointer;
        transition: all 0.15s;

        &:hover {
            background: var(--raised);
            border-color: var(--line-3);
        }
    }

    #file-preview pre {
        background: var(--code-bg);
        border: 1px solid var(--line);
        border-radius: 0.375rem;
        padding: 0.75rem 1rem;
        overflow-x: auto;
        font-size: 0.8rem;
        line-height: 1.5;
        color: var(--text);
    }
}



/* Add Skill modal — rules copied from assets/css/ui.css (.modal-overlay,
   .modal, .modal-header, #skill-form, .modal-actions, .error), re-scoped
   under the component. Open/close is CSS-driven off [data-open] on the
   component root; the error box off [data-error] — no style.display in JS. */

/* The component sits as a direct body child (the overlay is position:fixed);
   display:contents keeps it from becoming a body-grid item. */
ui-skill-form {
    display: contents;

    .modal-overlay {
        position: fixed;
        inset: 0;
        background: hsl(0deg 0% 0% / 0.55);
        display: none;
        align-items: center;
        justify-content: center;
        z-index: 100;
    }

    &[data-open] .modal-overlay {
        display: grid;
        place-items: center;
    }

    .modal {
        background: var(--panel);
        border: 1px solid var(--line);
        border-radius: 0.6rem;
        width: 34rem;
        max-width: 92vw;
        max-height: 85vh;
        overflow-y: auto;
        box-shadow: 0 0.5rem 1.5rem hsl(0deg 0% 0% / 0.4), 0 0.1rem 0.3rem hsl(0deg 0% 0% / 0.3);
    }

    .modal-header {
        display: grid;
        grid-template-columns: auto 1fr auto;
        align-items: stretch;
        gap: 1.1rem;
        padding: 0 1.1rem;
        min-height: 2.8rem;
        border-bottom: 1px solid var(--line);

        h3 {
            font-size: 1rem;
            font-weight: 600;
            align-self: center;
        }

        .close-btn {
            align-self: center;
        }
    }

    .close-btn {
        background: none;
        border: 1px solid var(--line-3);
        color: var(--muted);
        border-radius: 0.25rem;
        padding: 0.1rem 0.4rem;
        font-size: 0.7rem;
        cursor: pointer;
        transition: all 0.15s;

        &:hover {
            background: var(--raised);
            border-color: var(--line-3);
        }
    }

    /* Tab strip lives in the modal header; panes toggle off the checked
       radio via :has() on the component root (labels aren't siblings of the
       bodies, so app's adjacent-sibling variant doesn't apply). No JS. */
    .ui-tabpanel {
        display: grid;
        grid-auto-flow: column;
        justify-content: start;

        > .ui-tabpanel-label {
            display: inline-grid;
            grid-auto-flow: column;
            align-items: center;
            padding: 0 0.75rem;
            cursor: pointer;
            user-select: none;
            color: var(--muted);
            font-size: 0.8rem;
            font-weight: 600;
            white-space: nowrap;
            border-bottom: 0.125rem solid transparent;

            > input[type="radio"] {
                position: absolute;
                opacity: 0;
                pointer-events: none;
                width: 0;
                height: 0;
            }

            &:hover {
                color: var(--text);
            }

            &:has(input:checked) {
                color: var(--text);
                border-bottom-color: var(--brand);
            }
        }

    }

    .ui-tabpanel-body {
        display: none;
    }

    &:has([name="skill-form-tab"][value="manual"]:checked) #skill-form,
    &:has([name="skill-form-tab"][value="import"]:checked) #skill-import-form {
        display: grid;
    }

    /* display comes from .ui-tabpanel-body (an id rule would out-rank the
       tab switcher's display:none) */
    #skill-form {
        gap: 0.85rem;
        padding: 1.1rem;

        label {
            display: grid;
            gap: 0.3rem;
            font-size: 0.8rem;
            font-weight: 600;
            color: var(--muted);
        }

        input,
        textarea {
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--line);
            border-radius: 0.3rem;
            padding: 0.45rem 0.6rem;
            font-family: inherit;
            font-size: 0.85rem;
            resize: vertical;
        }

        textarea#skill-form-body {
            font-family: "SF Mono", monospace;
            font-size: 0.8rem;
        }

        input:focus,
        textarea:focus {
            outline: none;
            border-color: var(--brand);
        }
    }

    #skill-import-form {
        gap: 0.85rem;
        padding: 1.1rem;
        align-content: start;

        label {
            display: grid;
            gap: 0.3rem;
            font-size: 0.8rem;
            font-weight: 600;
            color: var(--muted);
        }

        input {
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--line);
            border-radius: 0.3rem;
            padding: 0.45rem 0.6rem;
            font-family: inherit;
            font-size: 0.85rem;
        }

        input:focus {
            outline: none;
            border-color: var(--brand);
        }
    }

    .hint {
        font-weight: 400;
        color: var(--faint);
        text-transform: none;
        letter-spacing: normal;
    }

    .error {
        display: none;
        color: var(--stuck);
        font-size: 0.85rem;
        padding: 1rem 0;
    }

    &[data-error] [data-field="error"],
    &[data-import-error] [data-field="import-error"] {
        display: block;
    }

    .modal-actions {
        display: grid;
        justify-content: end;

        button {
            background: var(--brand);
            color: var(--bg);
            border: none;
            border-radius: 0.3rem;
            padding: 0.5rem 1.1rem;
            font-size: 0.85rem;
            font-weight: 600;
            cursor: pointer;

            &:disabled {
                opacity: 0.6;
                cursor: default;
            }
        }
    }
}



/* ui-entity-sidebar — vault filter + search/sort + entity list.
   Rules moved from assets/css/ui.css, re-scoped under the element. */

/* The component fills the #sidebar grid (ui.css owns #sidebar):
   header auto, list takes the rest and scrolls. */
ui-entity-sidebar {
    display: grid;
    grid-template-rows: auto 1fr;
    min-height: 0;
    overflow: hidden;

    .vault-picker {
        padding: 0.5rem 1rem 0.5rem;
        display: grid;
        gap: 0.4rem;

        /* ui-vault-picker trigger, at sidebar density. */
        .vault-trigger { font-size: 0.8rem; }
    }

    .ent-controls {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 0.3rem;
        padding: 0 1rem 0.5rem;

        input[type="text"] {
            min-width: 0;
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--line);
            border-radius: 4px;
            padding: 0.3rem 0.4rem;
            font-family: inherit;
            font-size: 0.8rem;

            &:focus { outline: 1px solid var(--brand); }
        }

        button {
            background: var(--bg);
            color: var(--muted);
            border: 1px solid var(--line);
            border-radius: 4px;
            padding: 0.3rem 0.5rem;
            font-size: 0.8rem;
            cursor: pointer;
            font-variant-numeric: tabular-nums;

            &:hover { color: var(--brand); border-color: var(--line-3); }
        }
    }

    .count {
        font-size: 0.7rem;
        color: var(--faint);
        padding: 0 1rem 0.5rem;
        border-bottom: 1px solid var(--line);
    }

    #entity-list {
        list-style: none;
        overflow-y: auto;
        padding: 0.25rem 0;
        min-height: 3.75rem;

        /* Entity row — icon spans both rows, then two text rows:
             [icon] [name] ............ [mentions]
             [icon] [kind] ............ [domain]   */
        /* renderChunked's load-more marker: no row chrome, just a box to observe. */
        li[data-sentinel] {
            padding: 0;
            border: 0;
            block-size: 0.0625rem;
            cursor: default;
        }

        li {
            padding: 0.4rem 1rem;
            cursor: pointer;
            border-left: 3px solid transparent;
            color: var(--muted);
            transition: all 0.15s ease;
            display: grid;
            /* col2 = minmax(0,1fr) so the name shrinks+ellipsises instead of overflowing;
               col3 capped so a long right-hand value (mentions/vaults) can't steal the
               name's width (multi-vault rows were collapsing "nats" → "n."). */
            grid-template-columns: auto minmax(0, 1fr) minmax(0, 6rem);
            align-items: baseline;
            column-gap: 0.5rem;
            row-gap: 0.1rem;

            &:hover {
                background: var(--raised);
                color: var(--text);
            }

            &[data-active] {
                background: var(--raised);
                border-left-color: var(--brand);
                color: var(--text);
            }

            > span {
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
                min-width: 0;
            }

            .ent-icon {
                grid-column: 1;
                grid-row: 1 / span 2;
                align-self: center;
                width: 1.7rem;
                height: 1.7rem;
                border-radius: 0.35rem;
                background: var(--raised);
                color: var(--faint);
                display: grid;
                place-items: center;
                font-size: 0.75rem;
                font-weight: 600;
                text-transform: uppercase;
            }

            &:hover .ent-icon { color: var(--brand); }

            /* pending-consolidation glyph sits in the slot as a status icon, not a letter badge */
            &[data-pending] .ent-icon {
                background: transparent;
                font-size: 0.95rem;
                text-transform: none;
            }

            .ent-name {
                grid-column: 2;
                grid-row: 1;
                font-size: 0.82rem;
            }

            .ent-mentions {
                grid-column: 3;
                grid-row: 1;
                justify-self: end;
                font-size: 0.68rem;
                color: var(--faint);
                font-variant-numeric: tabular-nums;
            }

            .ent-kind {
                grid-column: 2;
                grid-row: 2;
                justify-self: start;
                font-size: 0.6rem;
                color: var(--faint);
                text-transform: uppercase;
                letter-spacing: 0.04em;
            }

            .ent-domain {
                grid-column: 3;
                grid-row: 2;
                justify-self: end;
                font-size: 0.6rem;
                color: var(--faint);
                font-family: "SF Mono", monospace;
                max-width: 9rem;
            }
        }
    }

    .entity-stub {
        color: var(--faint);
        font-style: italic;
        font-size: 0.85rem;
        padding: 0.5rem 0;
    }

    .error {
        color: var(--stuck);
        font-size: 0.85rem;
        padding: 1rem 0;
    }
}

/* Vault-locked view (/vaults/<slug>/entities): the vault is already in the
   header — drop the per-row vault label. lockVaultSelect marks data-locked. */
ui-entity-sidebar:has(select[data-locked]) .ent-domain {
    display: none;
}



/* ui-entity-detail — two-column entity pane + empty-state view switch.
   Rules moved from assets/css/ui.css, re-scoped under the element.
   Visibility is CSS-driven off data-view / data-state / data-summary attrs. */

ui-entity-detail {
    display: block;
    /* Query container so the two-column ↔ stacked switch keys off the CONTENT
       width (inside #main, minus the 20rem sidebar), not the viewport. */
    container-type: inline-size;

    /* View switch: empty prompt ↔ entity. */
    .detail-empty {
        display: none;
        margin: 0;
        padding: 2rem 0;
        color: var(--muted);
        font-size: 0.9rem;
    }
    &[data-view="readme"] .detail-empty { display: block; }

    /* Entity detail: content left (same 720px cap as other panes), header/chips right. */
    #entity-detail { display: none; }
    &[data-view="entity"] #entity-detail {
        display: grid;
        /* side column capped at 20rem so wide viewports don't stretch the chips */
        grid-template-columns: minmax(0, 720px) minmax(0, 20rem);
        gap: 2rem;
        align-items: start;
    }
    .entity-main { min-width: 0; }
    .entity-side .skill-header {
        border-bottom: none;
        padding-bottom: 0;
        margin-bottom: 0;
    }
    @container (max-width: 1000px) {
        &[data-view="entity"] #entity-detail { grid-template-columns: 1fr; }
        .entity-side { order: -1; }
        .entity-side .skill-header {
            border-bottom: 1px solid var(--line);
            padding-bottom: 1rem;
        }
    }

    /* Load / error state (shown instead of JS-injected placeholder markup). */
    .loading {
        display: none;
        color: var(--faint);
        font-size: 0.85rem;
        padding: 2rem 0;
    }
    &[data-state="loading"] .loading { display: block; }
    .error {
        display: none;
        color: var(--stuck);
        font-size: 0.85rem;
        padding: 1rem 0;
    }
    &[data-state="error"] .error { display: block; }

    /* No-summary stub — visible only when the loaded entity has no summary. */
    .no-summary { display: none; }
    &[data-state="ready"][data-summary="stub"] .no-summary { display: block; }
    .entity-stub {
        color: var(--faint);
        font-style: italic;
        font-size: 0.85rem;
        padding: 0.5rem 0;
    }
    /* Old stub rendered inside #entity-body and inherited its code-chip style;
       the SSR stub sits beside it, so carry the rule over. */
    .no-summary code {
        background: var(--raised);
        padding: 0.1em 0.35em;
        border-radius: 3px;
        font-size: 0.85em;
        font-family: "SF Mono", "Fira Code", "Fira Mono", monospace;
        color: var(--clay);
    }

    /* Right-hand header (name / kind badge / meta + chips). */
    .skill-header {
        margin-bottom: 1.5rem;
        padding-bottom: 1rem;
        border-bottom: 1px solid var(--line);

        h2 {
            font-size: 1.4rem;
            font-weight: 600;
            color: var(--text);
        }

        .version {
            font-size: 0.75rem;
            font-weight: 500;
            color: var(--faint);
            background: var(--raised);
            padding: 0.15rem 0.5rem;
            border-radius: 4px;
            display: inline-block;
            margin-top: 0.25rem;
        }

        .description {
            font-size: 0.9rem;
            color: var(--muted);
            margin-top: 0.5rem;
            line-height: 1.6;
        }
    }
    .ent-chips {
        display: flex;
        flex-wrap: wrap;
        gap: 0.3rem;
        margin-top: 0.5rem;

        &:empty { display: none; }
    }
    .ent-chip {
        font-size: 0.7rem;
        padding: 0.1rem 0.45rem;
        border-radius: 3px;
        background: var(--raised);
        color: var(--muted);
        font-family: "SF Mono", monospace;

        &.vault { background: var(--clay-soft); color: var(--clay); }
    }
    .context-link {
        display: inline-grid;
        grid-auto-flow: column;
        align-items: center;
        min-height: 1.75rem;
        margin-top: 0.75rem;
        border: 1px solid var(--line);
        border-radius: 4px;
        padding: 0.25rem 0.55rem;
        color: var(--muted);
        font-size: 0.78rem;
        text-decoration: none;

        &:hover {
            border-color: var(--link);
            color: var(--link);
        }
    }

    /* Mentioned-in list. */
    #bundled-files {
        margin-top: 2rem;
        padding-top: 1rem;
        border-top: 1px solid var(--line);

        h3 {
            font-size: 0.85rem;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.06em;
            color: var(--faint);
            margin-bottom: 0.5rem;
        }
    }
    /* Mentioned-In tabs — radio-driven .ui-tabpanel (same pattern as the
       skill form): CSS :has() switches panes; the atom pane's rows are built
       lazily by JS on first activation. */
    #bundled-files .ui-tabpanel {
        display: grid;
        grid-auto-flow: column;
        justify-content: start;
        border-bottom: 1px solid var(--line);
        margin-bottom: 0.5rem;

        > .ui-tabpanel-label {
            display: inline-grid;
            grid-auto-flow: column;
            align-items: center;
            padding: 0.25rem 0.65rem;
            cursor: pointer;
            user-select: none;
            color: var(--muted);
            font-size: 0.78rem;
            font-weight: 600;
            white-space: nowrap;
            border-bottom: 0.125rem solid transparent;

            > input[type="radio"] {
                position: absolute;
                opacity: 0;
                pointer-events: none;
                width: 0;
                height: 0;
            }

            &:hover { color: var(--text); }

            &:has(input:checked) {
                color: var(--text);
                border-bottom-color: var(--brand);
            }
        }
    }

    #bundled-files .ui-tabpanel-body { display: none; }
    &:has([name="entity-mention-tab"][value="docs"]:checked) #entity-doc-list {
        display: block;
    }
    &:has([name="entity-mention-tab"][value="atoms"]:checked) #entity-atom-list {
        display: block;
    }

    #entity-doc-list,
    #entity-atom-list {
        list-style: none;

        li {
            padding: 0.3rem 0;
            font-size: 0.85rem;
        }

        a {
            color: var(--link);
            cursor: pointer;
            font-family: "SF Mono", "Fira Code", monospace;
            text-decoration: none;

            &:hover { text-decoration: underline; }
        }
    }

    /* Atom titles are long distilled sentences — one line each, ellipsised,
       so the list scans as rows instead of a wall of wrapped text. */
    #entity-atom-list li {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Markdown-rendered summary — mirrors the shared body typography from ui.css. */
    #entity-body {
        max-width: 720px;

        h1 {
            font-size: 1.3rem;
            font-weight: 600;
            margin: 1.5rem 0 0.75rem;
            color: var(--text);
        }

        h2 {
            font-size: 1.1rem;
            font-weight: 600;
            margin: 1.25rem 0 0.5rem;
            color: var(--text);
        }

        h3 {
            font-size: 1rem;
            font-weight: 600;
            margin: 1rem 0 0.5rem;
            color: var(--text);
        }

        p { margin: 0 0 0.75rem; color: var(--text); }

        ul,
        ol { margin: 0 0 0.75rem 1.25rem; }

        li { margin-bottom: 0.25rem; color: var(--text); }

        code {
            background: var(--raised);
            padding: 0.1em 0.35em;
            border-radius: 3px;
            font-size: 0.85em;
            font-family: "SF Mono", "Fira Code", "Fira Mono", monospace;
            color: var(--clay);
        }

        pre {
            background: var(--code-bg);
            border: 1px solid var(--line);
            border-radius: 6px;
            padding: 0.75rem 1rem;
            overflow-x: auto;
            margin: 0 0 0.75rem;
            font-size: 0.82rem;
            line-height: 1.5;

            code {
                background: none;
                padding: 0;
                color: var(--text);
            }
        }

        table {
            border-collapse: collapse;
            margin: 0 0 0.75rem;
            width: 100%;
            font-size: 0.85rem;
        }

        th,
        td {
            border: 1px solid var(--line);
            padding: 0.4rem 0.6rem;
            text-align: left;
        }

        th {
            background: var(--panel);
            color: var(--text);
            font-weight: 600;
        }

        td { color: var(--muted); }

        a {
            color: var(--link);
            text-decoration: none;

            &:hover { text-decoration: underline; }
        }

        hr {
            border: none;
            border-top: 1px solid var(--line);
            margin: 1rem 0;
        }

        blockquote {
            border-left: 3px solid var(--line-3);
            padding-left: 0.75rem;
            margin: 0 0 0.75rem;
            color: var(--muted);
        }
    }

    /* On-demand summary rebuild — lives in the side header, always available. */
    .consolidate-btn {
        display: block;
        margin-top: 0.5rem;
        padding: 0.2rem 0.6rem;
        border: 1px solid var(--brand);
        border-radius: 0.3rem;
        background: transparent;
        color: var(--brand);
        font: inherit;
        font-size: 0.78rem;
        cursor: pointer;

        &:hover:not(:disabled) {
            background: var(--clay-soft);
        }

        &:disabled {
            opacity: 0.6;
            cursor: progress;
        }
    }

    /* ── Relations panel ("how do you know?") ───────────────────────────── */
    .ent-relations {
        margin-top: 1.25rem;

        h3 {
            font-size: 0.82rem;
            font-weight: 650;
            color: var(--muted);
            text-transform: uppercase;
            letter-spacing: 0.06em;
            margin-bottom: 0.5rem;
        }

        ul { list-style: none; }
    }

    /* Empty state: hide the panel entirely rather than show a bare heading */
    &[data-relations="none"] .ent-relations { display: none; }

    .rel-row {
        summary {
            display: grid;
            grid-auto-flow: column;
            justify-content: start;
            align-items: center;
            gap: 0.5rem;
            padding: 0.3rem 0.4rem;
            border-radius: 0.3rem;
            cursor: pointer;
            list-style: none;

            &:hover { background: var(--raised); }
            &::-webkit-details-marker { display: none; }
        }

        .rel-type {
            font-size: 0.62rem;
            padding: 0.0625rem 0.375rem;
            border-radius: 0.125rem;
            letter-spacing: 0.05em;
            background: var(--bg);
            border: 1px solid var(--line-3);
            color: var(--muted);
            white-space: nowrap;

            /* Type colours mirror the knowledge-map edge palette */
            &[data-rel="part_of"] { color: var(--stuck); border-color: var(--stuck); }
            &[data-rel="depends_on"] { color: var(--link); border-color: var(--link); }
            &[data-rel="integrates_with"] { color: var(--ok); border-color: var(--ok); }
            &[data-rel="supersedes"] { color: var(--brand); border-color: var(--brand); }
        }

        .rel-arrow { color: var(--faint); }

        .rel-other {
            color: var(--link);
            text-decoration: none;
            font-size: 0.82rem;

            &:hover { text-decoration: underline; }
        }

        .rel-meta {
            color: var(--faint);
            font-size: 0.68rem;
            margin-left: auto;
        }
    }

    .rel-evidence {
        margin: 0.25rem 0 0.5rem 1.5rem;
        display: grid;
        gap: 0.25rem;

        li {
            font-size: 0.74rem;
            color: var(--muted);

            q { font-style: italic; }

            a {
                color: var(--link);
                font-size: 0.68rem;
                margin-left: 0.375rem;
                text-decoration: none;

                &:hover { text-decoration: underline; }
            }
        }
    }
}



/* Docs sidebar — rules copied from assets/css/ui.css (.vault-picker,
   .ent-controls, .count, #docs-list + .doc-title/.doc-vault, .loading,
   .error), re-scoped under the component. Do not edit ui.css — a central
   cleanup strips the old copies afterward. */

ui-docs-sidebar {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    min-height: 0; /* #sidebar's grid gives this the filling row */
    overflow: hidden;

    .vault-picker {
        padding: 0.5rem 1rem 0.5rem;
        display: grid;
        gap: 0.4rem;

        select {
            width: 100%;
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--line);
            border-radius: 4px;
            padding: 0.3rem 0.4rem;
            font-size: 0.8rem;
            font-family: inherit;

            &:focus {
                outline: 1px solid var(--brand);
            }
        }

        /* ui-vault-picker trigger, at the type select's density. */
        .vault-trigger { font-size: 0.8rem; }
    }

    .ent-controls {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 0.3rem;
        padding: 0 1rem 0.5rem;

        input[type="text"] {
            min-width: 0;
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--line);
            border-radius: 4px;
            padding: 0.3rem 0.4rem;
            font-family: inherit;
            font-size: 0.8rem;

            &:focus {
                outline: 1px solid var(--brand);
            }
        }

        button {
            background: var(--bg);
            color: var(--muted);
            border: 1px solid var(--line);
            border-radius: 4px;
            padding: 0.3rem 0.5rem;
            font-size: 0.8rem;
            cursor: pointer;
            font-variant-numeric: tabular-nums;

            &:hover {
                color: var(--brand);
                border-color: var(--line-3);
            }
        }
    }

    .count {
        font-size: 0.7rem;
        color: var(--faint);
        padding: 0 1rem 0.5rem;
        border-bottom: 1px solid var(--line);
    }

    #docs-list {
        list-style: none;
        overflow-y: auto;
        padding: 0.25rem 0;

        li {
            padding: 0.45rem 1rem;
            cursor: pointer;
            border-left: 3px solid transparent;
            color: var(--muted);
            transition: all 0.15s ease;
            display: grid;
            row-gap: 0.15rem;

            &:hover {
                background: var(--raised);
                color: var(--text);
            }

            &.active {
                background: var(--raised);
                border-left-color: var(--brand);
                color: var(--text);
            }
        }

        .doc-title {
            font-size: 0.82rem;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        /* Second line: author left, vault right. */
        .doc-meta {
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto;
            align-items: baseline;
            column-gap: 0.5rem;
            font-size: 0.68rem;
            color: var(--faint);
        }

        .doc-author {
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }

        .doc-vault {
            font-family: "SF Mono", monospace;
            font-size: 0.65rem;
            justify-self: end;
        }

        /* Placeholder rows (removed / replaced by the first render). */
        /* renderChunked's load-more marker: no row chrome, just a box to observe. */
        li[data-sentinel] {
            padding: 0;
            border: 0;
            block-size: 0.0625rem;
            cursor: default;
        }

        li.loading,
        li.error {
            cursor: default;
            display: block;
        }
    }

    .loading {
        color: var(--faint);
        font-size: 0.85rem;
    }

    .error {
        color: var(--stuck);
        font-size: 0.85rem;
    }
}

/* Vault-locked view (/vaults/<slug>/docs): every row is that vault — drop the
   per-row vault label. lockVaultSelect marks the filter data-locked. */
ui-docs-sidebar:has(select[data-locked]) .doc-vault {
    display: none;
}



/* Doc detail pane — rules copied from assets/css/ui.css (.skill-header block,
   .vault-trigger, .ent-chips/.ent-chip, #doc-body markdown typography,
   .loading, .error), re-scoped under the component. Everything is scoped
   under #doc-detail so nothing bleeds into the empty-state prompt.
   Do not edit ui.css — a central cleanup strips the old copies afterward. */

ui-doc-detail {
    display: block;

    /* empty ↔ doc view switch, driven by [data-view] on the component root.
       The .detail-empty prompt shows until a doc is selected. */
    > #doc-detail {
        display: none;
    }

    &[data-view="doc"] {
        > #doc-detail {
            display: block;
        }

        > .detail-empty {
            display: none;
        }
    }

    > .detail-empty {
        margin: 0;
        padding: 2rem 0;
        color: var(--muted);
        font-size: 0.9rem;
    }

    #doc-detail {
        .skill-header {
            margin-bottom: 1.5rem;
            padding-bottom: 1rem;
            border-bottom: 1px solid var(--line);

            h2 {
                font-size: 1.4rem;
                font-weight: 600;
                color: var(--text);
            }

            .version {
                font-size: 0.75rem;
                font-weight: 500;
                color: var(--faint);
                background: var(--raised);
                padding: 0.15rem 0.5rem;
                border-radius: 4px;
                display: inline-block;
                margin-top: 0.25rem;
            }
        }

        /* Vault selector and meta line share one row; it wraps on narrow panes. */
        .doc-head-row {
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            column-gap: 0.75rem;
            row-gap: 0.25rem;
            margin-top: 0.5rem;

            .description { margin-top: 0; }
        }

        /* ui-vault-picker trigger (replaces select#doc-vault): a compact pill
           beside the meta line; coarse pointers still get the 2.75rem target. */
        .vault-trigger {
            display: inline-grid;
            font-size: 0.75rem;
            color: var(--muted);
            background: var(--raised);
        }

        .skill-header .description {
            font-size: 0.9rem;
            color: var(--muted);
            margin-top: 0.5rem;
            line-height: 1.6;
        }

        .raw-toggle {
            font-size: 0.7rem;
            font-family: "SF Mono", monospace;
            color: var(--faint);
            background: var(--raised);
            border: 1px solid var(--line);
            border-radius: 3px;
            padding: 0.1rem 0.45rem;
            margin-left: 0.5rem;
            cursor: pointer;

            &:hover {
                color: var(--text);
                border-color: var(--line-3);
            }
        }

        /* Data doc marker in the meta line (ADR-0030); empty on ordinary docs. */
        .data-badge {
            font-size: 0.7rem;
            font-family: "SF Mono", monospace;
            color: var(--clay);
            background: var(--raised);
            border-radius: 0.2rem;
            padding: 0.1rem 0.45rem;
            margin-left: 0.5rem;
            white-space: nowrap;

            &:empty {
                display: none;
            }
        }

        .context-link {
            color: var(--link);
            font-size: 0.75rem;
            margin-left: 0.5rem;
        }

        /* Trash icon (Material Symbols, masked so it takes the button colour). */
        .delete-btn {
            display: inline-grid;
            place-items: center;
            padding: 0.15rem 0.3rem;
            vertical-align: middle;

            .icon-trash {
                display: block;
                width: 0.85rem;
                height: 0.85rem;
                background: currentColor;
                mask: url("/img/delete.svg") no-repeat center / contain;
            }
        }

        .delete-btn:hover {
            color: var(--stuck);
            border-color: var(--stuck);
        }

        /* Single-axis chip row — flex permitted here. */
        .ent-chips {
            display: flex;
            flex-wrap: wrap;
            gap: 0.3rem;
            margin-top: 0.5rem;

            &:empty {
                display: none;
                margin-top: 0;
            }
        }

        .ent-chip {
            font-size: 0.7rem;
            padding: 0.1rem 0.45rem;
            border-radius: 3px;
            background: var(--raised);
            color: var(--muted);
            font-family: "SF Mono", monospace;
        }

        /* Load/error state, driven by [data-state] on the component root. Errors are
           :empty-collapsed so the vault-reassign error only shows when filled. */
        .loading {
            display: none;
            color: var(--faint);
            font-size: 0.85rem;
            padding: 2rem 0;
        }
    }

    &[data-state="loading"] #doc-detail .loading {
        display: block;
    }

    #doc-detail {
        .error {
            color: var(--stuck);
            font-size: 0.85rem;
            padding: 1rem 0;

            &:empty {
                display: none;
            }
        }

        .vault-error {
            padding: 0.5rem 0 0;
        }

        .doc-error {
            padding: 1rem 0;
        }

        .doc-lineage {
            max-width: 720px;
            border: 1px solid var(--line);
            border-radius: 0.45rem;
            background: var(--panel);
            padding: 0.8rem;
            margin: 0 0 1rem;

            h3 {
                font-size: 0.88rem;
                font-weight: 650;
                margin-bottom: 0.6rem;
            }
        }

        .lineage-grid {
            display: grid;
            grid-template-columns: repeat(2, minmax(0, 1fr));
            gap: 0.75rem;

            section {
                min-width: 0;
            }

            h4 {
                color: var(--faint);
                font-size: 0.66rem;
                font-weight: 650;
                letter-spacing: 0.05em;
                margin-bottom: 0.35rem;
                text-transform: uppercase;
            }

            ul {
                list-style: none;
                display: grid;
                gap: 0.25rem;
            }

            li {
                display: grid;
                grid-template-columns: auto minmax(0, 1fr);
                gap: 0.45rem;
                align-items: baseline;
                color: var(--muted);
                font-size: 0.78rem;
                min-width: 0;
            }

            li.lineage-empty {
                display: block;
                color: var(--faint);
                font-style: italic;
            }

            span {
                color: var(--clay);
                font-family: "SF Mono", monospace;
                font-size: 0.68rem;
            }

            a {
                color: var(--link);
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
            }
        }
    }

    /* Raw ingested text — visible only in [data-mode=raw] (rendered is the
       default; #load resets the mode on every doc). */
    #doc-raw {
        display: none;
        max-width: 720px;
        background: var(--code-bg);
        border: 1px solid var(--line);
        border-radius: 6px;
        padding: 0.75rem 1rem;
        font-size: 0.82rem;
        line-height: 1.5;
        font-family: "SF Mono", "Fira Code", "Fira Mono", monospace;
        color: var(--text);
        white-space: pre-wrap;
        word-break: break-word;
    }

    /* "Showing the first N of M" — only in raw mode, only when capped. */
    .raw-note {
        display: none;
        max-width: 45rem;
        color: var(--faint);
        font-size: 0.78rem;
        margin-bottom: 0.5rem;
    }

    &[data-mode="raw"] {
        #doc-raw {
            display: block;
        }

        .raw-note:not(:empty) {
            display: block;
        }

        #doc-body {
            display: none;
        }
    }

    /* Markdown body typography (copied from the ui.css #doc-body variants). */
    #doc-body {
        max-width: 720px;

        h1 {
            font-size: 1.3rem;
            font-weight: 600;
            margin: 1.5rem 0 0.75rem;
            color: var(--text);
        }

        h2 {
            font-size: 1.1rem;
            font-weight: 600;
            margin: 1.25rem 0 0.5rem;
            color: var(--text);
        }

        h3 {
            font-size: 1rem;
            font-weight: 600;
            margin: 1rem 0 0.5rem;
            color: var(--text);
        }

        p {
            margin: 0 0 0.75rem;
            color: var(--text);
        }

        ul,
        ol {
            margin: 0 0 0.75rem 1.25rem;
        }

        li {
            margin-bottom: 0.25rem;
            color: var(--text);
        }

        code {
            background: var(--raised);
            padding: 0.1em 0.35em;
            border-radius: 3px;
            font-size: 0.85em;
            font-family: "SF Mono", "Fira Code", "Fira Mono", monospace;
            color: var(--clay);
        }

        pre {
            background: var(--code-bg);
            border: 1px solid var(--line);
            border-radius: 6px;
            padding: 0.75rem 1rem;
            overflow-x: auto;
            margin: 0 0 0.75rem;
            font-size: 0.82rem;
            line-height: 1.5;

            code {
                background: none;
                padding: 0;
                color: var(--text);
            }
        }

        table {
            border-collapse: collapse;
            margin: 0 0 0.75rem;
            width: 100%;
            font-size: 0.85rem;
        }

        th,
        td {
            border: 1px solid var(--line);
            padding: 0.4rem 0.6rem;
            text-align: left;
        }

        th {
            background: var(--panel);
            color: var(--text);
            font-weight: 600;
        }

        td {
            color: var(--muted);
        }

        a {
            color: var(--link);
            text-decoration: none;

            &:hover {
                text-decoration: underline;
            }
        }

        hr {
            border: none;
            border-top: 1px solid var(--line);
            margin: 1rem 0;
        }

        blockquote {
            border-left: 3px solid var(--line-3);
            padding-left: 0.75rem;
            margin: 0 0 0.75rem;
            color: var(--muted);
        }
    }

    @media (max-width: 760px) {
        #doc-detail .lineage-grid {
            grid-template-columns: 1fr;
        }
    }

    /* Delete confirmation dialog — native <dialog>
       (top layer via showModal). Delete's confirm button flips to the
       danger color below. */
    dialog.delete-confirm {
        /* the global `* { margin: 0 }` reset kills the UA's margin:auto dialog
           centering — restore it. */
        margin: auto;
        background: var(--panel);
        color: var(--text);
        border: 1px solid var(--line);
        border-radius: 0.6rem;
        padding: 1.1rem 1.25rem;
        width: 26rem;
        max-width: 92vw;
        box-shadow: 0 0.5rem 1.5rem hsl(0 0% 0% / 0.4), 0 0.1rem 0.3rem hsl(0 0% 0% / 0.3);

        &::backdrop {
            background: hsl(0 0% 0% / 0.55);
        }

        h3 {
            font-size: 1rem;
            font-weight: 600;
            margin-bottom: 0.6rem;
        }

        p {
            font-size: 0.9rem;
            color: var(--muted);
            line-height: 1.6;

            strong {
                color: var(--clay);
                font-family: "SF Mono", monospace;
                font-weight: 600;
            }
        }

        menu {
            list-style: none;
            display: grid;
            grid-auto-flow: column;
            justify-content: end;
            gap: 0.5rem;
            margin-top: 1rem;

            button {
                border: 1px solid var(--line-3);
                border-radius: 0.3rem;
                background: none;
                color: var(--muted);
                padding: 0.4rem 1rem;
                font-size: 0.85rem;
                font-weight: 600;
                cursor: pointer;

                &[value="confirm"] {
                    background: var(--brand);
                    border-color: var(--brand);
                    color: var(--bg);
                }

                &:hover {
                    color: var(--text);

                    &[value="confirm"] {
                        opacity: 0.9;
                        color: var(--bg);
                    }
                }
            }
        }
    }

    dialog.delete-confirm menu button[value="confirm"] {
        background: var(--stuck);
        border-color: var(--stuck);
    }
}



ui-add-knowledge {
    display: grid;
    /* Fill #main vertically: header is auto, the form takes the rest, and the
       editor row inside it absorbs the slack. minmax(0,1fr) (not 1fr) so the
       textarea's own min-height cannot push the grid past the panel. */
    min-height: 100%;
    grid-template-rows: auto minmax(0, 1fr);
    gap: 1.25rem;
    color: var(--text);

    .add-header {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        gap: 1rem;
        align-items: start;

        .description {
            max-width: 46rem;
            margin: 0.45rem 0 0;
            color: var(--muted);
            font-size: 0.9rem;
            line-height: 1.55;
        }
    }

    .eyebrow,
    .header-actions label > span {
        margin: 0;
        color: var(--faint);
        font-size: 0.7rem;
        font-weight: 700;
        letter-spacing: 0.08em;
        text-transform: uppercase;
    }

    /* Vault picker beside the format badge. Single-axis row → flex. */
    .header-actions {
        display: flex;
        align-items: center;
        gap: 0.75rem;

        label {
            display: flex;
            align-items: center;
            gap: 0.45rem;
        }

        .vault-trigger { min-width: 11rem; }
    }

    .format-badge {
        padding: 0.3rem 0.55rem;
        border: 0.0625rem solid var(--line-3);
        border-radius: 999rem;
        color: var(--muted);
        background: var(--raised);
        font-family: "SF Mono", "Fira Code", monospace;
        font-size: 0.7rem;
    }

    #add-knowledge-form {
        display: grid;
        /* tabs, editor (absorbs slack), then feedback + footer as auto rows. */
        grid-template-rows: auto minmax(0, 1fr);
        min-height: 0;
        gap: 1rem;
    }

    /* Write / Preview tabs — same radio-driven pattern as the entity page.
       Single-axis row, so flex: it lets the format badge sit hard right
       (margin-left:auto) while the tabs stay packed left. */
    .ui-tabpanel {
        display: flex;
        align-items: center;
        border-bottom: 0.0625rem solid var(--line);

        > .format-badge {
            margin-left: auto;
        }

        > .ui-tabpanel-label {
            display: inline-grid;
            padding: 0.3rem 0.75rem;
            cursor: pointer;
            user-select: none;
            color: var(--muted);
            font-size: 0.78rem;
            font-weight: 600;
            border-bottom: 0.125rem solid transparent;

            > input[type="radio"] {
                position: absolute;
                opacity: 0;
                pointer-events: none;
                width: 0;
                height: 0;
            }

            &:hover { color: var(--text); }

            &:has(input:checked) {
                color: var(--text);
                border-bottom-color: var(--brand);
            }

            /* Keyboard focus has to be visible — the real radio is hidden. */
            &:has(input:focus-visible) {
                outline: 0.125rem solid var(--brand);
                outline-offset: -0.125rem;
            }
        }
    }

    textarea {
        width: 100%;
        color: var(--text);
        background: var(--bg);
        border: 0.0625rem solid var(--line);
        border-radius: 0.4rem;
        font: inherit;
        box-shadow: inset 0 0.1rem 0.25rem hsl(0deg 0% 0% / 0.22);

        &:focus-visible {
            outline: 0.125rem solid var(--brand);
            outline-offset: 0.125rem;
            border-color: var(--brand);
        }
    }

    /* One pane at a time (tabs), so whichever is active spans the full panel.
       No frame of its own — the textarea already carries a border + inset
       shadow, and a panel around it just boxed a box. */
    .editor-grid {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        min-height: 18rem;
    }

    .editor-grid > .ui-tabpanel-body { display: none; }
    &:has([name="add-editor-tab"][value="write"]:checked) .editor-pane { display: grid; }
    &:has([name="add-editor-tab"][value="preview"]:checked) .preview-pane { display: grid; }

    .editor-pane,
    .preview-pane {
        grid-template-rows: minmax(0, 1fr) auto;
        min-width: 0;
    }

    .editor-pane {
        gap: 0.65rem;
    }

    textarea {
        height: 100%;
        min-height: 12rem;
        padding: 0.9rem;
        resize: none;
        /* One thin outline only: the shared inset shadow read as a second
           line inside the border at this size. */
        box-shadow: none;

        /* Focus ring flush with the border, so it thickens the existing line
           instead of drawing a second one outside it. */
        &:focus-visible {
            outline-offset: 0;
        }
        font-family: "SF Mono", "Fira Code", monospace;
        font-size: 0.84rem;
        line-height: 1.6;
    }

    /* Capture note and character count share the strip under the editor. */
    .editor-foot {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 1rem;
    }

    .capture-note,
    .character-count {
        color: var(--faint);
        font-size: 0.7rem;
    }

    .character-count {
        font-variant-numeric: tabular-nums;
    }

    .preview-pane {
        grid-template-rows: minmax(0, 1fr);
        gap: 0.65rem;
        overflow: auto;
    }

    .preview-empty {
        align-self: center;
        justify-self: center;
        color: var(--faint);
        font-size: 0.85rem;
    }

    .preview-content {
        min-width: 0;
        font-size: 0.9rem;
        line-height: 1.65;

        h1,
        h2,
        h3 {
            margin: 1.1rem 0 0.5rem;
            color: var(--text);
            font-weight: 650;
        }

        h1:first-child,
        h2:first-child,
        h3:first-child {
            margin-top: 0;
        }

        h1 { font-size: 1.45rem; }
        h2 { font-size: 1.2rem; }
        h3 { font-size: 1rem; }

        p,
        ul,
        ol,
        pre,
        blockquote {
            margin: 0 0 0.8rem;
        }

        ul,
        ol {
            padding-left: 1.3rem;
        }

        code {
            padding: 0.1rem 0.3rem;
            border-radius: 0.25rem;
            color: var(--clay);
            background: var(--code-bg);
            font-family: "SF Mono", "Fira Code", monospace;
            font-size: 0.86em;
        }

        pre {
            overflow-x: auto;
            padding: 0.8rem;
            border: 0.0625rem solid var(--line);
            border-radius: 0.4rem;
            background: var(--code-bg);

            code {
                padding: 0;
                color: var(--text);
                background: transparent;
            }
        }

        blockquote {
            padding-left: 0.8rem;
            border-left: 0.2rem solid var(--brand);
            color: var(--muted);
        }

        a {
            color: var(--link);
        }
    }

    .feedback {
        display: none;
        padding: 0.8rem 1rem;
        border-radius: 0.4rem;
        font-size: 0.85rem;
    }

    &[data-state="error"] .error {
        display: block;
        color: var(--stuck);
        border: 0.0625rem solid color-mix(in srgb, var(--stuck) 45%, transparent);
        background: color-mix(in srgb, var(--stuck) 10%, transparent);
    }

    &[data-state="success"] .success {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        gap: 0.45rem;
        color: var(--ok);
        border: 0.0625rem solid color-mix(in srgb, var(--ok) 45%, transparent);
        background: color-mix(in srgb, var(--ok) 10%, transparent);
    }

    /* Submit lives in the header row now, so the primary-button styling
       travels with it. */
    .header-actions {
        button[data-field="submit"] {
            padding: 0.65rem 1.1rem;
            border: 0;
            border-radius: 0.4rem;
            color: var(--bg);
            background: var(--brand);
            font: inherit;
            font-size: 0.85rem;
            font-weight: 700;
            cursor: pointer;
            box-shadow: 0 0.45rem 1rem hsl(0deg 0% 0% / 0.2),
                0 0.1rem 0.25rem hsl(0deg 0% 0% / 0.2);

            &:hover:not(:disabled) {
                filter: brightness(1.08);
            }

            &:disabled {
                opacity: 0.6;
                cursor: wait;
            }
        }
    }

    /* No 58rem split-collapse rule any more — tabs show one pane at any width. */
    @media (max-width: 38rem) {
        .add-header {
            grid-template-columns: 1fr;
        }

        .header-actions {
            flex-wrap: wrap;
        }

        &[data-state="success"] .success {
            grid-template-columns: 1fr;
        }
    }
}



ui-vault-profile {
    display: grid;
    gap: 1rem;
    max-width: 72rem;
    margin: 0 auto;

    .vault-desc {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        align-items: start;
        gap: 0.75rem;

        .vault-desc-text {
            color: var(--muted);
            font-size: 0.92rem;
            line-height: 1.55;
        }

        &[data-state="generating"] .vault-desc-text { color: var(--faint); font-style: italic; }
        &[data-state="error"] .vault-desc-text { color: var(--stuck); }
    }

    /* Icon-only nav actions (Context/hub, Regenerate/cached, Settings). Same
       currentColor mask treatment as the header #page-nav icons. */
    .vault-profile-head nav {
        .nav-icon {
            display: grid;
            place-items: center;
            padding: 0.25rem;
            background: none;
            border: none;
            cursor: pointer;
            color: var(--muted);
            opacity: 0.5;
            transition: opacity 0.15s, color 0.15s;

            &:hover { opacity: 1; color: var(--brand); }
            &:disabled { opacity: 0.35; cursor: default; }
        }

        .icon {
            display: block;
            width: 1.2rem;
            height: 1.2rem;
            background: currentColor;
            mask: no-repeat center / contain;

            &.icon-hub { mask-image: url("/img/hub.svg"); }
            &.icon-cached { mask-image: url("/img/cached.svg"); }
            &.icon-settings { mask-image: url("/img/settings.svg"); }
        }
    }

    .activity-head {
        display: grid;
        grid-auto-flow: column;
        justify-content: space-between;
        align-items: baseline;
        margin-bottom: 0.7rem;

        h2 { font-size: 0.9rem; font-weight: 650; }
        span { color: var(--faint); font-size: 0.78rem; font-variant-numeric: tabular-nums; }
    }

    .activity-scroll {
        overflow-x: auto;
        padding-bottom: 0.25rem;
    }

    .activity-heatmap {
        display: grid;
        grid-auto-flow: column;
        grid-template-rows: repeat(7, 1fr);
        grid-auto-columns: 1fr;
        gap: 3px;
        width: 100%;
        height: 7rem; /* fill the panel; the grid stretches the 7 rows to fit */
    }

    .heat-cell {
        border-radius: 2px;
        background: var(--raised);

        &[data-level="1"] { background: color-mix(in srgb, var(--brand) 30%, var(--raised)); }
        &[data-level="2"] { background: color-mix(in srgb, var(--brand) 55%, var(--raised)); }
        &[data-level="3"] { background: color-mix(in srgb, var(--brand) 78%, var(--raised)); }
        &[data-level="4"] { background: var(--brand); }
    }

    .activity-empty { color: var(--faint); font-size: 0.85rem; }

    /* Stat tiles between the heatmap and the panels, matching the home page. */
    .profile-metrics {
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: 0.75rem;

        /* Each tile deep-links to its filtered view. */
        a {
            border: 1px solid var(--line);
            background: var(--panel);
            border-radius: 0.45rem;
            padding: 0.7rem 0.85rem;
            display: grid;
            gap: 0.1rem;
            color: var(--text);
            text-decoration: none;
            transition: border-color 0.15s, background 0.15s;

            &:hover {
                border-color: var(--brand);
                background: var(--raised);
            }
        }

        span {
            font-size: 1.5rem;
            font-weight: 650;
            font-variant-numeric: tabular-nums;
        }

        label {
            color: var(--faint);
            font-size: 0.68rem;
            text-transform: uppercase;
            letter-spacing: 0.05em;
            cursor: pointer;
        }
    }

    /* Hero: avatar in column 1 alongside the stacked title (row 1) + auto-curated
       description (row 2). */
    .vault-hero {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        gap: 1rem;
        align-items: start;
    }

    .vault-hero-body {
        display: grid;
        gap: 0.5rem;
        min-width: 0;
    }

    .vault-avatar {
        width: 4rem;
        height: 4rem;
        border-radius: 0.6rem;
        object-fit: contain;

        /* The hero grid top-aligns the avatar with the back-link row; push it
           down by that row's height (0.78rem × 1.4 line-height, pinned on
           .back-link below) so it tops out level with the vault name. */
        margin-top: calc(0.78rem * 1.4);
    }

    /* Fallback when the vault has no custom avatar: a muted brain glyph filling
       the avatar footprint, no tile background or border. */
    .vault-avatar-ph {
        display: grid;
        place-items: center;
        background: none;

        /* `display: grid` would otherwise beat the UA [hidden] rule. */
        &[hidden] { display: none; }

        .icon {
            width: 100%;
            height: 100%;
            background: var(--muted);
            mask: url("/img/brain-icon.svg") no-repeat center / contain;
        }
    }

    .vault-profile-head {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: end;
        gap: 1rem;

        h1 {
            font-size: 1.6rem;
            font-weight: 650;
            line-height: 1.2;
        }

        nav {
            display: grid;
            grid-auto-flow: column;
            gap: 0.65rem;
        }
    }

    /* Block + pinned line-height so the row's height is the link's own
       (0.78rem × 1.4), not the parent's 1rem strut — .vault-avatar's
       margin-top mirrors it to top-align the avatar with the vault name. */
    .back-link {
        display: block;
        line-height: 1.4;
    }

    .back-link,
    .settings-link {
        color: var(--text);
        font-size: 0.78rem;
        text-decoration: underline dotted;
        text-underline-offset: 0.15em;
        text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);

        &:hover { color: var(--brand); text-decoration-style: solid; }
    }

    &[data-state="ready"] .loading,
    &[data-state="error"] .loading,
    &:not([data-state="error"]) .error {
        display: none;
    }

    .summary-grid {
        display: grid;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: 0.6rem;

        article {
            border: 1px solid var(--line);
            background: var(--panel);
            border-radius: 0.45rem;
            padding: 0.8rem 0.9rem;
            display: grid;
            gap: 0.1rem;
        }

        span {
            font-size: 1.35rem;
            font-weight: 650;
            font-variant-numeric: tabular-nums;
        }

        label {
            color: var(--faint);
            font-size: 0.72rem;
            text-transform: uppercase;
            letter-spacing: 0.05em;
        }
    }

    .profile-grid {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.8rem;
        align-items: start;
    }

    .panel {
        border: 1px solid var(--line);
        background: var(--panel);
        border-radius: 0.45rem;
        padding: 0.9rem;
        min-width: 0;

        h2 {
            font-size: 0.88rem;
            font-weight: 650;
            margin-bottom: 0.65rem;
        }

        ul {
            list-style: none;
            display: grid;
            gap: 0.45rem;
        }

        li {
            color: var(--muted);
            font-size: 0.82rem;
            min-width: 0;
        }

        a {
            color: var(--text);
            text-decoration: underline dotted;
            text-underline-offset: 0.15em;
            text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);

            &:hover { color: var(--brand); text-decoration-style: solid; }
        }
    }

    .coverage-meter {
        height: 0.55rem;
        background: var(--bg);
        border: 1px solid var(--line);
        border-radius: 99rem;
        overflow: hidden;
        margin-bottom: 0.55rem;

        span {
            display: block;
            height: 100%;
            width: 0;
            background: color-mix(in srgb, var(--brand) 50%, transparent);
        }
    }

    .coverage-panel p {
        color: var(--muted);
        font-size: 0.82rem;
        margin-bottom: 0.7rem;
    }

    .entity-list li {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto auto;
        gap: 0.5rem;
        align-items: baseline;

        a {
            color: var(--text);
            text-decoration: underline dotted;
            text-underline-offset: 0.15em;
            text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;

            &:hover { color: var(--brand); text-decoration-style: solid; }
        }

        a[data-stale="true"]::after {
            content: " stale";
            color: var(--stuck);
            font-size: 0.68rem;
        }

        span {
            color: var(--faint);
            font-size: 0.66rem;
            text-transform: uppercase;
        }

        strong {
            color: var(--text);
            font-size: 0.75rem;
            font-variant-numeric: tabular-nums;
        }
    }

    .bar-list li {
        display: grid;
        gap: 0.25rem;

        div {
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto;
            gap: 0.7rem;
        }

        span {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        /* Tag label is a link into the filtered Entities page. */
        a {
            color: var(--text);
            text-decoration: underline dotted;
            text-underline-offset: 0.15em;
            text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
            cursor: pointer;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;

            &:hover { color: var(--brand); text-decoration-style: solid; }
        }

        strong {
            color: var(--text);
            font-variant-numeric: tabular-nums;
        }

        /* Same treatment as the Atom-coverage bar: a rounded green pill. */
        meter {
            width: 100%;
            height: 0.55rem;
            border: 1px solid var(--line);
            border-radius: 99rem;
            overflow: hidden;
            background: var(--bg);

            &::-webkit-meter-bar {
                background: var(--bg);
                border: none;
                border-radius: 99rem;
            }

            &::-webkit-meter-optimum-value { background: color-mix(in srgb, var(--brand) 50%, transparent); }
            &::-moz-meter-bar { background: color-mix(in srgb, var(--brand) 50%, transparent); }
        }
    }

    @media (max-width: 760px) {
        .summary-grid,
        .profile-grid {
            grid-template-columns: 1fr;
        }
        .profile-metrics { grid-template-columns: repeat(2, 1fr); }
    }
}



ui-vault-metrics {
    display: grid;
    align-content: start;
    gap: 0.75rem;
    padding: 1rem;
    overflow-y: auto;

    header {
        display: grid;
        gap: 0.1rem;

        h2 {
            font-size: 0.95rem;
            font-weight: 650;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
    }

    .vm-titlerow {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr) auto;
        align-items: center;
        gap: 0.5rem;
    }

    /* Right-aligned cog to this vault's settings. */
    .vm-settings {
        display: grid;
        place-items: center;
        color: var(--muted);
        opacity: 0.5;
        transition: opacity 0.15s, color 0.15s;

        &:hover { opacity: 1; color: var(--brand); }

        .icon {
            width: 1.1rem;
            height: 1.1rem;
            background: currentColor;
            mask: url("/img/settings.svg") no-repeat center / contain;
        }
    }

    .vm-avatar {
        width: 1.5rem;
        height: 1.5rem;
        border-radius: 0.3rem;
        object-fit: contain;
        border: 1px solid var(--line);
    }

    /* Fallback avatar: a muted brain glyph filling the footprint, no tile. */
    .vm-avatar-ph {
        display: grid;
        place-items: center;
        border: none;

        /* `display: grid` would otherwise beat the UA [hidden] rule. */
        &[hidden] { display: none; }

        .icon {
            width: 100%;
            height: 100%;
            background: var(--muted);
            mask: url("/img/brain-icon.svg") no-repeat center / contain;
        }
    }

    /* Match the main sidebar list rows: muted, full-width hover, brand rail.
       Full-bleed against the 1rem root padding. */
    .vm-nav {
        display: grid;
        margin: 0 -1rem;
        padding: 0.25rem 0;
        border-top: 1px solid var(--line);

        a {
            display: grid;
            grid-template-columns: auto minmax(0, 1fr);
            align-items: center;
            gap: 0.6rem;
            padding: 0.45rem 1rem;
            border-left: 3px solid transparent;
            color: var(--muted);
            font-size: 0.82rem;
            text-decoration: none;
            transition: all 0.15s ease;

            &:hover {
                background: var(--raised);
                border-left-color: var(--brand);
                color: var(--text);
            }
        }

        .icon {
            width: 1.1rem;
            height: 1.1rem;
            flex-shrink: 0;
            background: currentColor;
            mask: no-repeat center / contain;

            &.icon-entities { mask-image: url("/img/entities.svg"); }
            &.icon-docs { mask-image: url("/img/docs.svg"); }
            &.icon-map { mask-image: url("/img/map.svg"); }
            &.icon-todos { mask-image: url("/img/todos.svg"); }
        }
    }

    .vm-error {
        color: var(--stuck);
        font-size: 0.8rem;
    }
}



ui-search-results {
    display: grid;
    gap: 1rem;
    max-width: 72rem;
    margin: 0 auto;

    .search-head {
        display: grid;
        grid-auto-flow: column;
        justify-content: start;
        align-items: baseline;
        gap: 0.75rem;
        border-bottom: 1px solid var(--line);
        padding-bottom: 0.9rem;

        h1 {
            font-size: 1.45rem;
            font-weight: 650;
        }

        span {
            color: var(--faint);
            font-size: 0.82rem;
            font-variant-numeric: tabular-nums;
        }
    }

    .empty,
    .loading,
    .error,
    ol {
        display: none;
    }

    &[data-state="idle"] .empty,
    &[data-state="loading"] .loading,
    &[data-state="error"] .error {
        display: block;
    }

    &[data-state="ready"] ol {
        display: grid;
    }

    .empty,
    .loading {
        color: var(--faint);
        font-size: 0.86rem;
    }

    .error {
        color: var(--error);
        font-size: 0.86rem;
    }

    ol {
        list-style-position: inside;
        gap: 0.75rem;
    }

    li {
        border-top: 1px solid var(--line);
        padding-top: 0.75rem;
        display: grid;
        gap: 0.4rem;

        header {
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto;
            gap: 0.75rem;
            align-items: baseline;
        }

        a {
            color: var(--link);
            text-decoration: none;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;

            &:hover {
                text-decoration: underline;
            }
        }

        strong {
            color: var(--text);
            font-variant-numeric: tabular-nums;
            font-size: 0.78rem;
        }

        .meta {
            color: var(--faint);
            font-size: 0.74rem;
        }

        p {
            color: var(--muted);
            font-size: 0.85rem;
            line-height: 1.55;
        }
    }
}



ui-inbox-board {
    /* Fill #main; the table takes the remaining height and only its body
       scrolls (shared ui-table pattern, like Users/Vaults). Flex, not grid
       rows: loading/error/summary come and go, so the row count varies. */
    display: flex;
    flex-direction: column;
    gap: 1rem;
    height: 100%;
    min-height: 0;

    /* Info note under the table: circled "i" + muted text. */
    .inbox-info {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        margin: 0;
        padding: 0.5rem 0.75rem;
        border: 1px solid var(--line);
        border-radius: 0.4rem;
        background: var(--panel);
        color: var(--muted);
        font-size: 0.8rem;

        &::before {
            content: "i";
            flex: none;
            display: grid;
            place-items: center;
            width: 1rem;
            height: 1rem;
            border: 1px solid currentColor;
            border-radius: 50%;
            font-size: 0.65rem;
            font-weight: 700;
            font-style: italic;
            line-height: 1;
        }
    }

    .loading,
    .error,
    .inbox-summary,
    .inbox-table {
        display: none;
    }

    &[data-state="loading"] .loading,
    &[data-state="error"] .error {
        display: block;
    }

    &[data-state="ready"] {
        .inbox-summary { display: block; }
        .inbox-table { display: grid; flex: 1; }
    }

    .inbox-summary {
        color: var(--muted);
        font-size: 0.82rem;
    }
    /* Empty when there are no rows — the table body says so instead. */
    &[data-state="ready"] .inbox-summary:empty { display: none; }

    /* Shared .ui-table owns header/body/row layout; only the column tracks,
       status accents and the multi-line Entry cell live here. */
    .inbox-table {
        grid-template-columns: 6rem 8rem 5rem 5rem minmax(0, 1fr) 5rem;
        font-size: 0.85rem;

        .row[data-status="errored"],
        .row[data-status="failed"] {
            box-shadow: inset 3px 0 var(--stuck);
        }
        .row[data-status="pending"],
        .row[data-status="review"] {
            box-shadow: inset 3px 0 var(--brand);
        }

        .cell.entry {
            white-space: normal;
        }
        .cell.empty {
            grid-column: 1 / -1;
            color: var(--muted);
        }

        button.retry {
            padding: 0.2rem 0.6rem;
            border: 1px solid var(--line);
            border-radius: 0.3rem;
            background: none;
            color: var(--text);
            font-size: 0.75rem;
            font-weight: 600;
            cursor: pointer;
            transition: background 0.15s, color 0.15s;

            &:hover:not(:disabled) {
                background: var(--brand);
                color: var(--bg);
            }

            &:disabled {
                color: var(--faint);
                cursor: default;
            }
        }

        strong {
            display: block;
            color: var(--text);
            font-family: "SF Mono", monospace;
            font-size: 0.74rem;
        }

        em {
            display: block;
            color: var(--faint);
            font-style: normal;
            overflow-wrap: anywhere;
        }

        p {
            color: var(--muted);
            margin-top: 0.2rem;
            overflow-wrap: anywhere;
        }
    }

    /* Narrow: one column — cells stack inside each row; the header row would
       stack too, so it goes. */
    @media (max-width: 760px) {
        .inbox-table { grid-template-columns: minmax(0, 1fr); }
        .inbox-table .ui-table-header { display: none; }
    }
}



/* ui-ask-panel — RAG ask pane (/ui/ask main pane).
   Rules moved from assets/css/ui.css (#ask-detail / .ask-* / #ask-answer
   typography), re-scoped under the component element. */

ui-ask-panel {
    display: block;
    max-width: 47.5rem; /* 760px in old #ask-detail */

    /* ── State panes — visibility driven by data-state on the component root ── */
    .ask-empty,
    .loading,
    .error,
    #ask-answer {
        display: none;
    }
    &[data-state="idle"] .ask-empty {
        display: block;
    }
    &[data-state="loading"] .loading {
        display: block;
    }
    &[data-state="error"] .error {
        display: block;
    }
    &[data-state="answer"] #ask-answer {
        display: block;
    }

    /* ── Header ── */
    .skill-header {
        margin-bottom: 1.5rem;
        padding-bottom: 1rem;
        border-bottom: 1px solid var(--line);

        h2 {
            font-size: 1.4rem;
            font-weight: 600;
            color: var(--text);
        }
        .description {
            font-size: 0.9rem;
            color: var(--muted);
            margin-top: 0.5rem;
            line-height: 1.6;
        }
    }

    /* ── Answer body ── */
    .ask-body {
        font-size: 0.9rem;
        line-height: 1.65;
    }
    .ask-empty {
        color: var(--faint);
        font-size: 0.85rem;
    }
    .loading {
        color: var(--faint);
        font-size: 0.85rem;
        padding: 2rem 0;
    }
    .error {
        color: var(--stuck);
        font-size: 0.85rem;
        padding: 1rem 0;
    }

    /* ── Sources box — shown only once sources arrive (data-has-sources) ── */
    #ask-sources {
        display: none;
    }
    &[data-has-sources="true"] #ask-sources {
        display: block;
        margin-top: 1.5rem;
        padding-top: 1rem;
        border-top: 1px solid var(--line);
    }
    #ask-sources h3 {
        font-size: 0.85rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.06em;
        color: var(--faint);
        margin-bottom: 0.5rem;
    }
    .file-list {
        list-style: none;

        li {
            padding: 0.3rem 0;
        }
        a {
            font-size: 0.85rem;
            font-family: "SF Mono", "Fira Code", monospace;
            color: var(--link);
            cursor: pointer;
            transition: color 0.15s;

            &:hover {
                text-decoration: underline;
            }
        }
    }
    .ask-score {
        font-size: 0.7rem;
        color: var(--faint);
        font-variant-numeric: tabular-nums;
        margin-left: 0.4rem;
    }

    /* ── Answer markdown — mirrors the shared body typography ── */
    #ask-answer {
        h1,
        h2,
        h3 {
            font-weight: 600;
            margin: 1rem 0 0.5rem;
            color: var(--text);
        }
        h1 {
            font-size: 1.2rem;
        }
        h2 {
            font-size: 1.05rem;
        }
        h3 {
            font-size: 0.95rem;
        }
        p,
        li {
            color: var(--text);
        }
        p {
            margin: 0 0 0.75rem;
        }
        ul,
        ol {
            margin: 0 0 0.75rem 1.25rem;
        }
        li {
            margin-bottom: 0.25rem;
        }
        a {
            color: var(--link);
            text-decoration: none;

            &:hover {
                text-decoration: underline;
            }
        }
        code {
            background: var(--raised);
            padding: 0.1em 0.35em;
            border-radius: 0.1875rem;
            font-size: 0.85em;
            font-family: "SF Mono", "Fira Code", monospace;
            color: var(--clay);
        }
        pre {
            background: var(--code-bg);
            border: 1px solid var(--line);
            border-radius: 0.375rem;
            padding: 0.75rem 1rem;
            overflow-x: auto;
            margin: 0 0 0.75rem;
            font-size: 0.82rem;

            code {
                background: none;
                padding: 0;
                color: var(--text);
            }
        }
    }
}



/* ui-metrics-panel — /healthz dashboard (/ui/metrics main pane).
   Rules moved from assets/css/ui.css (#metrics-detail / .metrics-* /
   .metric-*), re-scoped under the component element. */

ui-metrics-panel {
    display: block;
    /* No max-width of its own — it was 900px from the old dedicated /metrics
       page, which made this panel narrower than the Processing and link-card
       sections beside it. The page wrapper (.settings-page) owns the cap. */

    /* ── State panes — visibility driven by data-state on the component root ── */
    .loading,
    .error,
    .metrics-grid {
        display: none;
    }
    &[data-state="loading"] .loading {
        display: block;
    }
    &[data-state="error"] .error {
        display: block;
    }
    &[data-state="ready"] .metrics-grid {
        display: grid;
    }

    .loading {
        color: var(--faint);
        font-size: 0.85rem;
        padding: 2rem 0;
    }
    .error {
        color: var(--stuck);
        font-size: 0.85rem;
        padding: 1rem 0;
    }

    /* ── Metric cards ── */
    /* Six fixed columns — auto-fill packed 8 narrow cards in at this width and
       wrapped the longer values. No top margin: the panel is the first thing
       under the page title, and the parent grid's gap already spaces it. */
    .metrics-grid {
        grid-template-columns: repeat(6, minmax(0, 1fr));
        gap: 0.75rem;
        margin: 0 0 1rem;
    }

    @media (max-width: 64rem) {
        .metrics-grid {
            grid-template-columns: repeat(3, minmax(0, 1fr));
        }
    }

    @media (max-width: 36rem) {
        .metrics-grid {
            grid-template-columns: repeat(2, minmax(0, 1fr));
        }
    }
    .metric-card {
        background: var(--panel);
        border: 1px solid var(--line);
        border-radius: 0.5rem;
        padding: 0.9rem 1rem;
    }
    .metric-value {
        font-size: 1.6rem;
        font-weight: 600;
        color: var(--text);
        font-variant-numeric: tabular-nums;
        white-space: nowrap;
    }

    /* The unit rides with the number but at label weight — "221.7 MB" stays on
       one line and the eye lands on the figure, not the suffix. */
    .metric-unit {
        margin-left: 0.2rem;
        font-size: 0.85rem;
        font-weight: 500;
        color: var(--muted);

        &:empty {
            display: none;
        }
    }
    .metric-label {
        font-size: 0.7rem;
        text-transform: uppercase;
        letter-spacing: 0.05em;
        color: var(--faint);
        margin-top: 0.25rem;
    }
}



/* ui-shortcuts — the `?` help overlay. The host renders nothing itself; only
   the dialog is visible, and only while open. */

ui-shortcuts {
    display: contents;
}

.shortcuts-dialog {
    max-width: 26rem;
    /* The global reset zeroes margins, which is what centres a native modal —
       restore it or the dialog pins to the top-left. */
    margin: auto;
    padding: 1.25rem;
    border: 1px solid var(--line);
    border-radius: 0.6rem;
    background: var(--panel);
    color: var(--text);

    &::backdrop {
        background: hsl(0deg 0% 0% / 0.55);
    }

    header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        margin-bottom: 0.9rem;

        h3 {
            margin: 0;
            font-size: 1rem;
            font-weight: 650;
        }
    }

    .shortcuts-close {
        border: 0;
        background: none;
        color: var(--faint);
        font: inherit;
        font-size: 0.9rem;
        cursor: pointer;

        &:hover { color: var(--text); }
    }

    /* Keys left, meaning right — a two-column <dl> so the pairing is semantic
       rather than positional. */
    .shortcuts-list {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        align-items: baseline;
        gap: 0.55rem 1rem;
        margin: 0;

        dt {
            display: flex;
            gap: 0.2rem;
            white-space: nowrap;
        }

        dd {
            margin: 0;
            color: var(--muted);
            font-size: 0.85rem;
        }

        kbd {
            padding: 0.1rem 0.35rem;
            border: 1px solid var(--line);
            border-radius: 0.25rem;
            background: var(--bg);
            color: var(--text);
            font-family: inherit;
            font-size: 0.72rem;
        }
    }
}



/* ui-profile — the caller's own page. Master/detail via CSS Grid; the master is
   a fixed column, the detail takes the rest and scrolls independently. */
ui-profile {
    display: grid;
    grid-template-rows: auto minmax(0, 1fr);
    gap: 1rem;
    min-height: 0;

    .profile-title-row {
        display: grid;
        grid-template-columns: auto auto 1fr;
        align-items: center;
        gap: 0.75rem;
    }
    .profile-meta {
        display: inline-grid;
        grid-auto-flow: column;
        gap: 0.75rem;
        color: var(--muted);
        font-size: 0.85rem;
    }

    .profile-detail {
        display: grid;
        grid-template-rows: auto auto auto minmax(0, 1fr);
        gap: 0.75rem;
        min-height: 0;
    }
    .profile-detail-head {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto;
        align-items: start;
        gap: 1rem;
    }
    .profile-hint {
        color: var(--muted);
        font-size: 0.85rem;
        margin: 0;
        max-width: 44rem;
    }

    /* Radio-driven tabs — the house .ui-tabpanel pattern (entity detail, skill
       form). :has() switches panes, so there is no JS toggling class names and
       no state to keep in sync. Its styles are declared per consumer, not
       globally, so they are repeated here deliberately. */
    .ui-tabpanel {
        display: grid;
        grid-auto-flow: column;
        justify-content: start;
        border-bottom: 1px solid var(--line);
        margin-bottom: 0.5rem;

        > .ui-tabpanel-label {
            display: inline-grid;
            grid-auto-flow: column;
            align-items: center;
            padding: 0.25rem 0.65rem;
            cursor: pointer;
            user-select: none;
            color: var(--muted);
            font-size: 0.78rem;
            font-weight: 600;
            white-space: nowrap;
            border-bottom: 0.125rem solid transparent;

            > input[type="radio"] {
                position: absolute;
                opacity: 0;
                pointer-events: none;
                width: 0;
                height: 0;
            }

            &:hover { color: var(--text); }

            &:has(input:checked) {
                color: var(--text);
                border-bottom-color: var(--brand);
            }
        }
    }

    .ui-tabpanel-body { display: none; }
    &:has([name="profile-detail-tab"][value="tokens"]:checked) [data-pane="tokens"] {
        display: grid;
        grid-template-rows: auto auto minmax(0, 1fr);
        gap: 0.75rem;
        min-height: 0;
    }

    .add-btn {
        background: var(--clay-soft);
        color: var(--clay);
        border: 1px solid var(--line);
        border-radius: 0.3rem;
        padding: 0.2rem 0.5rem;
        font-size: 0.68rem;
        font-weight: 600;
        cursor: pointer;
        transition: background 0.15s, color 0.15s;
        white-space: nowrap;

        &:hover {
            background: var(--brand);
            color: var(--bg);
        }
    }

    /* .ui-table is a shared skeleton (subgrid rows, fixed header, scrolling
       zebra body); each consumer declares its OWN column widths. Without this
       every cell stacked vertically — the markup was right and the grid had no
       tracks to place it into. */
    .ui-table {
        grid-template-columns: minmax(8rem, 1fr) minmax(8rem, 1.2fr) 9rem 6rem;
        font-size: 0.85rem;
    }

    /* An unscoped token reaches everything its owner does (ADR-0028 §4). Say so
       in the row rather than leaving the cell blank — blank reads as "fine". */
    .scope-unscoped {
        color: var(--warn);
    }

    .link-btn {
        background: none;
        border: none;
        color: var(--brand);
        font-size: 0.85rem;
        cursor: pointer;
        padding: 0;

        &:hover { text-decoration: underline; }
    }

    /* Dialogs. Native <dialog> carries no app styling of its own and the rules
       are declared per component, not globally — reusing the element without
       these gives a white box in the top-left corner with UA buttons. Matched
       to the settings dialogs so the page belongs to the same product. */
    dialog {
        /* The global `* { margin: 0 }` reset kills the UA's margin:auto dialog
           centering — restore it, or showModal() renders top-left. */
        margin: auto;
        background: var(--panel);
        color: var(--text);
        border: 1px solid var(--line);
        border-radius: 0.6rem;
        padding: 1.1rem 1.25rem;
        width: 26rem;
        max-width: 92vw;
        box-shadow: 0 0.5rem 1.5rem hsl(0 0% 0% / 0.4), 0 0.1rem 0.3rem hsl(0 0% 0% / 0.3);

        &::backdrop { background: hsl(0 0% 0% / 0.55); }

        h3 {
            font-size: 1rem;
            font-weight: 600;
            margin-bottom: 0.6rem;
        }

        label {
            display: grid;
            gap: 0.25rem;
            font-size: 0.8rem;
            color: var(--muted);
            margin-bottom: 0.75rem;
        }
        /* Scope picker: a checkbox per Vault. Sunken + scrolling, so a long Vault
           list cannot push the dialog buttons off-screen. */
        fieldset.vault-picker {
            border: 1px solid var(--line);
            border-radius: 0.375rem;
            padding: 0.5rem 0.6rem 0.6rem;
            margin-bottom: 0.75rem;
            display: grid;
            gap: 0.35rem;
            background: var(--bg);
            box-shadow: inset 0 1px 2px hsl(0 0% 0% / 0.25);

            legend {
                font-size: 0.8rem;
                color: var(--muted);
                padding: 0 0.3rem;
            }
        }

        .vault-list {
            display: grid;
            gap: 0.3rem;
            max-height: 9rem;
            overflow-y: auto;

            /* The rows are label.inline, which the rule below lays out; they carry
               no margin of their own so the grid gap is the only spacing. */
            label.inline { margin-bottom: 0; }
        }

        input[type="text"] {
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--line);
            border-radius: 0.375rem;
            padding: 0.35rem 0.6rem;
            font-size: 0.9rem;

            &:focus {
                outline: none;
                border-color: var(--brand);
            }
        }

        /* Scope hint under the Vaults picker. */
        small {
            color: var(--muted);
            font-size: 0.75rem;
        }

        /* A checkbox reads as a control with its text beside it, not above it —
           the grid `label` above would stack them. */
        label.inline {
            grid-auto-flow: column;
            grid-template-columns: auto 1fr;
            align-items: center;
            gap: 0.45rem;
            justify-content: start;
        }

        .error {
            color: var(--clay);
            font-size: 0.8rem;
            min-height: 1rem;
        }

        menu {
            list-style: none;
            display: grid;
            grid-auto-flow: column;
            justify-content: end;
            gap: 0.5rem;
            margin-top: 1rem;

            button {
                border: 1px solid var(--line-2);
                border-radius: 0.3rem;
                background: none;
                color: var(--muted);
                padding: 0.4rem 1rem;
                font-size: 0.85rem;
                font-weight: 600;
                cursor: pointer;

                &.danger-confirm {
                    background: var(--stuck);
                    border-color: var(--stuck);
                    color: var(--bg);
                }

                &[type="submit"], &[value="done"] {
                    background: var(--brand);
                    border-color: var(--brand);
                    color: var(--bg);
                }
            }
        }
    }

    /* The one-time reveal. Monospace and wrapping, because it will be copied by
       hand and a truncated token is worse than an ugly one. */
    .token-value {
        background: var(--bg);
        border: 1px solid var(--line);
        border-radius: 0.375rem;
        padding: 0.6rem;
        font-family: ui-monospace, monospace;
        font-size: 0.85rem;
        overflow-wrap: anywhere;
        /* Inset: this is a value to read out of, not a raised control. */
        box-shadow: inset 0 1px 2px hsl(0 0% 0% / 0.25);
    }

    &[data-state="loading"] .profile-detail { opacity: 0.5; }
}



/* ui-settings-home — Settings landing (/ui/settings): metrics panel, the
   processing-lane toggle, and link-cards to the subsections. The users/vaults
   summary moved into the metrics panel.
   Token bar / status rules carried over from ui-settings-admin; link-cards
   styled like its .settings-section panels. */

ui-settings-home {
    display: grid;
    gap: 1.5rem;
    align-content: start;

    .settings-workspace {
        display: flex;
        align-items: center;
        gap: 0.75rem;
    }

    /* Remove = a circled cross on the avatar's top-right corner. Almost invisible
       (5%) until the avatar is hovered (or the button focused), then solid accent. */
    .ws-avatar-wrap {
        position: relative;

        /* No frame around the picture itself. */
        .avatar-preview {
            border: 0;
        }
        /* Hover = an accent border, not the shared dark wash over the image. */
        .avatar-field::after {
            background: none;
            border: 0.1rem solid var(--brand);
        }
    }
    .ws-avatar-remove {
        position: absolute;
        top: -0.4rem;
        right: -0.4rem;
        display: grid;
        place-items: center;
        width: 1.25rem;
        height: 1.25rem;
        padding: 0;
        border: 0.1rem solid hsl(0 0% 100% / 0.35);
        border-radius: 50%;
        background: hsl(0 0% 0% / 0.35);
        color: hsl(0 0% 100% / 0.55);
        opacity: 0.05;
        cursor: pointer;
        transition: opacity 0.15s, background 0.15s, border-color 0.15s, color 0.15s;

        &[hidden] {
            display: none;
        }
        svg {
            width: 0.55rem;
            height: 0.55rem;
            fill: none;
            stroke: currentColor;
            stroke-width: 1.5;
            stroke-linecap: round;
        }
    }
    .ws-avatar-wrap:hover .ws-avatar-remove,
    .ws-avatar-remove:hover,
    .ws-avatar-remove:focus-visible {
        opacity: 1;
        background: var(--brand);
        border-color: var(--brand);
        color: var(--bg);
    }

    .settings-status {
        color: var(--ok);
        font-size: 0.85rem;

        /* Empty most of the time — don't let it hold a grid row open. */
        &:empty {
            display: none;
        }

        &[data-error="true"] {
            color: var(--stuck);
        }
    }
    .add-btn {
        background: var(--clay-soft);
        color: var(--clay);
        border: 1px solid var(--line);
        border-radius: 0.3rem;
        padding: 0.2rem 0.5rem;
        font-size: 0.68rem;
        font-weight: 600;
        text-transform: none;
        letter-spacing: normal;
        cursor: pointer;
        transition: background 0.15s, color 0.15s;

        &:hover {
            background: var(--brand);
            color: var(--bg);
        }
    }

    /* ── Workspace line (hidden until /auth/me answers) ─────────────────── */
    .settings-account {
        display: none;
        margin: 0;
        font-size: 1.5rem;
        font-weight: 600;
        line-height: 1.2;
        overflow-wrap: anywhere;
    }
    &[data-account="loaded"] .settings-account {
        display: block;
    }

    /* ── Processing lane toggle (hidden until loaded) ────────────────────── */
    .settings-llm {
        display: none;
        background: var(--panel);
        border: 1px solid var(--line);
        border-radius: 0.5rem;
        padding: 0.75rem 1rem;
        gap: 0.5rem;

        h2 {
            font-size: 1rem;
            font-weight: 600;
            margin: 0;
        }
    }
    &[data-state="loaded"] .settings-llm {
        display: grid;
    }
    /* Wins over the rule above (more specific): a lone option hides the section. */
    &[data-state="loaded"] .settings-llm[hidden] {
        display: none;
    }
    .settings-llm-hint {
        margin: 0;
        font-size: 0.85rem;
        color: var(--muted);
    }

    .settings-llm-options {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
        gap: 0.75rem;
        margin-top: 0.25rem;
    }

    /* Card is the label; the radio stays a real radio for keyboard/AT. */
    .settings-llm-option {
        &[hidden] {
            display: none;
        }
        display: grid;
        grid-template-columns: auto minmax(0, 1fr);
        gap: 0.25rem 0.5rem;
        align-items: start;
        /* Cards stretch to equal height; pack rows to the top so the shorter
           card's text doesn't drift down to meet the taller one's. */
        align-content: start;
        padding: 0.75rem 0.9rem;
        border: 1px solid var(--line);
        border-radius: 0.5rem;
        background: var(--bg);
        font-size: 0.9rem;
        color: var(--text);
        cursor: pointer;
        transition: border-color 0.15s, background 0.15s;

        /* Radio drawn like the Getting Started step markers (ui-vault-nav):
           grey ring → accent ring on hover/focus → solid accent tick when
           chosen. Still a native radio underneath (keyboard, AT). The tick is
           the label's ::before in the same cell — pseudo-elements on <input>
           don't render in every engine. */
        input {
            grid-area: 1 / 1;
            appearance: none;
            width: 1.35rem;
            height: 1.35rem;
            margin: 0;
            border: 1px solid var(--line-3);
            border-radius: 50%;
            background: transparent;
            cursor: inherit;
            transition: border-color 0.15s, background 0.15s;

            &:checked {
                border-color: var(--accent);
                background: var(--accent);
            }
        }

        &::before {
            grid-area: 1 / 1;
            place-self: center;
            content: "\2713";
            color: var(--accent-fg);
            font-size: 0.72rem;
            font-weight: 600;
            line-height: 1;
            pointer-events: none;
            visibility: hidden;
        }
        &:has(input:checked)::before {
            visibility: visible;
        }
        &:hover:not(:has(input:disabled)) input:not(:checked) {
            border-color: var(--accent);
        }

        .option-title {
            grid-row: 1;
            align-self: center;
            font-weight: 650;
        }

        /* Description and note sit under the title, clear of the radio. */
        .option-desc,
        .option-note {
            grid-column: 2;
            font-size: 0.8rem;
            color: var(--muted);
        }

        .option-note {
            font-style: normal;
            color: var(--faint);

            &:empty { display: none; }
        }

        /* Only while this lane is the active one. */
        .option-warn {
            grid-column: 2;
            display: none;
            padding: 0.35rem 0.5rem;
            border-radius: 0.3rem;
            border: 1px solid var(--stuck);
            background: color-mix(in srgb, var(--stuck) 12%, transparent);
            color: var(--stuck);
            font-size: 0.75rem;
            font-weight: 600;
            line-height: 1.4;
        }

        &:has(input:checked) .option-warn {
            display: block;
        }

        &:hover:not(:has(input:disabled)) {
            border-color: var(--line-3);
        }

        &:has(input:checked) {
            border-color: var(--brand);
            background: var(--raised);
        }

        /* Keyboard focus must show on the card — the radio itself is small. */
        &:has(input:focus-visible) {
            outline: 0.125rem solid var(--brand);
            outline-offset: 0.125rem;
        }

        /* Either option can be unavailable (fast unconfigured, private by plan). */
        &:has(input:disabled) {
            color: var(--muted);
            background: var(--panel);
            cursor: not-allowed;
            opacity: 0.65;
        }
    }

    /* Off-network confirmation. Native <dialog>, so ::backdrop, Esc and the
       focus trap are the platform's job, not ours. */
    .llm-confirm {
        max-width: 30rem;
        /* The global reset zeroes margins, which is what centres a native
           modal — restore it or the dialog pins to the top-left. */
        margin: auto;
        padding: 1.25rem;
        border: 1px solid var(--line);
        border-radius: 0.6rem;
        background: var(--panel);
        color: var(--text);

        &::backdrop {
            background: hsl(0deg 0% 0% / 0.55);
        }

        h3 {
            margin: 0 0 0.6rem;
            font-size: 1rem;
            font-weight: 650;
        }

        p {
            margin: 0 0 0.6rem;
            font-size: 0.85rem;
            line-height: 1.5;
            color: var(--muted);
        }

        .llm-confirm-note {
            color: var(--faint);
            font-size: 0.8rem;
        }
    }

    .llm-confirm-actions {
        display: flex;
        justify-content: flex-end;
        gap: 0.5rem;
        margin-top: 1rem;

        button {
            padding: 0.45rem 0.85rem;
            border: 1px solid var(--line);
            border-radius: 0.4rem;
            background: var(--bg);
            color: var(--text);
            font: inherit;
            font-size: 0.85rem;
            font-weight: 600;
            cursor: pointer;

            &:hover { border-color: var(--line-3); }

            /* The consequential one is the off-network switch, not the cancel. */
            &.danger {
                border-color: var(--stuck);
                background: var(--stuck);
                color: var(--bg);

                &:hover { filter: brightness(1.08); }
            }
        }
    }

    .settings-llm-status {
        font-size: 0.85rem;
        color: var(--ok);

        &[data-error="true"] {
            color: var(--stuck);
        }
    }

    /* ── Link-cards to the subsections ───────────────────────────────────── */
    .settings-links {
        display: grid;
        grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
        gap: 1rem;
    }
    .settings-link-card {
        /* [icon] [title / description] — the icon spans both rows. */
        display: grid;
        grid-template-columns: 1.75rem minmax(0, 1fr);
        column-gap: 0.75rem;
        row-gap: 0.25rem;
        align-content: start;
        background: var(--panel);
        border: 1px solid var(--line);
        border-radius: 0.5rem;
        padding: 1rem 1.25rem;
        color: var(--text);
        text-decoration: none;
        transition: background 0.15s, border-color 0.15s;

        h2 {
            grid-column: 2;
            font-size: 1rem;
            font-weight: 600;
            margin: 0;
        }
        p {
            grid-column: 2;
            margin: 0;
            font-size: 0.85rem;
            color: var(--muted);
        }
        /* Masked glyph in the muted text colour; accent on hover. */
        .settings-link-icon {
            grid-column: 1;
            grid-row: 1 / span 2;
            align-self: center;
            width: 1.75rem;
            height: 1.75rem;
            background: var(--muted);
            mask: no-repeat center / contain;
            transition: background 0.15s;

            &.icon-users { mask-image: url("/img/group.svg"); }
            &.icon-vaults { mask-image: url("/img/vault.svg"); }
        }
        &:hover {
            background: var(--raised);
            border-color: var(--line-3);

            .settings-link-icon {
                background: var(--brand);
            }
        }
    }
}



/* ui-settings-users — Settings/Users subsection (/ui/settings/users):
   full-width user table (shared .ui-table) with per-row token issue, an
   add-user <dialog> opened from the title row, and the one-time token-reveal
   <dialog> (margin:auto centering fix from ui-doc-detail). */

ui-settings-users {
    /* Fill #main so the user table's BODY is the scroller (shared ui-table
       pattern). The title, count and add button are in the app header
       (_header.eta), so the table section is the only row. */
    display: grid;
    grid-template-rows: minmax(0, 1fr);
    gap: 1rem;
    height: 100%;

    /* ── Token gate + body reveal: CSS-driven via data-state on the root ── */
    #users-body {
        display: none;
    }
    &[data-state="ready"] #users-body {
        /* Status line (errors only, usually hidden) + the table, which takes
           the remaining height. Flex, not grid rows: a hidden status line
           drops out of the track list and the table fell into the `auto` row. */
        display: flex;
        flex-direction: column;
        min-height: 0;

        .ui-table { flex: 1; }
    }

    .settings-status {
        color: var(--ok);
        font-size: 0.85rem;

        &:empty {
            display: none;
        }
        &[data-error="true"] {
            color: var(--stuck);
        }
    }

    /* ── User results — shared .ui-table consumer (components/ui-table) ────
       Only this table's column tracks + local text styles live here; the
       skeleton (subgrid rows, fixed header, scrolling zebra body) is shared. */
    .ui-table {
        grid-template-columns: minmax(10rem, 1fr) minmax(14rem, 1.2fr) 7rem;
        font-size: 0.85rem;

        .name-link {
            display: flex;
            align-items: center;
            gap: 0.5rem;
            min-width: 0;

            [data-field="name"] {
                overflow: hidden;
                text-overflow: ellipsis;
            }

            color: var(--link);
            text-decoration: none;

            &:hover {
                text-decoration: underline;
            }
        }
    }
    .link-btn {
        background: none;
        border: none;
        color: var(--link);
        cursor: pointer;
        font-size: 0.8rem;
        padding: 0;

        &:hover {
            text-decoration: underline;
        }
    }

    /* Row avatar: a circle with the image, or the name's initial. */
    .user-avatar {
        flex: none;
        display: grid;
        place-items: center;
        width: 1.5rem;
        height: 1.5rem;
        border-radius: 50%;
        overflow: hidden;
        background: var(--raised);
        color: var(--muted);
        font-size: 0.7rem;
        font-weight: 600;

        img {
            width: 100%;
            height: 100%;
            object-fit: cover;
        }
    }

    /* ── Add-user dialog chrome (mirrors ui-settings-vaults) ── */
    dialog.user-add {
        /* the global `* { margin: 0 }` reset kills the UA's margin:auto dialog
           centering — restore it. */
        margin: auto;
        background: var(--panel);
        color: var(--text);
        border: 1px solid var(--line);
        border-radius: 0.6rem;
        padding: 1.1rem 1.25rem;
        width: 26rem;
        max-width: 92vw;
        box-shadow: 0 0.5rem 1.5rem hsl(0 0% 0% / 0.4), 0 0.1rem 0.3rem hsl(0 0% 0% / 0.3);

        &::backdrop {
            background: hsl(0 0% 0% / 0.55);
        }

        h3 {
            font-size: 1rem;
            font-weight: 600;
            margin-bottom: 0.6rem;
        }


        label {
            display: grid;
            gap: 0.25rem;
            font-size: 0.8rem;
            color: var(--muted);
            margin-bottom: 0.75rem;
        }
        .role-note {
            font-size: 0.78rem;
            color: var(--faint);
            line-height: 1.5;
        }
        input[type="text"],
        input[type="email"],
        select {
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--line);
            border-radius: 0.375rem;
            padding: 0.35rem 0.6rem;
            font-size: 0.9rem;

            &:focus {
                outline: none;
                border-color: var(--brand);
            }
        }

        .error {
            color: var(--stuck);
            font-size: 0.85rem;

            &:empty {
                display: none;
            }
        }

        menu {
            list-style: none;
            display: grid;
            grid-auto-flow: column;
            justify-content: end;
            gap: 0.5rem;
            margin-top: 1rem;

            button {
                border: 1px solid var(--line-3);
                border-radius: 0.3rem;
                background: none;
                color: var(--muted);
                padding: 0.4rem 1rem;
                font-size: 0.85rem;
                font-weight: 600;
                cursor: pointer;

                &[type="submit"] {
                    background: var(--brand);
                    border-color: var(--brand);
                    color: var(--bg);
                }

                &:hover {
                    color: var(--text);

                    &[type="submit"] {
                        opacity: 0.9;
                        color: var(--bg);
                    }
                }
            }
        }
    }

    /* ── One-time token reveal — native <dialog> (top layer via showModal) ── */
    dialog.token-reveal {
        margin: auto;
        background: var(--panel);
        color: var(--text);
        border: 1px solid var(--line);
        border-radius: 0.6rem;
        padding: 0;
        width: 34rem;
        max-width: 92vw;
        max-height: 85vh;
        overflow-y: auto;
        box-shadow: 0 0.5rem 1.5rem hsl(0deg 0% 0% / 0.4), 0 0.1rem 0.3rem hsl(0deg 0% 0% / 0.3);

        &::backdrop {
            background: hsl(0deg 0% 0% / 0.55);
        }

        .modal-header {
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto;
            align-items: center;
            padding: 0.9rem 1.1rem;
            border-bottom: 1px solid var(--line);

            h3 {
                font-size: 1rem;
                font-weight: 600;
                margin: 0;
            }
        }
        .close-btn {
            background: none;
            border: 1px solid var(--line-3);
            color: var(--muted);
            border-radius: 0.25rem;
            padding: 0.1rem 0.4rem;
            font-size: 0.7rem;
            cursor: pointer;
            transition: all 0.15s;

            &:hover {
                background: var(--raised);
                border-color: var(--line-3);
            }
        }
        .settings-warn {
            color: var(--clay);
            font-size: 0.85rem;
            margin: 0.75rem 1.1rem 0.5rem;
        }
        .settings-token {
            background: var(--code-bg);
            border: 1px solid var(--line);
            border-radius: 0.375rem;
            padding: 0.75rem;
            margin: 0 1.1rem 1.1rem;
            font-family: ui-monospace, monospace;
            word-break: break-all;
            color: var(--ok);
        }
    }
}



/* ui-settings-user — single-user detail page (/ui/settings/users/<id>):
   (the title — Settings > Users > name (email) — is in the app header) name edit form, and the "Grant Options"
   sub-tab — every vault with an access toggle + role select in a shared
   .ui-table. Token gate + data-state reveal mirror ui-settings-users. */

ui-settings-user {
    display: grid;
    grid-template-rows: minmax(0, 1fr);
    height: 100%;

    /* ── Token gate + body reveal: CSS-driven via data-state on the root ── */
    #user-body {
        display: none;
    }
    &[data-state="ready"],
    &[data-state="ready-empty"] {
        #user-body {
            /* status + form + note + tabs stack at the top; the vault table
               takes the rest and only its body scrolls. Flex, not a fixed
               row list: the status line comes and goes, and when it showed
               every child shifted a track — the tabs got the 1fr row and the
               table fell to the bottom. */
            display: flex;
            flex-direction: column;
            gap: 0.75rem;
            min-height: 0;

            .ui-table { flex: 1; }
        }
    }
    .grants-empty {
        display: none;
        color: var(--muted);
        font-size: 0.85rem;
        margin: 0;
    }
    &[data-state="ready-empty"] {
        .ui-table {
            display: none;
        }
        .grants-empty {
            display: block;
        }
    }
    /* Load errors arrive before "ready" — reveal only the status line. */
    &[data-state="error"] #user-body {
        display: block;

        > :not(.settings-status) {
            display: none;
        }
    }

    .settings-status {
        color: var(--ok);
        font-size: 0.85rem;

        &:empty {
            display: none;
        }
        &[data-error="true"] {
            color: var(--stuck);
        }
    }

    /* What the membership controls do — help text under the form. */
    .role-note {
        font-size: 0.78rem;
        color: var(--faint);
        line-height: 1.5;
    }

    /* ── Head row — name form left, membership (role) form right-aligned ── */
    .user-head {
        display: grid;
        grid-template-columns: auto auto;
        justify-content: space-between;
        align-items: end;
        gap: 0.75rem 1.5rem;
    }

    /* ── Header edit form — display name, PATCH on Save ────────────────── */
    #user-detail-form {
        display: grid;
        grid-auto-flow: column;
        justify-content: start;
        align-items: end;
        gap: 0.75rem;

        label {
            display: grid;
            gap: 0.25rem;
            font-size: 0.8rem;
            color: var(--muted);
        }
        input[type="text"] {
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--line);
            border-radius: 0.375rem;
            padding: 0.35rem 0.6rem;
            font-size: 0.9rem;

            &:focus {
                outline: none;
                border-color: var(--brand);
            }
        }
        input[type="text"] {
            width: 16rem;
        }
        button[type="submit"] {
            background: var(--brand);
            border: 1px solid var(--brand);
            border-radius: 0.3rem;
            color: var(--bg);
            padding: 0.4rem 1rem;
            font-size: 0.85rem;
            font-weight: 600;
            cursor: pointer;

            &:hover {
                opacity: 0.9;
            }
        }
    }

    /* ── Membership form — role picker + suspend/remove ───────────────── */
    #membership-form {
        display: grid;
        grid-auto-flow: column;
        justify-content: start;
        align-items: end;
        gap: 0.75rem;

        label {
            display: grid;
            gap: 0.25rem;
            font-size: 0.8rem;
            color: var(--muted);
        }
        select {
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--line);
            border-radius: 0.375rem;
            padding: 0.35rem 0.6rem;
            font-size: 0.9rem;
            width: 10rem;

            &:focus {
                outline: none;
                border-color: var(--brand);
            }
        }
        button {
            border: 1px solid var(--brand);
            border-radius: 0.3rem;
            background: var(--brand);
            color: var(--bg);
            padding: 0.4rem 1rem;
            font-size: 0.85rem;
            font-weight: 600;
            cursor: pointer;

            &.danger {
                background: none;
                border-color: var(--stuck);
                color: var(--stuck);
            }
            &:hover {
                opacity: 0.9;
            }
            &:disabled {
                opacity: 0.6;
                cursor: not-allowed;
            }
            &[aria-busy="true"] {
                cursor: progress;
            }
        }
    }

    /* ── Suspend/remove confirmation (mirrors ui-settings-vaults) ──────── */
    dialog.member-confirm {
        /* the global `* { margin: 0 }` reset kills the UA's margin:auto dialog
           centering — restore it. */
        margin: auto;
        background: var(--panel);
        color: var(--text);
        border: 1px solid var(--line);
        border-radius: 0.6rem;
        padding: 1.1rem 1.25rem;
        width: 26rem;
        max-width: 92vw;
        box-shadow: 0 0.5rem 1.5rem hsl(0 0% 0% / 0.4), 0 0.1rem 0.3rem hsl(0 0% 0% / 0.3);

        &::backdrop {
            background: hsl(0 0% 0% / 0.55);
        }
        h3 {
            font-size: 1rem;
            font-weight: 600;
            margin-bottom: 0.6rem;
        }
        p {
            font-size: 0.9rem;
            color: var(--muted);
            line-height: 1.6;
        }
        menu {
            list-style: none;
            display: grid;
            grid-auto-flow: column;
            justify-content: end;
            gap: 0.5rem;
            margin-top: 1rem;

            button {
                border: 1px solid var(--line-3);
                border-radius: 0.3rem;
                background: none;
                color: var(--muted);
                padding: 0.4rem 1rem;
                font-size: 0.85rem;
                font-weight: 600;
                cursor: pointer;

                &.danger-confirm {
                    background: var(--stuck);
                    border-color: var(--stuck);
                    color: var(--bg);
                }
                &:hover {
                    color: var(--text);

                    &.danger-confirm {
                        opacity: 0.9;
                        color: var(--bg);
                    }
                }
            }
        }
    }

    /* ── Sub tabs ──────────────────────────────────────────────────────── */
    .sub-tabs {
        display: grid;
        grid-auto-flow: column;
        justify-content: start;
        gap: 0.25rem;
        border-bottom: 1px solid var(--line);

        .sub-tab {
            background: none;
            border: none;
            border-bottom: 2px solid transparent;
            color: var(--muted);
            padding: 0.35rem 0.75rem;
            font-size: 0.85rem;
            font-weight: 600;
            cursor: pointer;

            &.active {
                color: var(--text);
                border-bottom-color: var(--brand);
            }
        }
    }

    /* ── Grant options table — Access (fixed) | Vault name ─────────────── */
    .ui-table {
        grid-template-columns: 13rem minmax(12rem, 1fr);
        font-size: 0.85rem;
    }

    /* Access — none|viewer|member button group (segmented control). */
    .btn-group {
        display: inline-grid;
        grid-auto-flow: column;
        border: 1px solid var(--line);
        border-radius: 0.3rem;
        overflow: hidden;
        vertical-align: middle;

        button {
            background: none;
            border: none;
            color: var(--muted);
            padding: 0.2rem 0.6rem;
            font-size: 0.75rem;
            font-weight: 600;
            cursor: pointer;
            transition: background 0.15s, color 0.15s;

            &:not(:first-child) {
                border-left: 1px solid var(--line);
            }
            &[aria-pressed="true"] {
                background: var(--brand);
                color: var(--bg);
            }
            &:hover:not([aria-pressed="true"], :disabled) {
                color: var(--text);
            }
            &:disabled {
                cursor: not-allowed;
                opacity: 0.6;
            }
        }
    }
}



/* ui-settings-vaults — Vaults subsection (/ui/settings/vaults): full-width
   vault table (shared .ui-table) with per-row delete + content counts, an
   add-vault <dialog> (display name + slug) opened from the title row, and a
   native <dialog> delete confirmation (margin:auto centering fix from
   ui-doc-detail). */

ui-settings-vaults {
    /* Fill #main so the vault table's BODY is the scroller (shared ui-table
       pattern). The title, count and add button are in the app header
       (_header.eta), so the table section is the only row. */
    display: grid;
    grid-template-rows: minmax(0, 1fr);
    gap: 1rem;
    height: 100%;

    /* ── No-token gate: CSS-driven via data-state on the root ────────────── */
    /* ── Body: status block + the table, which takes the remaining height ── */
    #vaults-body {
        display: grid;
        grid-template-rows: auto minmax(0, 1fr);
        min-height: 0;
    }

    /* ── Error + status lines (:empty-collapsed) ─────────────────────────── */
    .error {
        color: var(--stuck);
        font-size: 0.85rem;
        margin-bottom: 0.75rem;

        &:empty {
            display: none;
        }
    }
    /* ── Vault results — shared .ui-table consumer (components/ui-table) ────
       Only this table's column tracks + local text styles live here; the
       skeleton (subgrid rows, fixed header, scrolling zebra body) is shared. */
    .ui-table {
        /* Display name (or vault key) flexes | counts | actions */
        grid-template-columns: minmax(8rem, 1fr) 9rem 9rem 6rem 5rem 5rem;
        font-size: 0.85rem;

        .mono {
            font-family: ui-monospace, monospace;
            color: var(--muted);
        }
        .muted {
            color: var(--faint);
        }
        /* "Set name" sits right after the vault key it belongs to. */
        [data-field="set-name"] {
            margin-left: 0.6rem;
        }
        /* Column headers that carry a tooltip. */
        .hint {
            cursor: help;
        }
        .name-link {
            color: var(--link);
            text-decoration: none;

            /* A bare vault key reads as a key: monospace. */
            &.is-key {
                font-family: ui-monospace, monospace;
            }

            &:hover {
                text-decoration: underline;
            }
        }
        .actions a {
            color: var(--link);
            text-decoration: none;

            &:hover {
                text-decoration: underline;
            }
        }
    }
    .link-btn {
        background: none;
        border: none;
        color: var(--link);
        cursor: pointer;
        font-size: 0.8rem;
        padding: 0;

        &:hover {
            text-decoration: underline;
        }
        &.danger {
            color: var(--stuck);
        }
        /* Trash icon (Material Symbols, masked so it takes the button colour). */
        &.icon-btn {
            display: inline-grid;
            place-items: center;
            padding: 0.15rem 0.3rem;
            /* Same colour as the column headers (--faint, ui-table-header); red only
               on hover so the destructive action reads when you reach for it. */
            color: var(--faint);

            &:hover:not(:disabled) {
                color: var(--stuck);
            }
            &:hover {
                text-decoration: none;
            }
            .icon-trash {
                display: block;
                width: 0.95rem;
                height: 0.95rem;
                background: currentColor;
                mask: url("/img/delete.svg") no-repeat center / contain;
            }
        }
        &:disabled {
            color: var(--faint);
            cursor: not-allowed;

            &:hover {
                text-decoration: none;
            }
        }
    }

    /* ── Dialogs — shared chrome (add + delete confirmation) ─────────────── */
    dialog {
        /* the global `* { margin: 0 }` reset kills the UA's margin:auto dialog
           centering — restore it. */
        margin: auto;
        background: var(--panel);
        color: var(--text);
        border: 1px solid var(--line);
        border-radius: 0.6rem;
        padding: 1.1rem 1.25rem;
        width: 26rem;
        max-width: 92vw;
        box-shadow: 0 0.5rem 1.5rem hsl(0 0% 0% / 0.4), 0 0.1rem 0.3rem hsl(0 0% 0% / 0.3);

        &::backdrop {
            background: hsl(0 0% 0% / 0.55);
        }

        h3 {
            font-size: 1rem;
            font-weight: 600;
            margin-bottom: 0.6rem;
        }

        p {
            font-size: 0.9rem;
            color: var(--muted);
            line-height: 1.6;

            strong {
                color: var(--clay);
                font-family: "SF Mono", monospace;
                font-weight: 600;
            }
        }

        /* Add-vault form fields. */
        label {
            display: grid;
            gap: 0.25rem;
            font-size: 0.8rem;
            color: var(--muted);
            margin-bottom: 0.75rem;
        }
        input[type="text"] {
            background: var(--bg);
            color: var(--text);
            border: 1px solid var(--line);
            border-radius: 0.375rem;
            padding: 0.35rem 0.6rem;
            font-size: 0.9rem;

            &:focus {
                outline: none;
                border-color: var(--brand);
            }
        }

        menu {
            list-style: none;
            display: grid;
            grid-auto-flow: column;
            justify-content: end;
            gap: 0.5rem;
            margin-top: 1rem;

            button {
                border: 1px solid var(--line-3);
                border-radius: 0.3rem;
                background: none;
                color: var(--muted);
                padding: 0.4rem 1rem;
                font-size: 0.85rem;
                font-weight: 600;
                cursor: pointer;

                &[type="submit"] {
                    background: var(--brand);
                    border-color: var(--brand);
                    color: var(--bg);
                }
                &.danger-confirm {
                    background: var(--stuck);
                    border-color: var(--stuck);
                    color: var(--bg);
                }

                &:hover {
                    color: var(--text);

                    &[type="submit"],
                    &.danger-confirm {
                        opacity: 0.9;
                        color: var(--bg);
                    }
                }
            }
        }
    }
}



/* ui-settings-billing — Settings → Billing: plan, subscription status, and the
   Stripe Customer Portal link (same shape as Levirge Search's Workspace pane). */

ui-settings-billing {
    display: grid;
    gap: 1rem;
    align-content: start;

    main {
        display: grid;
        gap: 0.75rem;
    }

    .billing-message {
        color: var(--muted);
        font-size: 0.85rem;

        &:empty {
            display: none;
        }
    }
    &[data-state="error"] .billing-message {
        color: var(--error);
    }

    .billing-panel {
        display: none;
        gap: 0.75rem;
        background: var(--panel);
        border: 1px solid var(--line);
        border-radius: 0.5rem;
        padding: 0.75rem 1rem;
    }
    &[data-state="loaded"] .billing-panel {
        display: grid;
    }

    dl {
        display: grid;
        grid-template-columns: max-content 1fr;
        gap: 0.4rem 1.5rem;
        margin: 0;
    }
    dt {
        color: var(--muted);
    }
    dd {
        margin: 0;
    }

    .billing-status {
        &[data-status="active"] { color: var(--ok); }
        &[data-status="past_due"] { color: var(--warn); }
        &[data-status="canceled"] { color: var(--error); }
    }

    /* No subscription → nothing to manage in Stripe. */
    .billing-manage {
        display: none;
        justify-self: start;
        color: var(--brand);
        font-weight: 600;
    }
    &[data-subscription="true"] .billing-manage {
        display: inline;
    }
}



/* ui-settings-vault — single-vault detail page (/ui/settings/vaults/<vault>):
   display-name edit form (title, key and created date are in the app header), and the "User Grant
   Options" sub-tab — every user with a none|viewer|member button group in a
   shared .ui-table. Mirrors ui-settings-user. */

ui-settings-vault {
    display: grid;
    /* One row: the body. (There used to be a title row above it — an unused 1fr
       row after the body would be exactly the kind of gap nobody asked for.) */
    grid-template-rows: minmax(0, 1fr);
    height: 100%;

    /* ── Token gate + body reveal: CSS-driven via data-state on the root ── */
    #vault-body {
        display: none;
    }
    &[data-state="ready"],
    &[data-state="ready-empty"] {
        #vault-body {
            /* Stack compactly, top-aligned — no row stretches (a fixed 1fr row
               left a big gap once the avatar row was added). Page scrolls if the
               grants table gets long. */
            display: grid;
            grid-auto-rows: auto;
            gap: 0.75rem;
            min-height: 0;
            align-content: start;
        }
    }
    /* Unregistered vault: a name field instead of the error. */
    #vault-register {
        display: none;
    }
    &[data-state="unregistered"] #vault-register {
        display: grid;
        gap: 0.75rem;
        align-content: start;

        .register-note {
            margin: 0;
            font-size: 0.85rem;
            color: var(--muted);
        }
        #vault-register-form {
            display: grid;
            grid-template-columns: minmax(12rem, 20rem) auto;
            justify-content: start;
            align-items: end;
            gap: 0.75rem;

            label {
                display: grid;
                gap: 0.25rem;
                font-size: 0.8rem;
                color: var(--muted);
            }
        }
    }
    .grants-empty {
        display: none;
        color: var(--muted);
        font-size: 0.85rem;
        margin: 0;
    }
    &[data-state="ready-empty"] {
        .ui-table {
            display: none;
        }
        .grants-empty {
            display: block;
        }
    }
    /* Load errors arrive before "ready" — reveal only the status line. */
    &[data-state="error"] #vault-body {
        display: block;

        > :not(.settings-status) {
            display: none;
        }
    }

    .settings-status {
        color: var(--ok);
        font-size: 0.85rem;

        &:empty {
            display: none;
        }
        &[data-error="true"] {
            color: var(--stuck);
        }
    }

    /* ── Identity form — [avatar][name][save] over [description] ────────── */
    #vault-detail-form {
        display: grid;
        gap: 0.75rem;

        /* Its own grid: when the Description spanned these three columns, its
           width (up to 46rem) was spread over the `auto` ones — the avatar column
           grew to ~190px, leaving a gap before the name. */
        .identity-row {
            display: grid;
            grid-template-columns: auto minmax(12rem, 20rem) auto;
            justify-content: start;
            align-items: end;
            gap: 0.75rem;
        }

        .description-field {
            display: grid;
            grid-template-columns: 1fr auto;
            align-items: start;
            gap: 0.5rem 0.75rem;
            max-width: 46rem;

            .field-label {
                grid-column: 1 / -1;
                font-size: 0.8rem;
                color: var(--muted);
            }
            .vault-description {
                margin: 0;
                font-size: 0.85rem;
                line-height: 1.45;
                color: var(--text);
                /* Info text: half strength, so it reads as background to the fields. */
                opacity: 0.5;

                /* No description yet — the placeholder must not read as content. */
                &:empty::before {
                    content: "No description yet.";
                    color: var(--faint);
                }
            }
            button {
                background: none;
                border: 1px solid var(--line);
                border-radius: 0.3rem;
                color: var(--muted);
                padding: 0.3rem 0.7rem;
                font-size: 0.78rem;
                font-weight: 600;
                cursor: pointer;
                white-space: nowrap;

                &:hover:not(:disabled) {
                    color: var(--text);
                    border-color: var(--line-3);
                }
                &:disabled {
                    cursor: progress;
                    opacity: 0.6;
                }

                /* Icon-only, like the vault Profile page's Regenerate (muted, 50%,
                   accent on hover). */
                &.nav-icon {
                    display: grid;
                    place-items: center;
                    padding: 0.25rem;
                    border: none;
                    color: var(--muted);
                    opacity: 0.5;
                    transition: opacity 0.15s, color 0.15s;

                    &:hover:not(:disabled) {
                        opacity: 1;
                        color: var(--brand);
                    }
                    &:disabled {
                        opacity: 0.35;
                    }
                    .icon-cached {
                        display: block;
                        width: 1.2rem;
                        height: 1.2rem;
                        background: currentColor;
                        mask: url("/img/cached.svg") no-repeat center / contain;
                    }
                }
            }
        }

        label:not(.avatar-field) {
            display: grid;
            gap: 0.25rem;
            font-size: 0.8rem;
            color: var(--muted);
        }
        button[type="submit"] {
            align-self: end;
        }
    }

    /* ── Priorities panel — the vault's LLM guidance, its own PATCH ─────── */
    #vault-priorities-form {
        display: grid;
        gap: 0.75rem;
        max-width: 46rem;

        /* Must live here: the id selector outranks .tab-panel[hidden], so the
           generic hide rule alone leaves this panel visible. */
        &[hidden] {
            display: none;
        }

        label {
            display: grid;
            gap: 0.25rem;
            font-size: 0.8rem;
            color: var(--muted);
        }
        small {
            color: var(--faint);
            font-size: 0.72rem;
            line-height: 1.35;
        }
        button[type="submit"] {
            justify-self: start;
        }
    }

    /* Shared field + submit chrome across both forms. */
    input[type="text"],
    textarea {
        background: var(--bg);
        box-shadow: inset 0 1px 3px hsl(0 0% 0% / 0.25);
        color: var(--text);
        border: 1px solid var(--line);
        border-radius: 0.375rem;
        padding: 0.35rem 0.6rem;
        font-size: 0.9rem;
        width: 100%;
        box-sizing: border-box;

        &:focus {
            outline: none;
            border-color: var(--brand);
        }
    }
    textarea {
        font: inherit;
        line-height: 1.4;
        min-height: 6rem;
        resize: vertical;
    }
    button[type="submit"] {
        background: var(--brand);
        border: 1px solid var(--brand);
        border-radius: 0.3rem;
        color: var(--bg);
        padding: 0.4rem 1rem;
        font-size: 0.85rem;
        font-weight: 600;
        cursor: pointer;

        &:hover {
            opacity: 0.9;
        }
    }

    /* Tab panels — one visible at a time; `hidden` must beat the grid display. */
    .tab-panel[hidden] {
        display: none;
    }

    /* ── Sub tabs ──────────────────────────────────────────────────────── */
    .sub-tabs {
        display: grid;
        grid-auto-flow: column;
        justify-content: start;
        gap: 0.25rem;
        border-bottom: 1px solid var(--line);

        .sub-tab {
            background: none;
            border: none;
            border-bottom: 2px solid transparent;
            color: var(--muted);
            padding: 0.35rem 0.75rem;
            font-size: 0.85rem;
            font-weight: 600;
            cursor: pointer;

            &.active {
                color: var(--text);
                border-bottom-color: var(--brand);
            }
        }
    }

    /* ── User grant table — shared .ui-table consumer ──────────────────── */
    .ui-table {
        grid-template-columns: minmax(10rem, 0.8fr) minmax(12rem, 1fr) 13rem;
        font-size: 0.85rem;
    }

    /* Access — none|viewer|member button group (segmented control). */
    .btn-group {
        display: inline-grid;
        grid-auto-flow: column;
        border: 1px solid var(--line);
        border-radius: 0.3rem;
        overflow: hidden;
        vertical-align: middle;

        button {
            background: none;
            border: none;
            color: var(--muted);
            padding: 0.2rem 0.6rem;
            font-size: 0.75rem;
            font-weight: 600;
            cursor: pointer;
            transition: background 0.15s, color 0.15s;

            &:not(:first-child) {
                border-left: 1px solid var(--line);
            }
            &[aria-pressed="true"] {
                background: var(--brand);
                color: var(--bg);
            }
            &:hover:not([aria-pressed="true"]) {
                color: var(--text);
            }
        }
    }
}



/* Shared vault picker. The trigger sits wherever its <select data-vault-picker>
   was (outside this element), so .vault-trigger is a global rule; hosts
   restyle it in place (e.g. ui-search-bar's borderless segment). */

/* The host renders nothing itself (only its dialog, in the top layer). Without this
   it is a body child with no grid-area, so the page shell auto-places it into an
   extra implicit row AFTER the footer — plus the 0.5rem row gap before it. Same fix
   as ui-shortcuts. */
ui-vault-picker {
  display: contents;
}

.vault-trigger {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 1rem;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
    padding: 0.35rem 0.5rem 0.35rem 0.6rem;
    background: var(--bg);
    color: var(--text);
    border: 1px solid var(--line);
    border-radius: 0.3rem;
    font: inherit;
    font-size: 0.85rem;
    text-align: left;
    cursor: pointer;

    span {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* Same masked expand_more chevron as the account drawer caret. */
    &::after {
        content: "";
        width: 1rem;
        height: 1rem;
        background: var(--muted);
        mask: url("/img/expand-more.svg") no-repeat center / contain;
        opacity: 0.6;
    }

    &:hover::after { opacity: 1; }

    &:focus-visible {
        outline: 1px solid var(--brand);
    }

    &:disabled {
        opacity: 0.5;
        cursor: default;
    }

    .vt-avatar {
        width: 1.5rem;
        height: 1.5rem;
        border-radius: 0.3rem;
        object-fit: contain;

        &[hidden] { display: none; }
    }
    /* No uploaded avatar: muted brain glyph, as in the dialog rows. */
    .vt-avatar-ph {
        background: var(--muted);
        mask: url("/img/brain-icon.svg") no-repeat center / 80%;
    }

    /* Locked to one vault (vault-scoped views): just avatar + name. */
    /* Back chevron: the dropdown chevron turned to point left. */
    .vt-back {
        width: 1rem;
        height: 1rem;
        background: var(--muted);
        mask: url("/img/expand-more.svg") no-repeat center / contain;
        rotate: 90deg;

        &[hidden] { display: none; }
    }

    /* Locked to one vault (vault-scoped views): ‹ avatar name — a link back to
       the vault profile. */
    &[data-locked] {
        grid-template-columns: 1rem 1.5rem minmax(0, 1fr);
        gap: 0.5rem;
        padding-inline: 0;
        background: none;
        border-color: transparent;
        font-size: 0.95rem;
        font-weight: 600;
        cursor: pointer;

        &::after { display: none; }
        &:hover [data-field="label"] { color: var(--brand); }
        &:hover .vt-back { background: var(--text); }
    }

    /* Touch: 2.75rem (44px) minimum target. */
    @media (pointer: coarse) {
        min-height: 2.75rem;
        font-size: 0.95rem;
    }
}

ui-vault-picker dialog {
    /* the global `* { margin: 0 }` reset kills the UA's margin:auto centering. */
    margin: auto;
    width: 32rem;
    max-width: 92vw;
    background: var(--panel);
    color: var(--text);
    border: 1px solid var(--line);
    border-radius: 0.6rem;
    padding: 1.1rem 1.25rem;
    box-shadow: 0 0.5rem 1.5rem hsl(0 0% 0% / 0.4), 0 0.1rem 0.3rem hsl(0 0% 0% / 0.3);

    &::backdrop {
        background: hsl(0 0% 0% / 0.55);
    }

    h3 {
        font-size: 1rem;
        font-weight: 600;
        margin-bottom: 0.6rem;
    }

    /* Rows: avatar spans both lines, name over description. Whole-width
       buttons so a thumb can't miss. */
    .vault-options {
        display: grid;
        gap: 0.35rem;
        max-height: 60vh;
        overflow-y: auto;
    }

    .vault-option {
        display: grid;
        grid-template-columns: 2.5rem 1fr;
        column-gap: 0.75rem;
        align-items: center;
        min-height: 3.5rem;
        padding: 0.6rem 0.75rem;
        text-align: left;
        font: inherit;
        color: var(--text);
        background: none;
        border: 1px solid var(--line);
        border-radius: 0.45rem;
        cursor: pointer;

        &:hover,
        &:focus-visible {
            background: var(--bg-raised);
            outline: none;
            border-color: var(--brand);
        }

        &:disabled {
            cursor: default;
            opacity: 0.7;
        }

        &[aria-current] {
            border-color: var(--brand);
        }

        .vo-avatar {
            grid-row: 1 / 3;
            width: 2.5rem;
            height: 2.5rem;
            border-radius: 0.4rem;
            object-fit: contain;

            &[hidden] { display: none; }
        }

        /* No uploaded avatar: muted brain glyph, as on the vault profile. */
        .vo-avatar-ph {
            background: var(--muted);
            mask: url("/img/brain-icon.svg") no-repeat center / 70%;
        }

        strong {
            font-size: 0.95rem;
            font-weight: 600;
        }

        .vo-desc {
            font-size: 0.8rem;
            color: var(--muted);
            line-height: 1.4;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;

            &:empty { display: none; }
        }
    }

    menu {
        list-style: none;
        display: grid;
        justify-content: end;
        margin-top: 1rem;

        button {
            border: 1px solid var(--line-3);
            border-radius: 0.3rem;
            background: none;
            color: var(--muted);
            padding: 0.4rem 1rem;
            font-size: 0.85rem;
            font-weight: 600;
            cursor: pointer;

            &:hover { color: var(--text); }
        }
    }
}


/* Getting-started step bodies in Home's step card (_onboard-*.eta). */
.help-body {
  max-width: 720px;
  a {
    color: var(--link);
  }
  /* Agent picker cards on the MCP Setup landing. */
  /* Agent cards on Getting Started: setup-method and auth tags. */
  .help-tags,
  .help-legend {
    em {
      display: inline-block;
      margin-right: 0.35rem;
      padding: 0.05rem 0.5rem;
      border: 1px solid var(--line-3);
      border-radius: 1rem;
      color: var(--muted);
      font-size: 0.75rem;
      font-style: normal;
    }
    em[data-tag="signin"] {
      border-color: var(--accent-line);
      color: var(--accent-hi);
    }
  }
  .help-cards .help-tags { margin-top: 0.35rem; }
  .help-cards.help-agents {
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
    a,
    label {
      grid-template-columns: auto minmax(0, 1fr);
      column-gap: 0.85rem;
      align-content: start;
      > :not(.agent-logo) { grid-column: 2; }
    }
  }
  .help-legend { margin-top: 1rem; }
  /* Box comes from the global .agent-logo (help pages); here the vendor sits on
     the logo span itself, not on an .agent-card. */
  .agent-logo {
    color: var(--text);
    &[data-vendor="claude"]::after { mask-image: url("/img/vendors/claude.svg"); }
    &[data-vendor="openai"]::after { mask-image: url("/img/vendors/openai.svg"); }
    &[data-vendor="terminal"]::after { mask-image: url("/img/vendors/terminal.svg"); }
  }

  .help-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 0.75rem;
    margin: 0.5rem 0 1rem;
    a,
    label {
      display: grid;
      gap: 0.25rem;
      padding: 0.9rem 1rem;
      background: var(--panel);
      border: 1px solid var(--line);
      border-radius: 0.5rem;
      text-decoration: none;
      transition: background 0.15s, border-color 0.15s;
      &:hover {
        background: var(--raised);
        border-color: var(--line-3);
      }
      strong {
        color: var(--text);
        font-size: 0.95rem;
      }
      span {
        color: var(--muted);
        font-size: 0.8rem;
      }
    }
  }
  h3 {
    font-size: 1rem;
    font-weight: 600;
    margin: 1rem 0 0.5rem;
    color: var(--text);
  }
  p,
  li {
    color: var(--muted);
  }
  ul,
  ol {
    margin: 0 0 0.75rem 1.25rem;
  }
  li {
    margin-bottom: 0.35rem;
  }
  .first-steps {
    display: grid;
    gap: 0.45rem;
    margin-left: 0;
    list-style-position: inside;
    li {
      border: 1px solid var(--line);
      border-radius: 0.4rem;
      background: var(--panel);
      padding: 0.55rem 0.7rem;
    }
  }
  strong {
    color: var(--text);
  }
  table {
    width: 100%;
    border-collapse: collapse;
    margin: 0 0 0.75rem;
    font-size: 0.85rem;
    th {
      text-align: left;
      color: var(--text);
      font-weight: 600;
    }
    th,
    td {
      padding: 0.4rem 0.6rem;
      border: 1px solid var(--line);
      color: var(--muted);
      vertical-align: top;
    }
  }
  code {
    background: var(--raised);
    padding: 0.1em 0.35em;
    border-radius: 3px;
    font-size: 0.85em;
    font-family: "SF Mono", "Fira Code", monospace;
    color: var(--clay);
  }
  pre {
    background: var(--code-bg);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: 0.75rem 1rem;
    overflow-x: auto;
    margin: 0 0 0.75rem;
    font-size: 0.82rem;
    line-height: 1.5;
    code {
      background: none;
      padding: 0;
      color: var(--text);
    }
  }
}

/* Tip panel under Getting started (Home and /setup/agent): soft accent tint, lightbulb,
   link to the full guide. Partial: templates/_tip-getting-started.eta. */
.tip-panel {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: 0.75rem;
  padding: 0.85rem 1rem;
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: 0.6rem;
  color: var(--muted);
  font-size: 0.9rem;

  p { margin: 0; line-height: 1.5; }
  a { color: var(--accent-hi); }
}
.tip-panel-icon {
  width: 1.2rem;
  height: 1.2rem;
  background: var(--accent);
  mask: url("/img/lightbulb.svg") no-repeat center / contain;
}

/* Getting started → Step 2.N (/setup/agent/<id>/<n>): one step of connecting an agent. */
/* Left-aligned with the header title (Steve): #main's 2rem padding is the only inset — no centred
   container, no side padding on the card. */
.setup-page { max-width: 44rem; }
/* As Home (ui-home.css): the first block lines up with the sidebar card, not 1.5rem below it. */
#main:has(> .setup-page) { padding-top: 0; }
.setup-welcome {
  display: grid;
  gap: 1.25rem;
  padding: 1rem 0;
  > * { max-width: 44rem; }
}
.setup-card {
  display: grid;
  gap: 0.75rem;
  padding: 1.25rem 0;
  /* No fill, no border (Steve): the steps sit on the page. */
  border: none;
  border-radius: 0.45rem;
  background: none;
  color: var(--muted);

  .setup-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    a {
      border: 1px solid var(--line-3);
      border-radius: 0.4rem;
      color: var(--text);
      font-size: 0.8rem;
      padding: 0.3rem 0.8rem;
      text-decoration: none;
      &:hover { border-color: var(--accent); }
    }
    .setup-next {
      background: var(--accent);
      border-color: var(--accent);
      color: var(--bg);
      font-weight: 600;
    }
  }
  .setup-step > p:first-child { margin-top: 0; }
  .setup-note { margin: 0.75rem 0 0; font-size: 0.85rem; }
}
