:root {
  --bg: #05070b;
  --card-bg: #0c121a;
  --card-bg-solid: #0c121a;
  --text: #eef5f7;
  --muted: #8fa0a7;
  --accent: #17d2c2;
  --accent-2: #ff4f92;
  --border: rgba(167, 225, 224, 0.16);
  --negative: #ff6375;
  --positive: #50e3a4;
  --shadow: rgba(0, 0, 0, 0.36);
  /* Surface tones shared by inputs, buttons, rows, bubbles — everything that
     used to hardcode a near-black. The light theme below only has to swap
     these variables; no individual component rules change. */
  --field-bg: #071018;
  --input-bg: rgba(255, 255, 255, 0.06);
  --sidebar-bg: #05080c;
  --bubble-bg: #111a24;
  --on-accent: #041014;
  /* Native widgets (calendar icons, spinners, scrollbars) follow the theme. */
  color-scheme: dark;
}

/* Light mode — toggled by the Settings > Dark/Light button (html.light,
   persisted in the `theme` cookie and applied before first paint by the
   inline script in <head> so there's no dark flash). */
html.light {
  --bg: #eef2f5;
  --card-bg: #ffffff;
  --card-bg-solid: #ffffff;
  --text: #16232a;
  --muted: #5c6e77;
  --border: rgba(23, 60, 70, 0.16);
  --shadow: rgba(30, 50, 60, 0.14);
  --field-bg: #f2f5f7;
  --input-bg: rgba(10, 45, 55, 0.05);
  --sidebar-bg: #fbfdfe;
  --bubble-bg: #eef2f4;
  --on-accent: #04252b;
  color-scheme: light;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  background:
    radial-gradient(circle at 15% 10%, rgba(23, 210, 194, 0.16), transparent 24rem),
    radial-gradient(circle at 85% 20%, rgba(255, 79, 146, 0.11), transparent 22rem),
    linear-gradient(145deg, #05070b 0%, #08121b 48%, #05070b 100%);
  /* Pin the wash to the viewport (cover-style) so it fills exactly the screen
     with no tiling/stretching on long pages: fixed attachment sizes the image
     to the viewport, 100% 100% + no-repeat guarantee a single full-bleed
     paint. */
  background-attachment: fixed;
  background-size: 100% 100%;
  background-repeat: no-repeat;
  color: var(--text);
  min-height: 100vh;
}
html.light body {
  background:
    radial-gradient(circle at 15% 10%, rgba(23, 210, 194, 0.14), transparent 24rem),
    radial-gradient(circle at 85% 20%, rgba(255, 79, 146, 0.08), transparent 22rem),
    linear-gradient(145deg, #eef2f5 0%, #e3ebf0 48%, #eef2f5 100%);
  background-attachment: fixed;
  background-size: 100% 100%;
  background-repeat: no-repeat;
}
/* Theme switch: colors cross-fade quickly on the big surfaces. Gradients
   (body background-image) can't animate — everything else covers it. */
body, .sidebar, .tile, .chart-card, .tab, .period-btn, .ask-drawer,
.ticket-ai-chat-col, .drilldown-panel, main {
  transition: background-color 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}
body.nav-open,
body.ask-open { overflow: hidden; }

/* Background is the static color wash on <body> above — no animated layers.
   (The drifting conic/grid "data field" was removed by request; coloring kept.) */
.topbar, main, .ask-drawer, .drilldown-overlay, .ask-drawer-overlay { position: relative; z-index: 1; }

/* Entrance: panels and tile rows fade up as they render. */
@keyframes fade-in-up {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}
.tab-panel.active { animation: fade-in-up 0.35s ease both; }
.tiles-row { animation: fade-in-up 0.4s ease both; }
.tiles-row:nth-child(2) { animation-delay: 0.06s; }
.tiles-row:nth-child(3) { animation-delay: 0.12s; }

@media (prefers-reduced-motion: reduce) {
  .tab-panel.active, .tiles-row { animation: none; }
  * { transition-duration: 0.01ms !important; }
}

.login-body { display: flex; align-items: center; justify-content: center; height: 100vh; }

.login-card {
  background: var(--card-bg);
  padding: 2.5rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  box-shadow: 0 18px 50px var(--shadow);
  width: 320px;
}
.login-card h1 { font-size: 1.25rem; margin: 0 0 1.5rem; }
.login-card label { display: block; margin-bottom: 1rem; font-size: 0.85rem; color: var(--muted); }
.login-card input {
  display: block;
  width: 100%;
  margin-top: 0.35rem;
  padding: 0.6rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--input-bg);
  color: var(--text);
  font-size: 1rem;
}
.login-card button,
.login-oauth-button {
  display: block;
  width: 100%;
  padding: 0.7rem;
  border: none;
  border-radius: 5px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 1rem;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}
.login-error { color: var(--negative); font-size: 0.85rem; margin: -0.5rem 0 1rem; }
.login-note { font-size: 0.86rem; margin: -0.5rem 0 1.2rem; }

/* --- Left sidebar navigation (vertical — room to grow as more product
   sections join Zendesk, e.g. Telnyx). Fixed on desktop; off-canvas on mobile. */
.sidebar {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: 272px;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 1.25rem 1rem;
  background: var(--sidebar-bg);
  border-right: 1px solid var(--border);
  z-index: 50;
  overflow-y: auto;
  /* The nav can outgrow short windows, but its scrollbar shouldn't read as a
     second full-height page scrollbar glued to the nav (Windows draws auto
     scrollbars as a permanent wide gutter) — keep it thin and near-invisible,
     appearing only when the nav actually overflows. */
  scrollbar-width: thin;
  scrollbar-color: rgba(143, 160, 167, 0.28) transparent;
}
.sidebar::-webkit-scrollbar { width: 6px; }
.sidebar::-webkit-scrollbar-track { background: transparent; }
.sidebar::-webkit-scrollbar-thumb { background: rgba(143, 160, 167, 0.28); border-radius: 5px; }
.sidebar-head { display: flex; align-items: center; justify-content: space-between; margin: 0 0 1.25rem; }
.sidebar-brand { font-size: 1.02rem; margin: 0; white-space: nowrap; letter-spacing: 0.01em; }
.sidebar-collapse {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--field-bg);
  cursor: pointer;
  flex-shrink: 0;
}
.sidebar-collapse:hover { border-color: var(--accent); }
.sidebar-collapse-arrow {
  width: 7px;
  height: 7px;
  border-left: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(45deg); /* « points left = collapse */
  transition: transform 0.18s ease;
  margin-left: 3px;
}
html.nav-collapsed .sidebar-collapse-arrow { transform: rotate(225deg); margin-left: -3px; } /* » points right = expand */

/* Collapsed icon rail (desktop only — mobile keeps the off-canvas drawer).
   Group icons remain clickable: tapping one expands the rail and opens that
   group (see app.js). */
@media (min-width: 861px) {
  html.nav-collapsed .sidebar { width: 72px; padding: 1.25rem 0.7rem; align-items: center; }
  html.nav-collapsed .sidebar-brand,
  html.nav-collapsed .nav-group-label,
  html.nav-collapsed .nav-group-chevron,
  html.nav-collapsed .sidebar .tabs,
  html.nav-collapsed .sidebar-footer { display: none; }
  html.nav-collapsed .sidebar-head { justify-content: center; margin-bottom: 1rem; }
  html.nav-collapsed .nav-group-toggle,
  html.nav-collapsed .tab.nav-direct { justify-content: center; padding: 0.55rem 0; width: 44px; }
  html.nav-collapsed main { margin-left: 72px; }
}

/* A nav entry hidden by this user's visibility preferences (Settings). */
.sidebar .nav-hidden { display: none !important; }

/* Accordion group: one top-level product entry ("Zendesk") whose pages expand
   beneath it. Collapsed by default; the open/closed choice persists per user
   via the nav_zendesk_open cookie (see app.js). */
