:root {
  color-scheme: light;

  /* --- Material-3-derived indigo palette (2026 redesign) — cool blue-white surfaces instead
     of the old stone/paper work-surface look. Values lifted from the approved design comp. --- */
  --ink: #0b1c30;
  --ink-soft: #464555;
  --ink-faint: #777587;
  --paper: #f8f9ff;
  --surface: #ffffff;
  --surface-sunken: #eff4ff;
  --line: #dce9ff;
  --line-strong: #c7c4d8;

  /* Aliases so nothing outside this pass has to change its variable names. */
  --color-bg: var(--paper);
  --color-surface: var(--surface);
  --color-surface-sunken: var(--surface-sunken);
  --color-border: var(--line);
  --color-border-strong: var(--line-strong);
  --color-text: var(--ink);
  --color-text-muted: var(--ink-soft);
  --color-text-faint: var(--ink-faint);

  /* --- Deep: dark inverse-surface panel, now used only for the embed-snippet code card
     (the sidebar itself is light in this palette — see .sidebar below). --- */
  --deep: #213145;
  --deep-surface: #2b3d54;
  --deep-line: #3a4d66;
  --deep-text: #c7d2e3;
  --deep-text-bright: #eaf1ff;

  /* --- Signal: primary indigo accent --- */
  --signal: #3525cd;
  --signal-hover: #2a1da4;
  --signal-soft: #e2dfff;

  /* --- Brass: secondary accent for "customized / overridden" and in-progress states --- */
  --brass: #92400e;
  --brass-soft: #fef3c7;

  --color-accent: var(--signal);
  --color-accent-hover: var(--signal-hover);
  --color-accent-soft: var(--signal-soft);
  --color-danger: #ba1a1a;
  --color-danger-soft: #ffdad6;
  --color-success: #005338;
  --color-success-soft: #d9fbe8;
  --color-warning: var(--brass);
  --color-warning-soft: var(--brass-soft);

  /* Plus Jakarta Sans / Inter / JetBrains Mono (see the <link> tags in each page's own
     <head>) with the same native-OS stacks as before appended as fallbacks — a page that
     hasn't loaded the webfont link still renders with the previous system-native look
     rather than a missing-font fallback. */
  --font-display: "Plus Jakarta Sans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-sans: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", "Segoe UI Mono", Menlo, Consolas, monospace;

  /* The uppercase mono "label" role (field captions, stat labels, table headers, section
     labels, badges) was independently hardcoded at 10.5px in six places, below the 11px
     functional-text floor. One token so the role stays a role, not six numbers that can
     drift again. */
  --text-label: 11px;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;

  --radius-sm: 8px;
  --radius-md: 10px;
  --radius-lg: 14px;

  --shadow-sm: 0 1px 2px rgba(11, 28, 48, 0.06);
  --shadow-md: 0 8px 24px rgba(11, 28, 48, 0.08);
  --shadow-lg: 0 20px 48px rgba(11, 28, 48, 0.18);

  --sidebar-width: 252px;
}

* { box-sizing: border-box; }

/* Material Symbols (see the <link> tag in each page's own <head>) render unfilled/regular
   weight by default — this is the one place that's configured, so every usage stays visually
   consistent without repeating font-variation-settings inline at each call site. */
.material-symbols-outlined {
  font-variation-settings: "FILL" 0, "wght" 400, "GRAD" 0, "opsz" 24;
  font-size: 20px;
  line-height: 1;
  display: inline-flex;
  vertical-align: middle;
  user-select: none;
}

body {
  font-family: var(--font-sans);
  background: var(--paper);
  color: var(--ink);
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; font-family: var(--font-display); font-weight: 600; letter-spacing: -0.01em; }
h1 { font-size: 25px; }
h2 { font-size: 17px; }
h3 { font-family: var(--font-mono); font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-soft); }
p { margin: 0; }
a { color: var(--signal); }
a:hover { color: var(--signal-hover); }

/* --- Layout primitives --- */
.row { display: flex; gap: var(--space-3); align-items: center; }
.stack { display: flex; flex-direction: column; gap: var(--space-3); }
.spacer { flex: 1; }

