@charset "UTF-8";
/* ============================================================
   Funnel Opt-in Tracker — monochrome instrument panel
   ============================================================ */
/* ── Theming ──────────────────────────────────────────────────────────────────
   :root IS dark — the default, and what an anonymous / signed-out visitor always
   gets. Light is an opt-in override keyed off `<html data-theme="light">`, stamped
   by the inline <head> script in index.html (before first paint, so a reload never
   flashes) and toggled from the rail. Signing out clears the key → back to dark.

   ⚠️ Every colour a rule needs MUST come from a token below, in BOTH blocks. A
   literal hex/rgba in a rule is a dark-only value that silently survives the theme
   flip — that's why the "on accent fill" / wash / hairline tokens exist rather than
   inline rgba(255,255,255,…): white-on-white is invisible, and nothing warns you. */
:root {
  /* Tell the browser which way native popups (select dropdowns, confirm() dialogs,
     date inputs, scrollbars, autofill) should render — the light block flips it. */
  color-scheme: dark;
  /* Black-and-white base, colored accents. The canvas, surfaces and BUTTONS are
     pure neutral grays (mono); color is reserved for accents that carry meaning —
     white for active/key-metric, green for cash, red for danger, violet tag. */
  --bg:        #0a0a0a;   /* near-black canvas */
  --surface:   #161616;   /* card */
  --surface-2: #1e1e1e;   /* elevated (card header / chips) */
  --line:      #2e2e2e;   /* hairline */
  --line-soft: #202020;   /* faint internal divider */
  --ink:       #ffffff;   /* white — headings + headline numbers */
  --text:      #d6d6d6;   /* body */
  --muted:     #8a8a8a;   /* secondary text */
  --faint:     #5a5a5a;   /* eyebrow labels, faintest */

  --accent:    #ffffff;   /* white accent — active nav, key metrics, focus, links */
  --accent-dim:#cfcfcf;   /* dimmed white */
  --accent-soft:rgba(255,255,255,0.10);
  --accent-ink:#0a0a0a;   /* dark text on white fills */
  --accent-edge:rgba(255,255,255,0.55);  /* the lit top edge of the one accent tile */
  --violet:    #c4b5fd;   /* masterclass tag */
  --violet-line:rgba(196,181,253,0.35);
  --good:      #58cc9a;   /* positive — cash / ROAS / best-in-column (green) */
  --warn:      #e5645e;   /* error / danger (red) */
  --link:      #e0e0e0;   /* inline links (bright neutral) */

  /* Text/fills that sit ON an accent-filled surface (white pill in dark, near-black
     pill in light) — they invert with the theme, opposite to --text & friends. */
  --on-accent-2:     rgba(10,10,10,0.62); /* secondary text on an accent fill */
  --on-accent-3:     rgba(10,10,10,0.5);  /* faintest text on an accent fill */
  --on-accent-strong:#3a3a3a;             /* badge text on an accent fill */
  --on-accent-wash:  rgba(0,0,0,0.06);    /* badge fill on an accent fill */
  --on-accent-line:  rgba(0,0,0,0.14);    /* hairline / disc on an accent fill */

  /* Translucent neutrals for the pill controls — ink-coloured, so they invert. */
  --wash-1: rgba(255,255,255,0.05);  /* button hover fill */
  --wash-2: rgba(255,255,255,0.08);  /* disc fill / data-bar */
  --wash-3: rgba(255,255,255,0.10);  /* pressed segment fill */
  --hair-1: rgba(255,255,255,0.16);  /* resting pill border */
  --hair-2: rgba(255,255,255,0.20);  /* date-picker control border */
  --hair-3: rgba(255,255,255,0.30);  /* hovered pill border */
  --hair-4: rgba(255,255,255,0.40);  /* pressed segment border */

  /* Speed-to-lead buckets, best → worst. A ramp, not five arbitrary hues: the bar is an
     ordered distribution, so the colour has to carry the order or it's just decoration. */
  --spd-1: #58cc9a;  --spd-2: #93cf85;  --spd-3: #cfc177;  --spd-4: #e0975c;  --spd-5: #e5645e;

  --menu-bg:  #1c1e22;    /* native <select> popup */
  --menu-ink: #dadbdf;
  --pop-bg:   rgba(24,24,24,0.96);   /* hover popovers (grade split / sales detail) */
  --grain-dot: oklch(1 0 0);         /* film-grain speck */
  --solid-hover: #d6d6d6; /* .btn.solid / .dr-quick-btn hover fill */
  --era-bg:  #d4d7dd;     /* webinar-list era divider pill */
  --era-ink: #14161a;

  --rail: 210px;          /* left navigation rail width */
  --shadow-1: 0 1px 2px rgba(0,0,0,0.5);
  --shadow-2: 0 10px 30px rgba(0,0,0,0.6);
  --shadow-up: 0 -6px 22px rgba(0,0,0,0.45);   /* mobile nav bar, casts upward */
  --shadow-pop: 0 4px 14px rgba(0,0,0,0.35);   /* small lift (chips, export rows) */

  --r-sm: 6px; --r-md: 9px; --r-lg: 13px;

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

  --display: "Outfit", system-ui, -apple-system, sans-serif;    /* geometric-grotesque display + body */
  --serif:   "Outfit", system-ui, sans-serif;                   /* no serif — fold into Outfit */
  --font: var(--display);
  --mono: "Geist Mono", "JetBrains Mono", ui-monospace, "SF Mono", monospace;

  --ease: cubic-bezier(0.16, 1, 0.3, 1);  /* expo-out */
}

/* ── Light theme ──────────────────────────────────────────────────────────────
   Same instrument panel, inverted: ink-on-paper instead of white-on-black. Only
   the colour tokens move — no rule, no geometry, no font changes below this block.
   The greens/reds/violet are DARKENED, not reused: #58cc9a cash on white is ~1.9:1
   contrast (unreadable), so each semantic hue gets a light-surface variant. */
:root[data-theme="light"] {
  color-scheme: light;
  --bg:        #f5f6f8;   /* soft paper canvas — not pure white, so cards read as cards */
  --surface:   #ffffff;   /* card */
  --surface-2: #eff1f4;   /* elevated (card header / chips) */
  --line:      #d5d9e0;   /* hairline */
  --line-soft: #e6e9ee;   /* faint internal divider */
  --ink:       #0d0f12;   /* near-black — headings + headline numbers */
  --text:      #363b43;   /* body */
  --muted:     #656b75;   /* secondary text */
  --faint:     #8f959f;   /* eyebrow labels, faintest */

  --accent:    #0d0f12;   /* the accent inverts too — active nav, key metrics, focus */
  --accent-dim:#3a3f47;
  --accent-soft:rgba(13,15,18,0.07);
  --accent-ink:#ffffff;   /* light text on the near-black fills */
  --accent-edge:rgba(13,15,18,0.5);
  --violet:    #6d28d9;
  --violet-line:rgba(109,40,217,0.32);
  --good:      #0f8a5f;
  --warn:      #c62f28;
  --link:      #1f2937;

  --on-accent-2:     rgba(255,255,255,0.68);
  --on-accent-3:     rgba(255,255,255,0.52);
  --on-accent-strong:#d2d4d8;
  --on-accent-wash:  rgba(255,255,255,0.12);
  --on-accent-line:  rgba(255,255,255,0.22);

  --wash-1: rgba(13,15,18,0.045);
  --wash-2: rgba(13,15,18,0.06);
  --wash-3: rgba(13,15,18,0.08);
  --hair-1: rgba(13,15,18,0.16);
  --hair-2: rgba(13,15,18,0.18);
  --hair-3: rgba(13,15,18,0.30);
  --hair-4: rgba(13,15,18,0.42);

  /* Darkened for paper, same ramp order — the dark values are 1.9:1 on white. */
  --spd-1: #0f8a5f;  --spd-2: #5c9440;  --spd-3: #9a7d1e;  --spd-4: #c2703a;  --spd-5: #c62f28;

  --menu-bg:  #ffffff;
  --menu-ink: #24282e;
  --pop-bg:   rgba(255,255,255,0.97);
  --grain-dot: oklch(0 0 0);
  --solid-hover: #2b3038;
  --era-bg:  #14161a;
  --era-ink: #f0f1f4;

  /* Shadows carry the depth that the dark theme got from contrast, so they're far
     softer here — a 0.5-alpha black drop on paper reads as dirt, not elevation. */
  --shadow-1: 0 1px 2px rgba(15,18,25,0.07);
  --shadow-2: 0 10px 30px rgba(15,18,25,0.13);
  --shadow-up: 0 -6px 22px rgba(15,18,25,0.10);
  --shadow-pop: 0 4px 14px rgba(15,18,25,0.14);
}
/* The mark is a white-alpha PNG — on paper it'd be an invisible rectangle. Inverting
   the alpha mask paints it near-black; there is no colour in the file to distort. */
:root[data-theme="light"] .rail-logo,
:root[data-theme="light"] .brand-logo { filter: invert(1); }
/* Brightness-up lightens a dark header but washes out a light one — flip the sign. */
:root[data-theme="light"] .wb-head:hover { filter: brightness(0.975); }

* { box-sizing: border-box; margin: 0; }
/* native select dropdown items — force dark so white text never lands on a white menu */
select option, select optgroup { background: var(--menu-bg); color: var(--menu-ink); }
/* Reserve the scrollbar gutter always, so expanding/loading a card (page grows
   past the viewport → scrollbar appears) doesn't shift the layout / jitter the rail. */
html { -webkit-text-size-adjust: 100%; scrollbar-gutter: stable; }
body {
  font-family: var(--font);
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
  letter-spacing: -0.011em;
  min-height: 100dvh;
  padding: var(--space-6) clamp(var(--space-5), 4vw, var(--space-9)) var(--space-9);
  padding-left: calc(var(--rail) + clamp(var(--space-5), 3vw, var(--space-8)));
  position: relative;
}

/* faint film-grain texture so the dark surface isn't flat */
.grain {
  position: fixed; inset: 0; pointer-events: none; z-index: 0; opacity: 0.035;
  background-image: radial-gradient(var(--grain-dot) 0.5px, transparent 0.5px);
  background-size: 3px 3px;
}
body > * { position: relative; z-index: 1; }

::selection { background: var(--accent); color: var(--accent-ink); }

/* ── Mobile nav: burger, scrim, drawer close ──────────────────────────────────
   All three are display:none until the ≤640px block turns them on — above that the
   rail is simply always on screen and none of this exists.
   ⚠️ z-index budget: burger 100 sits above the topbar (60) and content, but BELOW the
   add-webinar drawer (120), the mobile date popover (200) and the export modal (300),
   so it can never float on top of an open dialog. That's also why it doesn't double as
   the close button — at z-index 100 it would be buried under its own scrim. The drawer
   carries its own ✕ instead, and the burger just fades out while open. */
.nav-burger {
  display: none; position: fixed; top: 10px; right: 12px; z-index: 100;
  width: 40px; height: 40px; place-items: center;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 9999px;
  color: var(--ink); cursor: pointer; box-shadow: var(--shadow-1);
  transition: border-color .16s var(--ease), opacity .24s var(--ease);
}
.nav-burger:hover { border-color: var(--faint); }
.nav-burger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
body.nav-open .nav-burger { opacity: 0; pointer-events: none; }
.nav-burger-box { position: relative; display: block; width: 16px; height: 11px; }
.nav-burger-box i {
  position: absolute; left: 0; width: 100%; height: 1.5px;
  border-radius: 2px; background: currentColor;
}
.nav-burger-box i:nth-child(1) { top: 0; }
.nav-burger-box i:nth-child(2) { top: 4.75px; }
.nav-burger-box i:nth-child(3) { top: 9.5px; }

.nav-scrim {
  display: none; position: fixed; inset: 0; z-index: 190;
  background: rgba(0,0,0,0.55);
  opacity: 0; pointer-events: none; transition: opacity .3s var(--ease);
}
body.nav-open .nav-scrim { opacity: 1; pointer-events: auto; }

/* Sits in .rail-brand next to the logo, so closing is where the drawer is — the
   burger is across the screen at the top right and covered by the scrim. */
