/* ============================================================
   Attribution Hub — Design tokens
   Brand palette: #101820 ink, #7BADD3 sky, #BABABA mid, white
   ============================================================ */

:root {
  /* Brand */
  --ink: #101820;
  --sky: #7BADD3;
  --mid: #BABABA;
  --white: #ffffff;

  /* Neutrals (cool-leaning, derived from ink) */
  --bg: #fafbfc;
  --surface: #ffffff;
  --surface-2: oklch(98.4% 0.003 230);
  --surface-3: oklch(96.5% 0.005 230);
  --line: oklch(92% 0.006 230);
  --line-strong: oklch(87% 0.008 230);

  /* Text */
  --text: #101820;
  /* --text-1 is referenced in next-actions.jsx and tabs.jsx and was never
     defined here, so it silently resolved to `inherit`, the headline of the
     top next-action and the heading of every withheld note have never been the
     colour anyone chose. Aliased rather than renamed at the call sites so the
     name keeps working wherever else it turns up. */
  --text-1: #101820;
  --text-2: oklch(38% 0.015 230);
  --text-3: oklch(55% 0.012 230);
  --text-4: oklch(70% 0.01 230);

  /* Accent (the sky blue, darkened slightly for AA contrast on white) */
  --accent: #7BADD3;
  --accent-ink: oklch(48% 0.09 235);   /* readable on white */
  --accent-bg: oklch(96% 0.025 235);
  --accent-line: oklch(85% 0.05 235);

  /* Semantic — desaturated, financial-clarity feel */
  --good: oklch(58% 0.11 155);
  --good-bg: oklch(96% 0.03 155);
  --warn: oklch(70% 0.13 75);
  --warn-bg: oklch(97% 0.04 75);
  --bad: oklch(58% 0.16 25);
  --bad-bg: oklch(96% 0.03 25);

  /* Type */
  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  /* Radius */
  --r-sm: 4px;
  --r-md: 6px;
  --r-lg: 8px;
  --r-xl: 12px;

  /* Shadow (very subtle, Stripe-ish) */
  --shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.04);
  --shadow-md: 0 1px 3px oklch(0% 0 0 / 0.06), 0 4px 12px oklch(0% 0 0 / 0.04);
  --shadow-lg: 0 8px 24px oklch(0% 0 0 / 0.08), 0 2px 6px oklch(0% 0 0 / 0.04);

  /* Sizes */
  --row-h: 44px;
  --topbar-h: 56px;
  --sidebar-w: 76px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-feature-settings: 'cv02','cv03','cv04','cv11';
}

/* density variants */
body.density-dense { --row-h: 36px; font-size: 13px; }
body.density-spacious { --row-h: 56px; font-size: 15px; }

/* Numbers always tabular */
.num, td.num, th.num, .kpi-value, .mono { font-variant-numeric: tabular-nums; }
.mono { font-family: var(--font-mono); }

button { font-family: inherit; cursor: pointer; }

a { color: var(--accent-ink); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ============================================================ Shell */

.app {
  display: grid;
  grid-template-columns: var(--sidebar-w) 1fr;
  grid-template-rows: var(--topbar-h) 1fr;
  grid-template-areas: "logo topbar" "sidebar main";
  height: 100vh;
  height: 100dvh;   /* 100vh on a phone is measured against the LARGEST viewport,
                       so the last row sits under the browser chrome. dvh tracks
                       the address bar; the vh line above it is the fallback. */
  width: 100%;      /* 100vw includes the scrollbar gutter and causes a 15px
                       horizontal scroll on every desktop browser that shows one. */
  overflow: hidden;
}

.logo-cell {
  grid-area: logo;
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  background: var(--surface);
}
.logo-mark {
  width: 28px; height: 28px;
  background: var(--ink);
  border-radius: var(--r-md);
  display: grid; place-items: center;
  color: white; font-weight: 700; font-size: 13px;
  letter-spacing: -0.02em;
}

.topbar {
  grid-area: topbar;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  display: flex; align-items: center;
  padding: 0 16px;
  gap: 16px;
}

.sidebar {
  grid-area: sidebar;
  background: var(--surface);
  border-right: 1px solid var(--line);
  display: flex; flex-direction: column;
  align-items: center;
  padding: 8px 0;
  gap: 2px;
}

.sidebar-icon {
  width: 64px;
  padding: 6px 4px 5px;
  border-radius: var(--r-md);
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  color: var(--text-3);
  background: transparent; border: 0;
  transition: all 120ms ease;
  cursor: pointer;
}
.sidebar-icon:hover { background: var(--surface-3); color: var(--text); }
.sidebar-icon.active { background: var(--ink); color: white; }
.sidebar-icon svg { width: 18px; height: 18px; }
.sidebar-icon .nav-label {
  font-size: 9.5px;
  letter-spacing: 0.02em;
  line-height: 1.1;
  font-weight: 500;
  white-space: nowrap;
}
.sidebar-icon[disabled] { opacity: 0.35; cursor: not-allowed; }

.sidebar-spacer { flex: 1; }

.main {
  grid-area: main;
  overflow: auto;
  background: var(--bg);
}

/* ============================================================ Topbar bits */

.client-switch {
  display: flex; align-items: center; gap: 8px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 6px 10px 6px 8px;
  min-width: 220px;
  cursor: pointer;
  transition: border-color 120ms ease;
  position: relative;
}
.client-switch:hover { border-color: var(--line-strong); }

.client-avatar {
  width: 22px; height: 22px;
  border-radius: var(--r-sm);
  display: grid; place-items: center;
  font-size: 11px; font-weight: 600;
  color: white;
  flex-shrink: 0;
}

.client-meta {
  display: flex; flex-direction: column;
  line-height: 1.15;
  flex: 1;
  min-width: 0;
}
.client-meta .name { font-weight: 550; font-size: 13px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.client-meta .sub { font-size: 11px; color: var(--text-3); font-family: var(--font-mono); }

.status-dot {
  width: 6px; height: 6px; border-radius: 50%;
  flex-shrink: 0;
}
.status-dot.good { background: var(--good); box-shadow: 0 0 0 2px var(--good-bg); }
.status-dot.warn { background: var(--warn); box-shadow: 0 0 0 2px var(--warn-bg); }
.status-dot.bad  { background: var(--bad);  box-shadow: 0 0 0 2px var(--bad-bg); }

.client-popover {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  width: 320px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  z-index: 20;
  /* Ten hubs for the internal role: scroll rather than run off a laptop. */
  max-height: min(560px, calc(100vh - 90px));
  overflow-y: auto;
}
.client-popover-header {
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-3); font-weight: 600;
}
.client-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  border: 0; background: transparent;
  width: 100%; text-align: left;
  cursor: pointer;
}
.client-row:hover { background: var(--surface-2); }
.client-row.active { background: var(--accent-bg); }
.client-row .meta { flex: 1; min-width: 0; }
.client-row .meta .n { font-weight: 550; font-size: 13px; }
.client-row .meta .s { font-size: 11px; color: var(--text-3); font-family: var(--font-mono); }

.topbar-spacer { flex: 1; }