.container { max-width: 720px; margin: 0 auto; padding: var(--space-6) var(--space-4); }
.container-narrow { max-width: 420px; margin: 0 auto; padding: var(--space-6) var(--space-4); }

/* --- App shell (sidebar + content), used by the dashboard --- */
/* height (not min-height) + overflow-y on each pane independently: the sidebar's own
   content always fits, so it should never need to scroll just because .content is taller
   than the viewport — previously .app-shell only had a min-height, so the flex row grew
   past 100vh with .content's content and stretched .sidebar along with it, scrolling both
   together. */
.app-shell { display: flex; height: 100vh; background: var(--paper); }
.sidebar {
  width: var(--sidebar-width);
  flex-shrink: 0;
  background: var(--surface);
  border-inline-end: 1px solid var(--line);
  padding: var(--space-5) var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  overflow-y: auto;
  color: var(--ink-soft);
}
.sidebar-brand { padding: 0 var(--space-2) var(--space-5); font-weight: 600; font-size: 16px; color: var(--ink); border-bottom: 1px solid var(--line); margin-bottom: var(--space-3); }
.sidebar-brand .domain { display: block; font-family: var(--font-mono); font-weight: 500; font-size: 11px; letter-spacing: 0.02em; color: var(--ink-faint); margin-top: 5px; }
.sidebar-brand-row { display: flex; align-items: center; gap: 7px; font-family: var(--font-display); }
.sidebar-nav-item {
  display: flex; align-items: center; gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 13.5px;
  font-weight: 500;
  cursor: pointer;
  border: none;
  background: none;
  text-align: start;
  width: 100%;
}
.sidebar .sidebar-nav-item:hover { background: var(--surface-sunken); color: var(--ink); }
.sidebar-nav-item.active {
  background: var(--signal);
  color: #fff;
  font-weight: 600;
  box-shadow: var(--shadow-sm);
}
/* Same recurring specificity bug CLAUDE.md documents for button hovers (a bare :hover rule
   outranking an equal/lower-specificity class): .sidebar .sidebar-nav-item:hover (3 classes)
   beats .sidebar-nav-item.active (2 classes) on its own, so hovering the selected tab silently
   reverted it to the unselected gray/ink colors. Re-assert the active look at equal specificity
   under :hover instead of leaving it to lose. */
.sidebar .sidebar-nav-item.active:hover { background: var(--signal); color: #fff; }
.sidebar-footer { margin-top: auto; padding: 0 var(--space-2); border-top: 1px solid var(--line); padding-top: var(--space-3); }
.sidebar-footer .sidebar-nav-item { color: var(--ink-soft); }
.sidebar-footer .sidebar-nav-item:hover { color: var(--ink); }

.sidebar-nav-icon {
  font-size: 20px; line-height: 1; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px;
  color: inherit;
}
.sidebar-nav-icon svg { width: 18px; height: 18px; display: block; }

/* .content scrolls full-width (flex:1) so the wheel/trackpad works anywhere over the pane,
   not just over the centered column; .content-inner carries the actual max-width/centering
   so the scrollable box isn't itself narrowed to that column. position:relative makes .content
   the containing block for its absolutely-positioned descendants (e.g. the visually-hidden
   native <select>s behind Appearance's corner/language pickers) — without it, an absolute
   descendant with no closer positioned ancestor falls back to <body>, and its static-position
   offset (which tracks how far down the tab's content it sits) inflates <html>'s own
   scrollHeight past the viewport. That produced a second, outer browser scrollbar on top of
   .content's own — confirmed directly on the Appearance tab, whose hidden #languageSelect sits
   ~1076px down the flow while the viewport is 900px tall. */
.content { flex: 1; overflow-y: auto; position: relative; }
/* 1320px, not the original 920px — the tenant dashboard's Overview/Knowledge Base grids (stat
   tiles, bento cards, wide tables) need real horizontal room, and 920px left a wide, unused
   margin on either side on anything short of an actual ultra-wide monitor (confirmed directly:
   a 16" MacBook's own browser window, not an unusually large screen, already showed it). Also
   the value admin.html's own `.content { max-width: 1320px }` override was clearly trying to
   reach for its data-dense tables — that rule targets the wrong element (.content, not
   .content-inner) so it was never actually doing anything; this makes that intent real instead
   of leaving two different "intended" widths that don't agree. */
.content-inner { padding: var(--space-6) var(--space-7); max-width: 1320px; margin-inline: auto; }
.content-header { margin-bottom: var(--space-6); }
.content-header .sub { color: var(--ink-soft); margin-top: var(--space-1); }

/* --- Mobile app-shell: sidebar becomes an off-canvas drawer below 768px --- */
/* Hidden entirely above the breakpoint; only rendered as a fixed-position trigger + overlay
   on narrow viewports, so desktop markup/behavior is untouched. */
.sidebar-toggle {
  display: none;
  position: fixed;
  top: var(--space-3);
  inset-inline-start: var(--space-3);
  z-index: 62;
  width: 40px;
  height: 40px;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink);
}
.app-shell .sidebar-toggle:hover { background: var(--surface-sunken); }
/* flex-shrink:0 + min-width — this SVG has no width/height XML attributes (only viewBox),
   and as a flex item (the button is display:flex once the mobile media query kicks in) that
   makes Chromium's automatic-minimum-size algorithm miscompute its min-content width down to
   ~6px instead of the intended 18px, while height stays correct (confirmed directly:
   getBoundingClientRect measured [6, 18] with only width:18px set, [18, 18] once shrink was
   disabled). Without this the hamburger icon renders as a barely-visible sliver. */