.nav-close {
  display: none; margin-left: auto; place-items: center;
  width: 30px; height: 30px; flex: none;
  background: transparent; border: 1px solid var(--line); border-radius: 9999px;
  color: var(--muted); font-size: 0.82rem; line-height: 1; cursor: pointer;
  transition: color .14s var(--ease), border-color .14s var(--ease);
}
.nav-close:hover { color: var(--ink); border-color: var(--faint); }
.nav-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── Left navigation rail ─────────────────────────────── */
.rail {
  position: fixed; top: 0; left: 0; bottom: 0; width: var(--rail); z-index: 90;
  display: flex; flex-direction: column;
  padding: var(--space-6) var(--space-4) var(--space-5);
  background: linear-gradient(180deg, var(--surface) 0%, var(--bg) 100%);
  border-right: 1px solid var(--line);
}
.rail-brand { display: flex; align-items: center; gap: var(--space-3); padding: 0 var(--space-3) var(--space-6); }
.rail-logo { height: 26px; width: auto; display: block; }
.rail-eyebrow {
  font-family: var(--mono); font-size: 0.56rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.14em; color: var(--faint);
  padding: 0 var(--space-3) var(--space-3);
}
.rail-nav { display: flex; flex-direction: column; gap: 2px; }
.rail-item {
  position: relative; display: flex; align-items: center; gap: 11px;
  width: 100%; text-align: left; cursor: pointer;
  padding: 9px 12px; border: 1px solid transparent; border-radius: var(--r-md);
  background: transparent; color: var(--muted);
  font-family: var(--font); font-weight: 500; font-size: 0.88rem; letter-spacing: -0.01em;
  transition: color .16s var(--ease), background .16s var(--ease);
}
.rail-item:hover { color: var(--ink); background: var(--surface-2); }
.rail-item.is-active { color: var(--ink); background: var(--accent-soft); }
.rail-item.is-active::before {
  content: ""; position: absolute; left: -1px; top: 7px; bottom: 7px;
  width: 3px; border-radius: 0 3px 3px 0; background: var(--accent);
}
.rail-item:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.rail-ico { width: 18px; text-align: center; font-size: 1rem; line-height: 1; opacity: .85; flex-shrink: 0; }
.rail-item.is-active .rail-ico { opacity: 1; }
.rail-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail-sep { height: 1px; background: var(--line-soft); margin: var(--space-4) var(--space-3); }
.rail-foot { margin-top: auto; display: flex; flex-direction: column; gap: var(--space-3); padding-top: var(--space-5); }
.rail-foot .btn { justify-content: flex-start; }

/* Icon-only rail on narrower screens — reclaim table width. Bounded at 641px: below
   that the rail goes off-canvas behind the burger and gets its labels back, so these
   stripping rules must not reach it (they'd fight the drawer block rule for rule). */
@media (min-width: 641px) and (max-width: 1000px) {
  :root { --rail: 62px; }
  .rail { padding: var(--space-6) 10px var(--space-5); align-items: stretch; }
  .rail-brand { justify-content: center; padding: 0 0 var(--space-6); }
  .rail-eyebrow { display: none; }
  .rail-label { display: none; }
  .rail-item { justify-content: center; padding: 11px 0; gap: 0; }
  .rail-item.is-active::before { left: -10px; }
  .rail-foot .btn { justify-content: center; }
  .rail-foot .btn .btn-label { display: none; }
  /* The lockup is a horizontal mark + "IMA ACCELERATOR" (1521×317) — at 26px tall that's
     125px, hanging 31px past a 62px rail, so what actually showed was the MIDDLE OF THE
     WORDMARK with the mark itself clipped off the left edge. Swap in the mark alone
     (the same artwork, cropped to its ink bbox). `content` re-points the <img>; the alt
     text and the light-mode invert on .rail-logo both still apply. */
  .rail-logo { content: url("/ima-mark-white.png"); height: 24px; }
  /* NB: the identity chip's icon-only overrides can't live here — .whoami-* is defined
     further down the file and would win on source order (that's what left the avatar
     4.5px off-centre). They sit next to those rules instead; search "icon-only rail". */
}
/* ── Phones: the rail goes off-canvas behind a burger ─────────────────────────
   This WAS a fixed bottom bar, and it didn't survive contact with the real nav: eight
   view icons + Add + Export + the theme switch + the identity chip do not fit across
   390px, so the icons crushed together into an unreadable emoji strip and the chip ran
   off the right edge. There are simply too many destinations for a tab bar (which tops
   out around five).
   So: the same rail, slid in from the left, with its DESKTOP internals intact — labels,
   section eyebrow, footer stack. A drawer has the room a bottom bar never had, which is
   the whole reason to use one. Nothing is stripped here, which is why the icon-only
   block above stops at 641px rather than being undone rule-by-rule down here. */
@media (max-width: 640px) {
  .rail {
    top: 0; left: 0; bottom: 0; right: auto;
    width: min(272px, 82vw); height: auto;
    padding: var(--space-6) var(--space-4) calc(var(--space-5) + env(safe-area-inset-bottom, 0px));
    border-right: 1px solid var(--line);
    box-shadow: var(--shadow-2);
    z-index: 200;                      /* over the scrim (190), under the burger's peers */
    overflow-y: auto; overscroll-behavior: contain;
    transform: translateX(-100%);
    /* visibility keeps the closed drawer out of the tab order; as a discrete property it
       flips to visible for the whole opening transition and holds until the close ends. */
    visibility: hidden;
    transition: transform .34s var(--ease), visibility .34s;
  }
  body.nav-open .rail { transform: none; visibility: visible; }
  .nav-burger { display: grid; }
  .nav-close { display: grid; }
  .nav-scrim { display: block; }
  /* The drawer scrolls itself; the page behind must not scroll with it. */
  body.nav-open { overflow: hidden; }
  /* No rail gutter to reserve any more, and no bottom bar to clear. */
  body { padding-left: clamp(var(--space-4), 4vw, var(--space-6)); padding-bottom: var(--space-9); }
  .toast { bottom: var(--space-6); }
  /* Keep a long/wrapping view title from running under the fixed burger. */
  .viewhead { padding-right: 48px; }
}

/* ── Topbar ───────────────────────────────────────────── */
.topbar {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--space-5); flex-wrap: wrap;
  padding-bottom: var(--space-6);
  border-bottom: 1px solid var(--line-soft);
  position: relative; z-index: 60;  /* lift so the calendar popover escapes content */
}
.brand { display: flex; align-items: center; gap: var(--space-4); }
.brand-logo { height: 30px; width: auto; display: block; flex-shrink: 0; }
.brand-divider { width: 1px; height: 24px; background: var(--line); flex-shrink: 0; }
.brand-sub { color: var(--faint); font-size: 0.78rem; }
@media (max-width: 560px) { .brand-divider, .brand-sub { display: none; } }
.topbar-actions { display: flex; gap: var(--space-3); align-items: center; flex-wrap: wrap; }
.ver-filter { display: flex; align-items: center; gap: var(--space-3); }
.ver-filter > span { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.12em; color: var(--faint); font-weight: 600; }
.ver-filter select { width: auto; min-width: 140px; padding: 9px 32px 9px 12px; font-size: 0.84rem; background-color: var(--surface); }
.hint { font-size: 0.78rem; color: var(--muted); line-height: 1.55; }

/* Contextual view title (left of the topbar) — reinforces "where am I". */
.viewhead { min-width: 0; }
.view-title {
  font-size: clamp(1.35rem, 1rem + 1.4vw, 1.85rem); font-weight: 700;
  letter-spacing: -0.03em; color: var(--ink); line-height: 1.05; text-wrap: balance;
}
.viewhead-meta { display: flex; align-items: center; gap: var(--space-4); flex-wrap: wrap; margin-top: 5px; }
.view-sub { font-size: 0.82rem; color: var(--muted); letter-spacing: -0.005em; }
.viewhead-meta .view-sub::after { content: "·"; margin-left: var(--space-4); color: var(--faint); }
.viewhead-meta .view-sub:only-child::after { content: none; }
/* freshness pill — how stale the 15-min sync is, always visible on the main views */
.freshness {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: 0.66rem; font-weight: 600; letter-spacing: 0.02em;
  color: var(--muted); white-space: nowrap;
}
.freshness::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--good); box-shadow: 0 0 7px var(--good); }
.freshness.stale::before { background: var(--warn); box-shadow: none; }
.freshness[hidden] { display: none; }

/* ── Buttons ──────────────────────────────────────────── */
.btn {
  font-family: var(--font); font-weight: 600; font-size: 0.86rem;
  border-radius: var(--r-sm); padding: 9px 15px; cursor: pointer;
  display: inline-flex; align-items: center; gap: 7px;
  border: 1px solid transparent; transition: all 0.18s var(--ease);
}
.btn-ico { font-size: 1.05em; line-height: 1; }
.btn.solid { background: var(--accent); color: var(--accent-ink); font-weight: 700; border-color: var(--accent); }
.btn.solid:hover { background: var(--accent-dim); border-color: var(--accent-dim); transform: translateY(-1px); }
.btn.ghost { background: transparent; color: var(--muted); border-color: var(--line); }
.btn.ghost:hover { color: var(--text); border-color: var(--faint); background: var(--surface); }
.btn:active { transform: translateY(0); }

.icon-btn {
  background: transparent; border: 1px solid var(--line); color: var(--muted);
  width: 32px; height: 32px; border-radius: var(--r-sm); cursor: pointer;
  font-size: 0.9rem; transition: all 0.18s var(--ease);
}
.icon-btn:hover { color: var(--text); border-color: var(--faint); }

/* ── Totals strip ─────────────────────────────────────── */
.totals {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px; background: var(--line-soft);
  border: 1px solid var(--line-soft); border-radius: var(--r-md);
  overflow: hidden; margin: var(--space-6) 0;
}
.totals[hidden] { display: none; } /* class display: grid otherwise beats the hidden attr */
.total { background: var(--surface); padding: var(--space-5) var(--space-6); }
.total.accent { background: var(--surface-2); }
.total-label {
  display: block; font-size: 0.68rem; text-transform: uppercase;
  letter-spacing: 0.12em; color: var(--faint); font-weight: 600;
}
.total-val {
  display: block; font-family: var(--mono); font-weight: 600;
  font-size: clamp(1.75rem, 1rem + 2.4vw, 2.6rem); margin-top: 8px; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -0.045em; color: var(--text);
}
.total.accent .total-val { color: var(--good); }

/* ── Board / webinar cards ────────────────────────────── */
.board { display: flex; flex-direction: column; gap: var(--space-5); margin-top: var(--space-4); }
/* Era divider in the webinar list (current rollout vs. the June 7–24 webinars). */
.wb-era-sep { display: flex; justify-content: center; margin: var(--space-7) 2px var(--space-4); }
.wb-era-sep span {
  position: relative;
  background: var(--era-bg); color: var(--era-ink); padding: 5px 14px; border-radius: 999px;
  font-family: var(--mono); font-size: 0.58rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.16em;
}
/* downward tail under the pill → points to the webinars below */
.wb-era-sep span::after {
  content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: var(--era-bg);
}

.wb {
  background: var(--surface);
  border: 1px solid var(--line-soft); border-radius: var(--r-md);
  overflow: hidden; animation: rise 0.5s var(--ease) both;
}
.wb-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  flex-wrap: wrap; padding: var(--space-5) var(--space-6);
  border-bottom: 1px solid transparent; background: var(--surface-2);
  cursor: pointer; user-select: none; transition: background 0.15s var(--ease);
}
.wb-head:hover { background: var(--elevated, var(--surface-2)); filter: brightness(1.08); }
.wb-head:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.wb.open .wb-head { border-bottom-color: var(--line-soft); }
.chevron { color: var(--muted); font-size: 0.9rem; display: inline-block; transition: transform 0.25s var(--ease); }
.wb.open .chevron { transform: rotate(90deg); color: var(--accent); }

/* collapse animation via grid-template-rows */
.wb-body { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.3s var(--ease); }
.wb.open .wb-body { grid-template-rows: 1fr; }
.wb-body > .vtable { overflow: hidden; min-height: 0; }

.wb-title { display: flex; align-items: center; gap: var(--space-4); min-width: 0; }
.wb-name { font-weight: 800; font-size: 1.05rem; letter-spacing: -0.02em; }
.wb-meta { display: flex; align-items: center; gap: var(--space-4); }

/* Small "i" toggle that reveals the webinar ID next to the name. */
.id-btn {
  flex: 0 0 auto; width: 16px; height: 16px; line-height: 14px; padding: 0;
  border: 1px solid var(--line-soft); border-radius: 50%;
  background: transparent; color: var(--muted);
  font-size: 0.62rem; font-style: italic; font-weight: 700; font-family: Georgia, serif;
  cursor: pointer; opacity: 0.55; transition: opacity 0.12s, color 0.12s, border-color 0.12s;
}
.id-btn:hover { opacity: 1; color: var(--text); border-color: var(--faint); }
.id-btn.on { opacity: 1; color: var(--accent); border-color: var(--accent); }
.wb-id {
  font-size: 0.72rem; color: var(--muted); background: var(--bg);
  border: 1px solid var(--line-soft); padding: 1px 6px; border-radius: 4px;
  font-variant-numeric: tabular-nums; user-select: all;
}
.copy-btn {
  flex: 0 0 auto; padding: 0 4px; height: 16px; line-height: 14px;
  border: none; background: transparent; color: var(--muted);
  font-size: 0.8rem; cursor: pointer; opacity: 0.6; transition: opacity 0.12s, color 0.12s;
}
.copy-btn:hover { opacity: 1; color: var(--text); }
.copy-btn.ok { color: var(--accent); opacity: 1; }
.copy-btn.ok::after { content: " ✓"; }

.tag {
  font-size: 0.64rem; text-transform: uppercase; letter-spacing: 0.1em;
  font-weight: 700; padding: 3px 8px; border-radius: 0;
  background: var(--bg); color: var(--muted); border: 1px solid var(--line-soft);
}
.tag.event { color: var(--accent); }
.tag.masterclass { color: var(--violet); }
.window { font-size: 0.78rem; color: var(--muted); font-variant-numeric: tabular-nums; }
/* ── The two funnels on a Sales card ──────────────────────────────────────────
   Until now NOTHING named them: two identical strips in which "Showed", "Closes" and
   "Cash collected" each appeared TWICE, same words, same style. The only way to tell
   inbound from outbound was knowing the second one starts at "Sat calls".
   Both strips share ONE grid — a fixed label column, then 5 equal stage columns — so the
   stages line up vertically between them. Inbound's "Booked calls" and outbound's "Sat
   calls" are the same rung (the Overall tab's Booked = 4x4 + sat calls), so they sit in
   the same column; outbound simply has no applications stage, and that cell stays EMPTY
   rather than being dropped, which is exactly what holds the alignment. */