.date-range {
  display: flex; align-items: center; gap: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface);
  overflow: hidden;
}
.date-range button {
  border: 0; background: transparent;
  padding: 6px 10px;
  font-size: 12px; font-weight: 500;
  color: var(--text-2);
  border-right: 1px solid var(--line);
}
.date-range button:last-child { border-right: 0; }
.date-range button:hover { background: var(--surface-2); color: var(--text); }
.date-range button.active { background: var(--ink); color: white; }

.icon-btn {
  width: 32px; height: 32px;
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--r-md);
  display: grid; place-items: center;
  color: var(--text-2);
}
.icon-btn:hover { background: var(--surface-2); color: var(--text); }
.icon-btn svg { width: 16px; height: 16px; }

.user-chip {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 10px 4px 4px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  font-size: 12px; font-weight: 500;
}
.user-chip .avatar {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--ink);
  color: white;
  display: grid; place-items: center;
  font-size: 10px; font-weight: 600;
}

/* ============================================================ Page */

.page {
  max-width: 1440px;
  margin: 0 auto;
  padding: 24px 28px 80px;
}

.page-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 24px;
  margin-bottom: 24px;
}
.page-title {
  font-size: 22px; font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 4px;
}
.page-sub {
  font-size: 13px; color: var(--text-3);
  margin: 0;
}
.page-sub .mono { color: var(--text-2); }

.head-actions { display: flex; align-items: center; gap: 8px; }

.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface);
  font-size: 13px; font-weight: 500;
  color: var(--text);
}
.btn:hover { background: var(--surface-2); border-color: var(--line-strong); }
.btn.primary { background: var(--ink); color: white; border-color: var(--ink); }
.btn.primary:hover { background: oklch(20% 0.015 230); }
.btn svg { width: 14px; height: 14px; }

/* ============================================================ KPIs */

.kpi-grid {
  display: grid;
  /* auto-fit so the card count drives the column count (4 cards → 4 cols,
     5 cards → 5 cols) and there are never empty grid cells showing the
     grey track background as a blank block. */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
  margin-bottom: 24px;
}
.kpi {
  background: var(--surface);
  padding: 18px 20px 16px;
  display: flex; flex-direction: column;
  gap: 10px;
  position: relative;
}
.kpi-label {
  font-size: 12px;
  color: var(--text-3);
  font-weight: 500;
  display: flex; align-items: center; gap: 6px;
}
.kpi-label .info {
  width: 13px; height: 13px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  display: grid; place-items: center;
  font-size: 9px; color: var(--text-4);
}
.kpi-value {
  font-size: 26px; font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
.kpi-value .unit { color: var(--text-3); font-weight: 500; font-size: 18px; margin-left: 2px; }
.kpi-foot {
  display: flex; align-items: center; justify-content: space-between;
  gap: 6px; flex-wrap: wrap;
  font-size: 12px;
  color: var(--text-3);
}
.delta {
  display: inline-flex; align-items: center; gap: 3px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.delta.up { color: var(--good); }
.delta.down { color: var(--bad); }
.delta.flat { color: var(--text-3); }

.spark {
  position: absolute;
  right: 16px; top: 16px;
  width: 80px; height: 28px;
  opacity: 0.9;
}

/* ============================================================ Reconciliation panel */

.recon {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 0;
  margin-bottom: 24px;
  overflow: hidden;
}

.recon-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--line);
}
.recon-head h2 {
  font-size: 14px; font-weight: 600;
  margin: 0;
  display: flex; align-items: center; gap: 10px;
}
.recon-head h2 .target {
  font-size: 11px;
  font-weight: 500;
  color: var(--text-3);
  background: var(--surface-2);
  border: 1px solid var(--line);
  padding: 2px 8px;
  border-radius: 999px;
  font-family: var(--font-mono);
  white-space: nowrap;
}
.recon-head .legend { display: flex; gap: 16px; font-size: 12px; color: var(--text-3); }
.recon-head .legend span { display: inline-flex; align-items: center; gap: 6px; }
.recon-head .legend .swatch { width: 10px; height: 10px; border-radius: 2px; }
.recon-head .legend .dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }

.recon-body {
  display: grid;
  grid-template-columns: 1fr 280px;
  gap: 0;
}
.recon-chart-wrap {
  padding: 20px;
  border-right: 1px solid var(--line);
}
.recon-side {
  padding: 18px 20px;
  display: flex; flex-direction: column;
  gap: 14px;
}
.recon-side h3 {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-3); margin: 0; font-weight: 600;
}
.source-row {
  display: grid;
  grid-template-columns: 14px 1fr auto;
  align-items: center;
  gap: 10px;
  font-size: 13px;
}
.source-row .swatch { width: 10px; height: 10px; border-radius: 2px; }
.source-row .lbl { color: var(--text); }
.source-row .val { text-align: right; color: var(--text); font-variant-numeric: tabular-nums; font-weight: 500; }
.source-row .pct { font-size: 11px; color: var(--text-3); margin-left: 4px; font-variant-numeric: tabular-nums; }
.source-bar { height: 4px; background: var(--surface-3); border-radius: 2px; overflow: hidden; grid-column: 2 / -1; }
.source-bar > div { height: 100%; }
.source-bar.sold { height: 3px; margin-top: 3px; opacity: 0.5; }
.source-est { font-size: 10px; color: var(--text-3); margin-top: 3px; font-variant-numeric: tabular-nums; }
.source-est strong { color: var(--text-2); font-weight: 600; }

/* Coverage bar on KPI cards (replaced the old fake sparkline) */
.kpi-bar {
  height: 4px; background: var(--surface-3); border-radius: 2px;
  overflow: hidden; margin-top: 12px;
}
.kpi-bar > div { height: 100%; border-radius: 2px; transition: width 0.4s ease; }

/* Revenue-by-source panel body (replaced the variance chart) */
.recon-source {
  display: flex; align-items: center; gap: 28px;
  padding: 20px;
}
.recon-source-rows {
  flex: 1; display: flex; flex-direction: column; gap: 9px; min-width: 0;
}
.recon-top-driver {
  display: flex; flex-direction: column; gap: 1px;
  padding-bottom: 10px; margin-bottom: 4px;
  border-bottom: 1px solid var(--line);
}
.recon-top-driver .subtle { font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em; }
.recon-top-driver strong { font-size: 15px; }
.recon-top-driver .mono { font-size: 11px; color: var(--text-3); }
.source-row-main { min-width: 0; }
.source-row-main .source-bar { grid-column: auto; margin-top: 4px; }
.recon-note {
  margin: 0 20px 18px;
  padding: 10px 12px; border-radius: 8px;
  background: rgba(229, 158, 78, 0.08);
  border: 1px solid rgba(229, 158, 78, 0.25);
  font-size: 11.5px; color: var(--text-2); line-height: 1.5;
}
.recon-note strong { color: #e59e4e; }

/* ============================================================ Jobs table */

.section-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 12px;
}
.section-head h2 {
  font-size: 14px; font-weight: 600; margin: 0;
}
.tabs {
  display: flex; gap: 0;
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--r-md);
  overflow: hidden;
  font-size: 12px; font-weight: 500;
}
.tabs button {
  padding: 6px 12px; border: 0; background: transparent;
  color: var(--text-2);
  border-right: 1px solid var(--line);
}
.tabs button:last-child { border-right: 0; }
.tabs button:hover { background: var(--surface-2); }
.tabs button.active { background: var(--ink); color: white; }