.nav-group-toggle {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  padding: 0.55rem 0.7rem;
  border: 1px solid transparent;
  border-radius: 5px;
  background: transparent;
  color: var(--text);
  font-size: 0.92rem;
  font-weight: 700;
  cursor: pointer;
  text-align: left;
}
.nav-group-toggle:hover { border-color: var(--border); background: var(--input-bg); }
.nav-group.open > .nav-group-toggle { background: var(--input-bg); }
.nav-group-icon {
  width: 24px;
  height: 24px;
  border-radius: 5px;
  background: #17494d;
  color: #fff;
  font-size: 0.8rem;
  font-weight: 800;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.nav-group-icon-voip { background: #1f5f86; }
.nav-group-icon-office { background: #6b4a9c; }
.nav-group-icon-settings { background: #4a5560; }
.nav-group-chevron {
  margin-left: auto;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(-45deg); /* points right when closed */
  transition: transform 0.18s ease;
}
.nav-group.open .nav-group-chevron { transform: rotate(45deg); } /* points down */

.tabs { display: none; flex-direction: column; gap: 0.15rem; padding: 0.25rem 0 0.25rem 1.9rem; }
.nav-group.open .tabs { display: flex; }

/* Nested sub-accordion (e.g. VOIP's Data/Server/Device Providers) — collapsed
   independently of its parent group and of its sibling subgroups; the parent
   rule above would otherwise show every nested .tabs whenever VOIP is open,
   so this has to win regardless of the parent's own open state. */
.nav-subgroup-toggle {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.4rem 0.7rem;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 0.72rem;
  font-weight: 500; /* medium — 800 read too heavy for a second-level title */
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  text-align: left;
}
.nav-subgroup-toggle:hover { color: var(--text); }
.nav-subgroup-toggle .nav-group-chevron { width: 6px; height: 6px; margin-left: auto; }
.nav-subgroup.open > .nav-subgroup-toggle .nav-group-chevron { transform: rotate(45deg); }
/* The ONLY side-border "selected" treatment in the nav lives on the three
   second-level titles (Data Providers / Server Providers / Device Portals)
   while open — plus a slightly darker fill so the pressed state reads. */
.nav-subgroup.open > .nav-subgroup-toggle {
  color: var(--text);
  border-left: 2px solid rgba(23, 210, 194, 0.35);
  border-radius: 0;
  padding-left: 0.55rem;
  background: rgba(0, 0, 0, 0.18);
}
.nav-subgroup .tabs { padding-left: 0.9rem; display: none !important; }
.nav-subgroup.open .tabs { display: flex !important; }
.tab {
  border: 1px solid transparent;
  background: transparent;
  padding: 0.45rem 0.7rem;
  border-radius: 5px;
  cursor: pointer;
  color: var(--muted);
  font-size: 0.9rem;
  text-align: left;
  width: 100%;
}
.tab:hover { border-color: var(--border); color: var(--text); background: var(--input-bg); }
.tab.active { background: rgba(23,210,194,0.16); border-color: rgba(23,210,194,0.35); color: var(--text); }

/* Direct top-level page link (no accordion) — dressed like a group toggle so
   it sits naturally between the group entries, but it IS a .tab and
   navigates on click. */
.tab.nav-direct {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.7rem;
  color: var(--text);
  font-size: 0.92rem;
  font-weight: 700;
}
/* Selected state inverts against the theme (dark button on the light theme),
   instead of the teal tint the regular page links use. */
.tab.nav-direct.active {
  background: var(--text);
  color: var(--card-bg-solid);
  border-color: var(--text);
}
.nav-group-icon-kg { background: #8a6d1f; }

/* Settings > theme switch. Filled with the OPPOSITE mode's colors — in dark
   mode it's a light button reading "Light", in light mode a dark button
   reading "Dark" — so the fill previews exactly what clicking switches to. */
.theme-toggle { background: #eef2f5; color: #16232a; border-color: rgba(23, 60, 70, 0.2); font-weight: 600; }
.theme-toggle:hover { background: #ffffff; color: #16232a; border-color: var(--accent); }
html.light .theme-toggle { background: #0c121a; color: #eef5f7; border-color: rgba(167, 225, 224, 0.25); }
html.light .theme-toggle:hover { background: #05070b; color: #eef5f7; border-color: var(--accent); }

.sidebar-footer {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}
.sidebar-footer .ask-toggle { width: 100%; }
.sidebar-footer .logout { text-align: center; }

/* Logged-in user's profile row above Ask/Sign out — image if they've set
   one (Settings → Profile Image), initials circle otherwise. */
.sidebar-profile { display: flex; align-items: center; gap: 0.55rem; min-width: 0; }
.sidebar-profile-name {
  font-size: 0.8rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sidebar-avatar,
.avatar-preview {
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  border-radius: 5px;
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--field-bg);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.avatar-preview { width: 44px; height: 44px; }
.avatar-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar-initials { font-size: 0.72rem; font-weight: 700; color: var(--muted); letter-spacing: 0.03em; }

/* Dimmed backdrop behind the off-canvas sidebar on mobile. */
.sidebar-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  z-index: 45;
}
.sidebar-overlay.open { display: block; }

/* Slim top bar — mobile only (hamburger + title + Ask). */
.mobile-topbar {
  display: none;
  align-items: center;
  gap: 0.75rem;
  padding: 0.8rem 1rem;
  background: var(--sidebar-bg);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 40;
}
.mobile-topbar h1 { font-size: 1.05rem; margin: 0; flex: 1; white-space: nowrap; }
.nav-toggle {
  width: 42px;
  height: 42px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--input-bg);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 5px;
}
.nav-toggle span {
  width: 18px;
  height: 2px;
  border-radius: 5px;
  background: var(--text);
  transition: transform 0.18s ease, opacity 0.18s ease;
}
.nav-toggle.open span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle.open span:nth-child(2) { opacity: 0; }
.nav-toggle.open span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
.ask-toggle {
  border: 1px solid var(--accent);
  background: rgba(23,210,194,0.08);
  color: var(--accent);
  padding: 0.5rem 1.1rem;
  border-radius: 5px;
  cursor: pointer;
  font-size: 0.9rem;
  font-weight: 600;
}
.ask-toggle:hover { background: var(--accent); color: var(--on-accent); }
.logout { color: var(--muted); text-decoration: none; font-size: 0.85rem; }

main { margin-left: 272px; padding: 2rem; }
main > .tab-panel { max-width: 1100px; margin-left: auto; margin-right: auto; }
/* AI Ticket Support's two-column layout (chat + open-tickets list) benefits
   from the room a fixed 1100px cap doesn't give it — let it use the page. */
main > #tab-zendesk-ai-ticket.tab-panel { max-width: none; }
.tab-panel { display: none; }
.tab-panel.active { display: block; }

/* Box styling now comes from .chart-card (placeholderPanel() renders both
   classes on the same element) — this just narrows the description text. */
.placeholder-panel p { max-width: 680px; }

.settings-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.55rem; }
/* Admin's allowed-users management: minus button per row + add-from-staff
   row under the list. The minus is deliberately quiet until hovered.
   (.settings-list li is already a flex row — see its own rule.) */
/* --- Notifications versus boards: two columns head to head, good side vs
   bad side, with a color-coded top edge instead of heavy chrome. --- */
.vs-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; align-items: start; }
.vs-col {
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--field-bg);
  padding: 0.75rem 0.9rem 0.9rem;
  border-top: 3px solid var(--muted);
  min-width: 0;
}
.vs-col.vs-good { border-top-color: var(--positive); }
.vs-col.vs-bad { border-top-color: var(--negative); }
.vs-col h3 {
  margin: 0 0 0.6rem;
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
  /* The title's engraved underline runs completely across its column —
     same two-tone groove as every card header. */
  padding-bottom: 0.4rem;
  border-bottom: 1px solid rgba(0, 0, 0, 0.4);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12);
}
html.light .vs-col h3 { border-bottom-color: rgba(0, 0, 0, 0.22); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.85); }
.vs-list { list-style: none; margin: 0; padding: 0; counter-reset: vs; display: flex; flex-direction: column; gap: 0.45rem; }
.vs-list li {
  counter-increment: vs;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 0.5rem;
  font-size: 0.82rem;
  padding-bottom: 0.45rem;
  border-bottom: 1px solid var(--border);
}
.vs-list li:last-child { border-bottom: none; padding-bottom: 0; }
.vs-list li::before {
  content: counter(vs);
  font-size: 0.68rem;
  font-weight: 800;
  color: var(--muted);
  min-width: 1.1em;
}
/* Agent Standings podium — green side only: gold, silver, copper balls
   behind ranks 1/2/3. */
.vs-battle .vs-good .vs-list li::before {
  width: 18px;
  height: 18px;
  min-width: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.62rem;
  color: #10151c;
  align-self: center;
}
.vs-battle .vs-good .vs-list li:nth-child(1)::before { background: #d4a017; box-shadow: inset 0 -2px 3px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.3); }
.vs-battle .vs-good .vs-list li:nth-child(2)::before { background: #b8bfc6; box-shadow: inset 0 -2px 3px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.3); }
.vs-battle .vs-good .vs-list li:nth-child(3)::before { background: #b87346; box-shadow: inset 0 -2px 3px rgba(0, 0, 0, 0.25), 0 1px 2px rgba(0, 0, 0, 0.3); }
/* Drillable rows: the name and the numbers are separate targets — the
   underline lands on exactly the piece under the cursor, never its sibling. */
.vs-list li[data-agent-id] .vs-name,
.vs-list li[data-agent-id] .vs-val,
.vs-list li[data-dt] .vs-name,
.vs-list li[data-dt] .vs-val { cursor: pointer; }
.vs-list li[data-agent-id] .vs-name:hover,
.vs-list li[data-agent-id] .vs-val:hover,
.vs-list li[data-dt] .vs-name:hover,
.vs-list li[data-dt] .vs-val:hover { text-decoration: underline; }
.vs-name { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vs-val { font-size: 0.72rem; font-weight: 700; color: var(--muted); white-space: nowrap; }
.vs-sub {
  grid-column: 2 / -1;
  font-size: 0.7rem;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.vs-empty { font-size: 0.8rem; margin: 0; }
/* Repeat Clients totals line: two clickable chips under the board, same
   red/green split as everything else on this page. */
.vs-clients-totals { display: flex; gap: 0.6rem; flex-wrap: wrap; margin: 0.9rem 0 0; }
.vs-total-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.35rem 0.7rem;
  border-radius: 5px;
  font-size: 0.78rem;
  cursor: pointer;
  border: 1px solid var(--border);
}
.vs-total-chip:hover { text-decoration: underline; }
.vs-total-chip b { font-size: 0.95rem; }
.vs-total-chip.vs-total-bad { color: var(--negative); background: rgba(255, 99, 117, 0.1); }
.vs-total-chip.vs-total-good { color: var(--positive); background: rgba(80, 227, 164, 0.1); }
/* --- "Your Race to #1" fight-night scoreboard (see the reference image:
   contender left / champion right, initial tiles on the outer edges,
   segmented LED bars, name plates, race clock center). Deliberately a
   dark board in BOTH themes — it's a graphic, not a form. --- */
.race-board { display: flex; align-items: center; gap: 0.9rem; }
.race-board + .race-board { margin-top: 1.25rem; padding-top: 1.25rem; border-top: 1px solid var(--border); }
.race-fighter { flex: 1; min-width: 0; }
.race-plate {
  display: inline-block;
  padding: 0.3rem 1.1rem;
  border-radius: 5px;
  transform: skewX(-8deg);
  font-size: 0.78rem;
  font-weight: 900;
  font-style: italic;
  letter-spacing: 0.08em;
  color: #fff;
  background: #10151c;
  margin-bottom: 0.55rem;
}
.race-plate-contender { border: 2px solid #3091ec; }
.race-plate-champ { border: 2px solid #d99a2b; }
.race-fighter-target { text-align: right; }
.race-fighter-target .race-fighter-grid { flex-direction: row-reverse; }
.race-fighter-grid { display: flex; align-items: stretch; gap: 0.5rem; }
.race-initial {
  flex-shrink: 0;
  width: 52px;
  border-radius: 5px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.7rem;
  font-weight: 900;
  color: #fff;
  background: #10151c;
}
.race-initial-me { border: 3px solid #3091ec; }
.race-initial-target { border: 3px solid #e34f32; }
.race-bars { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.race-bar {
  position: relative;
  height: 30px;
  background: #10151c;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 5px;
  overflow: hidden;
}
/* The whole bar is one 100-slice track; the fill slides across it UNDER
   the text (which overlays, starting at the same edge the fill grows from). */
.race-bar-track {
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.06) 0 0.65%, transparent 0.65% 1%);
}
.race-bar-fill {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  background: repeating-linear-gradient(90deg, currentColor 0 0.65%, rgba(0, 0, 0, 0.45) 0.65% 1%);
}
.race-bar.is-mirror .race-bar-fill { left: auto; right: 0; }
/* Mirrored bars anchor BOTH grids from the right edge — a right-anchored
   fill with a left-anchored slice pattern painted misaligned seams in the
   middle of the champion's bars. */
.race-bar.is-mirror .race-bar-track { background: repeating-linear-gradient(270deg, rgba(255, 255, 255, 0.06) 0 0.65%, transparent 0.65% 1%); }
.race-bar.is-mirror .race-bar-fill { background: repeating-linear-gradient(270deg, currentColor 0 0.65%, rgba(0, 0, 0, 0.45) 0.65% 1%); }
.race-bar-tag {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  height: 100%;
  padding: 0 0.6rem;
  font-size: 0.7rem;
  font-weight: 700;
  color: #fff;
  white-space: nowrap;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9);
}
.race-bar.is-mirror .race-bar-tag { justify-content: flex-end; }
.race-bar-tag b { font-size: 0.95rem; }
.race-bar-fill.is-primary-me { color: #35c274; }
.race-bar-fill.is-primary-target { color: #f09a3e; }
.race-bar-fill.is-week { color: #3d8ae0; }
.race-bar-fill.is-week-target { color: #e0483d; }
.race-nameplate {
  background: #10151c;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 5px;
  color: #fff;
  font-weight: 800;
  font-size: 0.88rem;
  padding: 0.35rem 0.6rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.race-fighter-target .race-nameplate { text-align: right; }
.race-clock { flex-shrink: 0; text-align: center; display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; max-width: 110px; }
.race-clock b { font-size: 1.3rem; font-weight: 900; letter-spacing: 0.02em; font-variant-numeric: tabular-nums; }
/* The stake under the clock: its own filled chip so what it takes to win
   is impossible to miss. */
.race-clock .race-stake {
  display: inline-block;
  background: var(--accent);
  color: #041014;
  border-radius: 5px;
  padding: 0.25rem 0.5rem;
  font-size: 0.68rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  line-height: 1.25;
  max-width: 110px;
}
.race-line { font-size: 0.85rem; margin: 0.9rem 0 0; }
.race-line b { color: var(--accent); }
/* Light theme: the board trades black-and-white for gray-and-black — same
   structure, colored fills unchanged (they read fine on gray). */
html.light .race-plate,
html.light .race-initial,
html.light .race-bar,
html.light .race-nameplate { background: #dde3e8; color: #16232a; }
html.light .race-bar { border-color: rgba(23, 60, 70, 0.18); }
html.light .race-nameplate { border-color: rgba(23, 60, 70, 0.18); }
html.light .race-bar-track { background: repeating-linear-gradient(90deg, rgba(23, 60, 70, 0.1) 0 0.65%, transparent 0.65% 1%); }
html.light .race-bar.is-mirror .race-bar-track { background: repeating-linear-gradient(270deg, rgba(23, 60, 70, 0.1) 0 0.65%, transparent 0.65% 1%); }
html.light .race-bar-fill { background: repeating-linear-gradient(90deg, currentColor 0 0.65%, rgba(255, 255, 255, 0.55) 0.65% 1%); }
html.light .race-bar.is-mirror .race-bar-fill { background: repeating-linear-gradient(270deg, currentColor 0 0.65%, rgba(255, 255, 255, 0.55) 0.65% 1%); }
html.light .race-bar-tag { color: #16232a; text-shadow: 0 1px 2px rgba(255, 255, 255, 0.75); }

@media (max-width: 860px) {
  .race-board { flex-direction: column; gap: 0.9rem; }
  .race-fighter { width: 100%; }
  .race-clock { order: 1; }
  .race-fighter-me { order: 0; }
  .race-fighter-target { order: 2; }
}

/* Split battle titles: the two halves share ONE underline that runs
   completely across the board (same engraved two-tone as card headers). */
.vs-battle { margin-bottom: 1.1rem; }
.vs-battle:last-of-type { margin-bottom: 0; }
.vs-battle-titles {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding-bottom: 0.4rem;
  margin-bottom: 0.7rem;
  border-bottom: 1px solid rgba(0, 0, 0, 0.4);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12);
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
html.light .vs-battle-titles { border-bottom-color: rgba(0, 0, 0, 0.22); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.85); }
.vs-t-good { color: var(--positive); }
.vs-t-bad { color: var(--negative); }
.vs-battle .vs-col h3 { display: none; } /* the shared title bar replaces per-column headings */


/* Agents page "Graded" state/control (feeds the Notifications standings). */
.grading-toggle {
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--input-bg);
  color: var(--positive);
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.14rem 0.55rem;
  cursor: pointer;
}
.grading-toggle.is-omitted { color: var(--muted); }
.grading-toggle:hover { border-color: var(--accent); }
.grading-state { font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--positive); }
.grading-state.is-omitted { color: var(--muted); }

/* Grid row instead of plain flex: a fixed name column keeps Active/the
   trailing tag or remove-button in the same two columns on every row no
   matter how long any individual email is. */
.allowed-users-row {
  display: grid !important;
  grid-template-columns: minmax(0, 220px) auto 1fr;
  align-items: center;
  gap: 0.6rem;
}
.allowed-users-row code { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.allowed-users-row .status-badge { margin-left: 0; justify-self: start; }
.allowed-users-row .allowed-users-admin-tag,
.allowed-users-row .allowed-users-remove { margin-left: 0; justify-self: end; }
.allowed-users-remove {
  margin-left: auto;
  width: 20px;
  height: 20px;
  line-height: 1;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--input-bg);
  color: var(--muted);
  font-size: 0.85rem;
  font-weight: 700;
  cursor: pointer;
}
.allowed-users-remove:hover { color: #fff; background: var(--negative); border-color: var(--negative); }
/* House-style switches: flat rectangular track (max 5px radius, matching
   every other control in the app — no stadium/pill shapes), a sliding knob
   with its own subtle border and shadow so it reads as a physical switch
   rather than a generic rounded toggle. Same on/off mechanics as before. */
.ip-toggle,
.view-as-toggle {
  width: 38px;
  height: 20px;
  border-radius: 5px;
  border: 1px solid var(--border);
  cursor: pointer;
  position: relative;
  flex-shrink: 0;
  margin-left: auto;
  padding: 0;
  align-self: center; /* .card-title-row is baseline-aligned; the switch should center against the title text instead */
  transition: background-color 0.15s ease, border-color 0.15s ease;
}
.ip-toggle::after,
.view-as-toggle::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 15px;
  height: 14px;
  border-radius: 3px;
  transition: transform 0.15s ease;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}
/* Allowed IPs on/off — green means requests are actually being restricted,
   red means anyone can reach the portal (Zendesk login is still required
   either way). No label/tooltip by design. */
.ip-toggle { background: rgba(255, 99, 117, 0.14); border-color: rgba(255, 99, 117, 0.4); }
.ip-toggle::after { background: var(--negative); }
.ip-toggle.is-on { background: rgba(80, 227, 164, 0.14); border-color: rgba(80, 227, 164, 0.4); }
.ip-toggle.is-on::after { background: var(--positive); transform: translateX(18px); }
/* View as Agent — deliberately black/white/gray, not the accent color, so it
   reads as a utility/preview control rather than a themed feature. */
.view-as-toggle { background: var(--input-bg); }
.view-as-toggle::after { background: var(--muted); }
.view-as-toggle.active { background: rgba(0, 0, 0, 0.35); border-color: var(--text); }
.view-as-toggle.active::after { background: var(--text); transform: translateX(18px); }
html.light .view-as-toggle.active { background: rgba(0, 0, 0, 0.12); }
.allowed-ips-row { display: grid; grid-template-columns: minmax(0, 160px) 1fr auto; align-items: center; gap: 0.6rem; }
.allowed-ips-input {
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 0.22rem 0.4rem;
  font-size: 0.78rem;
  background: var(--field-bg);
  color: var(--text);
  flex: 1 1 140px;
  min-width: 0;
}
.allowed-users-admin-tag { margin-left: auto; font-size: 0.68rem; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.allowed-users-add { display: flex; align-items: center; gap: 0.5rem; margin-top: 0.75rem; flex-wrap: wrap; }
.allowed-users-add select {
  flex: 1 1 220px;
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 0.22rem 0.35rem;
  font-size: 0.7rem;
  font-weight: 600;
  background: var(--field-bg);
  color: var(--text);
  cursor: pointer;
}

/* Per-user Portal Access dropdown in the Users table (admins only). */
.portal-access-select {
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 0.2rem 0.3rem;
  font-size: 0.72rem;
  font-weight: 600;
  background: var(--field-bg);
  color: var(--text);
  cursor: pointer;
}
.portal-access-select:disabled { opacity: 0.5; cursor: default; }
.settings-list li { font-size: 0.95rem; }
.settings-list code {
  background: var(--input-bg);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 0.15rem 0.5rem;
  font-size: 0.9rem;
}

/* --- Operating Knowledge Graph ------------------------------------------ */
/* The KG (graph AND editor) runs full width — the only page that escapes the
   1100px column. Height fills the viewport minus the chrome above it. */
main > #tab-knowledge-graph.tab-panel { max-width: none; }
.kg-card { display: flex; flex-direction: column; }
.kg-toolbar { display: flex; align-items: flex-end; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.5rem; }
.kg-search-wrap { position: relative; flex: 1 1 300px; min-width: 240px; max-height: 400px; display: flex; flex-direction: column; }
.kg-ask-log {
  flex: 0 1 auto;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.35rem;
  margin-bottom: 0.35rem;
  padding: 0.4rem;
  background: var(--card-bg-solid);
  border: 1px solid var(--border);
  border-radius: 5px;
  max-height: 330px; /* widget total stays within 400px with the input row */
}
.kg-ask-row { display: flex; gap: 0.4rem; align-items: flex-end; }
#kg-search {
  flex: 1;
  min-width: 0;
  resize: none;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 0.3rem 0.5rem;
  font-size: 0.75rem;
  font-family: inherit;
  line-height: 1.4;
  background: var(--field-bg);
  color: var(--text);
}
.kg-search-results {
  display: none;
  position: absolute;
  top: calc(100% + 0.25rem);
  left: 0;
  right: 0;
  z-index: 40;
  max-height: 280px;
  overflow-y: auto;
  background: var(--card-bg-solid);
  border: 1px solid var(--border);
  border-radius: 5px;
  box-shadow: 0 12px 32px var(--shadow);
}
.kg-search-results.open { display: block; }
.kg-search-item {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  width: 100%;
  padding: 0.4rem 0.6rem;
  border: none;
  background: transparent;
  color: var(--text);
  font-size: 0.78rem;
  text-align: left;
  cursor: pointer;
}
.kg-search-item:hover { background: var(--input-bg); }
.kg-search-type { margin-left: auto; color: var(--muted); font-size: 0.65rem; text-transform: uppercase; }
.kg-search-empty { padding: 0.5rem 0.6rem; color: var(--muted); font-size: 0.75rem; }
#kg-layout {
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 0.22rem 0.35rem;
  font-size: 0.7rem;
  font-weight: 600;
  background: var(--field-bg);
  color: var(--text);
  cursor: pointer;
}
.kg-controls { display: flex; align-items: flex-end; gap: 0.4rem; flex-shrink: 0; }
.kg-type-filters { display: flex; gap: 0.25rem; flex-wrap: wrap; }
.kg-type-filters-row { margin-bottom: 0.75rem; }
.kg-type-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 0.18rem 0.4rem;
  font-size: 0.65rem;
  font-weight: 600;
  background: var(--field-bg);
  color: var(--muted);
  cursor: pointer;
  opacity: 0.55;
}
.kg-type-chip.on { color: var(--text); opacity: 1; }
.kg-type-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.kg-body { display: flex; gap: 0.75rem; align-items: stretch; }
.kg-canvas-wrap { flex: 1 1 auto; min-width: 0; position: relative; }
.kg-canvas { width: 100%; height: calc(100vh - 240px); min-height: 480px; padding: 0; }
.kg-zoom { position: absolute; right: 0.6rem; bottom: 0.6rem; display: flex; flex-direction: column; gap: 0.3rem; z-index: 10; }
.kg-zoom button {
  width: 30px;
  height: 30px;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--card-bg-solid);
  color: var(--text);
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
}
.kg-zoom button:hover { border-color: var(--accent); color: var(--accent); }
.kg-details {
  flex: 0 0 300px;
  height: calc(100vh - 240px);
  min-height: 480px;
  overflow-y: auto;
  font-size: 0.78rem;
}
.kg-details-hint { line-height: 1.5; }
.kg-details-head { display: flex; align-items: center; gap: 0.45rem; }
.kg-details-head .kg-type-dot { width: 10px; height: 10px; }
.kg-details-title { font-weight: 700; font-size: 0.9rem; }
.kg-details-type { color: var(--muted); font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.04em; margin: 0.15rem 0 0.4rem; }
.kg-section {
  margin: 0.7rem 0 0.3rem;
  padding-bottom: 0.25rem;
  font-size: 0.62rem;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border-bottom: 1px solid rgba(0, 0, 0, 0.4);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12);
}
html.light .kg-section { border-bottom-color: rgba(0, 0, 0, 0.22); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.85); }
.kg-prop { display: flex; justify-content: space-between; gap: 0.5rem; padding: 0.15rem 0; }
.kg-prop span { color: var(--muted); text-transform: capitalize; }
.kg-prop b { text-align: right; overflow-wrap: anywhere; }
.kg-rel-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.5rem;
  width: 100%;
  padding: 0.25rem 0.35rem;
  margin-bottom: 0.15rem;
  border: 1px solid var(--border);
  border-radius: 2px;
  background: var(--input-bg);
  color: var(--text);
  font-size: 0.72rem;
  cursor: pointer;
  text-align: left;
}
.kg-rel-row:hover { border-color: var(--accent); }
.kg-rel-row b { color: var(--accent); }
.kg-time-row { display: flex; gap: 0.5rem; padding: 0.2rem 0; border-bottom: 1px dashed var(--border); font-size: 0.72rem; }
.kg-time-row span { color: var(--muted); white-space: nowrap; flex-shrink: 0; min-width: 62px; }
.kg-actions { display: flex; gap: 0.35rem; flex-wrap: wrap; }
.kg-status { font-size: 0.72rem; margin: 0 0 0.5rem; }
/* Editor rows: collapsed = just the name; open = full editing surface. */
.kge-row-head {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  width: 100%;
  border: none;
  background: transparent;
  color: var(--text);
  font-size: 0.8rem;
  font-weight: 600;
  text-align: left;
  padding: 0.22rem 0.1rem;
  cursor: pointer;
}
.kge-row-head:hover .kge-row-name { color: var(--accent); }
.kge-row-meta { margin-left: auto; color: var(--muted); font-size: 0.62rem; }
.kge-chevron-row { width: 6px; height: 6px; transform: rotate(-45deg); }
.kge-chevron-row.open { transform: rotate(45deg); }
.kge-row-collapse { border: none; background: transparent; cursor: pointer; padding: 0 0.25rem; }

/* Graph Assistant — same open design language as the editor around it. */
/* The one house-style module inside the unboxed editor: it rides .chart-card
   (solid surface, engraved title row via the page scope) so it matches the
   Overview boxes. */
.kge-assist { margin-top: 2rem; max-width: 760px; background: var(--card-bg-solid); }
.kge-assist-log { display: flex; flex-direction: column; gap: 0.45rem; max-height: 320px; overflow-y: auto; margin-bottom: 0.6rem; }
.kge-msg { max-width: 92%; font-size: 0.78rem; line-height: 1.5; padding: 0.45rem 0.7rem; border-radius: 10px; }
.kge-msg-you { align-self: flex-end; background: rgba(23, 210, 194, 0.14); border: 1px solid rgba(23, 210, 194, 0.3); }
.kge-msg-ai { align-self: flex-start; background: var(--input-bg); border: 1px solid var(--border); }
.kge-msg-ai ol, .kge-msg-ai ul { margin: 0.3rem 0 0.3rem 1.1rem; padding: 0; }
.kge-msg-ai p { margin: 0 0 0.4rem; }
.kge-msg-ai p:last-child { margin-bottom: 0; }
.kge-msg-thinking { color: var(--muted); font-style: italic; }
.kge-assist-form { display: flex; gap: 0.5rem; }
.kge-assist-form { align-items: flex-end; }
.kge-assist-form textarea {
  flex: 1;
  min-width: 0;
  resize: none;
  overflow: hidden;
  border: none;
  border-bottom: 1px solid var(--border);
  background: transparent;
  color: var(--text);
  font-size: 0.8rem;
  font-family: inherit;
  line-height: 1.45;
  padding: 0.35rem 0.1rem;
}
.kge-assist-form textarea:focus { outline: none; border-bottom-color: var(--accent); box-shadow: 0 8px 10px -10px var(--accent); }
.kge-assist-form .kge-apply { padding: 0.35rem 1.2rem; flex-shrink: 0; }

/* --- Operator Console (plan / ledger / score above the graph) --- */
.kg-console { display: flex; flex-direction: column; }
.kg-console[hidden] { display: none !important; }
.kg-console .kgc-card { margin-bottom: 1.5rem; display: flex; flex-direction: column; }
.kgc-sub { font-size: 0.72rem; margin: -0.35rem 0 0.7rem; font-style: italic; }
.kgc-bucket { margin-bottom: 0.6rem; }
.kgc-bucket-head {
  display: flex; align-items: baseline; gap: 0.5rem;
  font-size: 0.66rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--accent); margin-bottom: 0.2rem;
}
.kgc-hint { color: var(--muted); font-weight: 500; text-transform: none; letter-spacing: 0; font-style: italic; }
.kgc-task { display: flex; align-items: baseline; gap: 0.4rem; flex-wrap: wrap; padding: 0.16rem 0; font-size: 0.78rem; border-bottom: 1px dashed var(--border); }
.kgc-task-label { font-weight: 600; }
.kgc-due {
  flex-shrink: 0; font-size: 0.62rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em;
  padding: 0.08rem 0.4rem; border-radius: 2px; background: rgba(255, 99, 117, 0.16); color: var(--negative);
}
.kgc-ctx { color: var(--muted); font-size: 0.7rem; }
.kgc-why { color: var(--accent); font-size: 0.66rem; font-weight: 700; }
.kgc-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem 0.4rem; margin-bottom: 0.7rem; }
.kgc-stat { text-align: center; padding: 0.35rem 0.15rem; background: var(--field-bg); border: 1px solid var(--border); border-radius: 5px; }
.kgc-stat b { display: block; font-size: 1.05rem; }
.kgc-stat span { font-size: 0.56rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.03em; }
.kgc-chain { font-size: 0.72rem; line-height: 1.6; padding: 0.45rem 0.55rem; background: var(--field-bg); border: 1px solid var(--border); border-radius: 5px; }
.kgc-chain b { color: var(--accent); }
.kgc-chain-label { display: block; font-size: 0.58rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); margin-bottom: 0.15rem; }
.kgc-foot { font-size: 0.64rem; font-style: italic; margin: auto 0 0; padding-top: 0.6rem; }
.kgc-score-layout { display: grid; grid-template-columns: 1fr auto; gap: 0.4rem 1.25rem; align-items: center; margin-bottom: 0.4rem; }
.kgc-score-bars { min-width: 0; }
.kgc-drill { cursor: pointer; }
.kgc-stat.kgc-drill:hover { border-color: var(--accent); }
.kgc-task.kgc-drill:hover .kgc-task-label { color: var(--accent); }
.kgc-bar-row.kgc-drill:hover .kgc-bar-label { color: var(--text); }
/* A drill that's currently showing on the graph wears a highlighted border —
   click it again to take its nodes back off the canvas. */
.kgc-stat.kgc-on { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent), 0 0 10px rgba(23, 210, 194, 0.35); }
.kgc-task.kgc-on { border-left: 3px solid var(--accent); padding-left: 0.35rem; border-bottom-color: var(--accent); }
.kgc-bar-row.kgc-on .kgc-bar-label { color: var(--accent); }

/* Your Briefing card: motivational opener, priority list, improvement tips. */
.kg-summary-card .kgc-chain { margin: 0.75rem 0; }
.kg-sum-opener {
  font-size: 0.95rem; line-height: 1.5; font-weight: 600; color: var(--text);
  border-left: 3px solid var(--accent); padding: 0.1rem 0 0.1rem 0.7rem; margin: 0 0 0.7rem;
}
.kg-sum-stats { display: flex; gap: 1.1rem; margin-bottom: 0.8rem; font-size: 0.72rem; color: var(--muted); }
.kg-sum-stats b { color: var(--text); font-size: 0.95rem; }
.kg-sum-section { margin-top: 0.9rem; }
.kg-sum-h { font-size: 0.62rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); margin: 0 0 0.4rem; }
.kg-sum-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.3rem; counter-reset: sum; }
.kg-sum-item {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0.4rem;
  padding: 0.35rem 0.45rem; background: var(--field-bg); border: 1px solid var(--border); border-radius: 5px;
}
.kg-sum-item::before { counter-increment: sum; content: counter(sum); font-weight: 800; font-size: 0.7rem; color: var(--accent); min-width: 1ch; }
.kg-sum-label { font-weight: 600; font-size: 0.82rem; }
.kg-sum-why { font-size: 0.58rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em; padding: 0.06rem 0.35rem; border-radius: 2px; }
.kg-sum-why-someoneiswaitingonyou { background: rgba(255, 99, 117, 0.16); color: var(--negative); }
.kg-sum-why-duenow { background: rgba(255, 182, 72, 0.18); color: #e0a52b; }
.kg-sum-why-upnext { background: rgba(31, 115, 183, 0.16); color: #3a7bd5; }
.kg-sum-why-onyourplate { background: rgba(138, 151, 160, 0.16); color: var(--muted); }
.kg-sum-ctx { font-size: 0.68rem; color: var(--muted); }
.kg-sum-improve { margin: 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: 0.35rem; }
.kg-sum-improve li { font-size: 0.8rem; line-height: 1.45; }
.kg-find-label { display: block; font-size: 0.58rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); margin: 0.75rem 0 0.3rem; }

/* Priority-item badges: "Chat" for tasks found in Google Chat (no Zendesk
   ticket), "★ Priority" for watch-list / urgent hits. */
.kg-sum-badge { font-size: 0.56rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em; padding: 0.06rem 0.35rem; border-radius: 2px; white-space: nowrap; }
.kg-sum-badge-chat { background: rgba(155, 140, 255, 0.18); color: #9b8cff; }
.kg-sum-badge-priority { background: rgba(255, 182, 72, 0.2); color: #e0a52b; }

/* "How to reach 100/100": one card per sub-score, weakest first. */
.kg-climb-list { list-style: none; counter-reset: climb; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.45rem; }
.kg-climb-item { padding: 0.5rem 0.6rem; background: var(--field-bg); border: 1px solid var(--border); border-radius: 5px; }
.kg-climb-head { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.2rem; }
.kg-climb-label { font-weight: 700; font-size: 0.78rem; }
.kg-climb-label::before { counter-increment: climb; content: counter(climb) ". "; color: var(--accent); }
.kg-climb-score { font-size: 0.7rem; font-weight: 800; color: var(--muted); flex-shrink: 0; }
.kg-climb-move { display: block; font-size: 0.76rem; line-height: 1.45; color: var(--text); }

/* Watch list: priority terms as removable chips + an add input. */
.kg-watch { margin-top: 0.6rem; }
.kg-watch-label { display: block; font-size: 0.58rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); margin-bottom: 0.3rem; }
.kg-watch-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.3rem; padding: 0.35rem 0.45rem; border: 1px solid var(--border); border-radius: 5px; background: var(--field-bg); }
.kg-watch-chips { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.kg-watch-chip { display: inline-flex; align-items: center; gap: 0.25rem; font-size: 0.72rem; font-weight: 600; padding: 0.12rem 0.2rem 0.12rem 0.45rem; border-radius: 3px; background: rgba(23, 210, 194, 0.14); border: 1px solid rgba(23, 210, 194, 0.3); }
.kg-watch-x { border: none; background: transparent; color: var(--muted); cursor: pointer; font-size: 0.95rem; line-height: 1; padding: 0 0.15rem; }
.kg-watch-x:hover { color: var(--negative); }
.kg-watch-input { flex: 1; min-width: 140px; border: none; background: transparent; color: var(--text); font-size: 0.78rem; padding: 0.15rem; outline: none; }
.kg-watch-hint { display: block; font-size: 0.64rem; margin-top: 0.25rem; }
.kgc-score-cell { display: flex; flex-direction: column; align-items: center; gap: 0.35rem; max-width: 220px; }
/* The grade: big presence on a solid accent block — readable anywhere. */
.kgc-score {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 0.25rem;
  padding: 0.55rem 1.4rem;
  border-radius: 5px;
  background: var(--accent);
}
.kgc-score-num { font-size: 2.8rem; font-weight: 800; line-height: 1; color: #041014; }
.kgc-score-max { color: rgba(4, 16, 20, 0.65); font-size: 0.9rem; font-weight: 700; }
.kgc-score-note { font-size: 0.62rem; line-height: 1.45; text-align: center; margin: 0; font-style: italic; }
.kgc-verdict { text-align: center; font-size: 0.74rem; font-weight: 600; margin: 0 0 0.7rem; }
.kgc-bar-row { display: grid; grid-template-columns: 120px 1fr 30px; align-items: center; gap: 0.5rem; margin-bottom: 0.3rem; }
.kgc-bar-label { font-size: 0.64rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); white-space: nowrap; }
.kgc-bar-track { height: 8px; background: var(--input-bg); border-radius: 999px; overflow: hidden; }
.kgc-bar-fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--accent), #4fd8ff); }
.kgc-bar-val { font-size: 0.68rem; font-weight: 700; text-align: right; }

/* Connected sources row on the page-top card: Zendesk rides the login;
   the Google Workspace tiles are layout-only until their connectors exist. */
.kg-connections { display: flex; gap: 0.6rem; flex-wrap: wrap; }
.kg-conn {
  position: relative;         /* anchor for the top-right "updated" corner */
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4rem 0.5rem;
  padding: 0.5rem 0.7rem 0.5rem;
  padding-right: 6.5rem;      /* leave room for the corner timestamp */
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--field-bg);
  font-size: 0.78rem;
}
/* Per-connection "updated HH:MM" in the top-right corner of its own box. */
.kg-conn-updated {
  position: absolute;
  top: 0.4rem;
  right: 0.6rem;
  font-size: 0.6rem;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.kg-conn-updated:empty { display: none; }
/* A source's own summary line, sitting on its own row inside the box. */
.kg-conn .kg-src-line { flex-basis: 100%; margin: 0.1rem 0 0; font-size: 0.68rem; color: var(--muted); }
.kg-conn .kg-src-line:empty { display: none; }
.kg-conn-icon {
  width: 22px;
  height: 22px;
  border-radius: 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.7rem;
  font-weight: 800;
  border: 1px solid var(--border);
  background: var(--input-bg);
  color: var(--muted);
  flex-shrink: 0;
}
.kg-conn-name { font-weight: 700; }
.kg-conn-state { font-size: 0.68rem; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
.kg-conn.is-connected { border-color: rgba(80, 227, 164, 0.4); }
.kg-conn.is-connected .kg-conn-state { color: var(--positive); }
.kg-conn.is-connected .kg-conn-icon { color: var(--positive); border-color: rgba(80, 227, 164, 0.4); }
.kg-conn.is-soon { opacity: 0.65; }
.kg-conn-action {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--input-bg);
  color: var(--text);
  cursor: pointer;
  text-decoration: none;
}
.kg-conn-action:hover { border-color: var(--accent); color: var(--accent); }
.kg-conn-connect { color: var(--accent); border-color: rgba(80, 227, 164, 0.4); }
.kg-conn-error { color: var(--negative); margin-top: 0.5rem; }

/* --- The whole Knowledge Graph is one open, gridded surface now (no Manage
   toggle). #kg-surface cancels main's padding so its blueprint-grid + aurora
   background runs edge-to-edge, and the cards inside it (console, graph block,
   category view, chat) go transparent so the grid shows through everywhere. */
#kg-surface {
  position: relative;
  margin: -2rem;            /* cancel main's padding: grid edge-to-edge, nav-aware */
  min-height: 100vh;
  padding: 1.5rem 2rem 3rem;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  background:
    radial-gradient(ellipse 60% 40% at 15% 0%, rgba(23, 210, 194, 0.08), transparent),
    radial-gradient(ellipse 50% 35% at 85% 10%, rgba(255, 79, 146, 0.05), transparent),
    linear-gradient(rgba(23, 210, 194, 0.035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(23, 210, 194, 0.035) 1px, transparent 1px);
  background-size: auto, auto, 32px 32px, 32px 32px;
}
html.light #kg-surface {
  background:
    radial-gradient(ellipse 60% 40% at 15% 0%, rgba(23, 210, 194, 0.10), transparent),
    radial-gradient(ellipse 50% 35% at 85% 10%, rgba(255, 79, 146, 0.06), transparent),
    linear-gradient(rgba(13, 140, 129, 0.06) 1px, transparent 1px),
    linear-gradient(90deg, rgba(13, 140, 129, 0.06) 1px, transparent 1px);
  background-size: auto, auto, 32px 32px, 32px 32px;
}
/* Cards on the surface lose their own box so the grid reads as one plane; the
   graph canvas and details panel keep their own inner boxing (.settings-box). */
#kg-surface .chart-card,
#kg-surface .kgc-card {
  background: transparent;
  border: none;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  padding: 0;
}
#kg-surface .kg-console { display: flex; flex-direction: column; gap: 1.5rem; }
.kg-surface-head .card-title-row { margin-bottom: 0.75rem; }
/* Let the header wrap on narrow widths instead of overflowing, and center the
   buttons/stamps against the title rather than baseline-aligning them. */