.sales-strip { margin: 0; border: 0; border-radius: 0; grid-template-columns: 92px repeat(5, 1fr); }
.sales-body > .sales-strip + .sales-strip { margin-top: var(--space-3); }
.fnl-lab { display: flex; flex-direction: column; justify-content: center; gap: 3px;
  background: var(--surface-2); padding: var(--space-4) var(--space-4); }
.fnl-tag { font-family: var(--mono); font-size: 0.62rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.1em; color: var(--ink); }
.fnl-hint { font-family: var(--mono); font-size: 0.55rem; color: var(--faint);
  letter-spacing: 0.04em; white-space: nowrap; }
/* The stage outbound doesn't have. Present so the columns align, mute so it never reads
   as "zero applications" — there is no such thing as an outbound application. */
.total.is-void { opacity: 0.28; }
.total.is-void .total-val { color: var(--faint); }
/* Narrow: the label takes its own full-width row and the stages reflow beneath it. */
@media (max-width: 900px) {
  .sales-strip { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
  .fnl-lab { grid-column: 1 / -1; flex-direction: row; align-items: baseline; gap: var(--space-3); padding: var(--space-3) var(--space-4); }
  .total.is-void { display: none; }   /* no column to hold open once they reflow */
}

/* ROAS + the show's cash, in the card header. ROAS is AD-SOURCED cash ÷ ad spend and the
   ad cash spans BOTH funnels, so it is a card-level number; as the fifth tile of the
   outbound strip it read as a setter metric and flattered them ~27% (July 12: 2.20x
   card-wide vs 1.74x for the setters' own cash on that spend). */
.wb-roas { position: relative; display: inline-flex; align-items: baseline; gap: 7px;
  padding: 4px 13px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--line-soft); }
.wb-roas[hidden] { display: none; }
/* ROAS is the verdict on the whole show, so it's sized like one: green ≥1x (the ads made
   money), red <1x (they lost it), matching the .num.perf-* convention everywhere else.
   ⚠️ perf-good/perf-bad are set on [data-s="roas"] by JS, but the shared rule only targets
   .num/.total-val/.mkt-cash — this chip is none of those, so it needs its own pair or the
   class lands and paints nothing (which is exactly what it did when this first shipped). */
.wb-roas-x { font-family: var(--mono); font-size: 1.15rem; font-weight: 700;
  color: var(--muted); font-variant-numeric: tabular-nums; letter-spacing: -0.03em; }
.wb-roas-x.perf-good { color: var(--good); }
.wb-roas-x.perf-bad  { color: var(--warn); }
/* The word stays faint and small in both states — it's a unit, not part of the verdict. */
.wb-roas-x::after { content: " ROAS"; font-size: 0.5em; font-weight: 700; color: var(--faint); letter-spacing: 0.1em; }
.wb-roas .sales-pop { border-radius: 999px; }
.wb-roas:hover .sales-pop:not(:empty) { opacity: 1; visibility: visible; transform: scale(1); }
/* cash collected always reads green (money in); ROAS is colored by profit/loss
   in JS (perf-good ≥1x, perf-bad <1x) so it flags losing webinars at a glance. */
.sales-strip .total-val[data-s="cash"],
.sales-strip .total-val[data-s="setCash"] { color: var(--good); }
/* Sales hover detail — frosted overlay ON TOP of the tile (blurs the value behind),
   same feel as the Funnel-Economics A/B/C/D popover. Neutral colour, not red. */
.total:has(.sales-pop) { position: relative; }
.sales-pop {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; text-align: center;
  padding: 8px var(--space-4);
  background: rgba(17, 17, 19, 0.55);
  backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
  font-family: var(--mono); font-size: 0.8rem; font-weight: 500; color: var(--muted);
  line-height: 1.4; letter-spacing: -0.01em;
  opacity: 0; visibility: hidden; transform: scale(1.015);
  transition: opacity 0.28s var(--ease), transform 0.28s var(--ease), visibility 0.28s;
  pointer-events: none;
}
.total:hover .sales-pop:not(:empty) { opacity: 1; visibility: visible; transform: scale(1); }
/* "N calls upcoming" sub-line under the primary popover detail */
.sales-pop .sp-sub { font-size: 0.72rem; font-weight: 600; color: var(--accent); letter-spacing: 0; }

/* ── Sales mode bar (lives in the topbar, Sales tab only) ── */
/* Holds the per-subtab controls: the Merge switch (Sales subtab) and mkt-controls,
   which fade in on the Marketing subtab. The bar sits where the date-picker/Add-webinar do. */
.mode-bar { display: none; align-items: center; gap: var(--space-4); }
body[data-view="sales"] .mode-bar { display: inline-flex; }
.board[hidden] { display: none; }

/* real on/off switch — checked = on (knob right, accent track) */
.mode-switch { display: inline-flex; align-items: center; gap: var(--space-3); cursor: pointer; user-select: none; flex: none; }
.mode-side { font-size: 0.82rem; font-weight: 600; letter-spacing: -0.01em; color: var(--faint); transition: color 0.2s var(--ease); }
.mode-side.is-active { color: var(--text); }
.mode-input { position: absolute; opacity: 0; width: 0; height: 0; }
.mode-track { position: relative; width: 46px; height: 26px; background: var(--surface-2); border: 1px solid var(--line); border-radius: 999px; transition: background 0.2s var(--ease), border-color 0.2s var(--ease); flex: none; }
.mode-knob { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%; background: var(--accent); transition: transform 0.22s var(--ease); }
.mode-input:checked + .mode-track { background: var(--accent-soft); border-color: var(--accent-dim); }
.mode-input:checked + .mode-track .mode-knob { transform: translateX(20px); }
.mode-input:focus-visible + .mode-track { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Merge Organic & Ads: only meaningful on the Sales subtab (JS sets [hidden] elsewhere —
   Marketing is per-source already, Speed-to-lead is per funnel). */
.merge-switch { margin-right: var(--space-2); }
.merge-switch[hidden] { display: none; }

/* ── Sales sub-navigation: Sales · Marketing · Speed to lead ── */
/* Underline tabs (not a segmented toggle) — three peers, one live at a time; the rule
   under the row doubles as the top edge of whichever panel is showing. */
.subbar { display: flex; align-items: center; margin: var(--space-6) 0 var(--space-5); border-bottom: 1px solid var(--line); }
.subtabs { display: inline-flex; gap: var(--space-6); }
.subtab { position: relative; border: 0; background: transparent; color: var(--faint); font: inherit; font-weight: 600; font-size: 0.88rem; letter-spacing: -0.01em; padding: 0 2px 12px; cursor: pointer; transition: color 0.2s var(--ease); }
.subtab:hover { color: var(--muted); }
.subtab.is-active { color: var(--text); }
.subtab::after { content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px; background: var(--accent); transform: scaleX(0); transform-origin: left; transition: transform 0.24s var(--ease); }
.subtab.is-active::after { transform: scaleX(1); }
.subtab:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.src-toggle { display: inline-flex; background: var(--surface); border: 1px solid var(--line); flex: none; }
.src-btn { border: 0; background: transparent; color: var(--muted); font: inherit; font-weight: 600; font-size: 0.78rem; padding: 7px 15px; cursor: pointer; transition: background 0.2s var(--ease), color 0.2s var(--ease); }
.src-btn + .src-btn { border-left: 1px solid var(--line); }
.src-btn.is-active { background: var(--accent); color: var(--accent-ink); }
/* Hidden by default; fades + slides in to the left of the pinned toggle when
   Marketing mode is on (JS toggles .is-shown). Controls keep their natural size
   (no width collapse → no layout shift), so the toggle never moves. */
.mkt-controls {
  display: inline-flex; align-items: center; gap: var(--space-3); flex: none; white-space: nowrap;
  opacity: 0; transform: translateX(8px); pointer-events: none; visibility: hidden;
  transition: opacity 0.26s var(--ease), transform 0.3s var(--ease), visibility 0.26s var(--ease);
}
.mkt-controls.is-shown { opacity: 1; transform: none; pointer-events: auto; visibility: visible; }
.mkt-select { background: var(--surface); border: 1px solid var(--line); color: var(--text); font: inherit; font-size: 0.85rem; padding: 9px 14px; cursor: pointer; width: auto; max-width: 220px; text-overflow: ellipsis; flex: none; }
.mkt-select:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.mkt-panel { margin-top: var(--space-5); }
/* xAI card wrapper around the breakdown table (matches the other tabs). */
.mkt-card { background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-md); overflow: hidden; }
.mkt-table { width: 100%; border-collapse: collapse; }
.mkt-table th { text-align: right; font-size: 0.62rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--faint); font-weight: 600; padding: 13px 16px; border-bottom: 1px solid var(--line); white-space: nowrap; }
.mkt-table td { text-align: right; padding: 13px 16px; border-bottom: 1px solid var(--line-soft); font-family: var(--mono); font-size: 0.92rem; font-variant-numeric: tabular-nums; color: var(--text); }
.mkt-table tbody tr:last-child td { border-bottom: 0; }
.mkt-table tbody tr:hover { background: var(--surface-2); }
.mkt-table th:first-child, .mkt-table td:first-child { text-align: left; }
.mkt-src { font-family: var(--font) !important; font-weight: 500; max-width: 360px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); }
.mkt-cash { color: var(--good); font-weight: 600; }
/* cells whose hover reveals the underlying count / cash */
.mkt-cp[data-tip], .mkt-cash[data-tip] { cursor: help; }
/* styled metric tooltip — xAI: canvas-soft fill, hairline border, Geist-Mono UPPERCASE
   tracked, ink text, rounded.sm, NO shadow (hairline carries elevation). body-mounted. */
.mkt-tip {
  position: fixed; z-index: 200; pointer-events: none;
  padding: 6px 9px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-md);
  color: var(--ink); font-family: var(--mono); text-transform: uppercase;
  font-size: 0.62rem; letter-spacing: 0.1em; line-height: 1.4;
  font-variant-numeric: tabular-nums; white-space: nowrap;
  opacity: 0; transform: translateY(3px);
  transition: opacity 0.12s var(--ease), transform 0.12s var(--ease);
}
.mkt-tip.show { opacity: 1; transform: translateY(0); }
.mkt-total td { border-top: 1px solid var(--line); border-bottom: 0; font-weight: 600; color: var(--ink); }

/* ── Speed to lead table (reuses the .mkt-table chrome) ── */
/* Durations: green ≤5 min, red >1 h — the same profit/loss language as ROAS. */
.stl-dur { font-weight: 600; }
.stl-dur.perf-good { color: var(--good); }
.stl-dur.perf-bad { color: var(--warn); }
/* Avg: uncoloured — one forgotten booker swings it, so it reports skew, not a verdict. */
.stl-avg { color: var(--muted); font-weight: 500; }
/* Distribution cells: each bucket's share of the DIALED bookers (count on hover).
   No in-cell bars — against right-aligned figures they read as stray blocks, not a
   gauge, and the percentages carry the shape on their own. */
.stl-b { color: var(--muted); cursor: help; }
.stl-note { margin-top: var(--space-4); font-size: 0.78rem; color: var(--faint); }
.stl-note code { font-family: var(--mono); color: var(--muted); }
.stl-note strong { color: var(--muted); font-weight: 600; }

/* ── Per-setter dropdown (who made the first dial) ── */
/* The webinar name IS the handle — a caret + a count badge, no extra column. */
.stl-toggle {
  display: inline-flex; align-items: center; gap: var(--space-2);
  border: 0; background: transparent; padding: 0; cursor: pointer;
  font: inherit; font-weight: 500; color: var(--ink); text-align: left;
  transition: color 0.2s var(--ease);
}
.stl-toggle:hover { color: var(--accent); }
.stl-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.stl-caret { font-style: normal; font-size: 0.7rem; color: var(--faint); transition: transform 0.2s var(--ease), color 0.2s var(--ease); }
.stl-toggle.is-open .stl-caret { transform: rotate(90deg); color: var(--accent); }
.stl-toggle:hover .stl-caret { color: var(--accent); }
/* Count badge: how many setters are behind the caret, so the row advertises the drill-down. */
.stl-n { font-family: var(--mono); font-style: normal; font-size: 0.6rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--faint); }
/* Setter rows: recessed a level (inset fill + accent spine) so they read as belonging to
   the show above, never as another show. */