.search-input {
  display: flex; align-items: center; gap: 6px;
  border: 1px solid var(--line);
  background: var(--surface);
  border-radius: var(--r-md);
  padding: 6px 10px;
  font-size: 12px;
  color: var(--text-3);
  min-width: 220px;
}
.search-input svg { width: 13px; height: 13px; }
.search-input input {
  border: 0; outline: none; background: transparent;
  font-family: inherit; font-size: 12px; color: var(--text);
  width: 100%;
}

.jobs-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  overflow: hidden;
}
.jobs-toolbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-2);
  gap: 10px;
}
.jobs-toolbar .filters { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }

.chip {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 500;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--surface-3);
  color: var(--text-2);
  border: 1px solid var(--line);
  font-variant-numeric: tabular-nums;
}
.chip.active { background: var(--ink); color: white; border-color: var(--ink); }
.chip .x { color: var(--text-4); font-size: 10px; cursor: pointer; }
.chip.good { background: var(--good-bg); color: var(--good); border-color: oklch(85% 0.06 155); }
.chip.warn { background: var(--warn-bg); color: oklch(45% 0.13 75); border-color: oklch(85% 0.07 75); }
.chip.bad  { background: var(--bad-bg);  color: var(--bad);  border-color: oklch(85% 0.07 25); }
.chip.accent { background: var(--accent-bg); color: var(--accent-ink); border-color: var(--accent-line); }

table.jobs {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
table.jobs th {
  text-align: left;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 8px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  position: sticky; top: 0;
}
table.jobs th.num { text-align: right; }
table.jobs td {
  padding: 0 14px;
  height: var(--row-h);
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
  white-space: nowrap;
}
table.jobs td.num { text-align: right; font-variant-numeric: tabular-nums; }
table.jobs tr:last-child td { border-bottom: 0; }
table.jobs tbody tr { cursor: pointer; }
table.jobs tbody tr:hover { background: var(--surface-2); }
table.jobs tbody tr.selected { background: var(--accent-bg); }

/* Simple panel tables (Quote vs Sales, Brands). `data-table` had no rules at
   all, so these rendered as bare browser tables: shrink-wrapped to the left of
   a full-width card, centred bold headers, no row lines. Same look as
   table.jobs, minus the click affordance. */
table.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
table.data-table th {
  text-align: left;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 10px 20px;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
table.data-table td {
  padding: 10px 20px;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
  font-variant-numeric: tabular-nums;
}
table.data-table tr:last-child td { border-bottom: 0; }
@media (max-width: 720px) {
  table.data-table th, table.data-table td { padding: 8px 10px; }
  /* The bars restate the two money columns beside them; on a phone the
     numbers win the width. */
  table.data-table .qvs-bar { display: none; }
}

/* Base look for a system tag ("ServiceTitan", "BND AI", a brand code). It was
   only ever styled inside drawer headings, so everywhere else it was bare
   text on whatever inline tint the caller passed. */
.source-tag {
  display: inline-block;
  font-size: 11px;
  line-height: 1.5;
  padding: 1px 7px;
  border: 1px solid var(--line);
  border-radius: 4px;
  background: var(--surface-2);
  color: var(--text-2);
  white-space: nowrap;
}

/* A channel name: readable dark text, channel colour on a dot. Replaces text
   painted in the channel colour, which made light channels unreadable —
   "Source not recorded" is #E5E5E5 on white. */
.src-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text-1);
  white-space: nowrap;
}
.src-label .src-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.14);
}

.cell-id { color: var(--text-3); font-family: var(--font-mono); font-size: 12px; }
.cell-customer { display: flex; align-items: center; gap: 8px; }
.cell-customer .av {
  width: 22px; height: 22px;
  border-radius: 50%;
  background: var(--surface-3);
  color: var(--text-2);
  display: grid; place-items: center;
  font-size: 10px; font-weight: 600;
  flex-shrink: 0;
}
.cell-customer .name { font-weight: 500; }
.cell-customer .phone { color: var(--text-3); font-family: var(--font-mono); font-size: 11px; }

.match-cell { display: inline-flex; align-items: center; gap: 6px; }
.match-cell .icon {
  width: 16px; height: 16px; border-radius: 50%;
  display: grid; place-items: center;
  flex-shrink: 0;
}
.match-cell .icon.good { background: var(--good-bg); color: var(--good); }
.match-cell .icon.warn { background: var(--warn-bg); color: oklch(45% 0.13 75); }
.match-cell .icon.bad  { background: var(--bad-bg);  color: var(--bad); }
.match-cell .icon svg { width: 10px; height: 10px; }
.match-cell .src { font-size: 12px; color: var(--text-2); }

/* Variance bar inside cells */
.var-bar {
  display: inline-block;
  width: 56px; height: 4px;
  background: var(--surface-3);
  border-radius: 2px;
  position: relative;
  vertical-align: middle;
  margin-left: 6px;
}
.var-bar .fill {
  position: absolute;
  top: 0; height: 100%;
  background: var(--accent);
  border-radius: 2px;
}
.var-bar .center { position: absolute; left: 50%; top: -1px; bottom: -1px; width: 1px; background: var(--text-4); }

/* ============================================================ Drawer */

.drawer-scrim {
  position: fixed; inset: 0;
  background: oklch(20% 0.02 230 / 0.35);
  backdrop-filter: blur(2px);
  z-index: 50;
  opacity: 0;
  pointer-events: none;
  transition: opacity 200ms ease;
}
.drawer-scrim.open { opacity: 1; pointer-events: auto; }

.drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: min(960px, 92vw);
  background: var(--surface);
  border-left: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  z-index: 51;
  transform: translateX(100%);
  transition: transform 240ms cubic-bezier(0.32, 0.72, 0, 1);
  display: flex; flex-direction: column;
}
.drawer.open { transform: translateX(0); }

.drawer-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 20px;
  border-bottom: 1px solid var(--line);
  flex-shrink: 0;
}
.drawer-head .crumbs { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-3); }
.drawer-head .crumbs .sep { color: var(--text-4); }
.drawer-head .crumbs .id { font-family: var(--font-mono); color: var(--text); }
.drawer-head .actions { display: flex; gap: 6px; align-items: center; }

.drawer-body {
  flex: 1;
  overflow: auto;
  display: grid;
  grid-template-columns: 1.05fr 1fr;
}

.drawer-pane {
  padding: 20px;
  overflow: auto;
}
.drawer-pane.left { border-right: 1px solid var(--line); }
.drawer-pane h3 {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-3); margin: 0 0 10px; font-weight: 600;
  display: flex; align-items: center; gap: 8px;
}
.drawer-pane h3 .source-tag {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-2);
  background: var(--surface-2);
  border: 1px solid var(--line);
  padding: 1px 6px;
  border-radius: 3px;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 500;
}

