/* pp-reply-console — design system, ported from the PP hero-light system (as shipped in HRMS /
   Client Portal). Self-contained: no external fonts, CDN or @import, because the CSP blocks all
   of it.

   LIGHT IS THE DEFAULT AND STAYS THE HOUSE LOOK. The header inherited from pp-ngen-social said
   light ONLY, on the reasoning that "this app is read by a first-year student on a laptop" — that
   is that app's audience, and it travelled here with the clone. This one is an internal tool for
   the GTM team, several of whom work it for hours, so a dark option was asked for and added.

   Dark is a TOKEN OVERRIDE, not a second stylesheet: :root[data-theme="dark"] redefines the same
   custom properties and every rule below is written against tokens. That is the only reason this
   was tractable at all — 367 var(--) uses against 61 literals, and the literals were tokenised
   first. Anything hardcoded here is a bug that will render light-on-light. */

:root {
  color-scheme: light;

  /* ---- Page ---- */
  --bg: #eef2f8; /* solid fallback; body paints the gradient below */
  --bg-page: linear-gradient(160deg, #f7f9fc 0%, #eaeff6 100%);

  /* ---- Ink scale ---- */
  --ink: #0f172a;      /* primary text */
  --ink-2: #475569;    /* secondary */
  --ink-3: #64748b;    /* tertiary / labels — minimum color for essential text on white */
  --ink-4: #94a3b8;    /* muted / subtitles / inactive icons — decorative only, never essential text */
  --ink-body: #334155; /* list/prose rows */

  /* ---- Surfaces ---- */
  --card: #ffffff;
  --card-2: #f8fafc;
  --side-bg: #f8fafc;

  /* ---- Lines ---- */
  --line: #e9edf3;
  --line-2: #e4e9f1;

  /* ---- Accent (blue family) ---- */
  --blue: #2563eb;
  --blue-deep: #1d4ed8;
  --sky: #38bdf8;
  --nav-active-bg: #eff6fb;
  --grad-avatar: linear-gradient(135deg, #2563eb, #38bdf8);

  /* ---- Status: ok / warn / bad / info (pill bg/border/text/dot) ---- */
  --ok: #059669; --ok-bg: #ecfdf5; --ok-line: #a7f3d0; --ok-dot: #10b981;
  --warn: #b45309; --warn-bg: #fffbeb; --warn-line: #fde68a; --warn-dot: #f59e0b;
  --bad: #b91c1c; --bad-bg: #fef2f2; --bad-line: #fecaca; --bad-dot: #ef4444;
  --info: #1d4ed8; --info-bg: #eff6fb; --info-line: #bfdbfe; --info-dot: #2563eb;
  --neutral-bg: #f1f5f9; --neutral-ink: #64748b; --neutral-line: #e2e8f0;

  /* ---- Shape + depth ---- */
  --r-sm: 8px;
  --r: 12px;
  --r-card: 13px;
  --r-lg: 13px;
  --r-nav: 9px;
  --r-pill: 999px;
  --r-ctl: 10px;
  --shadow-card: 0 1px 3px rgba(15, 23, 42, .04);
  --shadow-chip: 0 2px 6px rgba(15, 23, 42, .05);
  --shadow-sm: var(--shadow-card);
  --shadow: 0 4px 16px rgba(15, 23, 42, .08);
  --shadow-lg: 0 12px 32px rgba(15, 23, 42, .14);

  /* ---- Spacing scale: 8px intra-group, 16px+ inter-group ---- */
  --sp-1: 8px;
  --sp-2: 12px;
  --sp-3: 16px;
  --sp-4: 20px;
  --sp-5: 24px;
  --media-outline: rgba(0, 0, 0, .1); /* 1px keyline on avatars/logos */
  --toast-bg: #0f172a; --toast-ink: #ffffff;
}

/* ---- Reset & base ---- */

* { box-sizing: border-box; }

/* The [hidden] ATTRIBUTE ALWAYS WINS. Any class selector that sets `display` (`.btn`'s
   inline-flex, `.pick-bar`'s flex, a popover's flex) has the SAME specificity as the browser's
   own `[hidden] { display: none }` rule, and an author stylesheet is applied after the user-agent
   one -- so the class silently won every time, and JS toggling `hidden` did nothing visible. This
   surfaced as the bulk-selection bar reading "0 selected" on every page load, and would have hit
   the new filters popover the same way. One override here beats it everywhere, for good. */
[hidden] { display: none !important; }

/* overflow-x: clip contains the off-screen mobile drawer (translateX(100%))
   without creating a scroll container, so position: sticky keeps working. */
html { color-scheme: light; overflow-x: clip; }

body {
  margin: 0;
  min-height: 100vh;
  position: relative;
  isolation: isolate; /* keeps the ambient glows (z-index:-1) behind in-flow content */
  overflow-x: clip;
  background: var(--bg);
  background: var(--bg-page);
  color: var(--ink);
  font-family: -apple-system, "SF Pro Display", "Inter", "Helvetica Neue", system-ui, sans-serif;
  font-size: 14.5px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

/* Soft ambient page tints, fixed to the viewport so they read as page-level
   decoration rather than scrolling content. Low-opacity, purely cosmetic. */
body::before, body::after {
  content: ""; position: fixed; z-index: -1; border-radius: 50%; pointer-events: none;
}
body::before {
  right: -240px; bottom: -260px; width: 820px; height: 820px;
  background: radial-gradient(circle, rgba(56, 189, 248, .22) 0%, rgba(37, 99, 235, .07) 40%, transparent 70%);
}
body::after {
  left: -200px; top: -200px; width: 560px; height: 560px;
  background: radial-gradient(circle, rgba(99, 102, 241, .12) 0%, transparent 68%);
}

h1, h2, h3, h4 { margin: 0 0 12px; font-weight: 600; letter-spacing: -0.01em; text-wrap: balance; }
h2 { font-size: 20px; }
h3 { font-size: 15px; font-weight: 650; }
p { margin: 0 0 8px; text-wrap: pretty; }

a { color: var(--blue); text-decoration: none; transition: color 150ms ease; }
a:hover { text-decoration: underline; }

code {
  background: var(--card-2); border: 1px solid var(--line-2); border-radius: 5px;
  padding: 1px 6px; font-size: 12.5px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

::selection { background: rgba(37, 99, 235, .35); }

*:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

@media (prefers-reduced-motion: reduce) {
  * { transition-duration: 0.001ms !important; animation-duration: 0.001ms !important; }
  .skeleton { animation: none; }
}

.boot-loading { padding: 60px 20px; text-align: center; color: var(--ink-3); }

/* Visually hidden but still announced by screen readers. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Skip-to-content: off-screen until focused, then slides into the top-left. */
.skip-link {
  position: fixed; left: 8px; top: -60px; z-index: 100;
  background: var(--blue); color: #fff;
  padding: 8px 14px; border-radius: var(--r-sm); font-weight: 600;
  text-decoration: none; transition: top 150ms ease;
}
.skip-link:focus { top: 8px; }

/* =====================================================================
   App shell — persistent left sidebar (desktop) + top bar/drawer (mobile)
   ===================================================================== */

.app-shell { display: flex; align-items: flex-start; min-height: 100vh; }

/* ---- Sidebar (desktop, >=1000px) ---- */

.sidebar {
  /* 248, not 224: "Mahak needs to update" wrapped to two lines at the old width, which made three
     rows in the rail twice the height of the others and the whole column read as ragged. */
  width: 248px; flex: none; position: sticky; top: 0; height: 100vh;
  background: var(--side-bg); border-right: 1px solid var(--line); box-shadow: var(--shadow-sm);
  display: flex; flex-direction: column; padding: 20px 14px;
}
.sidebar-brand {
  display: flex; align-items: center; gap: 10px; padding: 4px 8px 20px;
  color: var(--ink); text-decoration: none;
}
.sidebar-brand:hover { text-decoration: none; }
.brand-mark { display: flex; align-items: flex-end; gap: 3px; height: 22px; flex: none; }
.brand-mark i { width: 5px; border-radius: 2px; display: block; }
.brand-mark i:nth-child(1) { height: 11px; background: var(--bad-dot); }
.brand-mark i:nth-child(2) { height: 16px; background: var(--warn-dot); }
.brand-mark i:nth-child(3) { height: 22px; background: var(--blue); }
.brand-wm { font-size: 15px; font-weight: 800; letter-spacing: -0.01em; }

.sidebar-nav { display: flex; flex-direction: column; gap: 2px; overflow-y: auto; flex: 1; }
.nav-group-label {
  font-size: 10.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase;
  color: var(--ink-3); padding: 16px 12px 6px;
}
.sidebar-nav a, .drawer-nav a {
  display: flex; align-items: center; gap: 11px; font-weight: 500;
  color: var(--ink-2); text-decoration: none;
  transition: background-color 150ms ease, color 150ms ease;
}
.sidebar-nav a { font-size: 13.5px; padding: 8px 12px; border-radius: var(--r-nav); color: var(--ink); font-weight: 550; }

/* A label never wraps. It truncates and keeps its full text in the tooltip, so one long name
   cannot make its row twice as tall as every other row. */
.nav-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Group heading. The rail used anonymous horizontal rules, which separated things without saying
   what separated them -- Nilesh, 2026-08-28: "the hierarchy... make it better". */
.nav-head {
  font-size: 10.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3, var(--ink-2)); opacity: .62;
  padding: 14px 12px 4px; margin-top: 4px; border-top: 1px solid var(--line);
}
.sidebar-nav > .nav-head:first-child { border-top: 0; margin-top: 0; padding-top: 4px; }

/* The count sits right, tabular so the column of numbers lines up rather than jittering. */
.nav-count { margin-left: auto; font-size: 12px; font-variant-numeric: tabular-nums; opacity: .7; }
/* A number on a page with work waiting should read as work, not decoration. */
a[data-nav="updates"] .nav-count, a[data-nav="queue"] .nav-count { opacity: 1; font-weight: 650; }
.sidebar-nav a:hover { background: var(--nav-active-bg); color: var(--ink); text-decoration: none; }
.sidebar-nav a.active { background: var(--nav-active-bg); color: var(--blue-deep); font-weight: 600; box-shadow: inset 3px 0 0 var(--blue); }

.nav-ic { width: 16px; height: 16px; flex: none; }
.nav-ic path, .nav-ic rect, .nav-ic circle, .nav-ic line { stroke: var(--ink-2); transition: stroke 150ms ease; }
a.active .nav-ic path, a.active .nav-ic rect, a.active .nav-ic circle, a.active .nav-ic line { stroke: var(--blue); }

/* Small red dot on the Admin nav item while the roster has placeholder emails. */
.nav-alert-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--bad-dot); flex: none; margin-left: auto;
}

.sidebar-foot {
  margin-top: auto; display: flex; align-items: center; gap: 9px;
  padding: 14px 8px 2px; border-top: 1px solid var(--line);
}
.foot-avatar {
  width: 26px; height: 26px; border-radius: 50%; background: var(--grad-avatar); flex: none;
  outline: 1px solid var(--media-outline); outline-offset: -1px;
}
.foot-who { font-size: 12px; color: var(--ink-3); line-height: 1.3; flex: 1; min-width: 0; }
.foot-who strong {
  display: block; color: var(--ink); font-size: 12.5px; font-weight: 700;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.foot-logout {
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: var(--r-sm); color: var(--ink-4);
  transition: background-color 150ms ease, color 150ms ease;
}
.foot-logout:hover { background: var(--bad-bg); color: var(--bad); text-decoration: none; }
.foot-logout svg { width: 15px; height: 15px; }
.foot-logout svg path { stroke: currentColor; }

/* Permanent "Stuck? Message Nilesh" affordance — sidebar footer + drawer. */
.stuck-link {
  display: flex; align-items: center; gap: 8px; margin-top: 10px;
  padding: 8px 8px; border-radius: var(--r-nav); font-size: 12.5px; font-weight: 600;
  color: var(--ink-3); transition: background-color 150ms ease, color 150ms ease;
}
.stuck-link:hover { background: var(--nav-active-bg); color: var(--blue-deep); text-decoration: none; }
.stuck-link svg { width: 16px; height: 16px; flex: none; }
.stuck-link svg circle, .stuck-link svg path { stroke: currentColor; }

/* ---- Mobile top bar (<1000px) ---- */

.topbar {
  display: none;
  position: sticky; top: 0; z-index: 20;
  background: var(--card); border-bottom: 1px solid var(--line); box-shadow: var(--shadow-sm);
}
.topbar-inner { display: flex; align-items: center; gap: 12px; padding: 0 16px; height: 56px; }
/* Email and theme sit at the far right; the brand keeps the left. */
.topbar-inner > .muted { margin-left: auto; }
.topbar-brand {
  display: flex; align-items: center; gap: 9px;
  font-weight: 800; font-size: 15px; letter-spacing: -0.01em; color: var(--ink); text-decoration: none;
}
.topbar-brand:hover { text-decoration: none; opacity: .85; }

.nav-toggle {
  display: none; flex-direction: column; align-items: center; justify-content: center;
  gap: 5px; width: 40px; height: 40px;
  border: none; background: transparent; border-radius: var(--r-sm); padding: 0;
  cursor: pointer; flex-shrink: 0;
  transition: background-color 150ms ease;
}
.nav-toggle:hover { background: var(--nav-active-bg); }
.nav-toggle-bar {
  width: 20px; height: 2px; border-radius: 2px; background: var(--ink);
  transition: transform 180ms ease, opacity 180ms ease;
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ---- Drawer (mobile nav) ---- */

.drawer-scrim {
  position: fixed; inset: 0; background: rgba(15, 23, 42, .4);
  opacity: 0; pointer-events: none; z-index: 30;
  transition: opacity 180ms ease;
}
.drawer-scrim.is-open { opacity: 1; pointer-events: auto; }

.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 31;
  width: 280px; max-width: 85vw;
  background: var(--card); box-shadow: var(--shadow-lg);
  /* Closed = display:none so the off-screen fixed panel creates NO horizontal
     overflow. It slides in on open; body.drawer-open clips the transient
     overflow during the animation. */
  display: none; flex-direction: column; padding: 18px;
  overflow-y: auto;
}
.drawer.is-open { display: flex; animation: drawer-in 180ms ease; }
@keyframes drawer-in { from { transform: translateX(100%); } to { transform: translateX(0); } }

.drawer-header {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 10px; padding-bottom: 16px; margin-bottom: 12px;
  border-bottom: 1px solid var(--line);
}
.drawer-user { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.drawer-user strong { font-size: 14.5px; font-weight: 650; color: var(--ink); }
.drawer-user .muted { font-size: 12.5px; overflow-wrap: anywhere; }
.drawer-close {
  width: 32px; height: 32px; flex-shrink: 0; border: none; background: transparent;
  border-radius: var(--r-sm); font-size: 20px; line-height: 1; color: var(--ink-3);
  cursor: pointer; transition: background-color 150ms ease, color 150ms ease;
}
.drawer-close:hover { background: var(--card-2); color: var(--ink); }

.drawer-nav { display: flex; flex-direction: column; gap: 2px; flex: 1; }
.drawer-nav a { min-height: 44px; padding: 0 14px; border-radius: var(--r-sm); font-size: 14.5px; }
.drawer-nav a:hover { background: var(--card-2); text-decoration: none; }
.drawer-nav a.active { background: var(--nav-active-bg); color: var(--blue-deep); font-weight: 650; box-shadow: inset 3px 0 0 var(--blue); }
.drawer-nav .nav-group-label { padding: 14px 14px 4px; }

.drawer-logout {
  display: flex; align-items: center; min-height: 44px; padding: 0 14px;
  margin-top: 8px; border-top: 1px solid var(--line);
  color: var(--bad); font-weight: 550; font-size: 14.5px;
}
.drawer-logout:hover { background: var(--bad-bg); border-radius: var(--r-sm); text-decoration: none; }

body.drawer-open { overflow: hidden; }

@media (max-width: 999.98px) {
  .sidebar { display: none; }
  .topbar { display: block; }
  .nav-toggle { display: flex; }
}

/* =====================================================================
   Layout
   ===================================================================== */

.shell-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
/* 1040px was the house default, inherited from a marketing-page layout. On a 1629px screen next to
   a 224px sidebar it left 365px of dead gutter -- a quarter of the usable width -- while the queue
   scrolled 13,000px vertically. This is a work surface, not an article: the reading-line argument
   for a narrow column does not apply to cards of name, company, links and a two-line quote.
   1440 uses the space on a laptop and still centres on a very wide monitor. */
/* min-width: 0 because this is a CSS Grid item (the 1fr track in .app-shell's `216px 1fr`) and a
   grid item's default min-width is auto, i.e. "never shrink below my widest child's content".
   The 10-column summary table is ~970px at its natural width, so on any window narrower than
   that this element refused to shrink and dragged the WHOLE page wide instead -- and html's
   overflow-x: clip (needed for the mobile nav drawer) then hid that overflow rather than letting
   it scroll, so the right side of the page became not just ugly but unreachable. This one
   property is what lets .table-scroll's own overflow-x: auto do its job. */
.container { max-width: 1440px; margin: 0 auto; padding: 18px 20px 48px; width: 100%; min-width: 0; }

/* Headings receive programmatic focus after each route render (a11y landmark
   move) — that focus is not operable, so it gets no visible ring. */
#view h1:focus, #view h2:focus, #view h3:focus { outline: none; }
.page-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 20px; flex-wrap: wrap; }
.page-head h1 { font-size: 24px; font-weight: 800; letter-spacing: -0.02em; color: var(--ink); margin: 0; }
.page-sub { font-size: 13px; color: var(--ink-3); max-width: 65ch; text-wrap: pretty; }

.grid-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 16px; margin-bottom: 16px; }

@media (max-width: 768px) {
  .container { padding: 16px 16px 64px; }
}
@media (max-width: 720px) {
  .grid-cards { grid-template-columns: 1fr; }
}

/* =====================================================================
   Card
   ===================================================================== */

.card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow-sm);
  padding: 14px 16px; margin-bottom: 10px;
}
.card > summary {
  cursor: pointer; font-weight: 650; color: var(--ink); list-style: none;
  display: flex; align-items: center; gap: 8px;
}
.card > summary::-webkit-details-marker { display: none; }
.card > summary::before {
  content: '▸'; display: inline-block; color: var(--ink-4); font-size: 11px;
  transition: transform 150ms ease;
}
.card[open] > summary::before { transform: rotate(90deg); }
.card > summary ~ * { margin-top: 14px; }
.card h3 { font-size: 15px; font-weight: 700; }