.stl-sub td { background: var(--surface-2); border-bottom: 1px solid var(--line-soft); }
.stl-sub:hover td { background: var(--surface-2); }
.stl-sub td:first-child { padding-left: 34px; box-shadow: inset 2px 0 0 var(--accent-dim); }
.stl-setter { font-family: var(--font) !important; font-weight: 500; color: var(--muted); }
/* A booking belongs to no single setter — only the dial does. Dash it, don't zero it. */
.stl-na { color: var(--faint); }
.mkt-total:hover td { background: transparent; }
.mkt-empty { color: var(--muted); padding: var(--space-8); text-align: center; border: 1px dashed var(--line); border-radius: var(--r-md); }
/* click-to-sort headers (mirror the Ad-by-Ad .at-th) */
.mkt-th { cursor: pointer; user-select: none; transition: color 0.12s var(--ease); }
.mkt-th:hover { color: var(--muted); }
.mkt-th.is-sorted { color: var(--ink); }
.mkt-th:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }
.mkt-sort { font-style: normal; font-size: 0.82em; opacity: 0.4; margin-left: 5px; }
.mkt-th.is-sorted .mkt-sort { opacity: 1; color: var(--good); }
/* step-conversion chip on the seam between two cards */
.sales-strip .total { position: relative; }
.sales-conv {
  position: absolute; left: 0; top: 50%; transform: translate(-50%, -50%); z-index: 6;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 999px;
  padding: 3px 9px; font-family: var(--mono); font-size: 0.68rem; font-weight: 700;
  color: var(--accent); white-space: nowrap; letter-spacing: -0.02em;
  box-shadow: var(--shadow-pop);
}
.sales-conv:empty { display: none; }
/* values must always fit their cell — never overflow / cut off */
.total { min-width: 0; }
.total-val { min-width: 0; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* Sales strip packs 6 tiles in a row → tighter padding + a font that reads well
   for short values (counts, %) yet keeps long money inside the cell. */
.sales-strip .total { padding: var(--space-4) var(--space-4); text-align: center; }
.sales-strip .total-val { font-size: clamp(1.3rem, 0.55rem + 1.5vw, 1.95rem); margin-top: 6px; text-align: center; }
.sales-strip .total-label { font-size: 0.62rem; text-align: center; }
.status { font-size: 0.7rem; font-weight: 700; letter-spacing: 0.04em; display: inline-flex; align-items: center; gap: 5px; }
.status::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.status.live { color: var(--good); }
.status.live::before { box-shadow: 0 0 8px currentColor; animation: pulse 1.6s infinite; }
.status.upcoming { color: var(--accent-dim); }
.status.ended { color: var(--faint); }

/* version table */
.vtable { padding: var(--space-3) var(--space-4) var(--space-4); }
.vt-row {
  display: grid;
  grid-template-columns: minmax(104px, 1.25fr) repeat(8, minmax(58px, 1fr));
  align-items: stretch; gap: var(--space-3);
  padding: 0 var(--space-4); border-radius: var(--r-sm);
}
/* cells carry the vertical padding (not the row) so each cell fills the full row
   height — that lets the group-separator border run unbroken top-to-bottom. */
.vt-row > span { display: flex; align-items: center; justify-content: flex-end; padding: 11px 0; }
.vt-row > .vt-ver { justify-content: flex-start; }
/* column-group separators: one continuous rule per boundary, drawn centered in
   the whitespace between the previous group's last value and this group's first
   value (numbers are right-aligned, so a plain column-edge border hugs the prev
   number — left:50%-4px lands it midway between the two values). */
.vt-row > .grp-pct, .vt-row > .grp-cost { position: relative; }
.vt-row > .grp-pct::before, .vt-row > .grp-cost::before {
  content: ""; position: absolute; top: 0; bottom: 0;
  width: 1px; background: var(--line);
  /* midpoint between prev value's end (cell left - 8px gap) and this value's
     start (right-aligned): 50% - (ownTextWidth + 8px)/2. Text width differs per
     group: pct values ("14.8%") ≈ 36px, cost values ("$14.24") ≈ 48px. */
}
.vt-row > .grp-pct::before { left: calc(50% - 22px); }
.vt-row > .grp-cost::before { left: calc(50% - 28px); }
.vt-head > span {
  font-size: 0.64rem; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--faint); font-weight: 700;
}
.vt-body .vt-row + .vt-row { border-top: 1px solid var(--line-soft); border-radius: 0; }
.vt-body .vt-row:hover { background: var(--surface-2); }
.vt-row.is-all { background: var(--accent-soft); }
.vt-row.is-all .vt-ver { color: var(--accent); }

.vt-ver { font-weight: 600; font-size: 0.86rem; }
.num { font-family: var(--mono); font-weight: 500; font-size: 0.98rem; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }
.num.muted { color: var(--muted); }
/* relative per-column coloring: best in column = green, rest = orange */
.num.good { color: var(--good); font-weight: 600; }
.num.mid { color: var(--muted); }
.vt-loading { padding: var(--space-5) var(--space-4); color: var(--faint); font-size: 0.86rem; animation: blink 1.1s var(--ease) infinite; }
.vt-loading.err { color: var(--warn); animation: none; }

/* ── Empty state ──────────────────────────────────────── */
.empty {
  text-align: center; padding: var(--space-9) var(--space-6);
  max-width: 46ch; margin: var(--space-8) auto;
}
.empty-art { font-size: 40px; color: var(--accent-dim); margin-bottom: var(--space-5); }
.empty h2 { font-size: 1.3rem; font-weight: 800; letter-spacing: -0.02em; }
.empty p { color: var(--muted); margin: var(--space-4) 0 var(--space-6); }

/* ── Drawer ───────────────────────────────────────────── */
.drawer { position: fixed; inset: 0; z-index: 120; visibility: hidden; }
.drawer[aria-hidden="false"] { visibility: visible; }
.drawer-scrim {
  position: absolute; inset: 0; background: rgba(0, 0, 0, 0.6);
  opacity: 0; transition: opacity 0.3s var(--ease);
}
.drawer[aria-hidden="false"] .drawer-scrim { opacity: 1; }
.drawer-panel {
  position: absolute; top: 0; right: 0; height: 100%;
  width: min(420px, 92vw); background: var(--surface);
  border-left: 1px solid var(--line);
  padding: var(--space-6) var(--space-6) var(--space-7);
  display: flex; flex-direction: column; gap: var(--space-5);
  overflow-y: auto;
  transform: translateX(100%); transition: transform 0.36s var(--ease);
  box-shadow: -24px 0 60px oklch(0.1 0.01 70 / 0.5);
}
.drawer[aria-hidden="false"] .drawer-panel { transform: translateX(0); }
.drawer-head { display: flex; align-items: center; justify-content: space-between; }
.drawer-head h2 { font-size: 1.25rem; font-weight: 800; letter-spacing: -0.02em; }

.field { display: flex; flex-direction: column; gap: 7px; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
.field-label { font-size: 0.74rem; font-weight: 600; color: var(--muted); letter-spacing: 0.01em; }
.field-label em { color: var(--faint); font-style: normal; }
input, select {
  font-family: var(--font); font-size: 0.9rem; color: var(--text);
  background: var(--bg); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: 10px 12px; width: 100%;
  transition: border-color 0.15s var(--ease);
}
input:focus, select:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
input::placeholder { color: var(--faint); }
select { cursor: pointer; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%2398a3bd' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; padding-right: 32px; }
input[type="date"] { font-family: var(--mono); }

/* segmented type control */
.seg { display: grid; grid-auto-flow: column; gap: 6px; }
.seg-multi { display: flex; flex-wrap: wrap; } /* version toggles: many items → wrap instead of one cramped row */
.seg.seg-multi button { text-transform: lowercase; } /* beat `.seg button { capitalize }` (later in file, equal specificity) → show root, /variationv2 lowercase */
.seg button {
  font-family: var(--font); font-weight: 600; font-size: 0.85rem;
  padding: 9px; border-radius: var(--r-sm); cursor: pointer;
  background: var(--bg); border: 1px solid var(--line); color: var(--muted);
  transition: all 0.15s var(--ease); text-transform: capitalize;
}
.seg button[aria-pressed="true"] { background: var(--surface-2); color: var(--text); border-color: var(--faint); }
.seg button:hover { color: var(--text); }
/* Add-a-custom-page row under the "Pages running" toggles. */
.ver-add { display: flex; gap: 6px; margin-top: 8px; }
.ver-add input { flex: 1; font-family: var(--mono); font-size: 0.82rem; padding: 8px 10px; }
.ver-add .btn { white-space: nowrap; }
/* Custom pages read differently from the built-in toggles: monospace slug + a dot. */
.seg.seg-multi button[data-custom="1"] { font-family: var(--mono); }
.seg.seg-multi button[data-custom="1"]::before { content: "＋ "; color: var(--faint); }

.form-err { color: var(--warn); font-size: 0.82rem; }
.drawer-foot { display: flex; justify-content: flex-end; gap: var(--space-3); margin-top: auto; padding-top: var(--space-4); }

/* ── Toast ────────────────────────────────────────────── */
.toast {
  position: fixed; bottom: var(--space-6); left: 50%; transform: translateX(-50%) translateY(10px);
  background: var(--surface-2); border: 1px solid var(--line); color: var(--text);
  padding: 11px 18px; border-radius: var(--r-sm); font-size: 0.86rem; font-weight: 500;
  z-index: 60; opacity: 0; transition: all 0.28s var(--ease); box-shadow: 0 12px 40px oklch(0.1 0.01 70 / 0.5);
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.toast.err { color: var(--warn); }

/* ── Motion ───────────────────────────────────────────── */
@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
@keyframes blink { 0%,100% { opacity: 0.4; } 50% { opacity: 0.85; } }

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

/* ── Responsive: version table scrolls horizontally on narrow screens ── */
@media (max-width: 760px) {
  /* must match .wb-body > .vtable specificity (collapse clip) to re-enable x-scroll.
     keep overflow-y hidden so the 0fr collapse animation still clips vertically. */
  .wb-body > .vtable { overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; }
  .vt-row { min-width: 800px; }
  .wb-head { gap: var(--space-3); }
}

/* date range picker */
.daterange { position: relative; display: flex; align-items: center; gap: 4px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 3px; }
.dr-trigger { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; background: transparent; border: 1px solid transparent; border-radius: var(--r-md); padding: 5px 12px; cursor: pointer; font-family: var(--font); transition: background .15s var(--ease), border-color .15s; }
.dr-trigger:hover { background: var(--surface-2); }
.dr-trigger.active { background: var(--surface-2); border-color: var(--hair-2); }
.dr-cap { font-size: 0.55rem; text-transform: uppercase; letter-spacing: 0.13em; color: var(--faint); font-weight: 600; }
.dr-val { font-family: var(--mono); font-size: 0.84rem; color: var(--text); letter-spacing: -0.02em; }
.dr-sep { color: var(--faint); font-size: 0.8rem; padding: 0 2px; }
.dr-pop { position: absolute; top: calc(100% + 8px); right: 0; z-index: 110; width: 286px; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 14px; }
.dr-pop[hidden] { display: none; }
.dr-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.dr-month { font-family: var(--mono); font-weight: 600; font-size: 0.86rem; letter-spacing: -0.01em; }
.dr-nav { width: 28px; height: 28px; background: transparent; border: 1px solid var(--hair-2); border-radius: 9999px; color: var(--muted); cursor: pointer; font-size: 1.1rem; line-height: 1; display: grid; place-items: center; transition: color .15s, border-color .15s; }
.dr-nav:hover { color: var(--ink); border-color: var(--hair-3); }
.dr-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.dr-dow { text-align: center; font-size: 0.56rem; color: var(--faint); font-weight: 600; text-transform: uppercase; padding: 2px 0 6px; }
.dr-day { aspect-ratio: 1; background: transparent; border: none; border-radius: var(--r-sm); color: var(--muted); font-family: var(--mono); font-size: 0.78rem; cursor: pointer; transition: background .12s, color .12s; }
.dr-day:hover:not(.is-disabled):not(.is-edge) { background: var(--surface-2); color: var(--text); }
.dr-day.in-range { background: var(--accent-soft); color: var(--text); }
.dr-day.is-edge { background: var(--accent); color: var(--accent-ink); font-weight: 600; }
.dr-day.is-disabled { color: var(--line); cursor: not-allowed; }

/* ── Menu blur scrim ── */
.fab-scrim { position: fixed; inset: 0; z-index: 70; background: rgba(8,8,9,0.4); backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px); opacity: 0; pointer-events: none; transition: opacity .32s var(--ease); }
body.menu-open .fab-scrim { opacity: 1; pointer-events: auto; }

/* ── Section views + floating burger menu ─────────────── */
.view[hidden] { display: none; }
/* topbar add/date controls only apply to Marketing */
body[data-view="sales"]   .topbar-actions,
body[data-view="organic"] .topbar-actions,
body[data-view="status"]  .topbar-actions,
body[data-view="overall"] .topbar-actions,
body[data-view="ads"]      .topbar-actions { display: none; }

.placeholder {
  text-align: center; max-width: 50ch; margin: clamp(48px, 12vh, 120px) auto 0;
  padding: var(--space-9) var(--space-6);
  background: var(--surface); border: 1px solid var(--line-soft);
}
.ph-mark { font-family: var(--mono); font-size: 34px; color: var(--accent); line-height: 1; margin-bottom: var(--space-5); }
.placeholder h2 { font-size: clamp(1.4rem, 1rem + 1.4vw, 1.9rem); font-weight: 700; letter-spacing: -0.03em; }
.placeholder p { color: var(--muted); margin: var(--space-4) 0 var(--space-5); line-height: 1.65; }
.ph-soon {
  display: inline-block; font-size: 0.64rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.16em;
  color: var(--accent); border: 1px solid var(--line); padding: 6px 12px;
}

/* floating menu */
.fab { position: fixed; right: clamp(16px, 3vw, 28px); bottom: clamp(16px, 3vw, 28px); z-index: 80; display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-3); pointer-events: none; }
.fab-toggle { pointer-events: auto; }
.fab-items { display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-3); margin-bottom: var(--space-2); }
.fab-item {
  font-family: var(--font); font-weight: 600; font-size: 0.84rem; color: var(--muted);
  background: var(--surface); border: 1px solid var(--line); padding: 11px 16px; cursor: pointer;
  display: inline-flex; align-items: center; gap: 10px; white-space: nowrap;
  box-shadow: 0 10px 30px rgba(0,0,0,0.45);
  opacity: 0; transform: translateY(16px) scale(0.96); pointer-events: none;
  transition: opacity .28s var(--ease), transform .4s var(--ease), color .15s, border-color .15s, background .15s;
}
.fab-item:hover { color: var(--text); border-color: var(--faint); }
.fab-item.is-active { color: var(--accent); background: var(--surface-2); border-color: var(--accent-soft); }
/* per-section emoji glyph (replaces the old square dot) */
.fab-item .fab-dot { width: auto; height: auto; background: none; font-size: 1.05rem; line-height: 1; opacity: 0.65; transition: opacity 0.15s var(--ease), transform 0.15s var(--ease); }
.fab-item:hover .fab-dot { opacity: 0.9; }
.fab-item.is-active .fab-dot { opacity: 1; transform: scale(1.08); }
.fab-sep { width: 64%; align-self: flex-end; height: 1px; background: var(--line); margin: 3px 4px; opacity: 0; transition: opacity .28s var(--ease); }
.fab.open .fab-sep { opacity: 0.55; }
.fab-item.fab-meta { color: var(--faint); }
.fab-item.fab-meta.is-active { color: var(--accent); }