.kg-head-row { flex-wrap: wrap; align-items: center; }
.kg-categories { margin-top: 0.25rem; }
/* Per-source summary lines under the header (Zendesk auto; Chat after a pull). */
.kg-src-line { font-size: 0.72rem; margin: 0.15rem 0 0; letter-spacing: 0.02em; }
.kg-src-line:empty { display: none; }
/* Each source's own Pull button (Connect uses the same shape). */
.kg-conn-pull {
  margin-left: 0.1rem;
  font-size: 0.66rem; font-weight: 700;
  padding: 0.2rem 0.55rem;
  border: 1px solid rgba(23, 210, 194, 0.4);
  border-radius: 999px;
  background: var(--input-bg);
  color: var(--accent);
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
}
.kg-conn-pull:hover:not(:disabled) { box-shadow: 0 0 12px rgba(23, 210, 194, 0.3); }
.kg-conn-pull:disabled { opacity: 0.45; cursor: not-allowed; color: var(--muted); border-color: var(--border); }
/* Disconnect: same button shape as Pull, but faded out until you hover/press
   it (it's a rare, secondary action — shouldn't compete with Pull). */
.kg-conn-pull-muted {
  color: var(--muted);
  border-color: var(--border);
  opacity: 0.55;
}
.kg-conn-pull-muted:hover:not(:disabled),
.kg-conn-pull-muted:focus-visible,
.kg-conn-pull-muted:active {
  opacity: 1;
  color: var(--negative);
  border-color: var(--negative);
  box-shadow: 0 0 12px rgba(255, 99, 117, 0.28);
}
/* The two timestamps: stacked vertically, right-aligned, pushed to the far
   right of the header so "Updated" sits directly above "Last pulled". */