.no-access {
  max-width: 420px; margin: 80px auto 0; text-align: center;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-lg);
  box-shadow: var(--shadow); padding: 40px 32px;
}
.no-access img { height: 40px; margin-bottom: 16px; }

/* =====================================================================
   Stat cards + panels
   ===================================================================== */

.stat-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(var(--stat-min, 150px), 1fr)); gap: 8px; margin-bottom: 10px; }
.stat-card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-card);
  box-shadow: var(--shadow-card); padding: 10px 12px;
}
.stat-k { font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-3); font-weight: 700; }
.stat-v {
  font-size: 26px; font-weight: 800; letter-spacing: -0.03em; margin-top: 5px; line-height: 1;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.stat-s { font-size: 12px; color: var(--ink-3); margin-top: 4px; }
/* A pending tile with nothing left in it. Deliberately quiet rather than green: "no work here"
   is the resting state, not an achievement to celebrate every time the page loads. */
.stat-card.is-clear { background: var(--card-2); box-shadow: none; }
.stat-card.is-clear .stat-v { color: var(--ink-4); }

.panels-row { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 12px; }
.panel {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-card);
  box-shadow: var(--shadow-card); padding: 16px 17px; margin-bottom: 0;
}
.panel h2 {
  font-size: 13.5px; font-weight: 800; letter-spacing: .01em; color: var(--ink);
  margin: 0 0 2px; display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.panel h2 .tag {
  font-size: 10px; font-weight: 700; color: var(--ok); background: var(--ok-bg);
  border: 1px solid var(--ok-line); padding: 2px 8px; border-radius: var(--r-pill); letter-spacing: .02em;
}
.panel h2 .tag-neutral { color: var(--ink-3); background: var(--neutral-bg); border-color: var(--neutral-line); }
.panel .psub { font-size: 12px; color: var(--ink-3); margin-bottom: 14px; }

.flow { display: flex; flex-direction: column; gap: 11px; margin-top: 2px; }
.flow-row { display: flex; align-items: center; gap: 10px; font-size: 12.5px; color: var(--ink-body); }
.flow-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ok-dot); flex: none; }