.job-hero {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 16px;
  margin-bottom: 18px;
}
.job-hero .row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.job-hero .amt {
  font-size: 30px; font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}
.job-hero .label { font-size: 11px; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.06em; }
.job-hero .meta { display: flex; flex-wrap: wrap; gap: 10px 18px; margin-top: 12px; font-size: 12px; }
.job-hero .meta .k { color: var(--text-3); }
.job-hero .meta .v { color: var(--text); font-weight: 500; }

.kv {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: 8px 12px;
  font-size: 13px;
  margin-bottom: 16px;
}
.kv dt { color: var(--text-3); }
.kv dd { margin: 0; color: var(--text); font-weight: 500; }
.kv dd.mono { font-family: var(--font-mono); font-size: 12px; }

.line-items {
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  overflow: hidden;
  margin-bottom: 16px;
}
.line-items table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.line-items th { text-align: left; font-size: 10px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-3); font-weight: 500; padding: 8px 12px; background: var(--surface-2); border-bottom: 1px solid var(--line); }
.line-items th.num, .line-items td.num { text-align: right; font-variant-numeric: tabular-nums; }
.line-items td { padding: 8px 12px; border-bottom: 1px solid var(--line); }
.line-items tr:last-child td { border-bottom: 0; }
.line-items tfoot td { background: var(--surface-2); font-weight: 600; }

/* Transcript / AI side */

.call-card {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: 14px 16px;
  margin-bottom: 16px;
}
.call-card .top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.call-card .top .l { display: flex; align-items: center; gap: 10px; }
.call-card .top .l .icon-wrap {
  width: 32px; height: 32px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  display: grid; place-items: center;
  color: var(--accent-ink);
}
.call-card .duration { font-family: var(--font-mono); font-size: 12px; color: var(--text-2); }
.call-card .player {
  margin-top: 12px;
  display: flex; align-items: center; gap: 10px;
}
.call-card .play-btn {
  width: 28px; height: 28px;
  border-radius: 50%;
  background: var(--ink);
  color: white;
  border: 0;
  display: grid; place-items: center;
  flex-shrink: 0;
}
.call-card .progress {
  flex: 1;
  height: 4px;
  background: var(--surface-3);
  border-radius: 2px;
  position: relative;
  overflow: hidden;
}
.call-card .progress .fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--ink); border-radius: 2px; }
.call-card .progress .waveform { position: absolute; inset: 0; opacity: 0.2; pointer-events: none; }

/* AI extraction */

.ai-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  margin-bottom: 16px;
  overflow: hidden;
}
.ai-card-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 12px 14px;
  background: linear-gradient(180deg, oklch(98% 0.012 235) 0%, var(--surface) 100%);
  border-bottom: 1px solid var(--line);
}
.ai-card-head .l { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; }
.ai-card-head .badge {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 7px;
  background: var(--surface);
  border: 1px solid var(--accent-line);
  border-radius: 999px;
  font-size: 10px;
  color: var(--accent-ink);
  font-weight: 500;
  font-family: var(--font-mono);
}
.ai-card-body { padding: 14px; }

.ai-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 16px;
  margin-bottom: 12px;
}
.ai-field {
  display: flex; flex-direction: column;
  gap: 3px;
  font-size: 12.5px;
}
.ai-field .k {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-3); font-weight: 600;
}
.ai-field .v { color: var(--text); font-weight: 500; }
.ai-field .v.mono { font-family: var(--font-mono); font-size: 12px; }

.score-bar {
  height: 6px;
  background: var(--surface-3);
  border-radius: 3px;
  overflow: hidden;
  position: relative;
}
.score-bar .fill { height: 100%; background: var(--accent); }
.score-bar .fill.good { background: var(--good); }
.score-bar .fill.warn { background: var(--warn); }
.score-bar .fill.bad { background: var(--bad); }

.tags { display: flex; flex-wrap: wrap; gap: 4px; }

/* Transcript */

.transcript {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--surface);
  overflow: hidden;
}
.transcript-head {
  padding: 10px 14px;
  border-bottom: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between;
  background: var(--surface-2);
}
.transcript-head .l { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 600; }
.transcript-body { padding: 12px 14px; max-height: 360px; overflow: auto; }

.utterance {
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: 8px 10px;
  padding: 6px 0;
  font-size: 13px;
  align-items: baseline;
}
.utterance .who {
  font-size: 11px;
  font-weight: 600;
  font-family: var(--font-mono);
  color: var(--text-3);
}
.utterance .who.agent { color: var(--accent-ink); }
.utterance .who.caller { color: var(--text); }
.utterance .text { color: var(--text); line-height: 1.55; }
.utterance .ts {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-4);
  display: block;
  margin-top: 2px;
}
.utterance mark {
  background: oklch(96% 0.03 235);
  color: var(--accent-ink);
  border-bottom: 1.5px solid var(--accent);
  padding: 0 2px;
  border-radius: 2px;
}

/* Status pills */
.pill {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px; font-weight: 500;
  font-variant-numeric: tabular-nums;
  white-space: nowrap; flex-shrink: 0;
}
.pill.good { background: var(--good-bg); color: var(--good); }
.pill.warn { background: var(--warn-bg); color: oklch(45% 0.13 75); }
.pill.bad  { background: var(--bad-bg);  color: var(--bad); }
.pill.neutral { background: var(--surface-3); color: var(--text-2); }
.pill .dot { width: 5px; height: 5px; border-radius: 50%; background: currentColor; }

/* ============================================================ Misc */
.divider { height: 1px; background: var(--line); margin: 18px 0; }

.subtle { color: var(--text-3); font-size: 12px; }
.muted-link { color: var(--text-3); font-size: 12px; }
.muted-link:hover { color: var(--accent-ink); }

/* Scrollbar polish */
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb { background: oklch(88% 0.005 230); border-radius: 5px; border: 2px solid var(--bg); }
*::-webkit-scrollbar-thumb:hover { background: oklch(80% 0.005 230); }
*::-webkit-scrollbar-track { background: transparent; }

/* Table sort caret */
th .caret { display: inline-block; margin-left: 4px; opacity: 0.5; font-size: 9px; }

/* Sync banner — subtle */
.sync-banner {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  font-size: 12px;
  color: var(--text-3);
}
.sync-banner .pulse {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--good);
  position: relative;
}
.sync-banner .pulse::after {
  content: ''; position: absolute; inset: -3px;
  border-radius: 50%;
  border: 1.5px solid var(--good);
  animation: pulse 2s ease-out infinite;
  opacity: 0;
}
@keyframes pulse {
  0% { transform: scale(0.5); opacity: 0.8; }
  100% { transform: scale(1.6); opacity: 0; }
}