.kg-stamps { margin-left: auto; display: flex; flex-direction: column; align-items: flex-end; gap: 0.1rem; line-height: 1.3; }
.kg-stamps .page-pulled,
.kg-stamps .kge-pulled { margin: 0; align-self: flex-end; opacity: 1; white-space: nowrap; }
.kg-pull-summary { font-size: 0.72rem; margin: 0.4rem 0 0; letter-spacing: 0.02em; }
.kg-pull-summary:empty { display: none; }

@media (max-width: 900px) {
  #kg-surface { margin: -1.25rem; padding: 1.25rem 1.25rem 2.5rem; }
}

/* Read-only expanded node body: properties as key/value rows, links as chips.
   No inputs — Pull Data owns the data. */
.kge-ro-body { padding: 0.15rem 0 0.4rem 1.1rem; display: flex; flex-direction: column; gap: 0.4rem; }
.kge-ro-props { display: flex; flex-direction: column; gap: 0.15rem; }
.kge-prop-ro { display: flex; gap: 0.5rem; font-size: 0.76rem; }
.kge-prop-ro-k { color: var(--muted); min-width: 90px; flex-shrink: 0; }
.kge-prop-ro-v { color: var(--text); word-break: break-word; }
.kge-ro-links { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.kge-row-head-open { font-weight: 700; }

/* No background/box on the editor header — it sits directly on the grid
   surface (which is why it also can't be sticky: unbacked text scrolling
   over content would be unreadable). Text colors ride the theme vars. */
.kge-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin: 0 0 1.5rem;
  padding: 0;
  color: var(--text);
}
.kge-pulled {
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.03em;
  align-self: center;
}
.kgc-empty { font-size: 0.85rem; margin: 0; }
.kge-title {
  font-size: 1.15rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: linear-gradient(90deg, var(--accent), #ff4f92);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.kge-sub { display: block; font-size: 0.68rem; font-weight: 500; letter-spacing: 0.04em; color: var(--muted); -webkit-text-fill-color: var(--muted); text-transform: none; }
.kge-topbar-actions { display: flex; gap: 0.5rem; }
.kge-apply {
  border: none;
  border-radius: 999px;
  padding: 0.45rem 1.6rem;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: #041014;
  background: linear-gradient(90deg, var(--accent), #4fd8ff);
  box-shadow: 0 0 18px rgba(23, 210, 194, 0.45);
  cursor: pointer;
}
.kge-apply:hover { box-shadow: 0 0 28px rgba(23, 210, 194, 0.7); }
.kge-apply:disabled { opacity: 0.6; cursor: wait; }
.kge-close {
  border: 1px solid rgba(23, 210, 194, 0.4);
  border-radius: 999px;
  padding: 0.45rem 1.2rem;
  font-size: 0.8rem;
  font-weight: 600;
  background: transparent;
  color: var(--text);
  cursor: pointer;
}
.kge-close:hover { box-shadow: 0 0 14px rgba(23, 210, 194, 0.3); }

.kge-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 1.25rem 2rem; align-items: start; }
.kge-section { min-width: 0; }
.kge-section.closed .kge-rows { display: none; }
.kge-chevron {
  width: 7px; height: 7px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: rotate(45deg);
  transition: transform 0.15s ease;
  flex-shrink: 0;
}
.kge-section.closed .kge-chevron { transform: rotate(-45deg); }
.kge-heading {
  cursor: pointer;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  padding-bottom: 0.35rem;
  margin-bottom: 0.4rem;
  /* Glowing underline instead of a box. */
  border-bottom: 1px solid var(--kge-c, var(--accent));
  box-shadow: 0 10px 14px -12px var(--kge-c, var(--accent));
}
.kge-count { color: var(--muted); font-weight: 600; }
.kge-add { margin-left: auto; border: none; background: transparent; color: var(--accent); font-size: 0.7rem; font-weight: 700; cursor: pointer; letter-spacing: 0.04em; }
.kge-add:hover { text-shadow: 0 0 8px rgba(23, 210, 194, 0.8); }
.kge-empty { color: var(--muted); font-size: 0.72rem; padding: 0.2rem 0; }

.kge-row { padding: 0.25rem 0.2rem; border-bottom: 1px solid var(--border); }
.kge-row:hover { background: linear-gradient(90deg, rgba(23, 210, 194, 0.06), transparent); }
.kge-row-main { display: flex; align-items: center; gap: 0.35rem; }
.kge-label {
  flex: 1;
  min-width: 0;
  border: none;
  border-bottom: 1px solid transparent;
  background: transparent;
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 600;
  padding: 0.15rem 0.1rem;
}
.kge-label:focus { outline: none; border-bottom-color: var(--accent); box-shadow: 0 8px 10px -10px var(--accent); }
.kge-mini {
  border: 1px solid var(--border);
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font-size: 0.62rem;
  font-weight: 700;
  padding: 0.12rem 0.5rem;
  cursor: pointer;
  letter-spacing: 0.03em;
}
.kge-mini:hover { color: var(--text); border-color: var(--accent); box-shadow: 0 0 8px rgba(23, 210, 194, 0.3); }
.kge-x { border: none; background: transparent; color: var(--muted); font-size: 0.85rem; line-height: 1; cursor: pointer; padding: 0 0.2rem; }
.kge-x:hover { color: var(--negative); text-shadow: 0 0 8px rgba(255, 99, 117, 0.8); }

.kge-props, .kge-links { padding: 0.3rem 0 0.4rem 0.6rem; display: flex; flex-direction: column; gap: 0.25rem; }
.kge-prop-row { display: flex; align-items: center; gap: 0.35rem; }
.kge-prop-k, .kge-prop-v, .kge-rel, .kge-target {
  border: none;
  border-bottom: 1px dashed var(--border);
  background: transparent;
  color: var(--text);
  font-size: 0.72rem;
  padding: 0.12rem 0.1rem;
}
.kge-prop-k { width: 110px; color: var(--muted); flex-shrink: 0; }
.kge-prop-v { flex: 1; min-width: 0; }
.kge-prop-k:focus, .kge-prop-v:focus, .kge-rel:focus, .kge-target:focus { outline: none; border-bottom-color: var(--accent); }
.kge-mini-label { font-size: 0.58rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); flex-shrink: 0; }
.kge-link { display: inline-flex; align-items: center; gap: 0.25rem; font-size: 0.7rem; color: var(--muted); }
.kge-link b { color: var(--text); font-weight: 600; }
.kge-newlink { display: flex; align-items: center; gap: 0.35rem; margin-top: 0.2rem; }
.kge-rel { width: 150px; flex-shrink: 0; }
.kge-target { flex: 1; min-width: 0; }

@media (max-width: 900px) {
  /* Graph: canvas on top (shorter, still touch-pannable/pinchable — cytoscape
     handles its own gestures), details below it, everything full width. */
  .kg-body { flex-direction: column; }
  .kg-canvas-wrap { width: 100%; }
  .kg-canvas { height: 55vh; min-height: 340px; }
  .kg-details { flex: none; width: 100%; height: auto; max-height: 45vh; }
  .kg-zoom button { width: 40px; height: 40px; font-size: 1.25rem; } /* thumb-sized */
  .kg-toolbar { align-items: stretch; }
  .kg-controls { width: 100%; justify-content: flex-start; }
  #kg-layout { flex: 1; }

  /* Console: stat tiles two-up, the grade stacks under its bars. */
  .kgc-stats { grid-template-columns: repeat(2, 1fr); }
  .kgc-score-layout { grid-template-columns: 1fr; justify-items: center; }
  .kgc-score-bars { width: 100%; }
  .kgc-bar-row { grid-template-columns: 104px 1fr 28px; }
  .kgc-bar-label { font-size: 0.6rem; }

  /* Editor: one column of sections; rows and link fields wrap instead of
     overflowing; touch-sized controls. */
  .kge-grid { grid-template-columns: 1fr; gap: 1rem; }
  .kge-row-main { flex-wrap: wrap; }
  .kge-label { flex: 1 1 100%; }
  .kge-newlink { flex-wrap: wrap; }
  .kge-rel { width: 100%; }
  .kge-target { flex: 1 1 100%; }
  .kge-mini { padding: 0.25rem 0.7rem; font-size: 0.68rem; }
  .kge-x { font-size: 1.05rem; padding: 0.1rem 0.45rem; }
  .kge-row-head { padding: 0.45rem 0.1rem; }
  .kge-assist { max-width: none; }
}

/* Zendesk Alerts (mock, not wired yet): grouped alert rows with delivery/
   audience chips and a status badge. */
.alerts-list { list-style: none; margin: 0; padding: 0.6rem; display: flex; flex-direction: column; gap: 0.55rem; }
.alerts-list li { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.alert-name { font-size: 0.85rem; font-weight: 700; white-space: nowrap; }
.alert-desc { color: var(--muted); font-size: 0.78rem; flex: 1 1 280px; min-width: 200px; }
.alert-chip {
  display: inline-block;
  padding: 0.14rem 0.5rem;
  border-radius: 2px;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  background: var(--input-bg);
  color: var(--muted);
  border: 1px solid var(--border);
}
.alert-chip.alert-chip-on { background: rgba(23, 210, 194, 0.16); border-color: rgba(23, 210, 194, 0.35); color: var(--text); }

/* Navigation Visibility controls (Settings > UNs & IPs) — every page listed
   out as a checkbox table, one column per sidebar section. */
.nav-prefs-card { position: relative; z-index: 2; }
/* One small horizontal row, sized like the timeline filter's buttons —
   label, user select, Save, and the status message all share a baseline. */
.nav-prefs-controls { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; margin-bottom: 1rem; }
.nav-prefs-inline-label { color: var(--muted); font-size: 0.7rem; font-weight: 600; }
.nav-prefs-controls select {
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 0.22rem 0.35rem;
  font-size: 0.7rem;
  font-weight: 600;
  line-height: 1.2;
  background: var(--field-bg);
  color: var(--text);
  cursor: pointer;
}
.nav-prefs-table { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; align-items: start; }
.nav-prefs-section {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  padding: 0.6rem;
  background: var(--field-bg);
  border: 1px solid var(--border);
  border-radius: 5px;
}
.nav-prefs-section h3 {
  margin: 0 0 0.45rem;
  padding-bottom: 0.35rem;
  font-size: 0.72rem;
  color: var(--muted);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  /* Engraved two-tone underline: a dark groove line with a light edge
     directly beneath it. */
  border-bottom: 1px solid rgba(0, 0, 0, 0.4);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12);
}
.nav-prefs-option { display: flex; align-items: center; gap: 0.5rem; padding: 0.3rem 0.45rem; border-radius: 5px; font-size: 0.85rem; cursor: pointer; }
.nav-prefs-option:hover { background: var(--input-bg); }
/* Locked while the section's master switch is off — no à-la-carte picking. */
.nav-prefs-option:has(input:disabled) { opacity: 0.45; cursor: not-allowed; }
.nav-prefs-option input:disabled { cursor: not-allowed; }
.nav-prefs-option input { margin: 0; cursor: pointer; }
.nav-prefs-option-group { font-weight: 700; }
/* Middle tier (VOIP's Data/Server/Device Portals) and their pages — indented
   to read as the hierarchy they are. */
.nav-prefs-option-sub { font-weight: 600; margin-left: 0.7rem; }
.nav-prefs-option-subitem { margin-left: 1.5rem; }
/* Save inherits .period-btn's small sizing; status text matches it. */
#nav-prefs-status { font-size: 0.7rem; }
/* On the light theme the groove reads through the highlight edge instead. */
html.light .nav-prefs-section h3 { border-bottom-color: rgba(0, 0, 0, 0.22); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.85); }