/* Status tab */
.st-badge { font-weight: 800; letter-spacing: 0.02em; }
.st-ok { color: var(--accent); }
.st-warn { color: var(--warn); }
.st-err { color: var(--warn); }
.st-time { font-size: 1.45rem; }
.st-meta { color: var(--muted); font-size: 0.86rem; line-height: 1.8; margin: var(--space-6) 0; }
.st-meta b { color: var(--text); font-weight: 600; }
.st-detail { font-family: var(--mono); font-size: 0.78rem; color: var(--faint); }
.st-detail.err { color: var(--warn); }
.st-table { padding: var(--space-3) var(--space-4) var(--space-4); margin-top: var(--space-4); }
.st-table .at-row { grid-template-columns: 1fr auto; }
/* per-source health row: Source · Last run · Status pill · Rows */
.st-table .at-row.st-src { grid-template-columns: 1fr auto 76px 72px; align-items: center; gap: var(--space-4); }
.st-when { font-family: var(--mono); font-size: 0.72rem; color: var(--faint); text-align: right; white-space: nowrap; }
.st-src .num { text-align: right; }
/* status pill — xAI pill shape (9999px) + hairline border, semantic text color */
.st-pill { justify-self: center; font-family: var(--mono); font-size: 0.58rem; font-weight: 700;
  letter-spacing: 0.08em; padding: 2px 9px; border-radius: 9999px; border: 1px solid var(--line);
  white-space: nowrap; text-align: center; }
.st-pill.st-ok { color: var(--accent); }
.st-pill.st-warn { color: var(--warn); border-color: rgba(255,122,23,0.4); }
.st-pill.st-err { color: var(--warn); border-color: rgba(229,100,94,0.4); }
.st-pill.st-muted { color: var(--faint); }
.st-rowerr { font-family: var(--mono); font-size: 0.68rem; color: var(--warn); padding: 1px var(--space-3) var(--space-3); }

/* ── Daily Report ─────────────────────────────────────── */
.drep-eyebrow { font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.62rem;
  font-weight: 700; color: var(--faint); padding: 0 var(--space-2) var(--space-3); }
.drep-mut { color: var(--faint); font-style: italic; }
/* NB: own prefix `drep-` — NOT `dr-`, which the date-picker calendar owns (.dr-day
   there has aspect-ratio:1, which would force every day card square / equal-height). */
.drep-day { background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-md); overflow: hidden; }
.drep-sum { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: var(--space-4);
  padding: var(--space-4) var(--space-5); cursor: pointer; list-style: none; user-select: none; transition: background .12s var(--ease); }
.drep-sum::-webkit-details-marker { display: none; }
.drep-sum::marker { content: ""; }
.drep-sum:hover { background: var(--surface-2); }
.drep-date { font-family: var(--font); font-weight: 600; font-size: 0.95rem; color: var(--ink); letter-spacing: -0.01em; }
.drep-date::before { content: "▸"; display: inline-block; margin-right: var(--space-3); color: var(--faint);
  font-size: 0.7rem; transition: transform .15s var(--ease); }
.drep-day[open] .drep-date::before { transform: rotate(90deg); }
.drep-pills { display: flex; gap: var(--space-2); flex-wrap: wrap; justify-content: flex-end; }
.drep-tot { font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 600; font-size: 1.05rem;
  color: var(--ink); min-width: 40px; text-align: right; }
.drep-day[open] .drep-sum { border-bottom: 1px solid var(--line-soft); }
/* body shows only when open, so closed days collapse to summary height (native) */
.drep-body { display: none; }
.drep-day[open] .drep-body { display: flex; flex-direction: column; gap: var(--space-5);
  padding: var(--space-4) var(--space-4) var(--space-5); }

/* source-group pill — xAI pill shape, hairline border, mono caps, restrained color */
.g-pill { font-family: var(--mono); font-size: 0.56rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 9999px; border: 1px solid var(--line); white-space: nowrap; color: var(--muted);
  font-variant-numeric: tabular-nums; }
.g-pill.g-ads     { color: var(--violet); border-color: var(--violet-line); }
.g-pill.g-youtube { color: var(--warn); border-color: rgba(255,122,23,0.35); }
.g-pill.g-email   { color: var(--good); border-color: rgba(160,195,236,0.35); }
.g-pill.g-other   { color: var(--muted); }

.drep-grphead { display: flex; align-items: center; gap: var(--space-3); font-family: var(--mono); text-transform: uppercase;
  letter-spacing: 0.1em; font-size: 0.66rem; font-weight: 700; color: var(--faint); padding: 0 var(--space-2) var(--space-3); }
.drep-grphead.g-ads     { color: var(--violet); }
.drep-grphead.g-youtube { color: var(--warn); }
.drep-grphead.g-email   { color: var(--good); }
.drep-grpn { font-variant-numeric: tabular-nums; color: var(--muted); }

/* exact-source table: utm_source · utm_campaign · utm_content · count (UTMs left-aligned) */
.drep-tbl { padding: 0; }
.drep-tbl .at-row { grid-template-columns: minmax(90px,1fr) minmax(110px,1.6fr) minmax(110px,1.6fr) 72px; min-width: 0; gap: var(--space-4); }
.drep-tbl .at-row > span { justify-content: flex-start; padding: 8px 0; font-size: 0.82rem; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; line-height: 1.4; }
.drep-tbl .at-row > span.num { justify-content: flex-end; text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.drep-tbl .at-head > span { font-size: 0.58rem; }

/* ── Export modal ─────────────────────────────────────── */
/* fade scrim + scale/slide the card on open; reverse on close (aria-hidden toggle) */
.exp-modal { position: fixed; inset: 0; z-index: 300; opacity: 0; visibility: hidden;
  transition: opacity .2s var(--ease), visibility 0s linear .2s; }
.exp-modal[aria-hidden="false"] { opacity: 1; visibility: visible; transition: opacity .2s var(--ease); }
.exp-scrim { position: absolute; inset: 0; background: rgba(0,0,0,0.6); -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); }
.exp-card { position: absolute; left: 50%; top: 50%;
  width: min(440px, calc(100vw - 32px)); background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: var(--space-6); display: flex; flex-direction: column; gap: var(--space-4);
  transform: translate(-50%,-50%) scale(0.96) translateY(8px); transition: transform .22s var(--ease); }
.exp-modal[aria-hidden="false"] .exp-card { transform: translate(-50%,-50%); }
.exp-head { display: flex; align-items: center; justify-content: space-between; }
.exp-head h2 { font-family: var(--font); font-weight: 600; font-size: 1.1rem; letter-spacing: -0.02em; color: var(--ink); }
.exp-x { background: transparent; border: none; color: var(--muted); font-size: 0.95rem; cursor: pointer; line-height: 1; padding: 4px; transition: color .12s var(--ease); }
.exp-x:hover { color: var(--ink); }
.exp-sub { color: var(--muted); font-size: 0.82rem; line-height: 1.5; margin-top: calc(-1 * var(--space-2)); }
.exp-label { font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.6rem; font-weight: 700; color: var(--faint); }
.exp-select { background: var(--surface-2); color: var(--ink); border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 10px 12px; font-family: var(--font); font-size: 0.9rem; width: 100%; margin-top: calc(-1 * var(--space-3)); }
/* Three exports (metrics · registrants · no-shows) as a STACKED LIST, not three fat
   side-by-side cards: at three-across each button was ~150px wide and had to wrap its
   sub-label onto three lines, which is what made them tall and cluttered. One tight row
   each — name, hint, and the file type — reads as a menu and stays 36px tall. */
.exp-actions { display: flex; flex-direction: column; gap: 6px; margin-top: var(--space-3); }
/* These must read as BUTTONS, not fields. Sitting directly under .exp-select, an
   outlined box with the same radius is indistinguishable from an input — so they get a
   filled surface, a download glyph, and a hover that LIFTS. The primary one is a solid
   white fill, which no input in this UI ever is. */