@media (max-width: 900px) {
  .panels-row { grid-template-columns: 1fr; }
}
@media (max-width: 480px) {
  .stat-row { grid-template-columns: 1fr; }
}

/* =====================================================================
   Forms
   ===================================================================== */

.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px 16px; margin-top: 8px; }
.form-grid label { display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; color: var(--ink-3); font-weight: 550; }
.form-grid label.full { grid-column: 1 / -1; }
.form-grid > button { grid-column: 1 / -1; justify-self: start; margin-top: 4px; }

input, select, textarea {
  font: inherit; padding: 9px 12px; min-height: 40px; border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--card); color: var(--ink); width: 100%;
  transition: border-color 150ms ease, box-shadow 150ms ease;
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--blue); box-shadow: 0 0 0 3px rgba(37, 99, 235, .35);
}
input[type="checkbox"] { width: auto; min-height: auto; }
input[type="file"] { padding: 7px 10px; }
textarea { min-height: 76px; resize: vertical; }

@media (max-width: 640px) {
  .form-grid { grid-template-columns: 1fr; }
  /* iOS Safari zooms the page when a focused field is under 16px. Base is
     14.5px via font:inherit, so bump inputs to 16px on phones only. */
  input, select, textarea { font-size: 16px; }
}

/* =====================================================================
   Buttons
   ===================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 9px 16px; min-height: 38px; border-radius: var(--r-ctl); border: 1px solid var(--line);
  background: var(--card); color: var(--ink-2); font: inherit; font-weight: 600; cursor: pointer;
  transition: background-color 150ms ease, border-color 150ms ease, transform 150ms ease;
  text-decoration: none;
}
.btn:hover { background: var(--card-2); border-color: var(--ink-4); text-decoration: none; }
/* Press feedback: atomic controls only (buttons, tabs) — never rows/cards,
   where a transform would wobble layout and break tooltip positioning. */
.btn:active { transform: scale(0.96); }
.btn:disabled { opacity: .55; cursor: default; }
.btn:disabled:active { transform: none; }

.btn-primary { background: var(--blue); border-color: var(--blue); color: #fff; box-shadow: var(--shadow-card); }
.btn-primary:hover { background: var(--blue-deep); border-color: var(--blue-deep); }

.btn-danger { background: var(--card); border-color: var(--line); color: var(--bad); }
.btn-danger:hover { background: var(--bad-bg); border-color: var(--bad-line); }

.btn-sm { padding: 5px 12px; min-height: 30px; font-size: 13px; }

/* =====================================================================
   Table (Admin: roster + audit)
   ===================================================================== */

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
th, td { text-align: left; padding: 11px 12px; border-bottom: 1px solid var(--line-2); white-space: nowrap; }
table td { font-variant-numeric: tabular-nums; }
th {
  color: var(--ink-3); font-weight: 650; font-size: 11.5px; text-transform: uppercase; letter-spacing: .03em;
  background: var(--card-2); border-bottom: 1px solid var(--line);
}

@media (max-width: 640px) {
  .table-wrap table, .table-wrap thead, .table-wrap tbody, .table-wrap th, .table-wrap td, .table-wrap tr {
    display: block;
  }
  .table-wrap thead { display: none; }
  .table-wrap tbody tr {
    border: 1px solid var(--line); border-radius: var(--r); margin-bottom: 10px; padding: 6px 12px;
    background: var(--card);
  }
  .table-wrap tbody tr:last-child { margin-bottom: 0; }
  .table-wrap td {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 8px 0; border-bottom: 1px solid var(--line-2); white-space: normal; text-align: right;
  }
  .table-wrap td:last-child { border-bottom: none; }
  .table-wrap td::before { content: attr(data-label); font-weight: 650; color: var(--ink-3); margin-right: auto; }
}

/* =====================================================================
   Chips / status pills — bg + border + text + dot anatomy
   ===================================================================== */

.chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 3px 11px; border-radius: var(--r-pill);
  font-size: 12px; font-weight: 700; white-space: nowrap; border: 1px solid transparent;
  background: var(--neutral-bg); color: var(--neutral-ink);
}
.chip-dot { width: 5px; height: 5px; border-radius: 50%; flex: none; background: currentColor; }

.chip-active { background: var(--ok-bg); color: var(--ok); border-color: var(--ok-line); }
.chip-pending { background: var(--warn-bg); color: var(--warn); border-color: var(--warn-line); }
.chip-rejected { background: var(--bad-bg); color: var(--bad); border-color: var(--bad-line); }
.chip-info { background: var(--info-bg); color: var(--info); border-color: var(--info-line); }

/* =====================================================================
   Toasts
   ===================================================================== */

.toasts { position: fixed; bottom: 20px; right: 20px; display: flex; flex-direction: column; gap: 8px; z-index: 100; max-width: calc(100vw - 40px); }
.toast {
  background: var(--toast-bg); color: var(--toast-ink); padding: 12px 16px; border-radius: var(--r); max-width: 320px;
  font-size: 13px; box-shadow: var(--shadow-lg); border-left: 3px solid var(--ok);
  animation: toast-in 200ms ease;
  display: flex; align-items: flex-start; gap: 10px;
}
.toast-error { border-left-color: var(--bad); }
.toast-dismiss {
  margin-left: auto; flex-shrink: 0; border: none; background: transparent; color: inherit;
  font-size: 16px; line-height: 1; cursor: pointer; padding: 0 2px; opacity: 0.75;
  position: relative;
}
.toast-dismiss:hover { opacity: 1; }
.toast-dismiss:active { transform: scale(0.96); }
.toast-dismiss::after { content: ""; position: absolute; inset: -6px; }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

/* =====================================================================
   Tabs — pill (Guide page)
   ===================================================================== */

.pill-tabs {
  display: flex; gap: 4px; padding: 4px; margin-bottom: 16px; width: fit-content; flex-wrap: wrap;
  background: var(--side-bg); border: 1px solid var(--line); border-radius: var(--r-pill);
}
.pill-tab {
  padding: 8px 16px; border: none; background: none; border-radius: var(--r-pill);
  font: inherit; font-size: 13.5px; font-weight: 600; color: var(--ink-3); cursor: pointer;
  transition: background-color 150ms ease, color 150ms ease, transform 150ms ease;
}
.pill-tab:hover { color: var(--ink); }
.pill-tab:active { transform: scale(0.96); }
.pill-tab[aria-selected="true"] { background: var(--card); color: var(--blue-deep); box-shadow: var(--shadow-card); }

/* =====================================================================
   Form drawer (submissions) — every add form lives here, never inline
   ===================================================================== */

.fdrawer-scrim {
  position: fixed; inset: 0; background: rgba(15, 23, 42, .4);
  opacity: 0; pointer-events: none; z-index: 40; transition: opacity 180ms ease;
}
.fdrawer-scrim.is-open { opacity: 1; pointer-events: auto; }
.fdrawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 41;
  width: 400px; max-width: 94vw; background: var(--card); box-shadow: var(--shadow-lg);
  display: none; flex-direction: column; padding: 20px; overflow-y: auto;
}
.fdrawer.is-open { display: flex; animation: drawer-in 200ms ease; }
.fdrawer-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding-bottom: 14px; margin-bottom: 6px; border-bottom: 1px solid var(--line);
}
.fdrawer-head h2 { font-size: 16px; font-weight: 800; margin: 0; }
.fdrawer-form { flex: 1; align-content: start; }
.fdrawer-foot {
  display: flex; justify-content: flex-end; gap: 8px;
  padding-top: 14px; margin-top: 10px; border-top: 1px solid var(--line);
}
body.fdrawer-open { overflow: hidden; }

/* =====================================================================
   Empty states
   ===================================================================== */

.empty-block { text-align: center; padding: 34px 16px; }
.empty-block .empty-glyph {
  width: 44px; height: 44px; border-radius: 50%; background: var(--nav-active-bg);
  display: inline-flex; align-items: center; justify-content: center; margin-bottom: 10px;
}
.empty-block .empty-glyph svg { width: 20px; height: 20px; }
.empty-block .empty-glyph svg path, .empty-block .empty-glyph svg rect,
.empty-block .empty-glyph svg circle, .empty-block .empty-glyph svg line { stroke: var(--blue); }
.empty-block p { color: var(--ink-2); font-size: 13.5px; margin: 0 auto 12px; max-width: 65ch; }

/* =====================================================================
   Filter bar (Submissions page)
   ===================================================================== */

.filter-bar {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: center; padding: 10px 14px;
  background: var(--side-bg); border: 1px solid var(--line); border-radius: var(--r-ctl); margin-bottom: 14px;
}
.filter-bar input[type=search] { flex: 1 1 220px; min-height: 38px; }
.filter-bar select { width: auto; min-height: 38px; }
.fb-item { display: flex; }

/* =====================================================================
   Utility
   ===================================================================== */