/* ============================================================================
   ABSENCE STATES, three kinds of nothing
   Added 2026-09-15. Design work and the full inventory behind it:
   .design-work/ (previews) and the "BND Attribution Hub" Claude Design project.

   A sweep of all nine hubs found 42 distinct null field paths, rendered
   identically as a dash. They are three different things:

     1. WITHHELD   we could compute a number and refuse, because it would be
                   false. A sentence already exists for most of these.
     2. NOT MEASURED  nothing connected to this hub records it. Not a judgement,
                   an absence of instrumentation, and the only family with a
                   remedy.
     3. NOT APPLICABLE  the row legitimately has no such value (snoozedUntil on
                   an un-snoozed item). These get NOTHING. That restraint is
                   what keeps the first two readable.

   The treatment inverts what shipped before: full text contrast, a hairline
   rule instead of a filled grey panel, and a two-word slug naming the kind. A
   grey wash with a grey rail is the language every dashboard uses for
   "disabled" and "loading", which is why the bravest writing in the product
   read as a bug.
   ========================================================================= */

.absence {
  border-top: 1px solid var(--line-strong);
  padding-top: 12px;
  max-width: 64ch;
  margin-bottom: 16px;
}
.absence-slug {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  margin-bottom: 8px;
  font-size: 11px; font-weight: 600;
  letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text-3);
}
.absence-slug .subject { font-weight: 500; letter-spacing: 0.06em; color: var(--text-4); }
.absence-slug .subject::before { content: '·'; margin-right: 8px; }

/* Full contrast. Muting this is what made it look like a loading state. */
.absence-body { margin: 0; font-size: 15px; line-height: 1.55; color: var(--text); }

/* Withheld: the footer is the arithmetic behind the refusal. */
.absence-basis {
  display: flex; gap: 18px; flex-wrap: wrap; margin-top: 10px;
  font-size: 12px; color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.absence-basis b { font-weight: 600; color: var(--text-2); }

/* Not measured: the footer is the wiring, so a client can see exactly which
   conversation closes the gap. */
.absence-wiring {
  display: grid; grid-template-columns: auto 1fr; gap: 4px 12px;
  margin: 12px 0 0; font-size: 12px; line-height: 1.5;
}
.absence-wiring dt {
  color: var(--text-4); font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase; font-size: 10.5px;
  padding-top: 1px; white-space: nowrap;
}
.absence-wiring dd { margin: 0; color: var(--text-2); }
.absence-wiring dd.absent { color: var(--text-3); }

/* KPI tile variant. A dash says "we failed to load this"; a short phrase at
   tile scale says "we decided not to publish this". */
.kpi-value.is-absent {
  font-size: 17px; font-weight: 600; line-height: 1.25;
  letter-spacing: 0; color: var(--text-2);
}
.kpi-foot .absence-why {
  color: var(--text-3);
  border-bottom: 1px solid var(--line-strong);
  padding-bottom: 1px;
}

/* Inside a table row, where there is no space for a paragraph: the cell names
   the kind, the sentence moves to a note under the table. Never $0. */
.absent-cell {
  display: inline-flex; align-items: baseline; gap: 6px;
  font-size: 12.5px; font-weight: 500; color: var(--text-3); white-space: nowrap;
}
.absent-cell .mark {
  font-size: 10px; font-weight: 700;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-4);
  border: 1px solid var(--line-strong); border-radius: 3px; padding: 1px 4px;
}

/* Coverage notes, demand-funnel.coverage.notes[] carries 2-3 on every hub.
   A list, not a paragraph: each is about a different instrument. */
.coverage { border-top: 1px solid var(--line); margin-top: 20px; padding-top: 14px; }
.coverage-head {
  font-size: 11px; font-weight: 600;
  letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--text-4); margin-bottom: 10px;
}
.coverage-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 9px; }
.coverage-list li {
  display: grid; grid-template-columns: 6px 1fr; gap: 11px;
  font-size: 13.5px; line-height: 1.5; color: var(--text-2); max-width: 72ch;
}
.coverage-list li::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  border: 1px solid var(--line-strong); margin-top: 7px;
}
.coverage-list li.has-remedy { color: var(--text); }

/* ============================================================================
   NEXT ACTIONS
   The API returns six for Advantage Air and they rendered at almost the same
   weight, so the page had six priorities, which is none, the component's own
   comment already said so. The change is rank, not colour: one action leads,
   the rest are a list. The panel also gets the heading it never had.
   ========================================================================= */

.na {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  padding: 20px 22px 18px;
  margin-bottom: 20px;
}
.na-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding-bottom: 12px; margin-bottom: 15px;
  border-bottom: 1px solid var(--line);
}
.na-head .na-title {
  font-size: 12px; font-weight: 600;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-3);
}
.na-head .na-window { font-size: 12px; color: var(--text-4); }
.na-rank {
  font-size: 11px; font-weight: 700;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--accent-ink); margin-bottom: 7px;
}
.na-lead-hl {
  font-size: 22px; line-height: 1.25; font-weight: 650;
  letter-spacing: -0.015em; color: var(--text); text-wrap: balance;
}
.na-lead-dt { font-size: 15px; line-height: 1.5; color: var(--text-2); margin-top: 7px; }
/* Every line has to be checkable, so the measurement sits under it as a
   citation rather than as more prose. */
.na-ev {
  margin-top: 9px; font-size: 12px; color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.na-more-label {
  margin: 22px 0 0; padding-top: 14px;
  border-top: 1px solid var(--line);
  font-size: 11px; font-weight: 600;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-4);
}
.na-sub { padding: 14px 0; border-bottom: 1px solid var(--line); }
.na-sub:last-child { border-bottom: 0; padding-bottom: 0; }
.na-sub-hl { font-size: 15px; font-weight: 600; line-height: 1.35; color: var(--text); }
.na-sub-dt { font-size: 14px; line-height: 1.5; color: var(--text-2); margin-top: 5px; }

/* ============================================================================
   PHONE, the layout this product did not have
   Before this block, styles.css contained ZERO @media queries across 28KB,
   and --sidebar-w: 76px was present at every width. On a 375px screen that is
   20% of the viewport spent on a vertical icon rail before any content is drawn.

   The audience is contractors, and contractors are on phones.
   ========================================================================= */

@media (max-width: 860px) {
  /* Two-column content grids collapse before the shell does, at this width
     the 280px rail has already stopped being a rail. */
  .recon-body { grid-template-columns: 1fr; }
  .drawer-body { grid-template-columns: 1fr; }
  .ai-grid { grid-template-columns: 1fr; }
  .client-switch { min-width: 0; }
  .search-input { min-width: 0; }
}