.sidebar-toggle svg { width: 18px; height: 18px; min-width: 18px; flex-shrink: 0; display: block; }
.sidebar-scrim {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(11, 28, 48, 0.45);
  z-index: 60;
}
.sidebar-scrim.visible { display: block; }

@media (max-width: 768px) {
  .sidebar-toggle { display: inline-flex; }
  .sidebar {
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;
    z-index: 61;
    transform: translateX(-100%);
    transition: transform 0.2s ease;
    /* Same clearance as .content below — the fixed toggle sits at top:12px, 40px tall, so an
       open drawer's own top padding must clear it too. Measured directly: without this, the
       toggle's (12,12)-(52,52) box overlapped .sidebar-brand's (12,24)-(239,94.5) box, sitting
       on top of the "U" in the brand name. */
    padding-top: calc(var(--space-3) + 40px + var(--space-3));
  }
  .sidebar.open { transform: translateX(0); }
  .content { padding: calc(var(--space-3) + 40px + var(--space-3)) var(--space-4) var(--space-5); }
}

/* --- Components --- */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-5);
}
.card + .card { margin-top: var(--space-4); }
/* The sibling-margin rule above assumes adjacent .card elements are always stacked
   vertically — it doesn't, since it's just a DOM-order selector. Inside a flex row
   (.stat-row already sets its own `gap` for spacing) it instead pushes every card but the
   first down by that margin, breaking their equal-height stretch: same bottom edge, shorter
   box. Cancelled here for any .card used as a direct row item. */
.stat-row > .card { margin-top: 0; }
.card-title { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-4); }

input[type=text], input[type=email], input[type=url], textarea, select {
  font-family: var(--font-sans);
  font-size: 14px;
  padding: 9px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  width: 100%;
}
/* input[type=color] is deliberately NOT in the rule above — it's a small fixed-size swatch,
   not a full-width text field, and every use of it already carries .color-swatch for its own
   sizing (see dashboard.html). Sharing that rule meant `input[type=color]` (element+attribute,
   higher specificity) always beat `.color-swatch`'s width/padding regardless of source order,
   so the swatch's actual rendered width was just whatever its flex row happened to leave
   available — usually far from the intended 36px, and inconsistent between swatches. */
input:focus, textarea:focus, select:focus { outline: 2px solid var(--signal); outline-offset: -1px; border-color: var(--signal); }
/* Verified directly (getComputedStyle on an actually-focused sidebar-nav-item, then a
   screenshot) that no visible ring rendered on keyboard focus — the heavy custom button
   reset above (border:none, background:none) also strips the browser's default one, with
   nothing here supplying a replacement. Sidebar items get a light-on-dark ring since they
   sit on --deep, not --surface; everything else gets the same ring the inputs above use.
   :focus-visible (not :focus) so a mouse click never shows a ring, only real keyboard focus. */