.muted { color: var(--ink-3); }
/* A boilerplate explanation moved out of permanent view into a hover tip -- the row drawer used to
   repeat the same paragraph under every control on every visit. cursor:help is the only affordance
   telling a reader there is more here, since a bare title attribute alone gives no visual cue. */
.info-dot { cursor: help; }
.text-red { color: var(--bad); font-weight: 550; }
.link { font-size: 13.5px; font-weight: 550; }
.btn-row { display: flex; gap: 8px; flex-wrap: wrap; }
.tabular { font-variant-numeric: tabular-nums; }
.u-row { display: flex; gap: var(--sp-1); align-items: center; }
.u-between { display: flex; justify-content: space-between; align-items: center; gap: 10px; flex-wrap: wrap; }
.u-mt { margin-top: 10px; }
.u-mb { margin-bottom: var(--sp-2); }
.u-mb-3 { margin-bottom: var(--sp-3); }
.u-fs12 { font-size: 12px; }
.u-fs125 { font-size: 12.5px; }
.u-span-all { grid-column: 1 / -1; }
.u-wrap { white-space: normal; }
.u-ml { margin-left: 6px; }
.u-note { font-size: 13px; margin: 0 0 4px; }

/* Loading skeleton block. */
.skeleton {
  background: linear-gradient(90deg, var(--line-2) 25%, var(--card-2) 37%, var(--line-2) 63%);
  background-size: 400% 100%;
  animation: sk 1.4s ease infinite;
  border-radius: var(--r-sm);
}
@keyframes sk { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }

/* Inline form-field error. */
.field-error { color: var(--bad); font-size: 12.5px; margin-top: 4px; text-wrap: pretty; }

/* Prose blocks — how_to / why_it_matters / narrative / submitted text. Capped
   measure so a long paragraph never runs full-width on a wide screen. */
.prose { white-space: pre-wrap; color: var(--ink-body); font-size: 13.5px; max-width: 65ch; margin: 0 0 8px; }
.prose:last-child { margin-bottom: 0; }

/* =====================================================================
   Task cards (Today + Week) — the core interactive unit of this app
   ===================================================================== */

.task-card { transition: border-color 150ms ease; }
.task-card.is-done { border-color: var(--ok-line); }
.task-head { display: flex; align-items: flex-start; gap: 14px; }
/* Checkbox sized well past the 24x24 hit-area floor — this is the primary
   action on the page for a first-time user, it should read as important. */
/* input.task-check (not just .task-check): input[type="checkbox"] above sets
   width:auto at equal-or-higher specificity ((0,1,1) attribute selector vs
   (0,1,0) class-only) and would silently win on width, leaving a checkbox
   narrower than the 24x24 CSS px hit-area floor. Tying specificity here lets
   source order (this rule comes later) settle it correctly. */
input.task-check { width: 24px; height: 24px; min-height: auto; flex: none; margin-top: 2px; accent-color: var(--blue); cursor: pointer; }
.task-body { flex: 1; min-width: 0; }
.task-title { margin: 0 0 6px; font-size: 15.5px; font-weight: 700; color: var(--ink); text-wrap: balance; }
.task-card.is-done .task-title { color: var(--ink-2); }
.task-meta { display: flex; gap: 6px; flex-wrap: wrap; }
.task-static-chip { flex: none; }

.task-how { margin-top: 12px; border-top: 1px solid var(--line-2); padding-top: 12px; }
.task-how > summary {
  cursor: pointer; font-weight: 600; font-size: 13px; color: var(--blue-deep); list-style: none;
  display: flex; align-items: center; gap: 6px;
}
.task-how > summary::-webkit-details-marker { display: none; }
.task-how > summary::before { content: '▸'; color: var(--ink-4); font-size: 10px; transition: transform 150ms ease; }
.task-how[open] > summary::before { transform: rotate(90deg); }
.task-how-body { margin-top: 10px; }

.prompt-block {
  margin-top: 12px; background: var(--card-2); border: 1px solid var(--line-2); border-radius: var(--r-sm);
  padding: 12px 14px;
}
.prompt-block-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.prompt-block-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3); }
.prompt-pre {
  margin: 0; white-space: pre-wrap; font-family: inherit; font-size: 13px; color: var(--ink-body);
  max-height: 260px; overflow-y: auto;
}

.task-submit {
  margin-top: 12px; background: var(--nav-active-bg); border: 1px solid var(--info-line); border-radius: var(--r-sm);
  padding: 12px 14px;
}
.task-submit-prompt { font-size: 13px; color: var(--ink-body); margin: 0 0 10px; text-wrap: pretty; }

.task-subs { margin-top: 12px; display: flex; flex-direction: column; gap: 10px; }

.subm-row {
  border: 1px solid var(--line-2); border-radius: var(--r-sm); padding: 10px 12px; background: var(--card-2);
}
.subm-row-compact { background: var(--card); }
.subm-row-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.subm-title { font-size: 13px; color: var(--ink); }
.subm-pre {
  margin: 0; font-family: inherit; font-size: 13px; max-height: 220px; overflow-y: auto;
  background: var(--card); border: 1px solid var(--line-2); border-radius: var(--r-sm); padding: 10px 12px;
}
.subm-text > summary { cursor: pointer; font-size: 12.5px; font-weight: 600; color: var(--blue-deep); list-style: none; }
.subm-text > summary::-webkit-details-marker { display: none; }
.subm-text[open] > summary { margin-bottom: 8px; }

/* =====================================================================
   Programme — week cards
   ===================================================================== */

.week-card {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-card);
  box-shadow: var(--shadow-card); padding: 16px 17px; display: flex; flex-direction: column; gap: 8px;
  text-decoration: none; color: inherit; transition: box-shadow 150ms ease, border-color 150ms ease;
}
.week-card:hover { text-decoration: none; box-shadow: var(--shadow); }
.week-card.is-current { border-color: var(--blue); box-shadow: 0 0 0 1px var(--blue), var(--shadow-card); }
.week-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.week-card-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3); }
.week-card-theme { font-size: 13.5px; color: var(--ink-body); margin: 0; text-wrap: pretty; }
.week-card-dates { font-size: 12px; color: var(--ink-4); }
.week-card-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 4px; font-size: 12px; color: var(--ink-3); }

.progress-bar { height: 6px; border-radius: var(--r-pill); background: var(--neutral-bg); overflow: hidden; }
.progress-bar-fill { height: 100%; background: var(--blue); border-radius: var(--r-pill); transition: width 300ms ease; }

/* =====================================================================
   Guide — reference docs + setup steps
   ===================================================================== */

.doc-pre {
  white-space: pre-wrap; font-family: inherit; font-size: 13px; color: var(--ink-body);
  max-height: 480px; overflow-y: auto;
  background: var(--card-2); border: 1px solid var(--line-2); border-radius: var(--r-sm);
  padding: 14px 16px; margin: 10px 0 0;
}
.guide-step { display: flex; gap: 14px; padding: 16px 0; border-bottom: 1px solid var(--line-2); }
.guide-step:last-child { border-bottom: none; padding-bottom: 0; }
.guide-step-num {
  flex: none; width: 28px; height: 28px; border-radius: 50%; background: var(--nav-active-bg); color: var(--blue-deep);
  display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 13px;
}
.guide-step-body { flex: 1; min-width: 0; }
.guide-step-body h3 { margin: 0 0 6px; }
.guide-stop-rule {
  margin-top: 8px; background: var(--warn-bg); border: 1px solid var(--warn-line); border-radius: var(--r-sm);
  padding: 12px 14px; color: var(--ink-body); font-size: 13.5px;
}

/* =====================================================================
   Admin — roster incomplete banner
   ===================================================================== */

.alert-banner {
  display: flex; align-items: center; gap: 10px; background: var(--bad-bg); border: 1px solid var(--bad-line);
  color: var(--bad); border-radius: var(--r-sm); padding: 12px 16px; margin-bottom: 16px; font-weight: 650; font-size: 13.5px;
}
.alert-banner svg { flex: none; width: 18px; height: 18px; }
.alert-banner svg path, .alert-banner svg circle { stroke: currentColor; }

/* =====================================================================
   Motion (opt-in so reduced-motion never sees it)
   ===================================================================== */

@media (prefers-reduced-motion: no-preference) {
  .view-enter { animation: view-in 200ms ease-out; }
  .stat-card, .panel, .week-card { transition: box-shadow 150ms ease, transform 150ms ease, border-color 150ms ease; }
  .stat-card:hover { transform: translateY(-1px); box-shadow: var(--shadow-chip); }
}
@keyframes view-in { from { opacity: 0; transform: translateY(6px); } }
/* ---- Reply Console additions -------------------------------------------------
   Appended to the shipped house stylesheet rather than editing it, so a future
   diff against client-portal/public/styles.css stays readable. Tokens only. */
.app-shell { display: grid; grid-template-columns: 216px 1fr; gap: var(--sp-4); align-items: start; }
@media (max-width: 860px) { .app-shell { grid-template-columns: 1fr; } .sidebar { display: none; } }
.sidebar nav { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-3); }
.sidebar nav a { display: flex; align-items: center; gap: 10px; padding: 9px 12px;
  border-radius: var(--r-nav); color: var(--ink-2); font-weight: 550; text-decoration: none; }
.sidebar nav a:hover { background: var(--card-2); }
.sidebar nav a.active { background: var(--nav-active-bg); color: var(--blue);
  box-shadow: inset 3px 0 0 var(--blue); }

.page-head h1 { font-size: 22px; margin: 0 0 2px; letter-spacing: -.01em; }
.page-head { margin-bottom: var(--sp-3); }

.row-list { display: flex; flex-direction: column; gap: var(--sp-1); }

/* --- Queue density -------------------------------------------------------
   43 cards at 250px each is 10,750px of scrolling to triage a day's replies. The height was
   padding and margins, not content, so it comes out of padding and margins. Deliberately NOT a
   multi-column grid: the queue is sorted by priority, and reading left-right-left-right down two
   columns breaks the one ordering guarantee the page makes. */