@media (max-width: 720px) {
  /* The rail is a desktop idiom. The same nav belongs at the bottom of a
     phone, in the thumb's reach, and app-shell.jsx already carries a short
     label on every item (Results, Jobs, Calls, Customers, Front desk, Alerts)
     and already drops the tabs a hub cannot measure, so the bar holds four
     items on hubs with no field-service system and six on those with one. */
  .app {
    /* minmax(0, 1fr), not 1fr. A grid track defaults to minmax(auto, 1fr) and
       therefore refuses to shrink below its content's min-content width, the
       topbar's search field and range buttons have a min-content of 680px, so
       every track in this grid became 680px inside a 375px viewport. `.app`
       also sets overflow:hidden, so the excess was CLIPPED rather than
       scrollable: a third of the page was simply unreachable on a phone.
       Caught by booting the real bundle at 375px; hand-built markup had not
       reproduced it. */
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: var(--topbar-h) 1fr auto;
    grid-template-areas: "topbar" "main" "sidebar";
  }
  /* Same rule one level down: a grid ITEM also defaults to min-width:auto. */
  .topbar, .main, .sidebar { min-width: 0; }
  .logo-cell { display: none; }

  .sidebar {
    flex-direction: row;
    border-right: 0;
    border-top: 1px solid var(--line);
    padding: 0;
    gap: 0;
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  .sidebar-icon {
    flex: 1 1 0; width: auto; min-width: 0;
    padding: 9px 2px 8px;
    min-height: 52px;              /* 44px target plus the label */
    border-radius: 0;
    justify-content: center;
  }
  /* The desktop active state is a filled dark pill, which is far too heavy
     repeated across a bottom bar. State reads from the cap and the weight, so
     it survives a greyscale screenshot into a client report. */
  .sidebar-icon.active { background: transparent; color: var(--accent-ink); font-weight: 600; }
  .sidebar-icon.active::before {
    content: ''; position: absolute; top: 0;
    width: 28px; height: 2px; border-radius: 0 0 2px 2px;
    background: var(--accent-ink);
  }
  .sidebar-icon { position: relative; }
  .sidebar-icon:hover { background: transparent; }
  .sidebar-spacer { display: none; }
  /* Settings is disabled and unbuilt; it does not earn a sixth of a phone nav. */
  .sidebar-icon[disabled] { display: none; }

  .main { padding-bottom: 8px; }
  .client-popover { width: min(320px, calc(100vw - 32px)); }

  /* The topbar carries seven children and a 16px gap, which is 96px of gap
     alone at 375px, every control was crushed to 14-35px and none was
     usable. Two of them do not earn a phone: the global search is a
     keyboard feature and every tab that needs one has its own, and the user
     chip repeats the client name the switcher beside it already shows. */
  /* A segmented control that does not fit becomes a scrolling strip rather
     than wrapping into two broken rows, `.tabs` has one border and one radius
     around the whole group, so a wrap splits the frame down the middle. */
  .section-head { flex-wrap: wrap; gap: 8px; }
  .tabs {
    overflow-x: auto;
    max-width: 100%;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .tabs::-webkit-scrollbar { display: none; }
  .tabs button { flex: none; white-space: nowrap; }

  /* `.name` is a nowrap + ellipsis container, which is right in a table column
     and wrong in a record: it clipped the REPEAT badge off the end of the
     customer's name entirely. In the record layout there is a whole row to
     use, so let it wrap and show the badge. */
  .cell-customer, .cell-customer > div { min-width: 0; }
  .cell-customer .name { white-space: normal; overflow: visible; }

  /* The filter toolbar is `justify-content: space-between` with a 240px search
     beside it, so at 375px the chip group was squeezed into a ~120px column and
     every chip wrapped onto two or three lines beside a large empty gap. The
     two halves stack instead, and the search takes the width it needs. */
  .jobs-toolbar { flex-direction: column; align-items: stretch; }
  .jobs-toolbar input { width: 100% !important; }
  /* The page head puts a right-aligned note beside the title; at this width it
     becomes a narrow ragged column, so it goes under the title. */
  .page-head { flex-direction: column; gap: 10px; }
  .head-actions { flex-wrap: wrap; }

  .topbar { gap: 8px; padding: 0 12px; }
  .topbar .search-input { display: none; }
  .topbar .user-chip { display: none; }
  /* What is left is identity and the window, which is what a phone needs. */
  .client-switch { min-width: 0; flex: 0 1 auto; }
  .date-range { flex: none; }

  /* Four numbers in two columns instead of one column of very tall tiles. */
  .kpi-grid { grid-template-columns: 1fr 1fr; }
  .kpi { padding: 13px 14px 12px; gap: 6px; }
  .kpi-label { font-size: 11.5px; }
  .kpi-value { font-size: 22px; }
  .kpi-value.is-absent { font-size: 15px; }
  /* With an odd number of tiles the last one would sit alone beside an empty
     track, and .kpi-grid paints its gaps with --line, so the dead cell shows as
     a grey block. The orphan takes the whole row instead. */
  .kpi:last-child:nth-child(odd) { grid-column: 1 / -1; }

  .na { padding: 16px 16px 14px; border-radius: var(--r-lg); }
  .na-lead-hl { font-size: 20px; }
  .na-lead-dt { font-size: 14.5px; }

  .absence { max-width: none; }
  .absence-slug { display: block; }
  .absence-slug .subject { display: block; margin-top: 3px; }
  .absence-slug .subject::before { content: none; }
  .absence-wiring { grid-template-columns: 1fr; gap: 2px; }
  .absence-wiring dt { margin-top: 8px; }
  .coverage-list li { max-width: none; }

  /* ---- tables become records -------------------------------------------
     The Calls table is eleven columns, about 34px each at 375px. Horizontal
     scroll is not a rescue: it hides Summary, the only column carrying
     anything a contractor would read. Nothing is dropped; the cells are
     re-ordered by what they are. The column order is fixed in tabs.jsx, and
     data-label on each cell is what makes the head readable without one. */
  table.jobs, table.jobs tbody { display: block; width: 100%; }
  table.jobs thead { display: none; }
  table.jobs tbody tr {
    display: flex; flex-wrap: wrap; align-items: baseline;
    width: 100%; box-sizing: border-box;
    gap: 5px 8px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-lg);
    padding: 12px 14px;
    margin-bottom: 10px;
  }
  table.jobs tbody td {
    display: block; border: 0; padding: 0;
    /* A flex item defaults to min-width:auto and will not shrink below its
       content, and several cells carry an inline max-width sized for a desktop
       column. Both have to be overridden or the card overflows the screen. */
    min-width: 0;
    max-width: 100% !important;
    /* table.jobs td is nowrap so columns keep their shape on desktop. In a
       record layout that is what clipped every call summary mid-sentence —
       the one column worth reading on a phone. */
    white-space: normal;
  }
  /* A cell that is empty in a record layout leaves a stray gap. This catches
     a genuinely empty <td>; one holding an empty <span> cannot be detected in
     CSS, so the chip run uses a tight row gap to keep the damage to a few px. */
  table.jobs tbody td:empty { display: none; }
  table.jobs tbody td[data-col="tag"]:has(> span:empty) { display: none; }
  table.jobs tbody td[data-col="who"]     { order: 1; flex: 1 1 auto; font-size: 15px; }
  table.jobs tbody td[data-col="when"]    { order: 2; margin-left: auto; font-size: 11px; color: var(--text-3); }
  table.jobs tbody td[data-col="meta"]    { order: 3; flex-basis: 100%; font-size: 12px; color: var(--text-3); }
  table.jobs tbody td[data-col="body"]    { order: 5; flex-basis: 100%; font-size: 14px; line-height: 1.5; color: var(--text-2); }
  table.jobs tbody td[data-col="tag"]     { order: 4; }
  table.jobs tbody td[data-col="num"]     { order: 3; font-variant-numeric: tabular-nums; }
  /* Leads tab: the editable controls sit under what the lead asked for, the
     note full width at the bottom, and the list scrolls with the page. */
  table.jobs tbody td[data-col="edit"]    { order: 6; }
  table.jobs tbody td[data-col="note"]    { order: 7; flex-basis: 100%; }
  .page .leads-scroll { max-height: none; overflow: visible; }
  /* The loading and empty rows are a single colSpan cell. */
  table.jobs tbody td[colspan] { flex-basis: 100%; }
  table.jobs tbody tr:hover { background: var(--surface); }

  /* tfoot was left behind: with the table and tbody switched to block, the
     totals row kept table-footer-group layout and its own intrinsic width,
     so it alone ran 480px wide inside a 375px viewport. It carries a label
     and a run of numbers, which is a definition list on a phone. */
  table.jobs tfoot { display: block; width: 100%; }
  table.jobs tfoot tr {
    display: flex; flex-wrap: wrap; align-items: baseline;
    gap: 6px 14px;
    width: 100%; box-sizing: border-box;
    padding: 12px 14px 2px;
  }
  table.jobs tfoot td {
    display: block; border: 0; padding: 0;
    min-width: 0; max-width: 100% !important;
    white-space: normal;
    font-variant-numeric: tabular-nums;
  }
  table.jobs tfoot td:first-child { flex-basis: 100%; color: var(--text-3); }
}

/* Leads tab list: its own scroll on desktop so the filters stay in view. The
   phone layout above turns this off. */
.leads-scroll { max-height: 72vh; overflow: auto; }

/* =========================================================================
   Google tab (google-panel.jsx), 2026-09-30. Business Profile, rankings,
   map grids and AI answers from the Den, plus the plan/lifetime block on
   Results. Map colours follow one scale everywhere on the tab: 1-3 good,
   4-10 accent, 11-20 warn, not found grey. "Not found" is never a number.
   ========================================================================= */
.g-section { margin-bottom: 32px; }
.g-section-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 16px; flex-wrap: wrap; margin-bottom: 12px;
}
.g-section-head h2 { font-size: 16px; font-weight: 600; margin: 0; letter-spacing: -0.01em; }
.g-section-head p { font-size: 13px; color: var(--text-3); margin: 3px 0 0; max-width: 72ch; }
.g-kpis { margin-bottom: 12px; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
/* The shared grid paints its 1px gaps with a grey background, so a row that
   wraps short shows the rest of the row as a grey slab. Here each tile draws
   its own hairline instead and the leftover space stays white. */
.g-kpis { background: var(--surface); }
.g-kpis .kpi { box-shadow: 0 0 0 1px var(--line); }
.g-kpis .kpi-value .unit { font-size: 15px; }
.g-flat { border: 0; border-radius: 0; margin: 0; }
.kpi-value.g-good { color: var(--good); }
.g-empty { padding: 20px; font-size: 13px; color: var(--text-2); }
.g-dim { color: var(--text-3); }

.g-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 12px; }
.g-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 16px 18px; min-width: 0;
}
.g-card h3 { font-size: 13px; font-weight: 600; margin: 0 0 12px; }