button:focus-visible, .btn:focus-visible, a:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 2px;
}
.sidebar-nav-item:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: -2px;
}
/* Scoped to bare `<label for="...">` field captions only (:not([class])) — the other labels
   in these pages are interactive wrappers with their own class (.priority-toggle,
   .file-picker-btn, .row for an inline checkbox+text pairing) whose own running text
   shouldn't be forced into small uppercase mono type. */
label:not([class]) { font-family: var(--font-mono); font-size: var(--text-label); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-soft); display: block; margin-bottom: var(--space-2); }

button, .btn {
  font-family: var(--font-sans);
  font-size: 13.5px;
  font-weight: 600;
  padding: 9px 16px;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  white-space: nowrap;
}
button:disabled { opacity: 0.5; cursor: default; }
.btn-primary, button { background: var(--signal); color: #fff; }
.btn-primary:hover:not(:disabled), button:hover:not(:disabled) { background: var(--signal-hover); }
.btn-secondary { background: var(--surface); color: var(--ink); border-color: var(--line-strong); }
.btn-secondary:hover:not(:disabled) { background: var(--surface-sunken); }
/* :hover:not(:disabled) on both, not just a bare :hover — the exact recurring bug CLAUDE.md
   documents (a bare `button:hover:not(:disabled)` a few lines up has just enough specificity
   to beat an unscoped hover of equal-or-lower weight). Without this, .btn-danger's own text
   color survives hover but its background flips to --signal-hover, landing on ~1.1:1 contrast
   — confirmed directly via a critique pass, on the Confirm button of every destructive dialog
   in both dashboards (Remove KB page, Remove lead field, Force reindex). */
.btn-danger { background: var(--color-danger-soft); color: var(--color-danger); }
.btn-danger:hover:not(:disabled) { background: var(--color-danger-soft); color: var(--color-danger); }
.btn-ghost { background: none; color: var(--ink-soft); }
.btn-ghost:hover:not(:disabled) { background: none; color: var(--ink); }
.btn-sm { padding: 5px 10px; font-size: 12.5px; }

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: var(--text-label);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.badge::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.badge-success { background: var(--color-success-soft); color: var(--color-success); }
.badge-warning { background: var(--brass-soft); color: var(--brass); }
/* The one state that's genuinely ongoing (a crawl/index actively running) gets the beacon
   pulse — every other badge stays still, so the motion itself carries meaning ("this is
   happening right now") instead of just being ambient decoration. */
@media (prefers-reduced-motion: no-preference) {
  .badge-warning::before { animation: beacon-pulse 1.6s ease-in-out infinite; }
}
@keyframes beacon-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.35; transform: scale(1.35); } }
.badge-danger { background: var(--color-danger-soft); color: var(--color-danger); }
.badge-neutral { background: var(--surface-sunken); color: var(--ink-soft); }

.status { font-size: 13px; color: var(--ink-soft); }
.status.error { color: var(--color-danger); }

.tabs { display: flex; gap: var(--space-1); border-bottom: 1px solid var(--line); margin-bottom: var(--space-5); }
.tab { padding: var(--space-2) var(--space-1); border-bottom: 2px solid transparent; color: var(--ink-soft); font-weight: 600; font-size: 13.5px; cursor: pointer; background: none; border-top: none; border-inline: none; }
.tab.active { color: var(--signal); border-bottom-color: var(--signal); }

.empty-state { text-align: center; padding: var(--space-6) var(--space-4); color: var(--ink-faint); font-family: var(--font-display); font-style: italic; font-size: 14.5px; }