.row-card { padding: 12px 14px; margin-bottom: 0; }
.row-card .reply-quote { margin: 8px 0; padding: 7px 12px; }
.row-card p { margin: 4px 0; }
.draft-preview { margin: 6px 0 0; }

/* Everything a person needs to open about this lead, on one line. Before this the console was a
   dead end: you could read a draft but not look the person up without going back to Clay. */
.lead-links { display: inline-flex; gap: 5px; flex-wrap: wrap; align-items: center;
  vertical-align: middle; margin-left: 8px; }
.lead-link {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; line-height: 1; text-decoration: none;
  padding: 4px 9px; border-radius: 999px;
  color: var(--ink-2); background: var(--card-2);
  border: 1px solid var(--line-2);
}
.lead-link:hover { color: var(--blue, #2563EB); border-color: var(--blue, #2563EB); background: var(--card); }
.lead-link b { font-weight: 600; }
/* A copyable value that is not a link -- an email we hold but should not fire a mail client for. */
.lead-link-flat { cursor: pointer; }
.lead-link-flat:hover { color: var(--ink); }
.lead-links .muted-note { font-size: 12px; color: var(--ink-3); }
/* Used only by the row DRAWER header now (row.js) -- the card itself uses .row-line below. */
.row-card-meta { display: flex; gap: 6px; flex-wrap: wrap; }

/* ONE LINE: name, source, product, status, and the two open/approve actions. Nilesh, 2026-08-07,
   after the first collapse pass still left 4-5 stacked lines: "still this has four to five
   sentences that are not needed... let's respect the spacing." Everything left of .row-spacer is
   identity; everything right of it is status and actions. flex-wrap is the fallback for a name +
   company + campaign combination too long for the width, not the normal case. */
.row-line { display: flex; align-items: center; flex-wrap: wrap; gap: 3px 6px; font-size: 13.5px; }
.row-line .pick { margin: 0 2px 0 0; }
.row-spacer { flex: 1 1 16px; }
.row-open {
  font-size: 12.5px; font-weight: 600; color: var(--ink-2); padding: 3px 2px;
}
.row-open:hover { color: var(--blue, #2563EB); text-decoration: none; }
.reply-quote { margin: var(--sp-2) 0; padding: 10px 14px; border-left: 3px solid var(--line-2);
  background: var(--card-2); border-radius: 0 var(--r-sm) var(--r-sm) 0; color: var(--ink-body);
  white-space: pre-wrap; }
.draft-preview { color: var(--ink-3); font-size: 14px; margin: 6px 0 0; }
.small { font-size: 12.5px; }

.msg { margin-bottom: var(--sp-3); }
.msg-label { display: block; font-size: 12px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-3); margin-bottom: 4px; }
.msg-text { width: 100%; box-sizing: border-box; padding: 12px 14px; font: inherit;
  line-height: 1.55; border: 1px solid var(--line-2); border-radius: var(--r-sm);
  background: var(--card); color: var(--ink); resize: vertical; }
.msg-text:focus { outline: 2px solid var(--blue); outline-offset: 1px; border-color: var(--blue); }

.thread { white-space: pre-wrap; font-size: 13px; color: var(--ink-2); margin: 0;
  max-height: 380px; overflow: auto; }
details.panel summary { cursor: pointer; font-weight: 650; }

.form-row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: var(--sp-2) 0; }
/* A dropdown of eight product names does not need 1300px. Widening the page made every unbounded
   control in a flex row stretch to fill it, which reads as broken rather than spacious. Controls
   get a width that matches what they hold; the row's free space goes to the label and hint text. */
.form-row select { flex: 0 0 auto; max-width: 260px; }
.form-row input[type="date"] { flex: 0 0 auto; }

.form-row input { flex: 1 1 280px; padding: 10px 12px; border: 1px solid var(--line-2);
  border-radius: var(--r-ctl); font: inherit; }
.form-row label { font-size: 13px; color: var(--ink-2); }

.sticky-actions { position: sticky; bottom: 0; display: flex; gap: 8px; padding: var(--sp-3) 0;
  background: linear-gradient(to top, var(--bg) 70%, transparent); }
.back-link { color: var(--ink-3); text-decoration: none; font-size: 13px; }
.scroll-x { overflow-x: auto; }
.tbl { width: 100%; border-collapse: collapse; font-size: 14px; }
.tbl th, .tbl td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
.tbl th { font-size: 12px; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-3); }
.cell-wide { max-width: 420px; }

.toast { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%) translateY(12px);
  background: var(--ink); color: #fff; padding: 10px 18px; border-radius: var(--r-pill);
  font-size: 14px; opacity: 0; pointer-events: none; transition: opacity .18s, transform .18s; z-index: 60; }
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast-bad { background: var(--bad); }
.boot-loading { padding: 48px; text-align: center; color: var(--ink-3); }

/* Route pills. The house sheet names its chips after ITS domain (.chip-sent, .chip-approved),
   so the semantic modifiers this app needs do not exist and every pill rendered neutral grey.
   Defined here from the shared status tokens rather than renamed, because "is this a booking or
   a correction" is the single most important thing to read at a glance on the queue. */
.chip-ok   { background: var(--ok-bg);   color: var(--ok);   border-color: var(--ok-line); }
.chip-warn { background: var(--warn-bg); color: var(--warn); border-color: var(--warn-line); }
.chip-bad  { background: var(--bad-bg);  color: var(--bad);  border-color: var(--bad-line); }
/* "We could not tell." Deliberately the quietest chip on the page: an unjudged lead deserves
   less attention than a judged one, not more, and it must never read as a negative verdict. */
.chip-muted { background: var(--card-2); color: var(--ink-3); border-color: var(--line-2); }

/* --- Client x product summary table ---------------------------------------
   Wide by design (10 columns), so it scrolls inside its own container rather
   than making the page scroll sideways. */