/* Ask AI Provider → Usage readout: compact token/cost table inside the same
   settings box, shown/hidden by the Usage button. Wide table scrolls inside
   the panel on narrow screens rather than stretching the card. */
.ai-usage-panel { margin-top: 0.9rem; overflow-x: auto; }
.ai-usage-table { border-collapse: collapse; font-size: 0.75rem; white-space: nowrap; }
.ai-usage-table th,
.ai-usage-table td { padding: 0.3rem 1.1rem 0.3rem 0; text-align: right; border-bottom: 1px solid var(--border); }
.ai-usage-table th {
  color: var(--muted);
  font-size: 0.65rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.ai-usage-table .aiu-period,
.ai-usage-table .aiu-provider { text-align: left; }
.ai-usage-table .aiu-period { color: var(--muted); font-weight: 700; }
.ai-usage-table .aiu-provider { font-weight: 600; }
.aiu-note { font-size: 0.7rem; margin: 0.5rem 0 0; }
/* Sub-headings inside the everyone-visible AI Usage & Cost card. */
.ai-usage-subhead {
  margin: 0 0 0.5rem;
  font-size: 0.7rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.ai-usage-subhead:not(:first-child) { margin-top: 1.1rem; }
#ai-usage-mine .ai-usage-table, #ai-usage-company .ai-usage-table { margin-bottom: 0.25rem; }

/* UNs & IPs: usernames and IP cards sit side by side on desktop. */
.settings-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; align-items: start; }
/* Shared inset panel — the Navigation Visibility column boxes set the look;
   reused across this settings page for lists and control rows. */
.settings-box {
  padding: 0.6rem;
  background: var(--field-bg);
  border: 1px solid var(--border);
  border-radius: 5px;
}
/* AI Guardrails free-text box — plain textarea in the house field style. */
.ai-guardrails-textarea {
  width: 100%;
  min-height: 120px;
  resize: vertical;
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 0.5rem 0.6rem;
  background: var(--input-bg);
  color: var(--text);
  font: inherit;
  font-size: 0.82rem;
  line-height: 1.4;
}
.ai-guardrails-controls { display: flex; align-items: center; gap: 0.6rem; margin-top: 0.6rem; }
/* Card titles on the Settings AND Overview pages carry the engraved two-tone
   underline the Navigation Visibility columns introduced. The Tickets by
   Assignee card's title lives in a .card-title-row (title + date cells), so
   the line goes under the whole row there. */
#tab-settings-uns-ips .chart-card > h2,
#tab-overview .chart-card > h2,
#tab-overview .card-title-row,
#tab-zendesk-ai-ticket .card-title-row,
#tab-satisfaction .chart-card h2,
#tab-sentiment .chart-card h2,
#tab-voip-alerts .chart-card > h2,
#tab-knowledge-graph .card-title-row {
  padding-bottom: 0.45rem;
  margin-bottom: 0.75rem;
  border-bottom: 1px solid rgba(0, 0, 0, 0.4);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12);
}
/* Tight cards on these pages — much less air above the headers. */
#tab-settings-uns-ips .chart-card,
#tab-overview .chart-card,
#tab-zendesk-ai-ticket .chart-card,
#tab-satisfaction .chart-card,
#tab-sentiment .chart-card,
#tab-voip-alerts .chart-card,
#tab-knowledge-graph .chart-card { padding: 0.85rem 1.5rem 1.25rem; }
html.light #tab-settings-uns-ips .chart-card > h2,
html.light #tab-overview .chart-card > h2,
html.light #tab-overview .card-title-row,
html.light #tab-zendesk-ai-ticket .card-title-row,
html.light #tab-satisfaction .chart-card h2,
html.light #tab-sentiment .chart-card h2,
html.light #tab-voip-alerts .chart-card > h2,
html.light #tab-knowledge-graph .card-title-row { border-bottom-color: rgba(0, 0, 0, 0.22); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.85); }
/* These cards are a shade of gray, not the bare-white --card-bg-solid every
   other card on the light theme uses. */
html.light #tab-settings-uns-ips .chart-card,
html.light #tab-overview .chart-card,
html.light #tab-zendesk-ai-ticket .chart-card,
html.light #tab-satisfaction .chart-card,
html.light #tab-sentiment .chart-card,
html.light #tab-voip-alerts .chart-card,
html.light #tab-knowledge-graph .chart-card { background: #eef1f3; }
/* The date-picker popover now lives inside a card; lift that card while the
   picker is open so it paints over the sibling cards below (each card's
   backdrop-filter isolates stacking order). Every page with a period
   toggle needs this, not just Overview — Notifications' picker was getting
   buried under the Ticket Drivers card below it with the old scoping. */