.g-bars { display: flex; flex-direction: column; gap: 7px; }
.g-bar-row { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) 52px; align-items: center; gap: 10px; font-size: 12.5px; }
.g-bar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-2); }
.g-bar-track { height: 8px; background: var(--surface-3); border-radius: 4px; overflow: hidden; }
.g-bar-track > span { display: block; height: 100%; background: var(--accent); border-radius: 4px; }
.g-bar-val { text-align: right; color: var(--text-2); }
.g-bar-row.you .g-bar-label { color: var(--text-1); font-weight: 600; }
.g-bar-row.you .g-bar-track > span { background: var(--ink); }

.g-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.g-table th { text-align: left; font-size: 11px; font-weight: 500; color: var(--text-3); padding: 0 0 6px; }
.g-table th.num, .g-table td.num { text-align: right; }
.g-table td { padding: 7px 0; border-top: 1px solid var(--line); }
.g-table td + td, .g-table th + th { padding-left: 12px; }

.g-table-card { margin-top: 4px; }
.g-toolbar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  flex-wrap: wrap; padding: 10px 14px; border-bottom: 1px solid var(--line);
}
.g-toolbar-right { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.g-chips { display: flex; gap: 6px; flex-wrap: wrap; }
.g-chips .chip { cursor: pointer; border: 1px solid var(--line); }
.g-search {
  border: 1px solid var(--line); border-radius: var(--r-md); padding: 6px 10px;
  font: inherit; font-size: 13px; min-width: 0; width: 220px; background: var(--surface);
}
.g-scroll { overflow-x: auto; }
table.g-kw tbody tr { cursor: default; }
.g-kw-name { font-weight: 500; }
.g-page { max-width: 220px; overflow: hidden; text-overflow: ellipsis; }
.g-more { padding: 10px 14px; border-top: 1px solid var(--line); }

.g-rank {
  display: inline-block; min-width: 26px; padding: 1px 6px; border-radius: var(--r-sm);
  text-align: center; font-weight: 600; font-variant-numeric: tabular-nums;
}
.g-rank.top { background: var(--good-bg); color: var(--good); }
.g-rank.page1 { background: var(--accent-bg); color: var(--accent-ink); }
.g-rank.low { background: var(--warn-bg); color: oklch(45% 0.13 75); }
.g-move { font-size: 10.5px; margin-left: 5px; font-weight: 600; }
.g-move.up { color: var(--good); }
.g-move.down { color: var(--bad); }

.g-grids { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; margin-bottom: 12px; }
.g-grid { display: grid; gap: 3px; max-width: 360px; }
.g-cell {
  aspect-ratio: 1; display: grid; place-items: center; border-radius: 4px;
  font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums;
}
.g-cell.skip { background: transparent; border: 1px dashed var(--line); }
.g-legend { display: flex; gap: 12px; font-size: 11.5px; color: var(--text-3); flex-wrap: wrap; }
.g-legend span { display: inline-flex; align-items: center; gap: 5px; }
.g-legend i { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }

.g-map-card { padding: 0; overflow: hidden; margin-bottom: 12px; }
.g-map-pick {
  padding: 12px 14px; border-bottom: 1px solid var(--line);
  display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: center;
}
.g-map-pick .tabs { width: max-content; max-width: 100%; overflow-x: auto; }
.g-map-pick .tabs button { white-space: nowrap; }
.g-map-modes { margin-left: auto; display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.g-kw-select { display: none; }
.g-toggle { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 500; color: var(--text-2); cursor: pointer; }
.g-toggle input { accent-color: var(--ink); }
.g-far {
  font-size: 12px; line-height: 1.45; color: oklch(40% 0.1 75);
  background: var(--warn-bg); border: 1px solid oklch(85% 0.07 75);
  border-radius: var(--r-md); padding: 8px 10px;
}
.g-moves-row { display: flex; gap: 14px; margin-top: 6px; font-size: 13px; color: var(--text-2); }
.g-moves-row b { font-size: 20px; font-weight: 600; color: var(--text-1); margin-right: 3px; }
.g-moves-row .up b { color: var(--good); }
.g-moves-row .down b { color: var(--bad); }
.g-trend { display: block; width: 100%; height: 40px; margin-top: 6px; }
.g-trend-axis { display: flex; justify-content: space-between; gap: 8px; font-size: 10.5px; color: var(--text-4); }
.kpi-value.g-money { font-size: 20px; margin: 4px 0 6px; }
.g-map-body { display: grid; grid-template-columns: minmax(0, 1fr) 320px; }
.g-map-wrap { position: relative; border-right: 1px solid var(--line); min-width: 0; }
.g-map-wrap .g-grid { margin: 16px; }
.g-map-title {
  position: absolute; z-index: 500; top: 10px; left: 56px; margin: 0;
  background: var(--surface); padding: 4px 10px; border-radius: var(--r-md);
  box-shadow: var(--shadow-sm); font-size: 13px;
}
.g-map { height: 480px; background: #eef1f3; }
.g-map .leaflet-tile-pane { filter: saturate(.55) contrast(.95); }
.g-map.leaflet-container { font-family: var(--font-sans); }
.g-map .leaflet-tooltip { font-size: 12px; line-height: 1.45; border-radius: 6px; }
.g-tip-dim { color: var(--text-3); }
.g-pin {
  width: 30px; height: 30px; border-radius: 50%; display: grid; place-items: center;
  font: 700 12px var(--font-mono); border: 2px solid #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .35);
}
.g-pin.sm { width: 24px; height: 24px; font-size: 10px; border-width: 1.5px; }
.g-biz {
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  background: var(--ink); color: #fff; font-size: 13px; border: 2px solid #fff;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .4);
}
.g-map-stats { padding: 0 0 14px; display: flex; flex-direction: column; }
.g-map-stats .g-far { margin: 14px 18px 0; }
.g-ms-sec { padding: 16px 18px; border-bottom: 1px solid var(--line); display: flex; flex-direction: column; gap: 10px; }
.g-ms-kpis { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.g-ms-label { font-size: 11px; color: var(--text-3); font-weight: 500; }
.g-ms-num { font-size: 22px; font-weight: 600; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; margin-top: 2px; white-space: nowrap; }
.g-ms-unit { font-size: 12px; font-weight: 500; color: var(--text-3); }
.g-ms-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; font-size: 12.5px; font-weight: 600; color: var(--text-1); }
.g-ms-head .g-dim { font-weight: 400; font-size: 11.5px; }
.g-ms-big { font-size: 22px; font-weight: 600; letter-spacing: -0.02em; font-variant-numeric: tabular-nums; }
.g-ms-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.g-ms-row { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; font-size: 13px; }
.g-ms-row .num { flex: none; font-weight: 500; }
.g-ms-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text-2); }
.g-ms-sub { display: flex; align-items: center; gap: 8px; margin-top: 4px; font-size: 11px; }
.g-ms-bar { flex: 1; height: 4px; background: var(--surface-3); border-radius: 2px; overflow: hidden; }
.g-ms-bar > span { display: block; height: 100%; background: var(--accent); border-radius: 2px; }
.g-ms-list li.you .g-ms-name { color: var(--text-1); font-weight: 600; }
.g-ms-list li.you .g-ms-bar > span { background: var(--ink); }
.g-ms-foot { font-size: 11.5px; color: var(--text-3); margin: 0; padding: 0 18px; }
.g-ms-sec .g-ms-foot { padding: 0; }
.g-map-stats > .g-ms-foot { padding-top: 12px; }
.g-map-stats .kpi-value { font-size: 24px; margin-top: 4px; }
.g-map-stats .kpi-value .unit { font-size: 13px; }
.g-small { font-size: 12px; }
.g-leaders { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; }
.g-leaders li { display: flex; justify-content: space-between; gap: 10px; color: var(--text-2); }
.g-leaders li span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.g-leaders li .num { flex: none; }
.g-leaders li.you { color: var(--text-1); font-weight: 600; }
.g-account { margin-top: 24px; }
/* Lifetime results and the team note sit side by side on a wide screen. Stacked,
   each was a full-width card holding a short block of text, and the note's
   80ch cap left two thirds of its card empty. */
.g-account.g-two {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  gap: 16px;
  align-items: stretch;
}
.g-account.g-two > .recon { margin: 0; }
@media (max-width: 960px) {
  .g-account.g-two { grid-template-columns: minmax(0, 1fr); }
}
.g-note { font-size: 12.5px; color: var(--text-3); margin: 0; padding: 12px 20px 16px; max-width: 80ch; }
.g-note-top { padding-bottom: 4px; color: var(--text-2); }
.g-team-note { font-size: 14px; line-height: 1.6; color: var(--text-1); max-width: none; padding: 14px 20px 18px; }

@media (max-width: 720px) {
  .g-search, .g-toolbar-right { width: 100%; }
  .g-kpis { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .g-kpis .kpi { padding: 14px 14px 12px; }
  .g-kpis .kpi-value { font-size: 22px; }
  /* Eleven towns wrap to five rows on a phone. One swipeable row instead. */
  .g-chips { flex-wrap: nowrap; overflow-x: auto; width: 100%; padding-bottom: 2px; }
  .g-chips .chip { flex: none; }
  /* The keyword table as records, like the Calls table: search on top, then
     each measure with its own label, since the header row is hidden. */
  .g-table-card { background: transparent; border: 0; }
  .g-table-card .g-toolbar { padding: 0 0 10px; border: 0; }
  .g-table-card .g-more { border: 0; padding: 0; }
  table.jobs.g-kw tbody td { height: auto; font-size: 13px; }
  table.jobs.g-kw tbody td.num { text-align: left; }
  table.jobs.g-kw td.g-kw-name { flex-basis: 100%; font-size: 14.5px; font-weight: 600; }
  table.jobs.g-kw td.g-kw-town { flex-basis: 100%; font-size: 12px; margin: -4px 0 4px; }
  table.jobs.g-kw td[data-l] { flex: 0 0 auto; margin-right: 8px; }
  table.jobs.g-kw td[data-l]::before {
    content: attr(data-l); display: block;
    font-size: 10.5px; font-weight: 500; color: var(--text-4);
    text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 2px;
  }
  table.jobs.g-kw td.g-page { flex-basis: 100%; }
  .g-grids, .g-split { grid-template-columns: minmax(0, 1fr); }
  .g-map-body { grid-template-columns: minmax(0, 1fr); }
  .g-map-wrap { border-right: 0; border-bottom: 1px solid var(--line); }
  .g-map { height: 360px; }
  .g-map-modes { margin-left: 0; }
  .g-ms-sec { padding: 14px 16px; }
  .g-kw-tabs { display: none; }
  .g-kw-select {
    display: block; width: 100%; font: inherit; font-size: 14px;
    padding: 8px 10px; border: 1px solid var(--line); border-radius: var(--r-md);
    background: var(--surface); color: var(--text-1);
  }
  .g-bar-row { grid-template-columns: minmax(0, 1fr) 70px 44px; }
}