.table-scroll { overflow-x: auto; margin: 0 -4px; }
.sum-table { width: 100%; border-collapse: collapse; font-size: 14px; min-width: 720px; }
.sum-table th, .sum-table td { padding: 7px 10px; border: 1px solid var(--line, #e3e6ea); }
.sum-table thead th { background: var(--card-2); font-weight: 600; text-align: left; line-height: 1.25;
                      vertical-align: bottom; white-space: nowrap; }
.sum-table td.num, .sum-table th.num { text-align: center; }
/* The merged client cell reads as a group label, not a data cell. */
.sum-table .sum-client { background: var(--card-2); font-weight: 600; vertical-align: middle;
                         white-space: nowrap; }
.sum-table .sum-product { font-weight: 500; white-space: nowrap; }
.sum-table tfoot th, .sum-table tfoot td { background: var(--card-2); font-weight: 600; }
.sum-table tbody tr:hover td { background: var(--card-2); }

/* A cell with a real count behind it -- see numTd()/openCell() in queue.js. A zero stays plain
   "·" with no hover treatment, because there is nothing for a click to open. */
.sum-table .num-click { cursor: pointer; color: var(--blue); text-decoration: underline; text-decoration-color: transparent; }
.sum-table .num-click:hover, .sum-table .num-click:focus-visible {
  background: var(--nav-active-bg); text-decoration-color: var(--blue); outline: none;
}
.sum-table tfoot .num-click { color: var(--blue); }

/* The drill-down popup: a centered modal rather than a cell-anchored popover, because the table
   scrolls horizontally in its own container and a cell near either edge would have nowhere
   sensible to anchor a floating panel. */
.cell-modal-backdrop {
  position: fixed; inset: 0; z-index: 60; display: flex; align-items: center; justify-content: center;
  background: rgba(15, 23, 42, .4); padding: 20px;
}
.cell-modal-box {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: var(--shadow-card); width: 100%; max-width: 460px; max-height: 78vh;
  display: flex; flex-direction: column; overflow: hidden;
}
.cell-modal-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 12px 16px; border-bottom: 1px solid var(--line); flex: none;
}
.cell-modal-head h3 { margin: 0; font-size: 14.5px; font-weight: 700; }
.cell-modal-body { padding: 6px 16px 14px; overflow-y: auto; }
.cell-modal-list { list-style: none; margin: 0; padding: 0; }
.cell-modal-list li {
  font-size: 13.5px; padding: 9px 0; border-bottom: 1px solid var(--line, #e3e6ea);
}
.cell-modal-list li:last-child { border-bottom: none; }
.cell-modal-list a { font-weight: 600; }

/* --- Rewrite panel + version history --------------------------------------
   The Rewrite box is the console's "terminal": a colleague types what they
   want changed in plain words and the draft is redone. Version history is the
   undo, and has to be obvious to someone who cannot open a database. */
.form-row-stack { display: block; }
.form-row-stack textarea { width: 100%; font: inherit; padding: 8px 10px; resize: vertical;
                           border: 1px solid var(--line, #e3e6ea); border-radius: 6px; }
.version-list { list-style: none; padding: 0; margin: 10px 0 0; }
.version-list li { border-top: 1px solid var(--line, #e3e6ea); padding: 9px 0;
                   display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }

/* Add-meeting form, collapsed by default so it never competes with the table above it. */
.add-meeting { margin-top: 14px; border-top: 1px solid var(--line, #e3e6ea); padding-top: 10px; }
.add-meeting summary { cursor: pointer; font-weight: 600; font-size: 14px; }
.add-meeting .form-row { margin-top: 8px; display: flex; gap: 8px; flex-wrap: wrap;
                         align-items: center; }
.add-meeting input, .add-meeting select { font: inherit; padding: 6px 9px;
                         border: 1px solid var(--line, #e3e6ea); border-radius: 6px; }

/* --- Queue usability pass --------------------------------------------------
   Age, presence, filters. */
.age { color: var(--ink-2, #5b6572); }
/* .age-warm was removed: one-day-old rows now read in ink. Rule deleted rather than left
   orphaned, so the next person does not find a colour nothing uses. */
.age-old  { color: var(--bad); font-weight: 700; }

/* Someone else has this row open. Deliberately quiet: it is information, not an error. */
.viewing { margin-left: auto; font-size: 12px; color: var(--ink-3); background: var(--card-2);
           border: 1px solid var(--warn-line); border-radius: 999px; padding: 2px 9px; }

.filter-bar {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 14px 0 10px;
  position: relative;   /* anchors .filters-pop -- see the comment above that rule */
}
.filter-bar input[type=search], .filter-bar select {
  font: inherit; padding: 7px 10px; border: 1px solid var(--line, #e3e6ea); border-radius: 6px; }
.filter-bar input[type=search] { flex: 1 1 260px; min-width: 200px; }

/* Copy controls */
.msg-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }

/* ONE message goes out next; the other seven are later steps in the sequence.
   The board carried 152 drafted messages against 726 words the prospects wrote, so a card that
   showed all eight cost about 55 minutes to clear. The blue rail marks the message that is
   actually being approved; the rest collapse but stay in the DOM, because save and approve
   collect .msg-text across the whole view. */
.panel-next { border-left: 3px solid var(--blue); }
.panel-next h2 { margin-bottom: 10px; }
.panel-next h2 .muted { font-weight: 600; letter-spacing: 0; }
.panel-next .msg { margin-bottom: 0; }

.rest-block { margin-top: 12px; padding: 0; }
.rest-block > summary {
  cursor: pointer; list-style: none; padding: 13px 17px;
  font-size: 13px; font-weight: 700; color: var(--ink-2);
  display: flex; align-items: center; gap: 8px;
}
.rest-block > summary::-webkit-details-marker { display: none; }
.rest-block > summary::before {
  content: "\203A"; font-size: 15px; line-height: 1; color: var(--ink-3);
  transition: transform .15s ease;
}
.rest-block[open] > summary::before { transform: rotate(90deg); }
.rest-block > summary:hover { color: var(--ink); }
.rest-block > summary:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
.rest-block > *:not(summary) { padding-left: 17px; padding-right: 17px; }
.rest-block > *:last-child { padding-bottom: 15px; }
/* The lead's thread: what people decided, and what the pipeline did. System lines are visually
   quieter than human ones -- a person's reasoning is the scarce thing here. */
/* A <select> ACTING AS A BUTTON must not inherit the full-width form styling.
   The base `input, select, textarea` rule sets width:100%, and .btn declares no width at all, so
   a class selector cannot override a property it never mentions. In a flex bar the select then
   takes a whole row on its own, which is why "Archive selected" read as missing while Export sat
   there looking like the only control. .filter-bar select already carries this same fix, so this
   is the second time the trap has been sprung. */
select.btn, .pick-bar select, .sticky-actions select { width: auto; min-height: 38px; }

.instruct { padding: 14px 16px; }
.instruct-row { display: flex; gap: 8px; align-items: center; }
.instruct-input {
  flex: 1; min-width: 0; padding: 9px 12px; font: inherit; color: var(--ink);
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-input, 8px);
}
.instruct-input:focus { outline: 2px solid var(--blue); outline-offset: 1px; border-color: var(--blue); }
.instruct-out { margin-top: 11px; }
/* The confirm step is the safety property, so it is visually the loudest thing in the box. */
.instruct-plan { border-left: 3px solid var(--blue); padding-left: 12px; }
.instruct-choices { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; align-items: flex-start; }

.notes-list { display: flex; flex-direction: column; gap: 9px; margin: 10px 0 14px; }
.note { border-left: 2px solid var(--line); padding: 2px 0 2px 11px; }
.note-system { opacity: .78; }
.note-system .note-body { font-style: italic; }
.note-note { border-left-color: var(--blue); }
.note-head { display: flex; align-items: baseline; gap: 8px; }
.note-who { font-size: 12px; font-weight: 700; color: var(--ink-2); }
.note-body { font-size: 13.5px; color: var(--ink); white-space: pre-wrap; margin-top: 1px; }
.note-input {
  width: 100%; box-sizing: border-box; padding: 10px 12px; font: inherit;
  color: var(--ink); background: var(--card); border: 1px solid var(--line);
  border-radius: var(--r-sm); min-height: 0; resize: vertical;
}
.note-input:focus { outline: 2px solid var(--blue); outline-offset: 1px; border-color: var(--blue); }

.rest-channel h3 {
  font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-3); margin: 14px 0 8px;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}
.copy-all { float: right; font-weight: 400; }
.nav-count { margin-left: auto; font-size: 12px; font-weight: 600; color: var(--ink-2, #5b6572);
             background: var(--card-2); border-radius: 999px; padding: 1px 8px; min-width: 20px;
             text-align: center; }
/* NO NUMBER MEANS NO PILL.
   min-width plus padding gives an empty badge a 36px body, and --card-2 is the same colour as
   --side-bg, so on an ordinary row that body was invisible and nobody noticed. On the ACTIVE row
   the background is --nav-active-bg instead, and the empty pill showed against it as a pale bar
   that reads like a broken value or a loading skeleton. Also covers the moment before the counts
   land, so no badge flashes in and out on load. */
.nav-count:empty { display: none; }
.sidebar nav a { display: flex; align-items: center; gap: 8px; }
.date-range { display: inline-flex; align-items: center; gap: 5px; font-size: 13px;
              color: var(--ink-2, #5b6572); }
.date-range input[type=date] { font: inherit; padding: 6px 8px;
              border: 1px solid var(--line, #e3e6ea); border-radius: 6px; }
.tag-product { font-weight: 600; color: var(--ink, #1c2430); }
/* Was a hardcoded #9a6b00 mustard, outside the token system entirely. "Campaign not mapped"
   is a missing value, not a warning: it reads as muted ink like any other absence. */
.tag-unmapped { font-weight: 600; color: var(--ink-3); }

/* THE CARD DEFAULT IS NOW JUST NAME, SOURCE, STATUS, PRODUCT. Nilesh, 2026-08-07: reading the
   quote, the whole thread breakdown, the message count/age/ICP line and the draft preview on
   every single card made the queue read as a wall of text before you had picked what to work on.
   Same disclosure pattern as "Refresh the campaign map" and "Add a meeting" below the table --
   closed by default, one click open, nothing about the card's data changes either way. */
.row-more { margin: 8px 0 4px; }
.row-more summary { cursor: pointer; font-size: 12.5px; font-weight: 600; color: var(--ink-2); list-style: none; }
.row-more summary::-webkit-details-marker { display: none; }
.row-more summary::before { content: '▸ '; }
.row-more[open] summary::before { content: '▾ '; }
.row-more[open] summary { margin-bottom: 6px; }

/* --- Several messages in one conversation ---------------------------------
   A prospect who writes twice before anyone answers produces two captured rows and two drafts.
   Navneet Garg showed up twice in the bookings that way. The card collapses them, and this block
   is what stops the collapse from hiding the disagreement: every message stays listed and
   clickable, because the newest draft is not automatically the right one. Dinesh Nair's last
   message routed to "ask availability" on its own, after he had already said the scope was not
   his remit. */
.thread-warn {
  margin: 8px 0 0; padding: 8px 12px;
  background: var(--card-2); border-left: 2px solid var(--line-2);
  border-radius: 0 var(--r-sm) var(--r-sm) 0; font-size: 13px; color: var(--ink-body);
}
.thread-warn strong { color: var(--ink); }
.thread-list { list-style: none; margin: 7px 0 0; padding: 0; display: flex;
  flex-direction: column; gap: 4px; }
.thread-list li { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.thread-list .chip { padding: 1px 7px; font-size: 11px; }

/* --- Row drawer -----------------------------------------------------------
   Opening a lead used to swap the whole page, which threw away your position in a 37-card queue
   every time you looked at one. The row now slides over the list instead.

   A distinct class from .drawer on purpose: that one is the 280px mobile NAV drawer inherited from
   the design system. This holds a full row -- thread, every drafted message, rewrite box, outcome
   controls -- so it is wide and it scrolls internally.

   The URL still changes to #/row/<key>. Deep links and browser Back keep working, and the
   viewing-heartbeat that tells colleagues you are on a row keys off the hash, so quietly opening
   without routing would have stopped that working. */
.row-drawer-scrim {
  position: fixed; inset: 0; background: rgba(15, 23, 42, .38);
  opacity: 0; pointer-events: none; z-index: 40;
  transition: opacity 160ms ease;
}
.row-drawer-scrim.is-open { opacity: 1; pointer-events: auto; }

.row-drawer {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 41;
  width: min(920px, 92vw);
  background: var(--bg); background: var(--bg-page);
  box-shadow: var(--shadow-lg);
  display: none; flex-direction: column;
  border-left: 1px solid var(--line);
}
.row-drawer.is-open { display: flex; animation: row-drawer-in 170ms ease; }
@keyframes row-drawer-in { from { transform: translateX(24px); opacity: .4; } to { transform: none; opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .row-drawer.is-open { animation: none; } }

/* Header stays put while the body scrolls, so Close is always reachable on a long thread. */
.row-drawer-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 16px; border-bottom: 1px solid var(--line);
  background: var(--card); flex: none;
}
.row-drawer-head .muted { font-size: 12.5px; }
.row-drawer-body { overflow-y: auto; padding: 14px 16px 32px; flex: 1; }
/* The row view ships its own back-link; inside the drawer the header owns closing. */
.row-drawer-body .back-link { display: none; }
/* Its sticky action bar must stick to the drawer, not the window. The page version fades out with
   a gradient into the page background; inside the drawer there is nothing behind it to fade into,
   so the row's own text showed through the buttons. Solid, edge-to-edge, with a rule above it. */
.row-drawer-body .sticky-actions {
  position: sticky; bottom: 0; z-index: 2;
  background: var(--card); border-top: 1px solid var(--line);
  margin: 16px -16px -32px; padding: 12px 16px;
  box-shadow: 0 -4px 12px rgba(15, 23, 42, .06);
}

/* While the drawer is open the list behind it must not scroll under the pointer. */
body.row-drawer-open { overflow: hidden; }

/* A product we INFERRED, never one we matched. Distinct from .tag-product on purpose: the moment
   a guess looks like a resolved fact, somebody sends copy written for the wrong client.
   Dashed, not coloured. The dash already says "not confirmed"; the amber fill was a third
   competing highlight on cards that often carry an ICP chip and an age badge too. */
.tag-suggested {
  display: inline-block; padding: 1px 8px; border-radius: var(--r-pill);
  font-size: 12px; font-weight: 600;
  background: var(--card-2); color: var(--ink-2); border: 1px dashed var(--ink-4);
}

/* The inferred-product block on a row. Bordered and tinted so it reads as a note about the row
   rather than a property of it. */
.suggestion {
  margin-top: 10px; padding: 10px 12px;
  background: var(--card-2); border: 1px solid var(--line-2);
  border-left: 2px solid var(--line-2); border-radius: var(--r-sm);
}
.suggestion p { margin: 0 0 6px; }
.suggestion .form-row { margin: 0; align-items: center; }

/* "edit" beside the product tag on a card. Small and quiet: it is there for the minority of rows
   where the label is wrong, and it must not compete with Open and Approve. Opens the row drawer,
   which now holds the campaign and product editor, so a wrong label is two clicks from fixed
   instead of requiring somebody to know the dropdown exists. */
.tag-edit {
  margin-left: 6px; font-size: 11.5px; font-weight: 600;
  color: var(--ink-3); text-decoration: none;
  border-bottom: 1px dotted var(--line-2);
}
.tag-edit:hover { color: var(--blue); border-bottom-color: var(--blue); text-decoration: none; }

/* The campaign/product editor on a row. Collapsed when the mapping looks settled, open when it is
   missing or only suggested -- the two cases where somebody is most likely to need it. */
.edit-block { margin-top: 10px; border-top: 1px solid var(--line); padding-top: 8px; }
.edit-block > summary { cursor: pointer; font-size: 13px; font-weight: 600; color: var(--ink-2); }
.edit-block > summary:hover { color: var(--blue); }
.edit-block .form-row { margin-top: 8px; }
.edit-block input { flex: 0 1 280px; }

/* Row selection for export. The checkbox sits first in the card header so a column of them reads
   as a column; the bar only appears once something is picked, so it costs nothing the rest of the
   time. */
.pick { display: inline-flex; align-items: center; margin-right: 8px; vertical-align: middle; }
.pick-box { width: 15px; height: 15px; cursor: pointer; accent-color: var(--blue); }

/* The select box on a CARD (the table version sits in its own cell and needs none of this).
   Nudged up a little so it reads against the name it belongs to rather than floating over the
   line below, and given a generous hit area: it is a 15px target being ticked repeatedly. */
/* Earlier messages of a conversation, inside More details. Ruled down the left so the thread
   reads as history behind the newest message rather than as more of the same reply. */
/* The meetings window picker: two rows of controls that must not become a wall. Wraps on narrow
   screens rather than scrolling sideways, and the date inputs stay on the baseline of the row. */
.mh-months { display: grid; gap: 8px; margin-bottom: 14px; }
.mh-months .form-row { flex-wrap: wrap; align-items: center; gap: 8px; }
.mh-months input[type="date"] { min-height: 34px; padding: 4px 8px; }
.mh-months p { margin: 0; }

.lead-thread { border-left: 2px solid var(--line); padding-left: 12px; margin: 0 0 10px; }
.lead-thread p { margin: 0 0 6px; }

.pick-lead { display: inline-flex; align-items: center; padding: 4px 8px 4px 0; margin: -4px 0; vertical-align: -2px; }
/* KEEPS the accent, deliberately. It is the only transient block on the page -- it does not exist
   until you tick a box -- so when it appears it should pull the eye. Colour spent on a state you
   created is colour that means something. */
.pick-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 8px 0 0; padding: 8px 12px;
  background: var(--info-bg); border: 1px solid var(--info-line); border-radius: var(--r-sm);
}
.pick-bar strong { font-size: 13px; color: var(--info); }

/* One button, one popover, for every filter but search -- see filterBar() in queue.js. Six
   dropdowns plus a date range used to sit open on the page at all times, nearly always on their
   do-nothing default.
   Anchored to the whole `.filter-bar` row (via left:0; right:0 below), NOT to the small button --
   a panel wide enough for six controls anchored off a 64px button ran off the edge of the screen
   on any window narrower than about 1400px, because its own content width had nothing to answer
   to. Spanning the bar it hangs off of means it is bounded by a width that already fits, on any
   window size, because everything else on the page already has to fit there too. */
.filters-wrap { position: static; }
.filters-badge {
  margin-left: 6px; background: var(--blue); color: #fff; border-radius: 999px;
  font-size: 11px; font-weight: 700; padding: 1px 6px;
}
.filters-pop {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 20;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px 16px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: var(--shadow-card); padding: 14px 16px;
}
.fp-row { display: flex; flex-direction: column; gap: 4px; font-size: 13px; color: var(--ink-2); }
.fp-row select {
  width: 100%; font: inherit; padding: 7px 9px;
  border: 1px solid var(--line, #e3e6ea); border-radius: 6px;
}
/* The date range reads as one line, not two stacked fields, so it spans every column instead of
   claiming a grid cell sized for a dropdown label. */
.fp-row.fp-dates { grid-column: 1 / -1; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 16px; }

/* One disclosure for both rare admin actions instead of two -- see summaryTable() in queue.js. */
.tools-section + .tools-section { margin-top: 14px; border-top: 1px dashed var(--line, #e3e6ea); padding-top: 12px; }
.tools-section h3 { font-size: 13px; font-weight: 700; margin: 0 0 6px; }

/* A referral pair, shown as one card. Green rather than amber: two separate cards read as a
   duplication problem, but a referral is not a problem -- it is the best outcome the queue
   produces, and it needs two sends because it involves two people. */
/* A referral is good news, not an alarm, and the route pill already says "Referral". It gets the
   accent as a left rule -- one thin blue line -- instead of a filled green panel. */
.thread-referral { background: var(--card-2); border-left-color: var(--blue); }
.thread-referral strong { color: var(--ink); }

/* Provenance. Quiet on the card -- it answers "which inbox do I open", which you need before
   replying but not while scanning -- and a proper labelled grid on the row. */
.src-line { margin: 4px 0 0; font-size: 12.5px; color: var(--ink-3); }
.src-chan { font-weight: 650; color: var(--ink-2); }
.src-mail { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
.src-ws { padding: 0 6px; font-size: 10.5px; letter-spacing: .04em; }
.src-grid {
  display: grid; grid-template-columns: max-content 1fr; gap: 4px 16px;
  margin: 8px 0 0; font-size: 13px;
}
.src-grid dt { color: var(--ink-3); }
.src-grid dd { margin: 0; color: var(--ink); overflow-wrap: anywhere; }

/* ---- Dark ----------------------------------------------------------------
   Re-derived, not inverted. Flipping lightness produces muddy mid-greys and destroys the contrast
   ratios the ink scale was chosen for, so each value is picked against the dark surface: ink runs
   light-to-mid, surfaces run near-black to slate, and the status tints become low-saturation
   washes rather than the pale pastels that only work on white.

   Applied on the root element, so it covers the drawer and the scrim too, both of which live
   outside #app. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #0b1120;
  --bg-page: linear-gradient(160deg, #0d1424 0%, #0a0f1c 100%);

  --ink: #e8edf5;      /* primary text */
  --ink-2: #b3becd;    /* secondary */
  --ink-3: #8c99ab;    /* tertiary / labels — still AA on --card */
  --ink-4: #6b7789;    /* decorative only */
  --ink-body: #c8d2df;

  --card: #131b2c;
  --card-2: #1a2336;
  --side-bg: #101828;

  --line: #26314a;
  --line-2: #2e3a55;

  --blue: #6ea8fe;         /* lifted: #2563eb on near-black fails contrast */
  --blue-deep: #93c0ff;
  --sky: #7dd3fc;
  --nav-active-bg: #17243d;
  --grad-avatar: linear-gradient(135deg, #6ea8fe, #38bdf8);

  /* Status: readable text on a low-saturation wash, not a pastel fill. */
  --ok: #6ee7b7;  --ok-bg: #10241e;  --ok-line: #1f4739;  --ok-dot: #34d399;
  --warn: #fcd34d; --warn-bg: #2a2113; --warn-line: #4d3d18; --warn-dot: #fbbf24;
  --bad: #fca5a5; --bad-bg: #2a1618; --bad-line: #4d2226; --bad-dot: #f87171;
  --info: #93c0ff; --info-bg: #15203a; --info-line: #26386a; --info-dot: #6ea8fe;
  --neutral-bg: #1a2336; --neutral-ink: #8c99ab; --neutral-line: #2e3a55;

  /* Shadow does almost nothing on a dark surface; depth comes from the border instead. */
  --shadow-card: 0 1px 2px rgba(0, 0, 0, .40);
  --shadow-chip: 0 2px 6px rgba(0, 0, 0, .45);
  --shadow-sm: var(--shadow-card);
  --shadow: 0 4px 16px rgba(0, 0, 0, .50);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, .60);

  --media-outline: rgba(255, 255, 255, .12);
  --toast-bg: #e8edf5; --toast-ink: #0b1120;
}

/* The ambient glows are tuned for a white page; at dark-mode luminance they read as smears. */
:root[data-theme="dark"] body::before { opacity: .35; }
:root[data-theme="dark"] body::after  { opacity: .30; }

/* Scrims sit over a dark page already, so the light-mode veil is too weak to separate layers. */
:root[data-theme="dark"] .row-drawer-scrim,
:root[data-theme="dark"] .drawer-scrim { background: rgba(0, 0, 0, .62); }

/* Form controls do not inherit the token set; color-scheme handles the chrome, these the rest. */
:root[data-theme="dark"] input,
:root[data-theme="dark"] select,
:root[data-theme="dark"] textarea {
  background: var(--card-2); color: var(--ink); border-color: var(--line-2);
}
:root[data-theme="dark"] ::selection { background: rgba(110, 168, 254, .35); }

/* The theme control itself. */
.theme-toggle {
  background: none; border: 1px solid var(--line-2); color: var(--ink-2);
  border-radius: var(--r-sm); padding: 4px 10px; font: inherit; font-size: 12.5px;
  cursor: pointer; line-height: 1.6;
}
.theme-toggle:hover { border-color: var(--blue); color: var(--blue); }

/* The sidebar footer already exists above (margin-top:auto + a top border), written for an avatar
   row this app never renders. Reused rather than redefined -- a second .sidebar-foot block would
   shadow it and the next person would have to work out which one wins. Only the difference is
   stated here: it is a flex row there, and here it holds one full-width control. */
.sidebar-foot .theme-toggle { flex: 1; text-align: center; }

/* --- Collapsible sidebar --------------------------------------------------
   The rail is position:fixed and rendered OUTSIDE .app-shell on purpose. A control inside the
   sidebar can only ever hide itself, which is the mistake the theme button made in the topbar.

   z-index sits above the page but below the row drawer (41) and its scrim (40), so opening a lead
   still covers it rather than leaving a stray button floating over the panel. */
.nav-toggle-rail {
  position: fixed; top: 14px; left: 232px; z-index: 25;
  width: 22px; height: 30px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  background: var(--card); color: var(--ink-3);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: var(--shadow-card); cursor: pointer;
  font-size: 15px; line-height: 1;
  transition: left 160ms ease, color 150ms ease, border-color 150ms ease;
}
.nav-toggle-rail:hover { color: var(--blue); border-color: var(--blue); }
@media (prefers-reduced-motion: reduce) { .nav-toggle-rail { transition: none; } }

:root[data-sidebar="hidden"] .sidebar { display: none; }
/* The later .app-shell rule is the grid one, so the collapsed state overrides its columns. */
:root[data-sidebar="hidden"] .app-shell { grid-template-columns: 1fr; }
:root[data-sidebar="hidden"] .nav-toggle-rail { left: 10px; }

/* Below 1000px the sidebar is already hidden and the topbar is the nav, so the rail would toggle
   something invisible. */
@media (max-width: 999.98px) { .nav-toggle-rail { display: none; } }

/* The conversation has moved past this draft.
   One of the few places colour is still spent, and it earns it: this is not a category, it is a
   condition that makes the copy below actively wrong to send. Amber like the other read-before-you-
   act signals, and stated in words so it does not depend on the colour alone. */
.stale-warn {
  margin: 8px 0; padding: 10px 12px;
  background: var(--warn-bg); border: 1px solid var(--warn-line);
  border-left: 3px solid var(--warn-dot); border-radius: var(--r-sm);
  font-size: 13px; color: var(--ink-body);
}
.stale-warn strong { color: var(--warn); display: block; margin-bottom: 3px; }

/* --- Learning page --------------------------------------------------------
   Three read-only cards. Only the repetition list needs styling of its own: a
   cluster that has recurred three or more times is the one worth turning into a
   rule, so it is the only thing here that earns colour. */
.lrn-cluster { margin-top: 10px; }
.lrn-cluster > summary { display: flex; gap: 8px; align-items: baseline; }
.lrn-hot { border-style: solid; border-color: var(--blue); color: var(--blue); }
.lrn-list { margin: 10px 0 2px; padding-left: 18px; display: grid; gap: 10px; }
.lrn-list li { line-height: 1.45; }

/* --- A sender has gone dark ----------------------------------------------
   Loud on purpose. Every other number on the queue stays plausible while an
   account is disconnected, so this is the one banner that must not read as
   decoration: it means replies are being sent to us and never arriving. */
.li-health-wrap { position: relative; }
.li-health {
  display: flex; align-items: center; justify-content: center; width: 30px; height: 30px;
  border-radius: 50%; border: 1px solid var(--line); background: var(--card); color: var(--ink-2);
  cursor: pointer;
}
.li-health:hover { background: var(--nav-active-bg); }
.li-health-warn { border-color: var(--warn-line); background: var(--warn-bg); color: var(--warn); }
.li-health-pop {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 20; min-width: 176px;
  background: var(--card); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: var(--shadow-card); padding: 10px 12px;
}
.li-health-row {
  display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--ink);
  padding: 3px 0;
}
.li-health-row strong { margin-left: auto; }
.li-health-row .dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.li-health-row .dot-ok { background: #16a34a; }
.li-health-row .dot-warn { background: var(--warn-dot); }


/* --- Today ----------------------------------------------------------------
   One booking per row, time in a fixed left column so the whole day reads as a
   single vertical timeline rather than a list of cards you have to parse
   individually. The time column is fixed-width and tabular-nums for the same
   reason: 9:00 and 11:30 have to start at the same x, or the eye cannot run
   down the column. Everything except the time and the name is deliberately
   quiet -- this page is scanned, not read. */
.td-row {
  display: grid; grid-template-columns: 84px minmax(0, 1fr) auto;
  gap: 12px; align-items: start;
  padding: 12px 0; border-top: 1px solid var(--line-2);
}
.td-row:first-of-type { border-top: 0; }
.td-time {
  font-variant-numeric: tabular-nums; font-weight: 800; font-size: 14px;
  color: var(--ink); white-space: nowrap; padding-top: 1px;
}
/* A booking whose time could not be read. Muted, because it is not an alarm on
   its own -- the row already carries a warning explaining it. */
.td-time-soft { font-weight: 650; font-size: 11.5px; color: var(--ink-3); line-height: 1.25; }
.td-body { min-width: 0; }
.td-body h3 { font-size: 13.5px; font-weight: 750; color: var(--ink); margin: 0 0 2px; }
.td-body p { margin: 2px 0; }
.td-body .chip { margin-right: 5px; }
.td-act { display: flex; gap: 6px; align-items: center; }
.td-span { margin: 0 0 12px; align-items: center; }

/* Stacked on a phone: a 84px time column plus a name plus a button does not fit
   at 390px, and the button wrapping under the time column looked like it
   belonged to the row above. */
@media (max-width: 620px) {
  .td-row { grid-template-columns: 1fr; gap: 6px; }
  .td-act { justify-content: flex-start; }
}

/* A rule under the last item of a nav group.
   On the ELEMENT rather than a separate <hr> node so the divider cannot drift away from the item
   it belongs to when the nav is re-rendered, and so an empty group leaves no orphan line. Margin
   below the border, not padding, so the rule sits in the gap between groups instead of inside the
   hit area of the link above it -- a divider that highlights on hover reads as a broken row. */
.sidebar nav a.nav-group-end { margin-bottom: 11px; position: relative; }
.sidebar nav a.nav-group-end::after {
  content: ''; position: absolute; left: 10px; right: 10px; bottom: -6px;
  border-bottom: 1px solid var(--line, rgba(127, 127, 127, .25));
}

/* Health page. The count is the headline because the count is what a person acts on, so it gets
   the width of a fixed column and everything else flows beside it. */
.diag-row { display: grid; grid-template-columns: 74px 1fr auto; gap: 14px; align-items: center; }
.diag-n { font-size: 26px; font-weight: 650; text-align: right; font-variant-numeric: tabular-nums; }
.diag-act { white-space: nowrap; }
@media (max-width: 640px) {
  .diag-row { grid-template-columns: 56px 1fr; }
  .diag-act { grid-column: 2; justify-self: start; }
}

/* Need to Reply / Interested / Not Interested. The reply itself is the point of the card, so the
   kind chip sits out of the way on the right rather than competing with it. */
.lead-card { margin-bottom: var(--sp-2); padding: 12px 14px; }
.lead-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.lead-who { min-width: 0; }
.lead-gist { margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lead-acts { margin-top: 8px; align-items: center; }
.lead-card .row-more { margin-top: 6px; }
.lead-card .prose { margin: 8px 0 6px; }
@media (max-width: 640px) { .lead-head { flex-direction: column; gap: 4px; } .lead-gist { white-space: normal; } }

/* Meetings hub view switcher. Sits above whichever view is mounted, so it needs to clear it. */
.mh-tabs { margin-bottom: var(--sp-3); }

.mh-months { margin-bottom: var(--sp-2); align-items: center; }
.mh-months select { padding: 4px 8px; }

/* The meetings behind the grid total. Each client/product block reads as its own small table so
   the count in its heading can be checked against the row above it. */
.ml-group { margin-top: var(--sp-4); }
.ml-group:first-of-type { margin-top: var(--sp-2); }
.ml-group h3 { margin: 0 0 6px; font-size: 14px; }

.ml-filter { flex-wrap: wrap; margin-bottom: var(--sp-2); }
.ml-group[hidden] { display: none; }

/* The shared list filter bar. Wraps on narrow screens rather than scrolling sideways. */
.lf-bar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: var(--sp-3); }
.lf-bar .lf-search { flex: 1 1 240px; min-width: 180px; padding: 6px 10px; }
.lf-bar .lf-sel { padding: 5px 8px; }
.lf-bar .lf-count { margin-left: auto; }

/* The facts inside More details. Two columns so the labels line up and the eye can run down them,
   which a comma-separated run of values cannot do. */
.lead-facts { display: grid; grid-template-columns: max-content 1fr; gap: 3px 14px; margin: 8px 0; font-size: 13px; }
.lead-facts dt { color: var(--ink-2); }
.lead-facts dd { margin: 0; color: var(--ink); min-width: 0; overflow-wrap: anywhere; }
@media (max-width: 560px) { .lead-facts { grid-template-columns: 1fr; gap: 0 0; } .lead-facts dt { margin-top: 6px; } }