.chart-card:has(.period-custom-picker.open) { position: relative; z-index: 5; }
@media (max-width: 900px) { .settings-grid { grid-template-columns: 1fr; } }
.settings-list li { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; }
.settings-list-note { color: var(--muted); font-size: 0.85rem; }
.status-badge {
  margin-left: auto;
  padding: 0.14rem 0.55rem;
  border-radius: 5px;
  font-size: 0.7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.status-badge.status-active { color: var(--positive); background: rgba(80, 227, 164, 0.12); }
.status-badge.status-planned { color: var(--muted); background: var(--input-bg); }
.status-badge.status-off { color: var(--negative); background: rgba(255, 99, 117, 0.12); }

/* Drill-in table status pill — custom-status label, colored by its Zendesk
   status category using Zendesk's own ticket-list palette. */
.status-pill {
  display: inline-block;
  padding: 0.1rem 0.4rem;
  border-radius: 5px;
  /* Inherits the host table's font size (the drill-in rows run ~10px) —
     a fixed larger size made the pills dwarf every other cell. */
  font-size: inherit;
  font-weight: 700;
  white-space: nowrap;
  /* Widest label allowed is "Waiting on Client" (17ch) — anything longer
     ellipsizes so the Subject column keeps its room. */
  max-width: 17ch;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
  color: #fff;
  background: #87929d; /* fallback = solved/closed gray */
}
.status-pill.status-cat-new { background: #ffb057; color: #4a2f00; }
.status-pill.status-cat-open { background: #e34f32; }
.status-pill.status-cat-pending { background: #3091ec; }
.status-pill.status-cat-hold { background: #2f3941; }
.status-pill.status-cat-solved, .status-pill.status-cat-closed { background: #87929d; }

.period-toggle { display: flex; gap: 0.25rem; margin: 0.25rem 0 0.75rem; flex-wrap: wrap; position: relative; }
.period-btn {
  border: 1px solid var(--border);
  background: var(--field-bg);
  color: var(--muted);
  padding: 0.22rem 0.48rem;
  border-radius: 2px;
  cursor: pointer;
  font-size: 0.7rem;
  line-height: 1.2;
  font-weight: 600;
}
.period-btn.active { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
.period-btn-custom { border-style: dashed; }
/* Shown only while its dropdown is open — a border, not the solid .active
   fill, so it reads as "picked" without impersonating the real applied
   period (whichever preset still shows .active underneath). */
.period-btn-custom.picker-open { border-style: solid; border-color: var(--accent); color: var(--text); }

/* Inline "pick your own date" popover — anchored under the toggle row it belongs to. */
.period-custom-picker {
  display: none;
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 0.4rem;
  z-index: 20;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.35rem;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 0.45rem;
  width: 380px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.12);
}
.period-custom-picker.open { display: flex; }
.custom-picker-group { display: flex; flex-direction: column; gap: 0.2rem; }
/* Hidden until JS shows it — only relevant once the picker's own Compare
   checkbox is checked (pickers with no such checkbox, e.g. Backlog's weeks-
   prior picker, show it unconditionally instead). */
.compare-date-group.compare-date-hidden { display: none; }
.custom-picker-range { display: flex; align-items: center; gap: 0.35rem; }
.period-custom-picker .compare-label {
  color: var(--muted);
  font-size: 0.62rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
/* Always-visible "Compare [N] week(s) back" opt-in, sitting in the same row
   as the period buttons. */
.compare-inline-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  margin-left: 0.6rem;
  cursor: pointer;
}
.compare-inline-toggle input[type="checkbox"] { margin: 0; cursor: pointer; }
.compare-inline-toggle .compare-label { color: var(--muted); font-size: 0.7rem; font-weight: 600; }
.compare-inline-toggle .compare-weeks,
.period-custom-picker .compare-weeks-prior {
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 0.15rem 0.25rem;
  font-size: 0.7rem;
  background: var(--field-bg);
  color: var(--text);
  cursor: pointer;
}
.period-custom-picker input[type="date"], .period-custom-picker input[type="number"] {
  border: 1px solid var(--border);
  border-radius: 2px;
  padding: 0.2rem 0.35rem;
  font-size: 0.7rem;
  background: var(--field-bg);
  color: var(--text);
  /* Native calendar-icon/spinner glyphs follow color-scheme, inherited from
     :root / html.light — no per-input override needed. */
}
/* Compare is display-only (auto-filled from Current + weeks-prior) —
   pointer-events: none also stops the native calendar popup, which some
   browsers still open on readonly date inputs. */
.period-custom-picker input[readonly] { pointer-events: none; color: var(--muted); border-style: dashed; }
.period-custom-picker span { color: var(--muted); font-size: 0.7rem; }

/* Plain-language date/time range shown directly on a Backlog tile, above its
   value, so it's always physically inside the box it describes rather than
   a separate header that has to stay aligned with tile columns below it. */
.tile-date-range {
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: 0.3rem;
  white-space: normal;
  line-height: 1.3;
}

/* Backlog page: six tiles, each metric as a Current/Compare pair back to back.
   The Compare tile's headline value IS the %-change (colored the same way a
   tile-pct-badge would be), not a restated raw number. */
.overview-tiles-six .tile-compare { background: rgba(91,100,114,0.08); }
.tile-value-muted { color: var(--muted); }
.tile-value-pct.positive { color: var(--positive); }
.tile-value-pct.negative { color: var(--negative); }
.tile-value-pct.neutral { color: var(--text); }
.period-custom-picker .custom-apply {
  border: none;
  background: var(--accent);
  color: var(--on-accent);
  padding: 0.24rem 0.55rem;
  border-radius: 2px;
  cursor: pointer;
  font-size: 0.7rem;
  font-weight: 700;
}

/* Every tab leads with its own title, THEN its timeline filter — never the
   other way around. */
.page-title {
  font-size: 1.3rem;
  font-weight: 700;
  margin: 0 0 1rem;
  letter-spacing: 0.01em;
}

/* Small CAPS section headers — the standard style for every section label site-wide,
   not just tile groups (see .chart-card h2 below, which shares the same treatment). */
.section-label {
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 0.6rem;
}
.section-label-spaced { margin-top: 1.75rem; }
.section-subtext { margin-top: -0.35rem; margin-bottom: 0.75rem; font-size: 0.82rem; }

.tile {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1.25rem 1.5rem;
  position: relative;
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.tile:hover { transform: translateY(-2px); box-shadow: 0 14px 36px var(--shadow); }
.tile-value { font-size: 1.8rem; font-weight: 700; }
.tile-label { color: var(--muted); font-size: 0.85rem; margin-top: 0.25rem; }
/* Timeframe context sits in the tile's top-right corner — inline after the
   label it wrapped onto a second (sometimes third) line when the period text
   carried dates. */
.tile-period {
  position: absolute;
  top: 0.55rem;
  right: 0.7rem;
  max-width: 60%;
  text-align: right;
  color: var(--muted);
  font-size: 0.62rem;
  font-weight: 400;
  opacity: 0.8;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.tile.clickable { cursor: pointer; transition: box-shadow 0.15s, border-color 0.15s; }
.tile.clickable:hover { border-color: var(--accent); box-shadow: 0 2px 18px rgba(23,210,194,0.18); }
.tile.has-pct { padding-bottom: 1.25rem; }
/* Brief in-place dim while a period-toggle change re-fetches just this tile —
   siblings (e.g. an all-time tile in the same row) are untouched, no flash. */
.tile.tile-refreshing { opacity: 0.45; transition: opacity 0.15s; }

/* % change vs. the previous equal period — pinned to the bottom-right of the tile,
   opposite the (left-aligned) label/value. */
.tile-pct-badge {
  display: inline-flex;
  align-items: center;
  width: max-content;
  margin-top: 0.55rem;
  font-size: 0.78rem;
  font-weight: 700;
  padding: 0.1rem 0.45rem;
  border-radius: 5px;
  cursor: pointer;
}
/* In-badge spinner while a compare-enabled load's second phase computes. */
.tile-pct-badge.tile-pct-loading { gap: 0.3rem; color: var(--muted); font-weight: 600; text-transform: uppercase; font-size: 0.6rem; letter-spacing: 0.04em; }
.spinner-xs { width: 10px; height: 10px; border-width: 2px; }
.tile-pct-badge.positive { color: var(--positive); background: rgba(80,227,164,0.12); }
.tile-pct-badge.negative { color: var(--negative); background: rgba(255,99,117,0.12); }
.tile-pct-badge.neutral { color: var(--muted); background: rgba(91,100,114,0.1); }

/* Grand-total tiles (all-time, not affected by the period toggle) — visually set
   apart from the period-scoped tiles beside them. */
.tile-grand-total { background: linear-gradient(135deg, rgba(23,210,194,0.26), rgba(255,79,146,0.12)); border-color: rgba(23,210,194,0.38); }
.tile-grand-total .tile-value { color: var(--text); }
.tile-grand-total .tile-label, .tile-grand-total .tile-period { color: var(--text); opacity: 0.8; }

/* Even tile-row grid: a row is exactly N columns wide (max 4). When the tile count
   for a group isn't a multiple of 4, the JS layout helper (renderTileGrid) puts the
   smaller remainder row FIRST, so e.g. 7 tiles render as a row of 3 then a row of 4. */
.tiles-row { display: grid; gap: 1rem; margin-bottom: 1rem; }
.tile-row-1 { grid-template-columns: 1fr; }
.tile-row-2 { grid-template-columns: repeat(2, 1fr); }
.tile-row-3 { grid-template-columns: repeat(3, 1fr); }
.tile-row-4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 720px) {
  .tile-row-3, .tile-row-4 { grid-template-columns: repeat(2, 1fr); }
}

.chart-card {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1.5rem;
  margin-bottom: 1.5rem;
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  transition: box-shadow 0.18s ease;
  animation: fade-in-up 0.4s ease both;
}
.chart-card:hover { box-shadow: 0 16px 38px var(--shadow); }
.chart-card h2 {
  font-size: 0.78rem;
  margin: 0 0 1rem;
  color: var(--muted);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.chart-card.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 2rem; }
.intro-note { margin-top: -0.35rem; font-size: 0.78rem; }

/* Status breakdown by category: donut + a legend mapping each base category
   to whichever custom statuses your team has configured under it. */
.status-category-layout {
  display: grid;
  grid-template-columns: minmax(220px, 320px) 1fr;
  gap: 2rem;
  align-items: start;
  margin-top: 0.5rem;
}
.status-category-legend { display: flex; flex-direction: column; gap: 0.85rem; }
.status-category-row { display: flex; align-items: flex-start; gap: 0.6rem; }
.status-category-swatch { width: 12px; height: 12px; border-radius: 3px; margin-top: 0.3rem; flex-shrink: 0; }
.status-category-text { display: flex; flex-direction: column; gap: 0.1rem; }
.status-category-name { font-size: 0.85rem; font-weight: 700; }
.status-category-count { color: var(--muted); font-weight: 400; }
.status-category-members { font-size: 0.8rem; color: var(--muted); line-height: 1.35; }

@media (max-width: 720px) {
  .status-category-layout { grid-template-columns: 1fr; }
}

tr.clickable-row { cursor: pointer; }
tr.clickable-row:hover { background: rgba(23,210,194,0.08); }

.donut-svg, .funnel-svg { width: 100%; height: auto; max-height: 220px; }
.donut-legend { display: flex; flex-wrap: wrap; gap: 0.6rem 1.2rem; margin-top: 1rem; font-size: 0.82rem; }
.donut-legend span { display: inline-flex; align-items: center; gap: 0.4rem; }
.donut-legend i { width: 10px; height: 10px; border-radius: 3px; display: inline-block; }

.funnel-row { margin-bottom: 0.9rem; }
.funnel-bar { height: 28px; border-radius: 5px; background: var(--accent); display: flex; align-items: center; padding: 0 0.75rem; color: var(--on-accent); font-size: 0.8rem; font-weight: 600; white-space: nowrap; }
.funnel-label { font-size: 0.78rem; color: var(--muted); margin-bottom: 0.25rem; }

.drilldown-overlay {
  display: none;
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.62);
  z-index: 100;
  align-items: flex-start;
  justify-content: center;
  padding: 4vh 1rem;
}
.drilldown-overlay.open { display: flex; }
.drilldown-panel {
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 5px;
  width: 100%;
  max-width: 900px;
  max-height: 90vh;
  display: flex;
  flex-direction: column;
  box-shadow: 0 20px 60px rgba(0,0,0,0.48);
}
/* Same house style as the page cards: engraved line under the header, and a
   gray (not white) panel on the light theme. Title left, timeframe right,
   with the close X kept in its own slot after the date. */
.drilldown-header {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.85rem 1.5rem 0.5rem;
  border-bottom: 1px solid rgba(0, 0, 0, 0.4);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12);
}
html.light .drilldown-header { border-bottom-color: rgba(0, 0, 0, 0.22); box-shadow: 0 1px 0 rgba(255, 255, 255, 0.85); }
html.light .drilldown-panel { background: #eef1f3; }
.drilldown-header h2 {
  margin: 0;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* Same treatment as the page card headers (Ticket Count etc.). */
  font-size: 0.78rem;
  color: var(--muted);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
#drilldown-date { flex: 0 1 auto; }
.drilldown-close { border: none; background: none; font-size: 1.5rem; line-height: 1; cursor: pointer; color: var(--muted); flex-shrink: 0; }

/* Ticket IDs sit in their own small colored box (like the Satisfaction/
   Sentiment counts): the accent teal, deepened on the light theme so the
   white text reads, lightened on dark with dark text. */
#drilldown-body a.dd-id {
  display: inline-block;
  padding: 0.18rem 0.45rem;
  border-radius: 2px;
  font-weight: 700;
  background: #63e0d3;
  color: #04302b;
}
html.light #drilldown-body a.dd-id { background: #0d8c81; color: #fff; }
#drilldown-body a.dd-id:hover { filter: brightness(1.12); }
#drilldown-body { padding: 1rem 1.5rem 1.5rem; overflow-y: auto; }
/* Compact rows (~10px) so the subject column actually fits alongside the
   requester/org/agent/status columns. */
#drilldown-body table { font-size: 0.625rem; width: 100%; }
/* The modal never scrolls sideways — columns are capped/wrapped to fit. */
#drilldown-body .table-scroll { overflow-x: hidden; }
#drilldown-body td, #drilldown-body th { padding: 0.3rem 0.5rem; }
/* Subjects get the widest column (225px), wrapping to two lines max with …
   on a third; organizations cap at 175px on one line so they never crowd
   the subject out. */
#drilldown-body .dd-subject {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  /* Cap only — a hard width/min-width forced the table wider than the
     panel and made the whole box scroll side to side. */
  max-width: 225px;
}
#drilldown-body .dd-org {
  max-width: 175px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Agent names: one line, ~12 characters wide, then … */
#drilldown-body .dd-agent {
  max-width: 12ch;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#drilldown-body a { color: var(--accent); text-decoration: none; }

.bar-chart { display: flex; align-items: flex-end; gap: 0.35rem; height: 180px; padding-top: 1.5rem; }
.bar-col { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; height: 100%; }
.bar-fill { width: 65%; max-width: 34px; background: linear-gradient(180deg, var(--accent), rgba(23,210,194,0.38)); border-radius: 4px 4px 1px 1px; min-height: 3px; }
.bar-value { font-size: 0.7rem; font-weight: 600; color: var(--text); margin-bottom: 0.3rem; }
.bar-label {
  font-size: 0.68rem; color: var(--muted); margin-top: 0.45rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}

/* Backlog page: Created/Solved pies side by side, and Status breakdown's own
   Current/Compare pair (bar tables) — same two-column layout reused for both. */
.compare-pair { display: flex; gap: 2rem; align-items: flex-start; flex-wrap: wrap; }
.compare-pair-col { flex: 1 1 200px; text-align: center; }
.compare-pair-wide .compare-pair-col { flex-basis: 320px; text-align: left; }
.compare-pair-label {
  font-size: 0.72rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.05em; margin-bottom: 0.5rem;
}
.compare-pair-label.current { color: var(--accent); }
.compare-pair-label.compare { color: var(--muted); }

/* Horizontal bar list — Status Breakdown, one row per configured status. */
.hbar-chart { display: flex; flex-direction: column; gap: 0.5rem; }
.hbar-row { display: grid; grid-template-columns: minmax(120px, 200px) 1fr auto; align-items: center; gap: 0.7rem; }
.hbar-label-col { overflow: hidden; }
.hbar-label { font-size: 0.82rem; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbar-suffix { font-size: 0.66rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbar-track { background: rgba(143,160,167,0.14); border-radius: 4px; height: 14px; overflow: hidden; }
.hbar-fill { height: 100%; background: linear-gradient(90deg, rgba(23,210,194,0.5), var(--accent)); border-radius: 4px; min-width: 2px; }
.hbar-value { font-size: 0.78rem; font-weight: 700; color: var(--text); min-width: 2ch; text-align: right; }

/* Total row: same grid so the number lines up under the counts above, but no
   bar in the middle column and a light divider to set it apart. Deliberately
   plain — the label matches the status-name font, the number matches the
   count font. */
.hbar-total-row { margin-top: 0.15rem; padding-top: 0.5rem; border-top: 1px solid var(--border); }
.hbar-total-row .hbar-track { background: none; }
.hbar-total-row .hbar-label { font-weight: 700; }

@media (max-width: 560px) {
  .hbar-row { grid-template-columns: minmax(90px, 130px) 1fr auto; }
}

table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
th, td { text-align: left; padding: 0.6rem 0.5rem; border-bottom: 1px solid var(--border); }
th { color: var(--muted); font-weight: 600; font-size: 0.7rem; text-transform: uppercase; }
th[data-sort], th[data-user-sort] { cursor: pointer; user-select: none; white-space: nowrap; }
th[data-sort]:hover, th[data-user-sort]:hover { color: var(--text); }
th[data-sort].sort-asc::after, th[data-user-sort].sort-asc::after { content: ' \25B2'; font-size: 0.7rem; }
/* AI Ticket Support open-tickets list: same arrows on its grid headers. */
.ticket-ai-sort { cursor: pointer; user-select: none; }
.ticket-ai-sort:hover { color: var(--text); }
.ticket-ai-sort.sort-asc::after { content: ' \25B2'; font-size: 0.6rem; }
.ticket-ai-sort.sort-desc::after { content: ' \25BC'; font-size: 0.6rem; }
th[data-sort].sort-desc::after, th[data-user-sort].sort-desc::after { content: ' \25BC'; font-size: 0.7rem; }
/* Segment-column sorts: the arrow wears the color of the side being sorted —
   green (positive), yellow-orange (neutral), red (negative). */
th[data-sort].sort-seg-good::after { color: var(--positive); }
th[data-sort].sort-seg-neu::after { color: #ffb057; }
th[data-sort].sort-seg-bad::after { color: var(--negative); }

/* One-line card header: title in the left cell, timeframe in the right —
   two even cells, never wrapping. */
.card-title-row { display: flex; align-items: baseline; gap: 0.75rem; white-space: nowrap; margin-bottom: 1rem; }
.card-title-row h2 { flex: 1 1 50%; margin: 0 !important; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.card-title-date { flex: 1 1 50%; text-align: right; color: var(--muted); font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; overflow: hidden; text-overflow: ellipsis; }

/* Per-page "last pulled" stamp + refresh button, next to the page title.
   page-pulled is deliberately lighter than --muted (a quiet timestamp, not
   competing with the title); margin-left:auto on it pushes both trailing
   items right whether or not a .card-title-date sibling is also present. */
.page-pulled {
  margin-left: auto;
  flex-shrink: 0;
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--muted);
  opacity: 0.7;
  white-space: nowrap;
}
.page-refresh {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--input-bg);
  color: var(--muted);
  cursor: pointer;
}
.page-refresh:hover { color: var(--text); border-color: var(--accent); }
.page-refresh.is-spinning svg { animation: page-refresh-spin 0.7s linear; }
@keyframes page-refresh-spin { to { transform: rotate(360deg); } }

/* Satisfaction & Sentiment counts: small timeline-filter-style boxes sitting
   side by side, one per NON-ZERO count (zeros render nothing). Dark theme
   wears light fills with dark text; the light theme flips to deep fills with
   white text, so the numbers always pop against their box. */
.seg-cell { white-space: nowrap; text-align: right; }

/* Every drillable cell shows what you're about to click into: hover
   underlines just that cell's value (accent-colored), cursor turns pointer.
   The satisfaction cell's own green/red buttons keep their button styling. */
#backlog-table td[data-cell] { cursor: pointer; }
#backlog-table td[data-cell]:hover { text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: 3px; color: var(--accent); }
#backlog-table td.seg-cell[data-cell]:hover { text-decoration: none; }
#backlog-table td.seg-cell[data-cell]:hover .metric-seg { filter: brightness(1.12); box-shadow: 0 0 0 1px var(--accent); }

/* Compare mode, Tickets by Assignee: a thick orange edge under an agent's
   row means a comparison row is tucked underneath (click the name to open);
   the revealed row is solid yellow-orange so it reads as "the comparison",
   never a live agent. */
tr.has-compare:not(.compare-open) > td { border-bottom: 5px solid rgba(255, 176, 87, 0.45); }
tr.has-compare .compare-toggle-cell { cursor: pointer; }
tr.has-compare .compare-toggle-cell:hover { text-decoration: underline; text-decoration-color: #ffb057; }
tr.compare-row > td { background: rgba(255, 176, 87, 0.16); color: var(--text); font-size: 0.72rem; }
html.light tr.compare-row > td { background: rgba(255, 176, 87, 0.30); }

/* Status Breakdown compare bars: the same status's comparison-window count,
   drawn right under the live bar in yellow-orange on a shared scale. */
/* Clickable status bars (current only — compare bars stay inert). */
.hbar-clickable { cursor: pointer; }
.hbar-clickable:hover .hbar-label { text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: 3px; color: var(--accent); }
.hbar-row-compare { margin-top: -0.35rem; }
.hbar-row-compare .hbar-track { height: 8px; }
.hbar-fill-compare { background: #ffb057; }
.hbar-row-compare .hbar-value { color: #b97a24; font-size: 0.68rem; }

/* Every row line in Tickets by Assignee wears the engraved two-tone edge
   (dark groove + light highlight beneath), matching the card headers. */
#backlog-table th, #backlog-table td {
  border-bottom: 1px solid rgba(0, 0, 0, 0.4);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12);
}
html.light #backlog-table th, html.light #backlog-table td {
  border-bottom-color: rgba(0, 0, 0, 0.22);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.85);
}
.metric-seg {
  display: inline-block;
  border: none;
  padding: 0.18rem 0.45rem;
  margin-right: 0.25rem;
  border-radius: 2px;
  font: inherit;
  font-size: 0.7rem;
  line-height: 1.2;
  font-weight: 700;
}
.metric-seg:last-child { margin-right: 0; }
button.metric-seg { cursor: pointer; }
button.metric-seg:hover { filter: brightness(1.12); }
.metric-seg.seg-pos { background: #7fe3b5; color: #04160d; }
.metric-seg.seg-neu { background: #ffc46b; color: #241300; }
.metric-seg.seg-neg { background: #ff9aa5; color: #2a0409; }
html.light .metric-seg.seg-pos { background: #0e7a4b; color: #fff; }
html.light .metric-seg.seg-neu { background: #a86400; color: #fff; }
html.light .metric-seg.seg-neg { background: #b0212e; color: #fff; }

/* Column-name icons: hidden on desktop (full labels show), shown on small
   screens where the labels hide — with tooltips carrying the full name/key.
   The key tooltips render small (~9px) so the hover card stays compact. */
/* Header keys use data-tip (the JS floating tooltip) rather than the CSS
   [data-tooltip] pseudo-elements — those were getting clipped by the table's
   own overflow scroll wrapper, which read as a broken z-index. */
#backlog-table .th-icon { display: none; vertical-align: middle; color: var(--muted); }
#backlog-table [data-tip] { cursor: pointer; }
@media (max-width: 900px) {
  #backlog-table { min-width: 0; width: 100%; font-size: 0.72rem; }
  #backlog-table .th-label { display: none; }
  #backlog-table .th-icon { display: inline-flex; }
  #backlog-table td, #backlog-table th { padding: 0.35rem 0.3rem; }
  /* Solved As Follower (4th column) is the least-load-bearing number here
     and the one that tipped the table into horizontal scrolling on phones —
     dropped on small screens; the full six columns remain on desktop. */
  #backlog-table th:nth-child(4),
  #backlog-table td:nth-child(4) { display: none; }
}
.table-scroll {
  width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.table-scroll table { min-width: 680px; }
/* Desktop-only floor — on phones the icon headers let it fit the viewport
   (see the max-width: 900px block above). */
@media (min-width: 901px) { #backlog-table { min-width: 900px; } }
.table-scroll::-webkit-scrollbar { height: 8px; }
.table-scroll::-webkit-scrollbar-thumb { background: rgba(143,160,167,0.38); border-radius: 5px; }

.ask-drawer-overlay {
  display: none;
  position: fixed; inset: 0;
  background: rgba(0, 0, 0, 0.52);
  z-index: 90;
}
.ask-drawer-overlay.open { display: block; }

.ask-drawer {
  position: fixed;
  top: 0; right: 0;
  width: min(420px, 100vw);
  height: 100vh;
  background: var(--card-bg-solid);
  border-left: 1px solid var(--border);
  box-shadow: -10px 0 40px rgba(0,0,0,0.4);
  z-index: 95;
  display: flex;
  flex-direction: column;
  padding: 1.5rem;
  transform: translateX(100%);
  transition: transform 0.25s ease;
}
.ask-drawer.open { transform: translateX(0); }
.ask-drawer.fullscreen { width: 100vw; max-width: none; }

.ask-view-toggle {
  margin-top: 0.75rem;
  padding: 0.5rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--card-bg);
  color: var(--muted);
  font-size: 0.82rem;
  cursor: pointer;
  width: 100%;
}
.ask-view-toggle:hover { border-color: var(--accent); color: var(--text); }
.ask-drawer-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1rem; }
.ask-drawer-header h2 { margin: 0; font-size: 1.05rem; }

.ask-source-toggle { display: flex; gap: 0.6rem; margin-bottom: 1rem; }
.ask-source-btn {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  padding: 0.6rem 0.4rem;
  border: 2px solid var(--border);
  border-radius: 5px;
  background: var(--field-bg);
  cursor: pointer;
  transition: border-color 0.15s, box-shadow 0.15s;
}
.ask-source-btn:hover { border-color: var(--accent); }
.ask-source-btn.active { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(23,210,194,0.15); }
.ask-source-icon {
  width: 36px;
  height: 36px;
  border-radius: 5px; /* square with slightly rounded corners */
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 1.1rem;
  color: #fff;
}
.ask-source-icon-zendesk { background: #17494d; }
.ask-source-icon-telnyx { background: #0a0a0a; }
.ask-source-name { font-size: 0.75rem; color: var(--muted); font-weight: 600; }
.ask-source-btn.active .ask-source-name { color: var(--text); }

#ask-log { flex: 1; overflow-y: auto; margin-bottom: 1rem; display: flex; flex-direction: column; gap: 0.5rem; }
.ask-msg { padding: 0.6rem 0.9rem; border-radius: 5px; max-width: 90%; font-size: 0.9rem; }
.ask-you, .ask-system { white-space: pre-wrap; }
.ask-you { align-self: flex-end; background: var(--accent); color: var(--on-accent); }
.ask-bot { align-self: flex-start; background: var(--bubble-bg); border: 1px solid var(--border); }
.ask-bot.thinking { color: var(--muted); font-style: italic; white-space: pre-wrap; }
/* Inline escape hatch inside the Thinking… bubble — aborts the request
   client-side only; nothing reaches the AI. */
.ask-stop-btn {
  margin-left: 0.4rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--negative);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 700;
  font-style: normal;
  padding: 0.12rem 0.5rem;
  cursor: pointer;
}
.ask-stop-btn:hover { filter: brightness(1.12); }
/* What the Thinking… bubble becomes after Stop Thinking. */
.ask-bot.ask-stopped { color: var(--muted); font-style: italic; }
.ask-bot p { margin: 0 0 0.6rem; }
.ask-bot p:last-child { margin-bottom: 0; }
.ask-bot ul, .ask-bot ol { margin: 0 0 0.6rem; padding-left: 1.3rem; }
.ask-bot ul:last-child, .ask-bot ol:last-child { margin-bottom: 0; }
.ask-bot a { color: inherit; text-decoration: underline; }
.ask-system {
  align-self: center;
  background: transparent;
  color: var(--muted);
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 0.3rem 0;
}
#ask-form { display: flex; flex-direction: column; gap: 0.5rem; }
#ask-input {
  flex: 1;
  min-width: 0;
  resize: none;
  overflow-y: hidden;
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  font-size: 0.95rem;
  font-family: inherit;
  line-height: 1.4;
  background: var(--input-bg);
  color: var(--text);
}
#ask-form button[type="submit"] { flex-shrink: 0; padding: 0.6rem 1.2rem; border: none; border-radius: 5px; background: var(--accent); color: var(--on-accent); cursor: pointer; }
.ask-attach-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent !important;
  color: var(--muted) !important;
  padding: 0.6rem 0.7rem !important;
  border-radius: 5px;
  transition: background 0.15s ease, color 0.15s ease;
}
.ask-attach-btn svg { display: block; }
.ask-attach-btn:hover { background: var(--input-bg) !important; color: var(--text) !important; }
.ask-attach-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.ask-attach-btn.has-image { background: rgba(23,210,194,0.16) !important; color: var(--accent) !important; }

.ask-attachment-preview { display: none; align-items: center; gap: 0.6rem; margin-bottom: 0.6rem; padding: 0.5rem; border: 1px solid var(--border); border-radius: 5px; background: var(--bubble-bg); }
.ask-attachment-preview.showing { display: flex; }
.ask-attachment-preview img { width: 44px; height: 44px; object-fit: cover; border-radius: 5px; }
.ask-attachment-preview .ask-attachment-name { flex: 1; font-size: 0.8rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ask-attachment-preview button { border: none; background: none; color: var(--negative); cursor: pointer; font-size: 1.1rem; padding: 0 0.3rem; }

.ask-msg img.ask-msg-image { max-width: 100%; border-radius: 5px; margin-top: 0.4rem; display: block; }

/* Add & Solve Ticket w. AI — ticket list on the left, chat on the right.
   The chat comes first in the markup (left on desktop) so it's also first
   on mobile when the columns stack — this page is meant to be usable on the
   go, and typing a new ticket shouldn't require scrolling past the list. */
.ticket-ai-toolbar { display: flex; gap: 0.4rem; margin: 0.25rem 0 1.25rem; flex-wrap: wrap; }
.ticket-ai-action { font-weight: 700; }
.ticket-ai-clear { color: var(--negative) !important; border-color: rgba(255,99,117,0.35) !important; }
.ticket-ai-clear:hover { background: rgba(255,99,117,0.1) !important; }

/* A fixed height ceiling (not just min-height) is what makes the chat log's
   overflow-y: auto actually kick in below — without a real ceiling the chat
   (and the page) just keeps growing as messages are added instead of
   scrolling internally, like the Ask side panel does. The ceiling lives on
   EACH COLUMN, not the flex container: this layout wraps at mid widths, and
   a height on the wrapping container left the wrapped chat column with no
   ceiling of its own — that was the "chat keeps growing" bug. */
.ticket-ai-layout { display: flex; gap: 1.5rem; align-items: flex-start; flex-wrap: wrap; }
.ticket-ai-chat-col {
  flex: 1 1 420px;
  max-width: 560px;
  min-width: 340px;
  /* 90% of the viewport height, floored at a flat 500px so the box never
     goes below that even on a short window. The inner log (min-height: 0)
     shrinks/scrolls to fit whatever this outer box ends up being. */
  height: 90vh;
  min-height: 500px;
  display: flex;
  flex-direction: column;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1rem;
}
.ticket-ai-list-col {
  flex: 2 1 560px;
  min-width: 340px;
  height: 90vh;
  min-height: 500px;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overflow-x: hidden;
}

#ticket-ai-list { display: flex; flex-direction: column; overflow-y: auto; overflow-x: hidden; }

/* Same small/minimal aesthetic as .period-toggle's buttons — a plain grid
   table, tight padding, muted borders, no heavy chrome. */
.ticket-ai-table { display: flex; flex-direction: column; gap: 0.3rem; }
.ticket-ai-table-head,
.ticket-ai-row {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) 0.8fr 0.8fr 0.9fr auto;
  gap: 0.5rem;
  align-items: center;
}
.ticket-ai-table-head {
  padding: 0 0.7rem 0.35rem;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.ticket-ai-row {
  width: 100%;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--field-bg);
  color: var(--text);
  text-align: left;
  cursor: pointer;
  font-size: 0.78rem;
}
.ticket-ai-row:hover { border-color: var(--accent); }
.ticket-ai-row-main { display: flex; align-items: baseline; gap: 0.4rem; min-width: 0; }
.ticket-ai-row-id { font-weight: 700; color: var(--accent); flex-shrink: 0; }
.ticket-ai-row-subject { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ticket-ai-row-org { font-size: 0.72rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Custom status label — same size as the row's other small fields, not the
   bigger house status-pill (this row is dense/list-style, not a table). */
.ticket-ai-row-status { font-size: 0.72rem; }
.ticket-ai-row-status .status-pill { text-transform: uppercase; }
.ticket-ai-row-requested { font-size: 0.72rem; color: var(--muted); }
.ticket-ai-row-age { font-weight: 700; color: var(--text); }
.ticket-ai-row-updated { font-size: 0.72rem; font-weight: 700; }
.ticket-ai-row-updated.staff { color: var(--positive); }
.ticket-ai-row-updated.client { color: var(--negative); }
/* The one deliberate emoji in the chrome: ✨ is the emerging shorthand for
   "AI" — a solid accent chip on each row that hands the ticket to the chat,
   while the row itself opens the real ticket in Zendesk. */
.ticket-ai-row-ai {
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--input-bg);
  padding: 0.2rem 0.45rem;
  font-size: 0.85rem;
  line-height: 1;
  cursor: pointer;
}
.ticket-ai-row-ai:hover { background: var(--field-bg); border-color: var(--accent); }
/* This button sits flush against the row's right edge — the default
   centered tooltip (left: 50%) would hang past it and force the list to
   scroll horizontally. Anchor to the right edge instead so it only ever
   grows leftward, inside the row. */
.ticket-ai-row-ai[data-tooltip]::before,
.ticket-ai-row-ai[data-tooltip]::after { left: auto; right: 0; transform: translate(0, -6px); }
.ticket-ai-row-ai[data-tooltip]:hover::before,
.ticket-ai-row-ai[data-tooltip]:hover::after,
.ticket-ai-row-ai[data-tooltip]:focus-visible::before,
.ticket-ai-row-ai[data-tooltip]:focus-visible::after { transform: translate(0, 0); }
.ticket-ai-row-ai[data-tooltip]::after { right: 6px; }

@media (max-width: 560px) {
  .ticket-ai-table-head { display: none; }
  .ticket-ai-row { grid-template-columns: 1fr; gap: 0.15rem; position: relative; }
  .ticket-ai-row-status, .ticket-ai-row-requested, .ticket-ai-row-updated, .ticket-ai-row-org { font-size: 0.7rem; }
  .ticket-ai-row-ai { position: absolute; top: 0.45rem; right: 0.45rem; }
}

/* The log is the inner box of the box-within-a-box layout (same inset panel
   as Settings' .settings-box). */
.ticket-ai-log {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  margin-bottom: 1rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 0.6rem;
  background: var(--field-bg);
  border: 1px solid var(--border);
  border-radius: 5px;
}
/* Tools (attach) sit on their own row above the input — on narrow phones a
   shared row left too little width for the textarea to be usable. */
.ticket-ai-form { display: flex; flex-direction: column; gap: 0.5rem; }
.ticket-ai-form-tools { display: flex; gap: 0.4rem; }
.ticket-ai-form-row { display: flex; gap: 0.5rem; align-items: flex-end; }
.ticket-ai-form textarea {
  flex: 1;
  min-width: 0;
  resize: none;
  overflow-y: hidden;
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  font-size: 0.95rem;
  font-family: inherit;
  line-height: 1.4;
  background: var(--input-bg);
  color: var(--text);
}
.ticket-ai-form button[type="submit"] { flex-shrink: 0; padding: 0.6rem 1.2rem; border: none; border-radius: 5px; background: var(--accent); color: var(--on-accent); cursor: pointer; }

@media (max-width: 860px) {
  /* Stacked on mobile — each area keeps its own independent scroll. */
  .ticket-ai-layout { display: block; }
  .ticket-ai-chat-col { height: 505px; min-width: 0; margin-bottom: 1.5rem; }
  .ticket-ai-list-col { flex-basis: auto; min-width: 0; max-height: 50vh; }
}

.error { color: var(--negative); }
.muted { color: var(--muted); }

/* Refresh state: existing content stays visible, dimmed, with a centered
   spinner overlaid — no blank flash. (tbody can't host pseudo-elements
   reliably, so its overlay rides the .table-scroll wrapper via :has.) */
.is-loading { position: relative; opacity: 0.45; pointer-events: none; transition: opacity 0.15s ease; }
.is-loading::after,
.table-scroll:has(> table > tbody.is-loading)::after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 22px;
  height: 22px;
  margin: -11px 0 0 -11px;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
tbody.is-loading::after { content: none; }
.table-scroll:has(> table > tbody.is-loading) { position: relative; }

.loading { display: flex; align-items: center; gap: 0.6rem; color: var(--muted); font-size: 0.9rem; padding: 0.5rem 0; }
.spinner {
  width: 16px; height: 16px;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  flex-shrink: 0;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Floating tooltip for tile %-badges (see app.js) — same bubble as the CSS
   [data-tooltip] ones, plus a tiny context-title line (the tile name +
   timeframe), since the open tooltip physically covers the tile's own label.
   The date-vs-date body line is styled identically to before. */
.floating-tip {
  position: fixed;
  transform: translate(-50%, -100%);
  z-index: 300;
  display: none;
  pointer-events: none;
  width: max-content;
  max-width: min(280px, 80vw);
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--card-bg-solid);
  color: var(--text);
  box-shadow: 0 12px 30px rgba(0,0,0,0.36);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.25;
  text-align: center;
  white-space: normal;
}
.floating-tip.show { display: block; }
.floating-tip-title {
  font-size: 0.5rem; /* ~8px */
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  margin-bottom: 0.15rem;
}

[data-tooltip] {
  position: relative;
  cursor: pointer;
}
[data-tooltip]::before,
[data-tooltip]::after {
  position: absolute;
  left: 50%;
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, -6px);
  transition: opacity 0.01s linear, transform 0.01s linear;
  z-index: 200;
}
[data-tooltip]::before {
  content: attr(data-tooltip);
  bottom: calc(100% + 8px);
  width: max-content;
  max-width: min(280px, 80vw);
  padding: 0.45rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 5px;
  background: var(--card-bg-solid);
  color: var(--text);
  box-shadow: 0 12px 30px rgba(0,0,0,0.36);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.25;
  text-align: center;
  white-space: normal;
}
[data-tooltip]::after {
  content: '';
  bottom: calc(100% + 3px);
  border: 5px solid transparent;
  border-top-color: var(--card-bg-solid);
}
[data-tooltip]:hover::before,
[data-tooltip]:hover::after,
[data-tooltip]:focus-visible::before,
[data-tooltip]:focus-visible::after {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* Operator Score tooltips: the labels sit at the far left of the page next to
   the nav, so the default centered tooltip ran off-screen / behind the nav.
   Anchor these LEFT (grow rightward from the label), smaller font, and a
   tighter width so they always fit on the page. */
.kg-score-tip[data-tooltip]::before {
  left: 0;
  transform: translate(0, -6px);
  max-width: min(240px, 68vw);
  font-size: 0.68rem;
  line-height: 1.3;
  text-align: left;
  padding: 0.35rem 0.5rem;
}
.kg-score-tip[data-tooltip]::after { left: 14px; transform: translate(0, -6px); }
.kg-score-tip[data-tooltip]:hover::before,
.kg-score-tip[data-tooltip]:focus-visible::before,
.kg-score-tip[data-tooltip]:hover::after,
.kg-score-tip[data-tooltip]:focus-visible::after { transform: translate(0, 0); }

@media (max-width: 900px) {
  /* Sidebar becomes an off-canvas drawer opened by the hamburger in the
     mobile top bar; a backdrop (.sidebar-overlay) closes it on tap-outside. */
  .mobile-topbar { display: flex; }
  .sidebar {
    width: 264px;
    transform: translateX(-100%);
    transition: transform 0.22s ease;
    box-shadow: 12px 0 34px rgba(0, 0, 0, 0.45);
  }
  .sidebar.open { transform: translateX(0); }
  /* Collapse is a desktop-rail feature; the mobile drawer already hides itself. */
  .sidebar-collapse { display: none; }
  main { margin-left: 0; padding: 1.25rem; }
  .chart-card.two-col { grid-template-columns: 1fr; }
}

@media (max-width: 560px) {
  .tile-row-2, .tile-row-3, .tile-row-4 { grid-template-columns: 1fr; }
  .period-custom-picker {
    position: static;
    flex-wrap: wrap;
    width: 100%;
  }
  .ask-drawer { padding: 1rem; }
}