.exp-go {
  display: flex; align-items: center; gap: 10px; width: 100%;
  /* Pill. The extra right padding balances the round cap against the .csv tag. */
  padding: 8px 16px 8px 8px; text-align: left; cursor: pointer;
  background: var(--surface-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: 999px;
  font: inherit;
  transition: background .16s var(--ease), border-color .16s var(--ease),
              transform .16s var(--ease), box-shadow .16s var(--ease);
}
.exp-go:hover { background: var(--accent-soft); border-color: var(--accent-dim);
  transform: translateY(-1px); box-shadow: var(--shadow-pop); }
.exp-go:active { transform: translateY(0); box-shadow: none; }
.exp-go:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* The download glyph — the clearest "this does something" signal in the row. A circle
   inside the pill, so the two radii agree instead of fighting. */
.exp-go-ic { flex: none; width: 26px; height: 26px; display: grid; place-items: center;
  border-radius: 50%; background: var(--wash-2); font-size: 0.78rem; line-height: 1; }
.exp-go-t { font-weight: 600; font-size: 0.85rem; white-space: nowrap; }
/* The hint takes the slack, so the .csv tag always parks hard right. */
.exp-go-s { flex: 1; min-width: 0; font-size: 0.7rem; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.exp-go-x { font-family: var(--mono); font-size: 0.62rem; color: var(--faint); letter-spacing: 0.04em; }

/* Primary = the default export. Solid fill, so the row is unmistakably a button. */
.exp-go.is-primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.exp-go.is-primary:hover { background: var(--accent-dim); border-color: var(--accent-dim); }
.exp-go.is-primary .exp-go-ic { background: var(--on-accent-line); }
.exp-go.is-primary .exp-go-s { color: var(--on-accent-2); }
.exp-go.is-primary .exp-go-x { color: var(--on-accent-3); }
/* Busy/done replace the row's contents with a single word (see `run` in app.js) — centre
   it so the row doesn't look left-adrift while it works. */
.exp-go.is-busy, .exp-go.is-done { justify-content: center; font-weight: 600; font-size: 0.85rem; }
.exp-go.is-busy { color: var(--muted); }
.exp-go[disabled] { cursor: default; }
.exp-go[disabled]:not(.is-busy):not(.is-done) { opacity: 0.45; }
/* completion signature moment: brief confirm before the modal closes */
.exp-go.is-done, .exp-go.is-done:hover { background: var(--good); border-color: var(--good); color: var(--accent-ink); }
@media (prefers-reduced-motion: reduce) {
  .exp-modal, .exp-modal .exp-card { transition: none; }
  .exp-modal[aria-hidden="false"] .exp-card, .exp-card { transform: translate(-50%,-50%); }
}
/* Pre-add checklist — reuses .exp-modal/.exp-card shell */
.chk-list { list-style: none; display: flex; flex-direction: column; gap: var(--space-3); margin: 0; padding: 0; }
.chk-list li { position: relative; padding-left: 26px; color: var(--ink); font-size: 0.9rem; line-height: 1.45; }
.chk-list li::before { content: "\2022"; position: absolute; left: 4px; top: -1px; color: var(--accent, var(--muted)); font-size: 1.1rem; line-height: 1.45; }
.chk-list code { font-family: var(--mono); font-size: 0.82em; background: var(--surface-2); border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; color: var(--ink); }
.chk-foot { display: flex; gap: var(--space-3); justify-content: flex-end; margin-top: var(--space-2); }
.fab.open .fab-item { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
.fab.open .fab-item:nth-child(1) { transition-delay: .02s; }
.fab.open .fab-item:nth-child(2) { transition-delay: .07s; }
.fab.open .fab-item:nth-child(3) { transition-delay: .12s; }

.fab-toggle {
  width: 54px; height: 54px; background: var(--accent); border: 1px solid var(--accent); cursor: pointer;
  display: grid; place-items: center; align-self: flex-end;
  box-shadow: 0 12px 34px rgba(0,0,0,0.55), 0 4px 12px rgba(0,0,0,0.5);
  transition: transform .3s var(--ease), background .2s var(--ease), border-color .2s;
}
.fab-toggle:hover { transform: translateY(-2px); }
.fab.open .fab-toggle { background: var(--surface-2); border-color: var(--line); }
.fab-burger { position: relative; width: 20px; height: 14px; }
.fab-burger i { position: absolute; left: 0; width: 100%; height: 2px; background: #0a0a0a; transition: transform .35s var(--ease), opacity .2s, background .2s; }
.fab-burger i:nth-child(1) { top: 0; }
.fab-burger i:nth-child(2) { top: 6px; }
.fab-burger i:nth-child(3) { top: 12px; }
.fab.open .fab-burger i { background: var(--text); }
.fab.open .fab-burger i:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.fab.open .fab-burger i:nth-child(2) { opacity: 0; }
.fab.open .fab-burger i:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* version row external-link icon */
.vt-ver { display: inline-flex; align-items: center; gap: 7px; }
.vt-link { display: inline-flex; align-items: center; color: var(--faint); transition: color .15s var(--ease), transform .15s var(--ease); }
.vt-link:hover { color: var(--accent); transform: translate(1px, -1px); }

/* ── Ad-by-Ad table ─────────────────────────────────────── */
.wb-body > .atable { overflow: hidden; min-height: 0; }  /* collapse clip (matches .vtable) */
.wb-body > .sales-body { overflow: hidden; min-height: 0; padding: var(--space-3) 0 var(--space-4); }  /* collapse clip for the Sales two-row body */
.atable { padding: var(--space-3) var(--space-4) var(--space-4); }
.at-body { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.at-row {
  display: grid;
  grid-template-columns: minmax(160px, 2.2fr) repeat(7, minmax(70px, 1fr));
  align-items: center; gap: var(--space-3); padding: 0 var(--space-4); min-width: 860px;
}
.at-row > span { display: flex; align-items: center; justify-content: flex-end; padding: 10px 0; }
.at-row > .at-name { display: block; min-width: 0; align-self: stretch; line-height: 40px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 600; font-size: 0.84rem; }
.at-head > span { font-size: 0.64rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--faint); font-weight: 700; }
.at-head > .at-name { line-height: 34px; }
/* click-to-sort column headers */
.at-th { cursor: pointer; gap: 5px; transition: color 0.12s var(--ease); }
.at-th:hover { color: var(--muted); }
.at-th.is-sorted { color: var(--text); }
.at-sort { font-size: 0.82em; opacity: 0.45; font-style: normal; }
.at-th.is-sorted .at-sort { opacity: 1; color: var(--accent); }
.at-th:focus-visible { outline: 1px solid var(--accent); outline-offset: 2px; }

/* instant, styled column tooltip (replaces slow native title) */
.at-th[data-tip], .ot-th[data-tip] { position: relative; }
.at-th[data-tip]::after, .ot-th[data-tip]::after {
  content: attr(data-tip);
  position: absolute; top: calc(100% + 9px); right: 0;
  width: max-content; max-width: 230px;
  padding: 9px 11px;
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-md); box-shadow: 0 8px 24px rgba(0,0,0,0.5);
  color: var(--muted); font-size: 0.72rem; font-weight: 500; line-height: 1.45;
  text-transform: none; letter-spacing: 0; text-align: left; white-space: normal;
  opacity: 0; visibility: hidden; transform: translateY(-3px);
  transition: opacity 0.1s var(--ease), transform 0.1s var(--ease), visibility 0.1s;
  pointer-events: none; z-index: 90;
}
.at-th[data-tip]:hover::after, .at-th[data-tip]:focus-visible::after,
.ot-th[data-tip]:hover::after { opacity: 1; visibility: visible; transform: translateY(0); }

/* Organic table — Video + 6 metric columns */
.atable.ot { padding: var(--space-5) var(--space-6) var(--space-6); }
.atable.ot .at-row { grid-template-columns: minmax(180px, 2.4fr) repeat(6, minmax(64px, 1fr)); }
.ot-th { display: flex; align-items: center; justify-content: flex-end; gap: 5px; }
.ot-count { color: var(--faint); font-size: 0.74rem; font-weight: 500; }
.ot-bar { display: flex; justify-content: flex-end; margin-bottom: var(--space-4); }
.ot-bar .btn { font-size: 0.8rem; padding: 7px 14px; }
.atable.ot .at-row.ot-unmatched { opacity: 0.42; }
.atable.ot .at-name a { color: inherit; text-decoration: none; }
.atable.ot .at-name a:hover { color: var(--accent); text-decoration: underline; }
/* Email table — Email/campaign + 8 metric columns (overrides the .ot 6-col grid) */
.atable.et .at-row { grid-template-columns: minmax(240px, 3.7fr) repeat(8, minmax(50px, 1fr)); }
/* Email name cell: label ellipsizes, funnel tag + "· N emails" badge never truncate. */
.atable.et .at-name { display: flex; align-items: center; gap: 7px; }
.atable.et .et-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.atable.et .at-name .tag, .atable.et .at-name .ot-count { flex-shrink: 0; }
/* ── Overall table ──────────────────────────────────────
   A real ruled table: webinar day + 9 metric columns, every cell boxed by its own
   column so a long figure ($151,038) can never bleed into its neighbour. The whole
   table scrolls as one (head + body together, unlike .at-body's own scroller), so a
   narrow window never desyncs a header from its numbers. */
.atable.ovt { padding: 0; overflow-x: auto; }
.atable.ovt .at-body { overflow-x: visible; }
/* name + the 9 funnel columns (OV_COLS, incl. Attended + Confirmed) + cash + spend */
.atable.ovt .at-row {
  grid-template-columns: minmax(150px, 1.2fr) repeat(9, minmax(104px, 1fr)) repeat(2, minmax(120px, 1.15fr));
  gap: 0; padding: 0; min-width: 1360px; align-items: stretch;
}
/* Vertical rules. Cells carry their own padding (the grid gap is gone), which is what
   guarantees the gutter between two adjacent numbers. */
.atable.ovt .at-row > span { padding: 13px 14px; border-left: 1px solid var(--line-soft); }
.atable.ovt .at-row > span:first-child { border-left: 0; }
/* ── Header sparkline: the missing dimension ──────────────────────────────────
   The tab had no TIME in it: six weeks of a business and no way to see whether it was
   growing. One line per column answers it for every stage at once, and it plots whatever
   the live mode shows, so the line always belongs to the number under it.

   NOTE: the cells themselves briefly carried an inline conversion + a data bar, replacing
   the Ratio mode. Reverted — three plain toggles read cleaner than two numbers and a bar
   stacked in every cell. The sparklines are the part that stayed. If you ever retry the
   in-cell version, the traps are: the conversion class must NOT be `.ov-sub` (that's the
   ad-account sub-ROW below), and a data bar must be emitted INSIDE the cell (`.at-row` is
   a grid — a sibling becomes its own grid item and shunts every column). */
.atable.ovt .at-head > span.ot-th { flex-direction: column; align-items: flex-end; gap: 4px; }
.atable.ovt .at-head > .at-name { flex-direction: row; }
.ov-thl { display: block; }
.ov-spark { display: block; width: 100%; max-width: 74px; height: 15px; overflow: visible; }
.ov-spark polyline { fill: none; stroke: var(--muted); stroke-width: 1; stroke-linejoin: round; stroke-linecap: round; }
.ov-spark circle { fill: var(--accent); stroke: none; }
.atable.ovt .at-head > .ov-th-cash .ov-spark polyline { stroke: var(--good); }
.atable.ovt .at-head > .ov-th-cash .ov-spark circle { fill: var(--good); }
.atable.ovt .at-head > span:last-child .ov-spark polyline { stroke: var(--warn); }
.atable.ovt .at-head > span:last-child .ov-spark circle { fill: var(--warn); }
/* The two money columns read at a glance: cash in is green, spend out is red. (In
   Costs mode the cash column becomes ROAS and keeps its own good/bad coloring.) */
.atable.ovt .num.ov-cash { color: var(--good); font-weight: 600; }
.atable.ovt .num.ov-spend { color: var(--warn); font-weight: 600; }
.atable.ovt .at-head > .ov-th-cash { color: var(--good); opacity: 0.8; }
.atable.ovt .at-head > span:last-child { color: var(--warn); opacity: 0.8; }
/* The row IS the day: one bold date, left-aligned, never truncated. */
.atable.ovt .at-name { display: flex; align-items: center; justify-content: flex-start; line-height: 1.2; }
.atable.ovt .ov-day { font-weight: 700; white-space: nowrap; }
/* ── Per-ad-account dropdown ── */
/* The date doubles as the handle (same pattern as Speed to lead's per-setter rows):
   just a caret + the day — the caret alone advertises the drill-down. */
.atable.ovt .ov-toggle { width: 100%; min-width: 0; }
.atable.ovt .ov-toggle .ov-day { overflow: hidden; text-overflow: ellipsis; }
/* Ad-account rows: recessed a level (inset fill + an accent spine) so they read as
   belonging to the day above, never as another day. */
.atable.ovt .at-body .at-row.ov-sub { background: var(--surface-2); }
.atable.ovt .at-body .at-row.ov-sub:hover { background: var(--surface-2); }
.atable.ovt .at-row.ov-sub > span { padding-top: 10px; padding-bottom: 10px; }
.atable.ovt .at-row.ov-sub > .at-name {
  padding-left: 32px; box-shadow: inset 2px 0 0 var(--accent-dim);
  font-weight: 500; font-size: 0.8rem; color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.atable.ovt .at-row.ov-sub .num { font-size: 0.82rem; color: var(--muted); }
.atable.ovt .at-row.ov-sub .num.ov-cash,
.atable.ovt .at-row.ov-sub .num.ov-spend,
.atable.ovt .at-row.ov-sub .num.perf-good,
.atable.ovt .at-row.ov-sub .num.perf-bad { color: inherit; }
.atable.ovt .at-row.ov-sub .num.ov-cash { color: var(--good); opacity: 0.85; }
.atable.ovt .at-row.ov-sub .num.ov-spend { color: var(--warn); opacity: 0.85; }
/* Header: its own band, so the ruled columns read as a table head. */
.atable.ovt .at-head { background: var(--surface-2); border-bottom: 1px solid var(--line); }
.atable.ovt .at-head > span { white-space: nowrap; padding-top: 12px; padding-bottom: 12px; }
.atable.ovt .at-head > .at-name { line-height: 1.2; }
.atable.ovt .at-body .at-row:hover { background: var(--surface-2); }
/* Footer row: separated from the data, same ruling. */
.atable.ovt .at-total { border-top: 1px solid var(--line); margin-top: 0; background: var(--surface-2); }
/* Counts ⇄ Costs switch, pinned right above the table — with air above it so it
   isn't glued to the topbar's rule. */
.ov-bar { display: flex; justify-content: flex-end; margin: var(--space-6) 0 var(--space-4); }

/* Space between the stacked YouTube + Email tables (no heading labels). */
#board-email { margin-top: var(--space-5); }
.at-body .at-row + .at-row { border-top: 1px solid var(--line-soft); }
.at-body .at-row:hover { background: var(--surface-2); }
.at-row.is-best { background: var(--accent-soft); }
.at-row.is-best .at-name { color: var(--accent); }
.at-total { border-top: 1px solid var(--line); margin-top: 2px; }
.at-total > span { font-weight: 700; }
.at-total > .at-name, .at-total > span:first-child { color: var(--muted); font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.08em; }
.at-sub { padding: var(--space-4) var(--space-4) var(--space-2); font-size: 0.62rem; text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--faint); font-weight: 700; border-top: 1px solid var(--line-soft); margin-top: var(--space-3); }
.at-muted .at-name { color: var(--muted); font-weight: 500; }
.at-warn { padding: var(--space-3) var(--space-4); color: var(--warn); font-size: 0.8rem; }

/* grade split for Form filled (A/B/C/D) — hover-only popover, absolute so it
   never changes the tile height; kept inside the tile so .totals overflow:hidden
   doesn't clip it. */
.total:has(.grade-split) { position: relative; }
.grade-split {
  position: absolute; inset: 0;
  padding: var(--space-5) var(--space-6);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 5px 11px;
  background: rgba(17,17,19,0.55);
  backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px);
  font-family: var(--mono); font-size: 0.82rem; color: var(--muted); font-variant-numeric: tabular-nums;
  opacity: 0; visibility: hidden; transform: scale(1.015);
  transition: opacity .3s var(--ease), transform .3s var(--ease), visibility .3s;
  pointer-events: none;
}
.total:hover .grade-split:not(:empty) { opacity: 1; visibility: visible; transform: scale(1); }
/* burger-style overlay: dim + blur the sibling tiles so the grade popover stands out */
.totals:has(.total:has(.grade-split):hover) .total:not(:has(.grade-split)) {
  filter: blur(2px); opacity: 0.5;
}
.totals .total { transition: filter .3s var(--ease), opacity .3s var(--ease); }
.grade-split i { width: 1px; height: 9px; background: var(--line-soft); display: inline-block; }
.grade-split .gr { font-weight: 700; margin-right: 3px; font-style: normal; }
.grade-split .gr-a { color: var(--accent); }
.grade-split .gr-b { color: var(--good); }
.grade-split .gr-c { color: var(--muted); }
.grade-split .gr-d { color: var(--warn); }

/* ─────────────────────────────────────────────────────────────────────────
   xAI type system — Inter (display + body), Geist Mono for eyebrows/labels/
   counters. Display = tight NEGATIVE tracking, ink white, modest weight (no
   bold). Eyebrows = Geist Mono UPPERCASE with positive tracking. */
.brand-sub { font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.1em; font-size: 0.6rem; color: var(--muted); }
/* Display headings: title-case, tight negative tracking, ink white. */
.wb-name { text-transform: none; letter-spacing: -0.02em; font-weight: 600; color: var(--ink); }
.empty h2, .drawer-head h2 { text-transform: none; letter-spacing: -0.025em; font-weight: 600; color: var(--ink); }
.placeholder h2 { text-transform: none; letter-spacing: -0.03em; font-weight: 600; color: var(--ink); }
/* Headline metric values → ink white. */
.total-val { color: var(--ink); }
/* Eyebrows / labels / counters → Geist Mono, uppercase, positive tracking. */
.total-label, .vt-head > span, .at-head > span, .ot-count, .dr-cap, .dr-month,
.ver-filter > span, .tag, .ph-soon, .at-sub, .at-total > .at-name,
.at-total > span:first-child, .mkt-table th { font-family: var(--mono); }
/* Running prose stays Inter (no serif in xAI) with a hair of negative tracking. */
.empty p, .placeholder p, .st-meta { font-family: var(--font); letter-spacing: -0.01em; }

/* ─── Monochrome finish: tinted depth, white accent, restrained translucent-white controls ─── */
/* Faint grain so the dark canvas isn't perfectly flat. */
.grain { display: block; opacity: 0.03; }
/* The old floating burger nav is replaced by the left rail. */
.fab, .fab-scrim { display: none !important; }

/* Soft black shadows return — depth from tinted shadow, not white glow. */
.rail { box-shadow: var(--shadow-1); }
.wb, .mkt-card, .drep-day, .totals { box-shadow: var(--shadow-1); }
.drawer-panel { box-shadow: var(--shadow-2); }
.toast, .dr-pop, .sales-conv, .exp-card,
.at-th[data-tip]::after, .ot-th[data-tip]::after, .mkt-tip { box-shadow: var(--shadow-2); }
.sales-pop, .grade-split { backdrop-filter: none; -webkit-backdrop-filter: none; background: var(--pop-bg); }

/* Interactive = translucent-white pill, transparent fill. */
.btn { background: transparent; border: 1px solid var(--hair-1); color: var(--text);
  border-radius: 9999px; font-weight: 500; letter-spacing: 0; text-transform: none; transition: all 0.16s var(--ease); }
.btn:hover { background: var(--wash-1); border-color: var(--hair-3); color: var(--ink); }
.btn.ghost { color: var(--muted); }
.btn.ghost:hover { color: var(--ink); }
/* Buttons stay black-and-white: primary CTA = white fill, dark text (no accent hue). */
.btn.solid { background: var(--ink); border-color: var(--ink); color: var(--accent-ink); font-weight: 600; box-shadow: var(--shadow-1); }
.btn.solid:hover { background: var(--solid-hover); border-color: var(--solid-hover); color: var(--accent-ink); transform: translateY(-1px); }
/* Pill-ify the remaining controls. (Text inputs / selects stay soft rects.) */
.icon-btn, .dr-nav, .ph-soon, .tag, .seg button, .src-toggle { border-radius: 9999px; }
.src-toggle { overflow: hidden; }
/* Toggle "on" states are also B&W — white fill / neutral highlight, not blue. */
.src-btn.is-active { background: var(--ink); color: var(--accent-ink); }
.seg button[aria-pressed="true"] { background: var(--wash-3); border-color: var(--hair-4); color: var(--ink); }
.placeholder { border-radius: var(--r-lg); }
/* Focus: white accent ring. */
input:focus, select:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

/* Stronger big-number hierarchy: the one accent tile per view reads white + heavier. */
.total.accent { box-shadow: inset 0 2px 0 var(--accent-edge), var(--shadow-1); }
.total.accent .total-val { color: var(--accent); font-weight: 700; }
.status.live { color: var(--good); }
.st-err { color: var(--warn); }

/* ── New components (rail redesign) ───────────────────────
   Skeleton loaders, two-step delete confirm, collapsed-card glance metric. */

/* Skeleton shimmer — matches the row shapes instead of a text placeholder. */
.skel-wrap { padding: var(--space-3) 0; }
.skel-row { display: flex; align-items: center; gap: var(--space-4); padding: 11px var(--space-4); }
.skel-row + .skel-row { border-top: 1px solid var(--line-soft); }
.skel { height: 11px; border-radius: 4px; background: linear-gradient(90deg, var(--surface-2) 25%, var(--line) 50%, var(--surface-2) 75%); background-size: 200% 100%; animation: shimmer 1.25s linear infinite; }
.skel.wide { flex: 2.2; } .skel.cell { flex: 1; }
@keyframes shimmer { to { background-position: -200% 0; } }
@media (prefers-reduced-motion: reduce) { .skel { animation: none; } }

/* Two-step delete confirm — replaces window.confirm(). First click arms the
   button (turns red, widens to "Remove?"); a second click within 3s deletes. */
.icon-btn[data-del] { transition: color .16s var(--ease), border-color .16s var(--ease), background .16s var(--ease), width .18s var(--ease); }
.icon-btn.armed {
  width: auto; padding: 0 11px; gap: 6px; color: var(--warn);
  border-color: var(--warn); background: rgba(240,101,94,0.1);
  font-family: var(--mono); font-size: 0.62rem; font-weight: 700;
  letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap;
}

/* Collapsed-card glance metric — the headline number in the card header, so you
   don't have to expand every card to see anything. Hidden until its data loads. */
.wb-glance { display: inline-flex; align-items: baseline; gap: 6px; margin-left: var(--space-4); }
.wb-glance:empty { display: none; }
/* Only the open card shows its opt-in glance; collapsed cards hide it (the number
   reflects the globally-scoped range, which is the open webinar's window). */
.wb:not(.open) .wb-glance { display: none; }
.wb-glance .g-val { font-family: var(--mono); font-weight: 600; font-size: 0.98rem; font-variant-numeric: tabular-nums; letter-spacing: -0.02em; color: var(--ink); }
.wb-glance .g-val.accent { color: var(--accent); }
.wb-glance .g-lab { font-family: var(--mono); font-size: 0.56rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--faint); }
@media (max-width: 680px) { .wb-glance { display: none; } }

/* ── Performance coloring — green = good, red = poor, only where objective ──
   Used for: best-in-column (green, already), ROAS profit/loss, and cost/rate
   outliers (a cost >2× the cheapest, or a rate <½ the best). Red is reserved for
   genuine underperformers so it never false-alarms on a near-tie. */
.num.perf-bad,  .total-val.perf-bad,  .mkt-cash.perf-bad  { color: var(--warn); font-weight: 600; }
.num.perf-good, .total-val.perf-good, .mkt-cash.perf-good { color: var(--good); font-weight: 600; }

/* ── Organic tab polish — summary strip, data-bars, channel subtotals ──────── */
.ot-tot { margin-top: 0; }
/* per-channel subheader: name left, its sign-up count + row count right */
.at-sub.ot-ch { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4); }
.at-sub.ot-ch > span:first-child { color: var(--ink); }
.ot-ch-meta { font-family: var(--mono); font-size: 0.62rem; letter-spacing: 0.02em; text-transform: none; color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* inline data-bar behind the Sign-ups/1k value (width ∝ value ÷ column max) */
.ot-bar-cell { position: relative; }
.ot-fill { position: absolute; top: 7px; bottom: 7px; right: 0; min-width: 2px; background: var(--wash-2); border-radius: 3px; pointer-events: none; }
.ot-fill.top { background: rgba(88,204,154,0.22); }
.ot-bar-v { position: relative; z-index: 1; }
.ot-bar-v.good { color: var(--good); font-weight: 600; }
.ot-vico { margin-right: 7px; opacity: 0.75; font-size: 0.9em; }

/* Ad-by-Ad per-card summary strip — sits above the ad table, full width. */
.at-strip:empty { display: none; }
.at-strip .ad-tot { margin: 0 0 var(--space-4); }

/* ── Date-picker quick-select (last 4 webinars) ───────────────────────────── */
.dr-quick { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); display: flex; flex-direction: column; gap: 5px; }
.dr-quick:empty { display: none; }
.dr-quick-lab { font-family: var(--mono); font-size: 0.56rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; color: var(--faint); padding: 0 2px 5px; }
/* each preset is a solid white button (like the primary CTA), dark text, with a
   dark pill "time" badge; the selected webinar gets a soft white halo ring. */