.pagination { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: var(--space-1); margin-top: var(--space-4); }
.pagination:empty { display: none; margin-top: 0; }
.pagination button {
  background: var(--surface); color: var(--ink-soft); border: 1px solid var(--line-strong);
  font-family: var(--font-mono); font-size: 12px; font-weight: 600;
  min-width: 30px; height: 30px; padding: 0 8px; justify-content: center;
}
.pagination button:hover:not(:disabled):not(.active) { background: var(--surface-sunken); color: var(--ink); }
.pagination button.active { background: var(--signal); border-color: var(--signal); color: #fff; cursor: default; }
.pagination-ellipsis { padding: 0 4px; color: var(--ink-faint); font-family: var(--font-mono); font-size: 12px; }

.top-links { font-size: 13px; }
.top-links a { color: var(--ink-soft); text-decoration: none; }
.top-links a:hover { color: var(--ink); }

/* Inline help hint — a visible, tap/click/keyboard-activatable replacement for a bare
   title="..." attribute (which shows nothing at all on touch, and nothing until an unhinted
   hover-and-wait on desktop). See the .hint click-delegation handler in each dashboard's own
   script block. */
.hint {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; flex-shrink: 0; padding: 0; margin: 0;
  border-radius: 50%; border: 1px solid var(--line-strong); background: var(--surface-sunken);
  color: var(--ink-soft); font-family: var(--font-mono); font-size: 10px; font-weight: 700; line-height: 1;
  cursor: help;
}
/* :hover:not(:disabled), not a bare :hover — caught by the design hook immediately after
   writing it: a plain `.hint:hover` loses to the generic `button:hover:not(:disabled)` a few
   lines up (same recurring specificity bug as .btn-danger/.btn-ghost above), which would
   otherwise flip the background to --signal-hover while this rule's own color:var(--signal)
   survives, landing on 1.3:1 contrast. */
/* --signal-hover, not --signal — --signal was tuned to 4.5:1 against white/paper specifically
   (see its own comment above), and lands at 4.4:1 against --surface-sunken's slightly duller
   green-gray. The already-darker hover variant clears it with real margin. */
.hint:hover:not(:disabled), .hint:focus-visible { background: var(--surface-sunken); border-color: var(--signal); color: var(--signal-hover); }
.hint-popover {
  position: fixed; z-index: 65; max-width: 260px;
  background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md); padding: var(--space-3); font-size: 12.5px; line-height: 1.45; color: var(--ink);
}

/* Custom confirm/alert dialogs — see ui-dialogs.js. Replaces the browser's native
   confirm()/alert() so admin/dashboard prompts look like part of the product. */
.ui-dialog-backdrop {
  position: fixed; inset: 0; background: rgba(11, 28, 48, 0.45);
  display: flex; align-items: center; justify-content: center;
  padding: var(--space-4); z-index: 1000;
}
.ui-dialog {
  background: var(--color-surface); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  padding: var(--space-5); max-width: 420px; width: 100%;
}
.ui-dialog-message { margin: 0 0 var(--space-4); color: var(--color-text); font-size: 14px; line-height: 1.5; white-space: pre-wrap; }
.ui-dialog-actions { display: flex; justify-content: flex-end; gap: var(--space-2); }

/* Per-row "Actions" dropdown (admin table rows) — groups several row actions behind one
   trigger instead of a row of individual buttons. See createActionsDropdown() in index.html. */
.actions-dropdown { position: relative; display: inline-block; }
.actions-dropdown-menu {
  position: absolute; top: 100%; right: 0; margin-top: var(--space-1);
  min-width: 200px; background: var(--color-surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-md); box-shadow: var(--shadow-md); padding: var(--space-1);
  z-index: 50; display: none;
}
.actions-dropdown-menu.open { display: block; }
.actions-dropdown-menu button {
  display: block; width: 100%; text-align: start; background: none; color: var(--color-text);
  border: none; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
  font-size: 13px; font-family: var(--font-sans); font-weight: 400; white-space: nowrap;
}
.actions-dropdown-menu button:hover:not(:disabled) { background: var(--surface-sunken); color: var(--color-text); }
.actions-dropdown-menu button:disabled { color: var(--ink-faint); cursor: not-allowed; }
.actions-dropdown-menu button.danger { color: var(--color-danger); }
.actions-dropdown-menu button.danger:hover:not(:disabled) { background: var(--color-danger-soft); color: var(--color-danger); }