.dr-quick-btn { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; text-align: left; cursor: pointer; background: var(--ink); color: var(--accent-ink);
  border: 1px solid var(--ink); border-radius: 9999px; padding: 8px 13px;
  font-family: var(--font); font-size: 0.82rem; font-weight: 600; box-shadow: var(--shadow-1);
  transition: background .16s var(--ease), border-color .16s var(--ease), transform .16s var(--ease); }
/* same hover as the Add-webinar CTA (.btn.solid): dim the fill + lift 1px */
.dr-quick-btn:hover { background: var(--solid-hover); border-color: var(--solid-hover); transform: translateY(-1px); }
.dr-quick-btn.is-active { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--accent-edge); }
.dr-quick-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; color: var(--accent-ink); }
.dr-quick-range { font-family: var(--mono); font-size: 0.63rem; font-weight: 700; color: var(--on-accent-strong); white-space: nowrap;
  flex-shrink: 0; font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
  background: var(--on-accent-wash); border: 1px solid var(--on-accent-line); border-radius: 999px; padding: 3px 8px; }

/* Mobile: the date-picker popover is right-anchored + 286px wide, so on a narrow
   screen it spills off the edge. Pin it to the viewport centre so it's always
   fully on-screen (DOM stays inside .daterange, so outside-click close still works). */
@media (max-width: 640px) {
  .dr-pop {
    position: fixed; left: 50%; right: auto; top: 50%;
    transform: translate(-50%, -50%);
    width: min(320px, calc(100vw - 24px));
    max-height: calc(100dvh - 32px); overflow-y: auto;
    z-index: 200;
  }
}

/* ── Closers subtab ── grouped Ads-only / Organic-only header over the same stl-table
   shell. The group labels aren't sortable (no data-sort); the sub-row headers are. */
.clos-table th.clos-grp-lbl { text-align: center; color: var(--muted); cursor: default; }
.clos-table th.clos-sep, .clos-table td.clos-sep { border-left: 1px solid var(--line); }
/* The group label carries the UNIT on the Setters tab ("· per booking" / "· per lead") —
   the two halves count different things, so this is load-bearing, not a caption. */
.clos-table th.clos-grp-lbl em { font-style: normal; font-weight: 500; color: var(--faint); text-transform: none; letter-spacing: 0; }

/* ── Setters / Closers: person-first tables ───────────────────────────────────
   Both are one row per PERSON, pooled across every show, with the show as the
   drill-down. See the block comments in app.js for why (per-show samples are a median
   of 6 — too thin to rank, and the old view coloured and sorted them anyway). */

/* A rate with too small a sample to be evidence. It still SHOWS — hiding it would just
   raise "where did that person go" — but it goes grey, wears its n, and sorts to the
   bottom of any rate column (see cmpRate/sortClos). The `n=` tag is what stops "50%"
   reading as the same claim as "35% of 68". */
.set-thin { color: var(--faint) !important; font-weight: 500 !important; }
.set-n { display: block; font-family: var(--mono); font-size: 0.58rem; font-style: normal;
  color: var(--faint); opacity: 0.85; letter-spacing: 0; line-height: 1.1; margin-top: 1px; }
/* "(not dialed)" is a bucket the sync emits, not a person — never let it read as a name. */
.set-bucket { font-style: italic; color: var(--faint) !important; }

/* Speed distribution: five disjoint buckets that sum to `dialed`. This was five separate
   % columns — five numbers per row to read and mentally re-stack. */
.spd-cell { min-width: 132px; }
.spd-bar { display: flex; width: 100%; height: 9px; border-radius: 3px; overflow: hidden;
  background: var(--line-soft); cursor: help; }
.spd-seg { display: block; height: 100%; }
.spd-seg.b5  { background: var(--spd-1); }
.spd-seg.b30 { background: var(--spd-2); }
.spd-seg.b60 { background: var(--spd-3); }
.spd-seg.bd  { background: var(--spd-4); }
.spd-seg.bx  { background: var(--spd-5); }

/* Close-rate bar. Scaled to the best rate on the board, NOT to 100% — every close rate
   here lives in 14–35%, so a 0–100% axis renders the whole team as identical stubs and
   the bar stops doing its one job. */
.rt-bar { display: block; width: 100%; height: 9px; border-radius: 3px; overflow: hidden;
  background: var(--line-soft); cursor: help; }
.rt-fill { display: block; height: 100%; border-radius: 3px; background: var(--accent-dim); }
.rt-fill.perf-good { background: var(--good); }
.rt-fill.perf-bad  { background: var(--warn); }

/* Never-rung banner. This number was `Bookings − Dialed`: a subtraction between two
   adjacent columns that nobody performs. Booked, then silence — it gets to be a number. */
.set-alert { display: flex; align-items: center; gap: var(--space-4);
  padding: var(--space-4) var(--space-5); margin-bottom: var(--space-4);
  background: var(--surface); border: 1px solid var(--line-soft);
  border-left: 3px solid var(--warn); border-radius: var(--r-md); box-shadow: var(--shadow-1); }
.set-alert-n { font-family: var(--mono); font-size: 1.5rem; font-weight: 600; color: var(--warn);
  font-variant-numeric: tabular-nums; letter-spacing: -0.03em; line-height: 1; }
.set-alert-t { font-size: 0.86rem; font-weight: 600; color: var(--ink); line-height: 1.35; }
.set-alert-t em { display: block; font-style: normal; font-size: 0.76rem; font-weight: 400; color: var(--muted); }

/* ── Scatter: dial speed vs confirm rate ──────────────────────────────────────
   The one question no table on this tab asks — does ringing sooner actually get calls
   confirmed? Measured r = 0.45 across the setters with a real sample. */
.sc-card { padding: var(--space-5) var(--space-6) var(--space-4); margin-bottom: var(--space-4); }
.sc-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-4);
  flex-wrap: wrap; margin-bottom: var(--space-5); }
.sc-title { font-weight: 600; font-size: 0.92rem; color: var(--ink); letter-spacing: -0.01em; }
.sc-sub { font-family: var(--mono); font-size: 0.62rem; text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--faint); }
/* ⚠️ Plot area + dots are HTML, NOT SVG. The plot must stretch to the card's width at a
   fixed height, and an SVG doing that (preserveAspectRatio="none") scales x and y by
   different factors — which renders every <circle> as a wide ellipse. Dots positioned in
   % and sized in px stay round at any width. Grid lines are a background gradient for the
   same reason: a line shears harmlessly, a circle doesn't. */
.sc-wrap { position: relative; padding: 0 0 22px 46px; }
.sc-plot {
  position: relative; height: 200px;
  border-left: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft);
  background-image:
    repeating-linear-gradient(to right, var(--line-soft) 0 1px, transparent 1px 25%),
    repeating-linear-gradient(to top,   var(--line-soft) 0 1px, transparent 1px 50%);
}
.sc-dot {
  position: absolute; border-radius: 50%;
  transform: translate(-50%, 50%);            /* left/bottom address the dot's CENTRE */
  background: var(--accent); opacity: 0.42;
  border: 1px solid var(--accent); cursor: help;
  transition: opacity .14s var(--ease);
}
.sc-dot:hover { opacity: 0.95; z-index: 2; }
.sc-ylab, .sc-xlab, .sc-ymax, .sc-ymin, .sc-xmin, .sc-xmax {
  position: absolute; font-family: var(--mono); font-size: 0.58rem; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--faint); white-space: nowrap;
}
.sc-ylab { left: 0; top: 50%; transform: rotate(-90deg) translateX(50%); transform-origin: left center; }
.sc-ymax { left: 46px; top: -6px; transform: translateX(-100%); padding-right: 6px; }
.sc-ymin { left: 46px; bottom: 22px; transform: translateX(-100%); padding-right: 6px; }
.sc-xlab { left: 50%; bottom: 0; transform: translateX(-50%); }
.sc-xmin { left: 46px; bottom: 0; }
.sc-xmax { right: 0; bottom: 0; }
.sc-note { font-size: 0.76rem; color: var(--muted); line-height: 1.5; margin-top: var(--space-4);
  padding-top: var(--space-4); border-top: 1px solid var(--line-soft); }
.sc-note strong { color: var(--text); font-weight: 600; }
@media (max-width: 640px) { .sc-plot { height: 150px; } .sc-card { padding: var(--space-4); } }

/* ── Auth: identity chip + access modal ───────────────────────────────────────
   Uses the app's own tokens (--surface-2 / --line / --muted) so it reads as part of
   the instrument panel. The first pass reused .exp-go/.exp-select — those are a
   full-width left-aligned pill and a label-hugging field with a negative top margin,
   so side-by-side in a row they collapsed. Dedicated classes instead. */

/* ── Appearance switch (dark ⇄ light) ────────────────────────────────────────
   Rail footer, between Export and the identity chip. Signed-in only — initAuth()
   unhides it, so an anonymous shell never offers a theme it wouldn't keep.
   Borderless by request: the track/knob already reads as a control, so an outline
   only competed with the two bordered buttons above. Padding matches .btn's interior
   (its 9px/15px minus the 1px border it has and this doesn't) to keep the footer's
   left edge aligned; the hover wash is what's left to signal it's pressable. */
.theme-row { display: flex; }
.theme-row[hidden] { display: none; }  /* .theme-row's display beats the UA [hidden] rule */
.theme-switch {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 8px 11px; cursor: pointer; user-select: none;
  background: transparent; border: 0; border-radius: 9999px;
  transition: background .16s var(--ease);
}
.theme-switch:hover { background: var(--wash-1); }
.theme-ico { font-size: 0.86rem; line-height: 1; flex: none; }
.theme-lab {
  flex: 1; min-width: 0; font-size: 0.78rem; font-weight: 500; color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: color .16s var(--ease);
}
.theme-switch:hover .theme-lab { color: var(--ink); }
/* The real checkbox drives state + keyboard/AT; the track is the painted skin. */
.theme-input { position: absolute; opacity: 0; width: 0; height: 0; }
/* Mirrors .mode-track/.mode-knob, scaled to fit beside a label in the 210px rail. */
.theme-track {
  position: relative; flex: none; width: 34px; height: 19px;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: 999px;
  transition: background .2s var(--ease), border-color .2s var(--ease);
}
.theme-knob {
  position: absolute; top: 2px; left: 2px; width: 13px; height: 13px;
  border-radius: 50%; background: var(--accent); transition: transform .22s var(--ease);
}
.theme-input:checked ~ .theme-track { background: var(--accent-soft); border-color: var(--accent-dim); }
.theme-input:checked ~ .theme-track .theme-knob { transform: translateX(15px); }
.theme-input:focus-visible ~ .theme-track { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Icon-only rail (641–1000px): 62px can't hold a label + a 34px track, so the sun/moon
   glyph carries the state alone — the same trade the .btn labels make. The <label for>
   keeps the whole pill tappable, so nothing is lost but the words.
   Bounded at 641px like the rail rules it follows: on a phone the switch lives in the
   slide-out drawer, which has the full 272px and shows the desktop switch. */
@media (min-width: 641px) and (max-width: 1000px) {
  .theme-lab, .theme-track { display: none; }
  .theme-switch { justify-content: center; padding: 9px 0; }
  .theme-ico { font-size: 1rem; }
}

/* Identity chip, pinned under the rail buttons. */
.whoami {
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px; margin-top: 2px;
  background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-md);
}
.whoami-id { display: flex; align-items: center; gap: 9px; min-width: 0; }
.whoami-pic {
  width: 26px; height: 26px; border-radius: 50%; flex-shrink: 0;
  object-fit: cover; background: var(--surface-2); border: 1px solid var(--line);
}
/* Shown only when Google gives us no picture — first initial on a neutral disc.
   ⚠️ `display: grid` beats the UA's `[hidden] { display: none }` on specificity, so
   without the rule below this disc stays visible NEXT TO the real avatar — two circles.
   Any class that sets `display` on a toggled element needs its own [hidden] escape. */
.whoami-fallback {
  display: grid; place-items: center;
  font-size: 0.7rem; font-weight: 600; color: var(--muted); text-transform: uppercase;
}
.whoami-fallback[hidden] { display: none; }
.whoami-meta { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.whoami-name { font-size: 0.76rem; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.whoami-email { font-size: 0.66rem; color: var(--faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Must LOOK pressable — the first version was a bare underlined link and read as text. */
.whoami-out {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  padding: 6px 10px; border-radius: var(--r-sm, 7px); cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--line);
  color: var(--muted); font-size: 0.74rem; font-weight: 500; text-decoration: none;
  transition: color .14s var(--ease), border-color .14s var(--ease), background .14s var(--ease);
}
.whoami-out:hover { color: var(--warn); border-color: rgba(229,100,94,0.45); background: rgba(229,100,94,0.07); }
.whoami-out:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.whoami-out-ico { font-size: 0.78rem; line-height: 1; }
.whoami-out-lab { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Identity chip on the icon-only rail (641–1000px). MUST live here, after the rules it
   overrides — the rail's own media block is ~1000 lines up, so `display: none` there
   loses to `.whoami-meta { display: flex }` below on source order alone. That bug shipped
   for a minute: the name/email collapsed to a sliver but still claimed its 9px flex gap,
   which shoved the avatar 4.5px off-centre. Kill the gap AND the element.
   62px of rail fits an avatar or a label, not both: "Sign out" wrapped onto two lines. */
@media (min-width: 641px) and (max-width: 1000px) {
  .whoami { padding: 8px; }
  .whoami-id { justify-content: center; gap: 0; }
  .whoami-meta { display: none; }
  .whoami-out { padding: 6px 0; gap: 0; }
  .whoami-out-lab { display: none; }
}

/* Add-person form. */
.set-form { display: flex; flex-direction: column; gap: 10px; margin-top: calc(-1 * var(--space-2)); }
.set-input {
  width: 100%; padding: 10px 12px;
  background: var(--surface-2); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r-md);
  font-family: var(--font); font-size: 0.9rem;
  transition: border-color .14s var(--ease);
}
.set-input::placeholder { color: var(--faint); }
.set-input:focus { outline: none; border-color: var(--accent-dim); }

/* Role picker: two selectable cards, not a <select> — the choice carries a real
   consequence (admins can grant access), so it should be visible, not hidden in a menu. */
.set-roles { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.set-role { cursor: pointer; }
.set-role input { position: absolute; opacity: 0; pointer-events: none; }
.set-role-box {
  display: flex; flex-direction: column; gap: 2px;
  padding: 9px 11px; height: 100%;
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-md);
  transition: border-color .14s var(--ease), background .14s var(--ease);
}
.set-role:hover .set-role-box { border-color: var(--accent-dim); }
.set-role input:checked + .set-role-box { border-color: var(--accent); background: var(--accent-soft); }
.set-role input:focus-visible + .set-role-box { outline: 2px solid var(--accent); outline-offset: 2px; }
.set-role-t { font-size: 0.82rem; font-weight: 600; color: var(--text); }
.set-role input:checked + .set-role-box .set-role-t { color: var(--ink); }
.set-role-s { font-size: 0.66rem; color: var(--faint); line-height: 1.3; }

.set-addbtn {
  width: 100%; padding: 9px 14px; cursor: pointer;
  background: var(--ink); color: var(--accent-ink);
  border: 1px solid var(--ink); border-radius: var(--r-md);
  font-family: var(--font); font-size: 0.85rem; font-weight: 600;
  transition: opacity .14s var(--ease);
}
.set-addbtn:hover { opacity: 0.88; }
.set-addbtn:disabled { opacity: 0.5; cursor: default; }
.set-addbtn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.set-msg { font-size: 0.76rem; color: var(--good); margin-top: calc(-1 * var(--space-2)); }
.set-msg.is-bad { color: var(--warn); }

/* People list. */
.set-list {
  margin-top: calc(-1 * var(--space-2));
  max-height: 220px; overflow-y: auto;
  border: 1px solid var(--line-soft); border-radius: var(--r-md);
}
.set-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-bottom: 1px solid var(--line-soft);
}
.set-row:last-child { border-bottom: 0; }
.set-em { flex: 1; min-width: 0; font-size: 0.79rem; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.set-tag {
  flex-shrink: 0; font-family: var(--mono);
  font-size: 0.55rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted); border: 1px solid var(--line); border-radius: 999px; padding: 2px 7px;
}
.set-tag.is-admin { color: var(--violet); border-color: var(--violet-line); }
.set-tag.is-locked { color: var(--faint); }
.set-rm {
  flex-shrink: 0; cursor: pointer; padding: 3px 9px;
  background: transparent; color: var(--faint);
  border: 1px solid var(--line); border-radius: var(--r-sm, 7px);
  font-family: var(--font); font-size: 0.7rem;
  transition: color .14s var(--ease), border-color .14s var(--ease);
}
.set-rm:hover { color: var(--warn); border-color: rgba(229,100,94,0.45); }
.set-rm:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.set-empty { padding: 14px 10px; font-size: 0.76rem; color: var(--faint); text-align: center; }
