/* =============================================================================
   Analytica CRM — Design System v2
   -----------------------------------------------------------------------------
   A single, self-contained stylesheet. No external fonts, no CDN, no build step.
   Organised as: tokens → base → primitives → shell → layout → data → overlays →
   page modules → states → responsive → print/motion.

   Rules that hold everywhere in here:
   · Every colour is a token. Never a raw hex outside the token blocks.
   · Every surface works in light AND dark. Theme is user-selectable (see [data-theme]).
   · Spacing comes off a 4px grid; type comes off a 9-step scale.
   · Nothing may clip text or overlap: flex/grid children get `min-width:0`,
     long strings get `overflow-wrap`, wide content scrolls inside its own box.
   ========================================================================== */

/* =============================================================================
   01 · TOKENS
   ========================================================================== */
:root{
  /* — neutral ramp (light) — */
  --n0:#ffffff;  --n25:#fcfdfe; --n50:#f7f9fb; --n100:#eff2f6; --n200:#e4e8ef;
  --n300:#d3d9e3; --n400:#a8b1c1; --n500:#78839a; --n600:#586274; --n700:#3f4859;
  --n800:#28303f; --n900:#161c28; --n950:#0b0f17;

  /* — brand — */
  /* Sampled from the Analytica wordmark: deep navy on the left through to teal on the
     right. The accent is the mid-tone so it reads as the brand without shouting. */
  --brand-50:#eef5f8; --brand-100:#d8e9ef; --brand-200:#b3d3de; --brand-300:#7bb4c7;
  --brand-400:#4a95ad; --brand-500:#2f7d95; --brand-600:#26647a; --brand-700:#1e4f60;
  --brand-800:#1a4152; --brand-900:#173544;

  /* — semantic surfaces — */
  --page:var(--n50);
  --surface:var(--n0);          /* cards, panels, menus */
  --surface-2:var(--n50);       /* inset wells, table heads, subtle fills */
  --surface-3:var(--n100);      /* hover fills, tracks */
  --panel:var(--n0);            /* legacy alias — same as --surface */
  --sidebar-bg:color-mix(in srgb, var(--n0) 78%, transparent);
  --topbar-bg:color-mix(in srgb, var(--n0) 82%, transparent);
  --scrim:rgba(11,15,23,.42);

  /* — semantic ink — */
  --ink:var(--n900);            /* primary text */
  --ink2:var(--n700);           /* secondary text */
  --muted:var(--n500);          /* tertiary / meta */
  --ink-invert:#ffffff;

  /* — lines — */
  --line:var(--n200);
  --line-2:var(--n300);         /* stronger divider / input border */
  --line-soft:color-mix(in srgb, var(--n200) 60%, transparent);

  /* — accent — */
  --accent:var(--brand-500);
  --accent-dk:var(--brand-600);
  --accent-soft:var(--brand-50);
  --accent-soft-2:var(--brand-100);
  --tint-ink:var(--brand-700);
  --accent-ring:color-mix(in srgb, var(--accent) 26%, transparent);

  /* — status — */
  --good:#12a150;   --good-soft:#e6f7ee;
  --warning:#c77700; --warning-soft:#fdf3e2;
  --serious:#e05500; --serious-soft:#fdeee3;
  --critical:#d92d20; --critical-soft:#fdecea;
  /* Lead-status tones. Their own tokens rather than borrowed semantic ones: "attempted" is orange
     because it is the second step of the pipeline, not because it is a warning, and won must stay
     the strongest green while contacted sits visibly lighter beneath it. */
  --st-new:#c9a100;      --st-new-soft:#fbf5d9;
  --st-attempt:#e05500;  --st-attempt-soft:#fdeee3;
  --st-contacted:#4caf50; --st-contacted-soft:#e9f7ea;
  --info:var(--accent); --info-soft:var(--accent-soft);

  /* — sequential ramp (magnitude only, single hue) — */
  /* single-hue magnitude ramp, on the brand teal so pipeline bars and the accent agree */
  --seq-1:#d8e9ef; --seq-2:#b3d3de; --seq-3:#8cbccb; --seq-4:#5fa3b8;
  --seq-5:#2f7d95; --seq-6:#26647a; --seq-7:#1e4f60;

  /* — elevation — */
  --shadow-1:0 1px 2px rgba(16,24,40,.05), 0 1px 3px rgba(16,24,40,.05);
  --shadow-2:0 2px 4px rgba(16,24,40,.05), 0 8px 20px -6px rgba(16,24,40,.12);
  --shadow-3:0 12px 24px -8px rgba(16,24,40,.16), 0 32px 64px -16px rgba(16,24,40,.24);
  --shadow-inset:inset 0 1px 0 rgba(255,255,255,.5);
  --ring-focus:0 0 0 3px var(--accent-ring);

  /* — radius — */
  --r-xs:6px; --r-sm:8px; --r-md:11px; --r-lg:15px; --r-xl:20px; --r-full:999px;
  --radius-sm:var(--r-sm); --radius-md:var(--r-md); --radius-lg:var(--r-lg); /* legacy aliases */

  /* — spacing (4px grid) — */
  /* Compact pass (2026-08-15): the top steps were carrying most of the page's excess whitespace,
     so they came down a notch while the small steps (control padding) stayed put. Data density up,
     tap targets untouched. */
  --s1:4px; --s2:8px; --s3:12px; --s4:14px; --s5:18px; --s6:22px;
  --s7:26px; --s8:34px; --s9:42px; --s10:56px;

  /* — type scale — */
  --fs-2xs:10.5px; --fs-xs:11.5px; --fs-sm:12.5px; --fs-base:13px; --fs-md:14px;
  --fs-lg:15.5px; --fs-xl:18px; --fs-2xl:22px; --fs-3xl:27px;
  --fs-label:12.5px; --fs-hint:12px;  /* legacy aliases */
  --lh-tight:1.25; --lh-snug:1.38; --lh:1.5;

  /* — motion — */
  --t-fast:110ms; --t:170ms; --t-slow:260ms;
  --ease:cubic-bezier(.2,.8,.2,1);
  --ease-spring:cubic-bezier(.34,1.28,.64,1);

  /* — shell metrics — */
  --topbar-h:52px;
  --side-w:236px;
  --rail-w:64px;
  --content-max:1440px;

  /* — z-index scale — */
  --z-sticky:20; --z-side:45; --z-topbar:50; --z-pop:60; --z-scrim:55;
  --z-dialog:70; --z-toast:80; --z-progress:90;

  color-scheme:light;
}

/* Dark tokens. Applied by OS preference unless the user has pinned light, and
   always when the user has pinned dark — so the in-app theme switcher wins over
   the OS in both directions. The ramp is written twice (media query + attribute
   selector) because CSS has no way to alias one custom-property block to two
   selectors without a preprocessor, and this file stays build-step-free. */
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .nav-group[data-group="marketing"]{--grp:#a78bfa}
  :root:not([data-theme="light"]) .nav-group[data-group="sources"]{--grp:#2dd4bf}
  :root:not([data-theme="light"]){
    --n0:#0e1219;  --n25:#11161f; --n50:#141a24; --n100:#1a212d; --n200:#252e3c;
    --n300:#333e4f; --n400:#5d6a7e; --n500:#8b96a8; --n600:#a8b2c2; --n700:#c3cbd7;
    --n800:#dde2ea; --n900:#eef1f6; --n950:#f8fafc;

    --page:#0a0e15;
    --surface:#12181f;
    --surface-2:#161d26;
    --surface-3:#1d2531;
    --panel:#12181f;
    --sidebar-bg:color-mix(in srgb, #0d131a 76%, transparent);
    --topbar-bg:color-mix(in srgb, #0d131a 82%, transparent);
    --scrim:rgba(0,0,0,.6);

    --ink:#eef1f6; --ink2:#c3cbd7; --muted:#8b96a8; --ink-invert:#0a0e15;

    --line:#232c3a; --line-2:#2f3a4a;
    --line-soft:color-mix(in srgb, #232c3a 70%, transparent);

    --accent:#5aa7c2; --accent-dk:#7dbdd4;   /* brand teal, lightened for dark-surface contrast — the light/dark accent finally agree on a hue */
    --accent-soft:#122b34; --accent-soft-2:#173a46;
    --tint-ink:#a8d4e2;
    --accent-ring:color-mix(in srgb, var(--accent) 34%, transparent);

    --good:#3ecf8e;   --good-soft:#10291f;
    --warning:#f2b544; --warning-soft:#2b2312;
    --serious:#fb8b4c; --serious-soft:#2d1d13;
    --critical:#ff6b5e; --critical-soft:#31171a;
    --st-new:#f2cf4a;      --st-new-soft:#2b2712;
    --st-attempt:#fb8b4c;  --st-attempt-soft:#2d1d13;
    --st-contacted:#6fcf7f; --st-contacted-soft:#132a18;
    --info:var(--accent); --info-soft:var(--accent-soft);

    --seq-1:#12303a; --seq-2:#17414f; --seq-3:#1f5a6d; --seq-4:#2b788f;
    --seq-5:#3f9bb4; --seq-6:#63b6cb; --seq-7:#92d0df;

    --shadow-1:0 1px 2px rgba(0,0,0,.4);
    --shadow-2:0 2px 6px rgba(0,0,0,.42), 0 10px 26px -8px rgba(0,0,0,.5);
    --shadow-3:0 18px 40px -10px rgba(0,0,0,.6), 0 40px 80px -20px rgba(0,0,0,.7);
    --shadow-inset:inset 0 1px 0 rgba(255,255,255,.06);

    color-scheme:dark;
  }
}
:root[data-theme="dark"] .nav-group[data-group="marketing"]{--grp:#a78bfa}
:root[data-theme="dark"] .nav-group[data-group="sources"]{--grp:#2dd4bf}
:root[data-theme="dark"]{
  --n0:#0e1219;  --n25:#11161f; --n50:#141a24; --n100:#1a212d; --n200:#252e3c;
  --n300:#333e4f; --n400:#5d6a7e; --n500:#8b96a8; --n600:#a8b2c2; --n700:#c3cbd7;
  --n800:#dde2ea; --n900:#eef1f6; --n950:#f8fafc;

  --page:#0a0e15;
  --surface:#12181f;
  --surface-2:#161d26;
  --surface-3:#1d2531;
  --panel:#12181f;
  --sidebar-bg:color-mix(in srgb, #0d131a 76%, transparent);
  --topbar-bg:color-mix(in srgb, #0d131a 82%, transparent);
  --scrim:rgba(0,0,0,.6);

  --ink:#eef1f6; --ink2:#c3cbd7; --muted:#8b96a8; --ink-invert:#0a0e15;

  --line:#232c3a; --line-2:#2f3a4a;
  --line-soft:color-mix(in srgb, #232c3a 70%, transparent);

  --accent:#5aa7c2; --accent-dk:#7dbdd4;   /* brand teal, lightened for dark-surface contrast — the light/dark accent finally agree on a hue */
  --accent-soft:#122b34; --accent-soft-2:#173a46;
  --tint-ink:#a8d4e2;
  --accent-ring:color-mix(in srgb, var(--accent) 34%, transparent);

  --good:#3ecf8e;   --good-soft:#10291f;
  --warning:#f2b544; --warning-soft:#2b2312;
  --serious:#fb8b4c; --serious-soft:#2d1d13;
  --critical:#ff6b5e; --critical-soft:#31171a;
  --st-new:#f2cf4a;      --st-new-soft:#2b2712;
  --st-attempt:#fb8b4c;  --st-attempt-soft:#2d1d13;
  --st-contacted:#6fcf7f; --st-contacted-soft:#132a18;
  --info:var(--accent); --info-soft:var(--accent-soft);

  --seq-1:#12303a; --seq-2:#17414f; --seq-3:#1f5a6d; --seq-4:#2b788f;
  --seq-5:#3f9bb4; --seq-6:#63b6cb; --seq-7:#92d0df;

  --shadow-1:0 1px 2px rgba(0,0,0,.4);
  --shadow-2:0 2px 6px rgba(0,0,0,.42), 0 10px 26px -8px rgba(0,0,0,.5);
  --shadow-3:0 18px 40px -10px rgba(0,0,0,.6), 0 40px 80px -20px rgba(0,0,0,.7);
  --shadow-inset:inset 0 1px 0 rgba(255,255,255,.06);

  color-scheme:dark;
}

/* =============================================================================
   02 · BASE
   ========================================================================== */
*{box-sizing:border-box;margin:0;padding:0}
*,*::before,*::after{min-width:0}
[hidden]{display:none!important}

html{
  scrollbar-width:thin;
  scrollbar-color:color-mix(in srgb, var(--ink) 22%, transparent) transparent;
  -webkit-text-size-adjust:100%;
}
::-webkit-scrollbar{width:12px;height:12px}
::-webkit-scrollbar-track{background:transparent}
::-webkit-scrollbar-thumb{
  background-color:color-mix(in srgb, var(--ink) 18%, transparent);
  border-radius:var(--r-full);border:3px solid transparent;background-clip:content-box;
}
::-webkit-scrollbar-thumb:hover{background-color:color-mix(in srgb, var(--ink) 30%, transparent)}
::-webkit-scrollbar-corner{background:transparent}

/* Best available locally-installed UI face, in preference order, then the platform
   default. No webfont is fetched — UIUX.md forbids external assets — so this picks the
   nicest thing already on the machine rather than shipping a binary. */
:root{
  --font-ui:"Inter var","Inter","SF Pro Text",ui-sans-serif,-apple-system,BlinkMacSystemFont,
            "Segoe UI Variable Text","Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}
body{
  font:var(--fs-base)/var(--lh) var(--font-ui);
  font-optical-sizing:auto;text-rendering:optimizeLegibility;
  background:var(--page);color:var(--ink);
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;
  overflow-wrap:break-word;
}
h1,h2,h3,h4{font-weight:640;letter-spacing:-.018em;line-height:var(--lh-tight);color:var(--ink)}
/* Numbers that get compared down a column must not wobble: lining tabular figures
   everywhere a figure appears in a table, tile, meter or money value. */
table,.tile .n,.tk-n,.coll-total,.bar-row .val,.score,.cm-v,.board-col-count,.board-col-sum,
.nav-badge,.notif-pop-count,.cell-age,.target-kpis,input[type=number]{
  font-variant-numeric:tabular-nums lining-nums;
  font-feature-settings:"tnum" 1,"lnum" 1;
}
h1{font-size:var(--fs-2xl);letter-spacing:-.028em}
h2{font-size:var(--fs-xl);letter-spacing:-.024em}
h3{font-size:var(--fs-md);letter-spacing:-.014em}
h4{font-size:var(--fs-base);letter-spacing:-.008em}
p{line-height:var(--lh)}
a{color:var(--accent);text-underline-offset:2px}
a:hover{color:var(--accent-dk)}
code,kbd,samp,.mono{font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,monospace}
::selection{background:color-mix(in srgb, var(--accent) 26%, transparent)}
:where(img,svg,video){max-width:100%}

/* one focus treatment for the whole app */
:where(button,a,input,select,textarea,summary,[tabindex]):focus-visible{
  outline:2px solid var(--accent);outline-offset:2px;box-shadow:var(--ring-focus);border-radius:var(--r-xs);
}

/* — text helpers — */
.muted{color:var(--muted);font-size:var(--fs-sm)}
.mono{font-size:var(--fs-hint);word-break:break-word;overflow-wrap:anywhere}
.err{color:var(--critical);font-size:var(--fs-base);margin-top:var(--s2);min-height:18px}
.hint{font-size:var(--fs-hint);color:var(--muted);line-height:var(--lh-snug)}
/* A hint inside a <label> inherited the label's 520 weight, so the same sentence read heavier there
   than the identical <p class="hint"> two rows below it — 27 of them across the app, and the two
   sitting side by side on My profile is where it shows. One weight for a hint, wherever it sits. */
label>.hint{font-weight:400}
.nowrap{white-space:nowrap}
.warn-line{
  display:flex;align-items:flex-start;gap:var(--s2);
  color:var(--ink2);font-weight:520;font-size:var(--fs-base);margin:var(--s2) 0;
  background:var(--serious-soft);border:1px solid color-mix(in srgb, var(--serious) 26%, transparent);
  border-radius:var(--r-sm);padding:var(--s2) var(--s3);
}

/* =============================================================================
   03 · BUTTONS
   ========================================================================== */
button,a.ghost,a.small,.btn{
  --btn-bg:var(--accent); --btn-ink:#fff;
  font:inherit;font-size:var(--fs-base);font-weight:560;line-height:1.2;
  display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);
  cursor:pointer;border:1px solid transparent;border-radius:var(--r-sm);
  padding:7px 14px;min-height:34px;
  background:var(--btn-bg);color:var(--btn-ink);
  box-shadow:var(--shadow-1);
  text-decoration:none;white-space:nowrap;
  transition:background var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease),
             box-shadow var(--t-fast) var(--ease),transform var(--t-fast) var(--ease),opacity var(--t-fast);
}
button:hover,a.ghost:hover,a.small:hover,.btn:hover{background:var(--accent-dk)}
button:active,a.ghost:active,a.small:active,.btn:active{transform:translateY(.5px) scale(.985)}
button:disabled,.btn:disabled{opacity:.5;cursor:not-allowed;transform:none}

button.ghost,a.ghost,.btn.ghost{
  background:var(--surface);color:var(--ink2);border-color:var(--line-2);box-shadow:var(--shadow-1);font-weight:520;
}
button.ghost:hover,a.ghost:hover,.btn.ghost:hover{background:var(--surface-3);color:var(--ink);border-color:var(--line-2)}

button.subtle{background:transparent;color:var(--ink2);border-color:transparent;box-shadow:none;font-weight:520}
button.subtle:hover{background:color-mix(in srgb, var(--ink) 7%, transparent);color:var(--ink)}

button.small,a.small,.btn.small{padding:4px 10px;min-height:28px;font-size:var(--fs-sm);border-radius:var(--r-xs)}
button.tiny{padding:2px 8px;min-height:24px;font-size:var(--fs-xs);border-radius:var(--r-xs)}

button.danger,.btn.danger{background:transparent;color:var(--critical);border-color:color-mix(in srgb, var(--critical) 40%, var(--line));box-shadow:none;font-weight:520}
button.danger:hover{background:var(--critical-soft);border-color:var(--critical);color:var(--critical)}
button.small.ghost.danger{color:var(--critical);background:var(--surface)}
button.small.ghost.danger:hover{background:var(--critical-soft)}

button.icon-btn,.icon-btn{
  min-width:32px;padding:0 var(--s2);text-align:center;font-weight:600;font-size:var(--fs-md);line-height:1;
}
.icon-btn-dots{font-size:18px;letter-spacing:.5px}

/* =============================================================================
   04 · FORM CONTROLS
   ========================================================================== */
label{display:block;font-size:var(--fs-label);font-weight:520;color:var(--ink2);margin-bottom:var(--s3)}
label input,label select,label textarea{margin-top:5px}
label.inline{margin:0;display:flex;flex-direction:column;gap:2px;font-size:var(--fs-xs);color:var(--muted)}
label.inline select,label.inline input{width:auto;min-width:130px;margin-top:0}
label.ac-anchor{position:relative}

input,select,textarea{
  /* font:inherit pulls the wrapping label's 520 weight into the field, so everything you TYPED
     rendered semi-bold. What you type is content, not a heading — normal weight, everywhere. */
  font:inherit;font-weight:400;font-size:var(--fs-base);color:var(--ink);
  background:var(--surface);border:1px solid var(--line-2);border-radius:var(--r-sm);
  padding:7px 11px;width:100%;min-height:34px;
  transition:border-color var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease),background var(--t-fast);
}
input::placeholder,textarea::placeholder{color:var(--n400)}
input:hover:not(:disabled),select:hover:not(:disabled),textarea:hover:not(:disabled){border-color:color-mix(in srgb, var(--ink) 24%, var(--line-2))}
input:focus,select:focus,textarea:focus{outline:none;border-color:var(--accent);box-shadow:var(--ring-focus)}
input:disabled,select:disabled,textarea:disabled{background:var(--surface-2);color:var(--muted);cursor:not-allowed}
input[readonly]{background:var(--surface-2);color:var(--ink2)}
textarea{min-height:96px;resize:vertical;line-height:var(--lh)}
input[type=search]{appearance:none}
input[type=number]{font-variant-numeric:tabular-nums}
input[type=range]{width:100%;accent-color:var(--accent);padding:0;min-height:0;border:0;background:transparent}
input[type=color]{padding:2px;min-height:34px;cursor:pointer}
input[type=file]{padding:6px 10px;background:var(--surface-2)}

select{
  appearance:none;-webkit-appearance:none;cursor:pointer;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2378839a' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-position:right 9px center;background-size:14px;padding-right:30px;
}
input[type=checkbox],input[type=radio]{
  /* min-width + flex-shrink:0 stop a checkbox being squeezed below its own size
     when it sits in a tight table header or flex row (the Leads select-all was 13px). */
  width:16px;height:16px;min-width:16px;min-height:16px;flex-shrink:0;
  accent-color:var(--accent);cursor:pointer;padding:0;
  transition:transform var(--t-fast) var(--ease-spring);
}
input[type=checkbox]:active,input[type=radio]:active{transform:scale(.9)}

.formgrid{display:grid;grid-template-columns:1fr 1fr;gap:0 var(--s4)}
.formgrid .full{grid-column:1/-1}
.q-row{display:grid;grid-template-columns:1fr 1fr;gap:var(--s4)}
.chk{display:flex;align-items:center;gap:var(--s2);font-size:var(--fs-base);color:var(--ink);margin:var(--s2) 0;cursor:pointer}
.chk input{width:auto;margin:0;flex-shrink:0}
.chkrow{display:flex;flex-wrap:wrap;gap:var(--s1) var(--s4);margin-top:var(--s1)}
.chkrow .chk{margin:0}

/* password reveal */
.pw-wrap{position:relative;display:block;margin-top:5px}
.pw-wrap input{margin-top:0!important;padding-right:42px;width:100%}
.pw-eye{
  position:absolute;right:3px;top:50%;transform:translateY(-50%);
  background:transparent;border:0;box-shadow:none;color:var(--muted);
  cursor:pointer;font-size:15px;line-height:1;padding:5px 8px;min-height:0;
;display:inline-flex;align-items:center;justify-content:center}
.pw-eye:hover{color:var(--ink);background:transparent}
.pw-eye.on{color:var(--accent)}
/* Two glyphs, one shown at a time: an open eye means "click to reveal", the struck-through eye means
   "it is visible now, click to hide". A single icon cannot say which state you are in. */
.pw-eye svg{width:17px;height:17px;display:block}
.pw-eye .pw-eye-off{display:none}
.pw-eye.on .pw-eye-on{display:none}
.pw-eye.on .pw-eye-off{display:block}

/* autocomplete */
.ac-box{
  position:absolute;top:100%;left:0;right:0;z-index:var(--z-pop);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);
  margin-top:5px;max-height:240px;overflow-y:auto;box-shadow:var(--shadow-2);padding:var(--s1);
}
.ac-item{padding:7px 10px;font-size:var(--fs-base);color:var(--ink);cursor:pointer;border-radius:var(--r-xs)}
.ac-item:hover,.ac-item.ac-active{background:var(--accent-soft);color:var(--tint-ink)}

/* on/off switch */
.switch{position:relative;display:inline-flex;align-items:center;width:40px;height:23px;cursor:pointer;margin-bottom:0;flex-shrink:0}
.switch input{position:absolute;opacity:0;width:0;height:0}
.switch span{position:absolute;inset:0;background:var(--n300);border-radius:var(--r-full);transition:background var(--t) var(--ease)}
.switch span::before{
  content:"";position:absolute;left:3px;top:3px;width:17px;height:17px;background:#fff;border-radius:50%;
  transition:transform var(--t) var(--ease-spring);box-shadow:0 1px 3px rgba(0,0,0,.3);
}
.switch input:checked+span{background:var(--good)}
.switch input:checked+span::before{transform:translateX(17px)}
.switch input:focus-visible+span{box-shadow:var(--ring-focus)}
.switch-row{display:flex;align-items:center;gap:var(--s3);font-size:var(--fs-base);color:var(--ink);margin:var(--s3) 0;cursor:pointer}

/* segmented controls */
.set-nav,.seg-inline,.net-seg{
  display:inline-flex;gap:2px;padding:3px;background:var(--surface-3);
  border:1px solid var(--line);border-radius:var(--r-md);
}
/* inline-flex, not flex: a section-tab strip hugs its tabs instead of stretching
   the full content width (which read as an empty rail beside the last tab). */
/* Settings uses a grouped vertical rail (see .set-layout) — ten flat tabs in a scrolling
   strip gave no sense of what belonged together. Other pages keep the horizontal strip:
   it stays on ONE line and scrolls if it doesn't fit. */
.set-nav{
  display:flex;flex-wrap:nowrap;margin:0 0 var(--s5);border-radius:var(--r-full);
  max-width:100%;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;
}
.set-nav::-webkit-scrollbar{display:none}
.set-nav .set-pill{flex:0 0 auto}
.set-nav{scroll-behavior:smooth}
.seg-inline{border-radius:var(--r-full)}
.set-pill,.net-seg button{
  background:transparent;color:var(--ink2);border:0;border-radius:var(--r-sm);
  padding:6px 15px;font-size:var(--fs-base);font-weight:520;box-shadow:none;min-height:30px;
  transition:background var(--t-fast),color var(--t-fast);
}
.set-nav .set-pill{border-radius:var(--r-full)}
.seg-inline .set-pill{padding:5px 14px;border-radius:var(--r-full)}
.set-pill:hover,.net-seg button:hover{background:color-mix(in srgb, var(--ink) 6%, transparent);color:var(--ink)}
.set-pill.on,.net-seg button.on{background:var(--surface);color:var(--ink);font-weight:620;box-shadow:var(--shadow-1)}
.set-intro{font-size:var(--fs-base);color:var(--ink2);margin:calc(var(--s1) * -1) 0 var(--s4);max-width:78ch}
.set-sec{display:block}

/* multi-select dropdown */
.dd{position:relative;display:inline-block}
.dd summary{
  list-style:none;cursor:pointer;padding:7px 12px;border:1px solid var(--line-2);border-radius:var(--r-sm);
  background:var(--surface);font-size:var(--fs-base);color:var(--ink);user-select:none;white-space:nowrap;
  display:inline-flex;align-items:center;gap:var(--s2);min-height:34px;
}
.dd summary::-webkit-details-marker{display:none}
.dd summary::after{content:"▾";color:var(--muted);font-size:11px}
.dd summary:hover{border-color:color-mix(in srgb, var(--ink) 24%, var(--line-2))}
.dd[open] summary{border-color:var(--accent);box-shadow:var(--ring-focus)}
.dd-panel{
  position:absolute;top:calc(100% + 4px);left:0;z-index:var(--z-pop);min-width:210px;max-height:290px;
  overflow-y:auto;background:var(--surface);border:1px solid var(--line);border-radius:var(--r-md);
  box-shadow:var(--shadow-2);padding:var(--s1);
}
.dd-opt{display:flex;align-items:center;gap:var(--s2);padding:6px 9px;margin:0;font-size:var(--fs-base);color:var(--ink);border-radius:var(--r-xs);cursor:pointer;user-select:none}
.dd-opt:hover{background:var(--surface-3)}

/* choice chips */
.sig-chips{display:flex;flex-wrap:wrap;gap:var(--s2)}
.sig-chip{
  position:relative;display:inline-flex;align-items:center;gap:var(--s2);margin:0;padding:6px 14px;
  font-size:var(--fs-sm);font-weight:520;color:var(--ink2);background:var(--surface);
  border:1px solid var(--line-2);border-radius:var(--r-full);cursor:pointer;user-select:none;
  transition:background var(--t-fast),border-color var(--t-fast),color var(--t-fast);
}
.sig-chip input{position:absolute;opacity:0;pointer-events:none}
.sig-chip:hover{border-color:color-mix(in srgb, var(--accent) 50%, var(--line-2));color:var(--ink)}
.sig-chip:has(input:checked){background:var(--accent-soft);border-color:var(--accent);color:var(--tint-ink);font-weight:600}
.sig-chip:has(input:focus-visible){outline:2px solid var(--accent);outline-offset:2px}

/* =============================================================================
   05 · APP SHELL — topbar + sidebar + content
   ========================================================================== */
#app{
  display:grid;
  grid-template-columns:var(--side-w) minmax(0,1fr);
  grid-template-rows:var(--topbar-h) minmax(0,1fr);
  grid-template-areas:"topbar topbar" "side main";
  min-height:100vh;min-height:100dvh;
  transition:grid-template-columns var(--t) var(--ease);
}
#app.rail{--side-w:var(--rail-w)}

/* — topbar — */
.topbar{
  grid-area:topbar;position:sticky;top:0;z-index:var(--z-topbar);
  display:flex;align-items:center;gap:var(--s3);
  padding:0 var(--s4) 0 var(--s3);
  background:var(--topbar-bg);
  backdrop-filter:blur(20px) saturate(180%);-webkit-backdrop-filter:blur(20px) saturate(180%);
  border-bottom:1px solid var(--line);
}
.tb-brand{
  display:inline-flex;align-items:center;gap:var(--s3);text-decoration:none;color:var(--ink);
  padding:var(--s1) var(--s2);border-radius:var(--r-sm);flex-shrink:0;
}
.tb-brand:hover{background:color-mix(in srgb, var(--ink) 5%, transparent);color:var(--ink)}
.tb-mark{
  width:30px;height:30px;border-radius:9px;flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;
  background:linear-gradient(145deg, var(--brand-400), var(--brand-600));
  color:#fff;box-shadow:0 1px 2px rgba(16,24,40,.28), inset 0 1px 0 rgba(255,255,255,.28);
}
.tb-mark svg{display:block}
/* The wordmark and the product name are two lines of one lockup. `line-height:1.05` squeezed them
   together and the PNG was being squashed by the flex row it sat in — `object-fit:contain` and an
   explicit `flex:0 0 auto` keep its aspect ratio whatever the row does, and there is now real space
   between the logo and "CRM" instead of them touching. */
.tb-word{display:flex;flex-direction:column;gap:4px;line-height:1.15;min-width:0}
/* align-self, not just width:auto — .tb-word is a flex COLUMN, so its default stretch was pulling
   the image to the column's width and squashing the wordmark. That was the compression. */
.tb-logo{height:18px;width:auto;max-width:none;flex:0 0 auto;align-self:flex-start;object-fit:contain;display:block}
:root[data-theme="dark"] .tb-logo,:root[data-theme="dark"] .login-logo{filter:brightness(0) invert(1) opacity(.92)}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .tb-logo,:root:not([data-theme="light"]) .login-logo{filter:brightness(0) invert(1) opacity(.92)}
}
.login-logo{height:26px;width:auto;display:block;margin-bottom:var(--s2)}
.sr-title{font-size:var(--fs-xs);font-weight:660;color:var(--accent);letter-spacing:.13em;text-transform:uppercase;margin-bottom:var(--s2)}
.tb-word b{font-size:var(--fs-md);font-weight:660;letter-spacing:-.02em}
.tb-word span{font-size:var(--fs-2xs);font-weight:640;letter-spacing:.13em;text-transform:uppercase;color:var(--muted);line-height:1}

.tb-divider{width:1px;height:24px;background:var(--line);flex-shrink:0}
.tb-spacer{flex:1;min-width:var(--s2)}

.tb-icon{
  background:transparent;color:var(--ink2);border:1px solid transparent;box-shadow:none;
  width:34px;height:34px;min-height:34px;padding:0;border-radius:var(--r-sm);flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;position:relative;
}
.tb-icon:hover{background:color-mix(in srgb, var(--ink) 7%, transparent);color:var(--ink)}
.tb-icon svg{display:block}
.tb-icon .nav-badge{position:absolute;margin:0}   /* size and offset: see the bell badge rule below */

kbd{
  font-family:inherit;font-size:var(--fs-2xs);font-weight:600;color:var(--muted);
  background:var(--surface);border:1px solid var(--line-2);border-bottom-width:2px;
  border-radius:5px;padding:1px 5px;line-height:1.5;white-space:nowrap;
}

/* user menu */
.usermenu{position:relative;flex-shrink:0}
.tb-user{
  display:inline-flex;align-items:center;gap:var(--s2);background:transparent;color:var(--ink);
  border:1px solid transparent;box-shadow:none;padding:3px var(--s2) 3px 3px;border-radius:var(--r-full);height:36px;
}
.tb-user:hover{background:color-mix(in srgb, var(--ink) 7%, transparent)}
.tb-user[aria-expanded="true"]{background:color-mix(in srgb, var(--ink) 9%, transparent)}
.avatar{
  width:28px;height:28px;border-radius:50%;flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;
  background:linear-gradient(145deg, var(--brand-400), var(--brand-700));
  color:#fff;font-size:var(--fs-xs);font-weight:700;letter-spacing:.02em;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.25);
}
.tb-user .tb-username{font-size:var(--fs-sm);font-weight:560;max-width:130px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tb-user svg{color:var(--muted);flex-shrink:0}

.pop{
  position:absolute;top:calc(100% + 6px);right:0;z-index:var(--z-pop);min-width:230px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-md);
  box-shadow:var(--shadow-3);padding:var(--s1);
  /* The menu grows with the number of remembered accounts, so it has to be able to scroll. Its two
     siblings (.popmenu, .notif-pop-body) already capped themselves; this one overflowed a short
     window with no way to reach Sign out. */
  max-height:min(80vh, 560px);overflow-y:auto;overscroll-behavior:contain;
  animation:popIn var(--t) var(--ease) both;
}
@keyframes popIn{from{opacity:0;transform:translateY(-6px) scale(.98)}to{opacity:1;transform:none}}
.pop-head{padding:var(--s3) var(--s3) var(--s2);border-bottom:1px solid var(--line);margin-bottom:var(--s1)}
.pop-head .welcome{display:block;font-size:var(--fs-base);font-weight:620;color:var(--ink);margin:0}
.pop-head .pop-sub{font-size:var(--fs-hint);color:var(--muted);margin-top:1px;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pop-item{
  display:flex;align-items:center;gap:var(--s2);width:100%;text-align:left;
  background:transparent;color:var(--ink2);border:0;box-shadow:none;font-weight:500;
  padding:7px var(--s3);border-radius:var(--r-xs);font-size:var(--fs-base);min-height:32px;justify-content:flex-start;
  text-decoration:none;
}
.pop-item:hover{background:var(--surface-3);color:var(--ink)}
.pop-item svg{color:var(--muted);flex-shrink:0}
/* Sign out is the one destructive item in this menu and now says so on its own terms rather than by
   accident: its red used to survive only because button.danger:hover happened to out-specify
   .pop-item:hover, so reordering two rules would have quietly turned it grey. */
.pop-item.danger,.pop-item.danger:hover{color:var(--critical);border:0;font-weight:620}
.pop-item.danger svg{color:var(--critical)}
.pop-item.danger:hover{background:var(--critical-soft)}
.pop-item.is-busy{opacity:.6;pointer-events:none}
.pop-sep{height:1px;background:var(--line);margin:var(--s1) 0}

/* ---- switch account rows (user menu) ----
   A two-line row: who, and what they are. The avatar is a plain initials disc rather than an icon so
   the eye can tell two remembered accounts apart at a glance. min-height is taller than a plain
   .pop-item because the row carries a subtitle; nothing changes size on hover, per the house rule. */
.switch-acct{min-height:42px;align-items:center}
.switch-av{
  flex:0 0 24px;width:24px;height:24px;border-radius:50%;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--surface-3);color:var(--ink2);
  font-size:var(--fs-2xs);font-weight:700;letter-spacing:.02em;
}
.switch-av{transition:background var(--t) var(--ease),color var(--t) var(--ease)}
.switch-acct:hover .switch-av{background:var(--accent);color:#fff}
.switch-who{display:flex;flex-direction:column;min-width:0;line-height:1.25}
.switch-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.switch-sub{font-size:var(--fs-2xs);color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.switch-acct.is-busy{opacity:.6;pointer-events:none}

/* ---- calendars card (Meetings) ----
   One row per connected mailbox: who it is on the left, what you can do with it on the right. Wraps
   to stacked on narrow screens rather than letting the buttons squeeze the address to nothing. */
.cal-list{display:flex;flex-direction:column}
.cal-row{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s3);flex-wrap:wrap;
  padding:var(--s3) 0;border-top:1px solid var(--line);
}
.cal-row:first-child{border-top:0}
.cal-who{min-width:0;display:flex;flex-direction:column;gap:2px}
.cal-who>strong{display:inline-flex;align-items:center;gap:var(--s2);flex-wrap:wrap}
.cal-acts{display:flex;gap:var(--s2);flex-shrink:0}

/* ---- notification bubble (anchored to the topbar bell) ----
   A "cloud" popover: rounded panel with a pointer aimed at the bell, scaling up
   from that corner so it reads as coming out of the icon rather than appearing
   over it. */
.notif-anchor{position:relative;flex-shrink:0}
.notif-pop{
  position:absolute;top:calc(100% + 11px);right:calc(var(--s2) * -1);z-index:var(--z-pop);
  width:min(392px,calc(100vw - 24px));
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-3);overflow:hidden;
  display:flex;flex-direction:column;max-height:min(560px,70vh);
  transform-origin:top right;
  animation:notifPopIn var(--t-slow) var(--ease-spring) both;
}
@keyframes notifPopIn{
  from{opacity:0;transform:translateY(-10px) scale(.9)}
  60%{opacity:1}
  to{opacity:1;transform:none}
}
/* the pointer — two stacked squares so the 1px border reads continuously */
.notif-pop::before,.notif-pop::after{
  content:"";position:absolute;top:-7px;right:26px;width:12px;height:12px;
  background:var(--surface);transform:rotate(45deg);
}
.notif-pop::before{border:1px solid var(--line);border-right:0;border-bottom:0}
.notif-pop::after{top:-5px}
.notif-pop-head{
  display:flex;align-items:center;gap:var(--s2);padding:var(--s3) var(--s4);
  border-bottom:1px solid var(--line);background:var(--brand-800);color:#fff;flex-shrink:0;
}
.notif-pop-head h4{font-size:var(--fs-md);font-weight:640;flex:1;min-width:0;color:#fff}
.notif-pop-head .muted{color:rgba(255,255,255,.75)}
/* The bubble's pointer is drawn under the head, so it takes the head's colour or the arrow stops
   matching the bubble it points out of. */
.notif-pop::before,.notif-pop::after{background:var(--brand-800)}
.notif-pop-count{
  font-size:var(--fs-2xs);font-weight:700;color:var(--brand-800);background:#fff;
  border-radius:var(--r-full);padding:2px 8px;font-variant-numeric:tabular-nums;
}
.notif-pop-body{overflow-y:auto;padding:var(--s2);display:flex;flex-direction:column;gap:6px;min-height:0}
/* compact variant of .notif-item for inside the bubble */
.notif-pop-body .notif-item{padding:10px var(--s3);border-radius:var(--r-sm);box-shadow:none;gap:var(--s2)}
.notif-pop-body .notif-item:hover{transform:none;background:var(--surface-2)}
.notif-pop-body .notif-text{font-size:var(--fs-sm);line-height:var(--lh-snug)}
.notif-pop-body .notif-go{font-size:var(--fs-xs)}
/* dismissible rows: the ✕ sits beside the link, not inside it */
/* wrap so the per-message jumps drop onto their own line under the row rather than squeezing in
   beside it — the existing two children still fit on one line, so nothing else moves. */
.notif-row{display:flex;align-items:stretch;gap:6px;min-width:0;flex-wrap:wrap}
.notif-row>.notif-item{flex:1;min-width:0}
.notif-row>.notif-acts{flex-basis:100%}
.notif-x{
  flex-shrink:0;width:28px;min-height:0;padding:0;border:1px solid var(--line);
  background:var(--surface);color:var(--muted);border-radius:var(--r-sm);
  font-size:11px;box-shadow:none;
}
.notif-x:hover{background:var(--critical-soft);color:var(--critical);border-color:color-mix(in srgb,var(--critical) 30%,transparent)}
.notif-list .notif-row{margin-bottom:var(--s2)}
.notif-clear{
  background:transparent;border:0;box-shadow:none;color:var(--accent);
  font-size:var(--fs-xs);font-weight:620;padding:3px 8px;min-height:0;flex-shrink:0;
}
.notif-clear:hover{background:var(--accent-soft);color:var(--tint-ink)}
/* less-urgent group — present but folded away */
.notif-minor{margin-top:var(--s2);border-top:1px solid var(--line);padding-top:var(--s2)}
.notif-minor>summary{
  list-style:none;cursor:pointer;font-size:var(--fs-xs);font-weight:620;color:var(--muted);
  display:inline-flex;align-items:center;gap:5px;padding:2px 4px;user-select:none;
}
.notif-minor>summary::-webkit-details-marker{display:none}
.notif-minor>summary::before{content:"▸";transition:transform var(--t) var(--ease)}
.notif-minor[open]>summary::before{transform:rotate(90deg)}
.notif-minor>summary:hover{color:var(--ink2)}
.notif-minor .notif-row{margin-top:6px}
.notif-minor.page{margin-top:var(--s4)}
.notif-pop-empty{
  padding:var(--s7) var(--s4);text-align:center;color:var(--muted);font-size:var(--fs-base);
  display:flex;flex-direction:column;align-items:center;gap:var(--s2);
}
.notif-pop-empty .empty-ic{
  width:40px;height:40px;border-radius:var(--r-md);display:inline-flex;align-items:center;justify-content:center;
  background:var(--good-soft);color:var(--good);
}
.notif-pop-foot{
  padding:var(--s2) var(--s4);border-top:1px solid var(--line);background:var(--surface-2);
  display:flex;align-items:center;justify-content:space-between;gap:var(--s2);flex-shrink:0;
}
@media (max-width:560px){
  .notif-pop{position:fixed;top:calc(var(--topbar-h) + 8px);right:var(--s3);left:var(--s3);width:auto}
  .notif-pop::before,.notif-pop::after{display:none}
}
.pop-label{font-size:var(--fs-2xs);font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--muted);padding:var(--s2) var(--s3) var(--s1)}

/* — sidebar — */
aside{
  grid-area:side;position:sticky;top:var(--topbar-h);
  height:calc(100vh - var(--topbar-h));height:calc(100dvh - var(--topbar-h));
  display:flex;flex-direction:column;gap:var(--s2);
  padding:var(--s3) var(--s2) var(--s2);
  background:var(--sidebar-bg);
  backdrop-filter:blur(20px) saturate(180%);-webkit-backdrop-filter:blur(20px) saturate(180%);
  border-right:1px solid var(--line);
  z-index:var(--z-side);
}
.brand{display:none} /* brand now lives in the topbar */

aside nav{display:flex;flex-direction:column;gap:0;flex:1;min-height:0;overflow-y:auto;overflow-x:hidden;padding-bottom:var(--s2)}
aside nav::-webkit-scrollbar{width:8px}
aside nav::-webkit-scrollbar-thumb{background:transparent}
aside nav:hover::-webkit-scrollbar-thumb{background:color-mix(in srgb, var(--ink) 16%, transparent)}

.nav-group{display:flex;flex-direction:column}
.nav-group-h{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s2);width:100%;
  background:transparent;color:var(--muted);border:0;box-shadow:none;border-radius:var(--r-xs);
  padding:var(--s4) var(--s3) var(--s1);font-size:var(--fs-2xs);font-weight:700;
  text-transform:uppercase;letter-spacing:.08em;min-height:0;
}
.nav-group-h:hover{background:transparent;color:var(--ink2)}
.nav-group-h>span{display:inline-flex;align-items:center;gap:var(--s2);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nav-group-chev{transition:transform var(--t) var(--ease);flex-shrink:0;opacity:.55}
.nav-group.collapsed .nav-group-chev{transform:rotate(-90deg)}
.nav-group-links{
  display:flex;flex-direction:column;gap:1px;margin-bottom:var(--s1);
  max-height:280px;opacity:1;overflow:hidden;
  transition:max-height var(--t-slow) var(--ease),opacity var(--t) var(--ease),margin-bottom var(--t);
}
.nav-group.collapsed .nav-group-links{max-height:0;opacity:0;margin-bottom:0}

aside nav a{
  position:relative;display:flex;align-items:center;gap:var(--s2);
  color:var(--ink2);text-decoration:none;
  padding:7px var(--s3);margin:0 var(--s1);border-radius:var(--r-sm);
  font-weight:500;font-size:var(--fs-base);min-width:0;
  transition:background var(--t-fast),color var(--t-fast);
}
aside nav a>span:not(.nav-badge):not(.tag){min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
aside nav a:hover{background:color-mix(in srgb, var(--ink) 6%, transparent);color:var(--ink)}
/* A hue per sidebar group, so the sections are distinguishable at a glance. It is
   deliberately applied in only two places — the group's label and the active item's
   indicator bar — so colour keeps meaning "which area am I in" and never competes with
   the status palette (green/amber/red) that means "how is this doing". */
.nav-group{--grp:var(--accent)}
.nav-group[data-group="pipeline"]{--grp:var(--brand-500)}
.nav-group[data-group="marketing"]{--grp:#7c5cf0}
.nav-group[data-group="sources"]{--grp:#0d9488}
.nav-group-h>span{color:color-mix(in srgb, var(--grp) 62%, var(--muted))}
aside nav a.active{background:color-mix(in srgb, var(--grp) 11%, transparent);color:color-mix(in srgb, var(--grp) 78%, var(--ink));font-weight:640}
aside nav a.active .nav-ic{opacity:1;color:var(--grp)}
aside nav a.active::before{
  content:"";position:absolute;left:calc(var(--s1) * -1);top:50%;transform:translateY(-50%);
  width:3px;height:18px;border-radius:0 3px 3px 0;background:var(--grp);
}
.nav-ic{flex-shrink:0;opacity:.7}
.nav-badge{
  display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;
  border-radius:var(--r-full);background:var(--critical);color:#fff;
  font-size:var(--fs-2xs);font-weight:700;margin-left:auto;flex-shrink:0;font-variant-numeric:tabular-nums;
}
aside nav a .tag{margin-left:auto;flex-shrink:0}

/* sidebar footer */
.side-foot{display:flex;align-items:center;gap:var(--s2);padding:var(--s2) var(--s1) 0;border-top:1px solid var(--line);flex-shrink:0}
.side-foot .rail-btn{
  background:transparent;color:var(--muted);border:0;box-shadow:none;font-size:var(--fs-sm);font-weight:500;
  justify-content:flex-start;flex:1;padding:6px var(--s2);min-height:32px;
}
.side-foot .rail-btn:hover{background:color-mix(in srgb, var(--ink) 6%, transparent);color:var(--ink)}
.side-foot .rail-btn svg{transition:transform var(--t) var(--ease)}
#app.rail .side-foot .rail-btn svg{transform:rotate(180deg)}
/* legacy user bar — user now lives in the topbar menu */
.userbar{display:none}

/* — rail (collapsed) sidebar — */
#app.rail aside{padding-left:var(--s2);padding-right:var(--s2)}
#app.rail aside nav a{justify-content:center;padding:9px 0;margin:0 2px}
#app.rail aside nav a>span:not(.nav-badge),#app.rail aside nav a .tag{display:none}
#app.rail aside nav a .nav-badge{
  display:inline-flex;position:absolute;top:2px;right:6px;min-width:15px;height:15px;padding:0 3px;
  font-size:9px;margin:0;
}
#app.rail .nav-ic{width:18px;height:18px}
#app.rail .nav-group-h{justify-content:center;padding:var(--s3) 0 var(--s1);pointer-events:none}
#app.rail .nav-group-h>span{display:none}
#app.rail .nav-group-h::after{content:"";display:block;width:18px;height:1px;background:var(--line-2)}
#app.rail .nav-group-chev{display:none}
#app.rail .nav-group.collapsed .nav-group-links{max-height:none;opacity:1;margin-bottom:var(--s1)}
#app.rail .side-foot .rail-btn{justify-content:center}
#app.rail .side-foot .rail-btn span{display:none}
/* hover label for rail items */
#app.rail aside nav a::after{
  content:attr(data-label);position:absolute;left:calc(100% + 10px);top:50%;transform:translateY(-50%) scale(.94);
  background:var(--n900);color:var(--n0);font-size:var(--fs-sm);font-weight:520;white-space:nowrap;
  padding:5px 10px;border-radius:var(--r-xs);box-shadow:var(--shadow-2);
  opacity:0;pointer-events:none;transition:opacity var(--t-fast),transform var(--t-fast) var(--ease);z-index:var(--z-pop);
}
#app.rail aside nav a:hover::after,#app.rail aside nav a:focus-visible::after{opacity:1;transform:translateY(-50%) scale(1)}
:root[data-theme="dark"] #app.rail aside nav a::after{background:var(--surface-3);color:var(--ink);border:1px solid var(--line)}

/* — main content — */
main{
  grid-area:main;min-width:0;
  padding:var(--s6) var(--s7) var(--s9);
  width:100%;max-width:var(--content-max);
  margin:0 auto;
}
.nav-toggle{display:none}

/* =============================================================================
   06 · PAGE HEADER & BREADCRUMBS
   ========================================================================== */
.crumbs{
  display:flex;align-items:center;gap:var(--s1);min-width:0;flex:1;
  font-size:var(--fs-sm);color:var(--muted);overflow:hidden;
}
.crumbs a{color:var(--muted);text-decoration:none;white-space:nowrap;border-radius:var(--r-xs);padding:2px 4px}
.crumbs a:hover{color:var(--ink);background:color-mix(in srgb, var(--ink) 6%, transparent)}
.crumbs .sep{color:var(--n400);flex-shrink:0}
.crumbs .cur{color:var(--ink);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;padding:2px 0}

.pagehead{
  display:flex;align-items:flex-end;justify-content:space-between;gap:var(--s4);
  margin-bottom:var(--s5);flex-wrap:wrap;
}
.pagehead>h2,.pagehead>h3{min-width:0}
.pagehead h2{font-size:var(--fs-2xl);font-weight:660;letter-spacing:-.026em;line-height:1.2}
.pagehead h3{font-size:var(--fs-lg);font-weight:640}
.pagehead .actions{display:flex;gap:var(--s3);flex-wrap:wrap;align-items:center;min-width:0}
/* Related actions sit together with a hairline seam, so a long toolbar reads as a few
   groups (view · data in-out · create) instead of one undifferentiated row of buttons. */
.btn-group{display:inline-flex;align-items:center;gap:0}
.btn-group>button,.btn-group>a{border-radius:0;margin:0}
.btn-group>:first-child{border-top-left-radius:var(--r-sm);border-bottom-left-radius:var(--r-sm)}
.btn-group>:last-child{border-top-right-radius:var(--r-sm);border-bottom-right-radius:var(--r-sm)}
.btn-group>:not(:first-child){margin-left:-1px}
.btn-group>button:hover,.btn-group>a:hover{position:relative;z-index:1}
.pagehead .actions select,.pagehead .actions input{width:auto;min-width:120px}
.pagehead .actions label.inline{align-self:center}
/* a subtitle line directly under the page title */
.pagehead .subtitle{font-size:var(--fs-base);color:var(--muted);font-weight:450;margin-top:5px;max-width:80ch}
/* The card's header strip, in the house dark teal-green (2026-08-22). Six of its ten uses sit
   directly above a table whose own header row is already brand-800 — white strip, dark band, rows —
   so one rule collapses that into a single header block. Negative margins pull it out to the card's
   edges (the card pads by --s5) and the top corners follow the card's radius, or it reads as a dark
   rectangle floating inside a white one. Everything inside is inverted: muted sub-lines, links and
   the small ghost buttons some heads carry all assume a light ground. */
.tablehead{
  display:flex;align-items:baseline;justify-content:space-between;gap:var(--s3);flex-wrap:wrap;
  background:var(--brand-800);color:#fff;
  padding:10px var(--s5);
  margin:calc(var(--s5) * -1) calc(var(--s5) * -1) var(--s4);
  border-radius:calc(var(--r-lg) - 1px) calc(var(--r-lg) - 1px) 0 0;
}
.tablehead h3{margin-bottom:0;color:#fff}
.tablehead .muted,.tablehead .metric-period{color:rgba(255,255,255,.75)}
.tablehead a{color:#fff;text-decoration:underline}
/* The controls a few heads carry — Events' month nav, "Show all leads", the Table/Board toggle. */
.tablehead button.small,.tablehead .btn-group button,.tablehead .net-seg button{
  background:rgba(255,255,255,.12);border-color:rgba(255,255,255,.28);color:#fff;
}
.tablehead button.small:hover,.tablehead .btn-group button:hover,.tablehead .net-seg button:hover{
  background:rgba(255,255,255,.22);border-color:rgba(255,255,255,.4);color:#fff;
}
.tablehead .net-seg button.on{background:#fff;color:var(--brand-800);border-color:#fff}
/* Groups a run of tiles under a labelled band, so eight KPIs read as two related
   sets instead of one undifferentiated wall. */
.section-head{
  font-size:var(--fs-sm);font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);margin:var(--s6) 0 var(--s3);display:flex;align-items:baseline;gap:6px;flex-wrap:wrap;
}
.section-head .muted{font-size:var(--fs-sm);font-weight:500;letter-spacing:0;text-transform:none}
.section-head:first-child{margin-top:0}
/* NOTE: `.head-row` is always a <tr> in this app (Events, Tenders, Business
   Network header rows). It must NOT be given a display/layout of its own —
   doing so detaches the header cells from the body columns and the column
   labels stop lining up with their data. Style the <th>s, never the row. */

/* =============================================================================
   07 · SURFACES — cards, tiles, KPI
   ========================================================================== */
.card{
  /* A whisper of a gradient — the surface reads as material, not a flat fill. Both themes: it mixes
     from the theme's own surface-2, so dark mode gets the same treatment without a second ramp. */
  background:linear-gradient(180deg, color-mix(in srgb, var(--surface-2) 38%, var(--surface)), var(--surface) 52px);
  border:1px solid var(--line);border-radius:var(--r-lg);
  padding:var(--s5);margin-bottom:var(--s5);box-shadow:var(--shadow-1);
}
.card h3{font-size:var(--fs-md);margin-bottom:var(--s4);font-weight:640;letter-spacing:-.012em}
/* No negative margin on a paragraph following a card heading: several headings carry
   their own inline margin-bottom, and pulling the paragraph up then overlapped them
   (Collections). Let normal flow handle the gap. */
.card>h3+p.muted{margin-bottom:var(--s4)}
.card.banner{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s4);flex-wrap:wrap;
  background:var(--surface-2);border-color:var(--line);
}
.card.banner p{margin:0}
/* parked-feature notice: informational, not alarming */
.card.banner.parked{
  border-color:color-mix(in srgb,var(--warning) 28%,var(--line));
  background:color-mix(in srgb,var(--warning) 7%,var(--surface));
}
.card.banner.parked>div{display:flex;flex-direction:column;gap:3px;min-width:0}
.card.banner.parked .muted{font-size:var(--fs-sm)}
/* icon + label buttons: keep the glyph optically aligned with the text */
button>svg,.btn>svg{width:15px;height:15px;flex-shrink:0}
.icon-btn>svg{width:16px;height:16px}
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:var(--s5);align-items:start}
.grid2>.card{margin-bottom:0}

/* KPI tiles */
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(196px,1fr));gap:var(--s3);margin-bottom:var(--s5)}
.tile{
  position:relative;overflow:hidden;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:var(--s4) var(--s4) var(--s4) var(--s5);box-shadow:var(--shadow-1);min-width:0;
}
.tile{--tile:var(--accent)}
.tile::before{
  content:"";position:absolute;left:0;top:var(--s4);bottom:var(--s4);width:3px;
  border-radius:0 3px 3px 0;background:var(--tile);opacity:.85;
}
/* A toned tile carries a verdict — failed, overdue — so the number takes the tone too. */
.tile.toned .n{color:var(--tile)}
.tile .n{
  font-size:var(--fs-3xl);font-weight:680;letter-spacing:-.03em;line-height:1.1;
  font-variant-numeric:tabular-nums;overflow-wrap:anywhere;
}
.tile .n .muted{font-size:var(--fs-lg);font-weight:600}
.tile .l{
  font-size:var(--fs-xs);color:var(--muted);text-transform:uppercase;letter-spacing:.07em;
  font-weight:640;margin-top:var(--s1);
}
.tile .sub{font-size:var(--fs-sm);color:var(--ink2);margin-top:6px}
/* The tile's own mark — a large, faint watermark in the bottom-right corner rather than a small
   badge. At 80% transparency it never competes with the number (still the first thing the eye lands
   on) but it is big enough to be recognised before the label is read, which is the whole job.
   Bottom-right, not top-right: the number and label keep their full width, so no label wraps to a
   second line just to make room for an ornament. */
.tile .tile-ic{
  position:absolute;bottom:9px;right:10px;
  display:inline-flex;align-items:center;justify-content:center;
  width:50px;height:50px;color:var(--muted);opacity:.2;pointer-events:none;
}
.tile .tile-ic svg{width:100%;height:100%;display:block}
/* A toned tile is already a verdict, so its mark carries the verdict's colour — at the same
   transparency, so the band stays even. */
.tile.toned .tile-ic{color:var(--tile);opacity:.22}
.tile .sub{padding-right:58px}
a.tile{display:block;color:inherit;text-decoration:none;transition:border-color var(--t),box-shadow var(--t),transform var(--t)}
a.tile:hover,a.tile:focus-visible{border-color:color-mix(in srgb, var(--accent) 45%, var(--line));box-shadow:var(--shadow-2);transform:translateY(-2px)}
/* A metric tile that is also a filter. Same box as the rest of the band — it must not look like a
   different kind of thing — with a pressed state for the filter currently in force. */
button.tile{
  /* display:block on purpose — the global button rule is inline-flex/center, which laid the
     number, label and sub out side by side and overlapping. A metric tile must look identical
     whether it is a div, a link or a filter button. */
  display:block;text-align:left;font:inherit;font-weight:inherit;color:inherit;cursor:pointer;
  min-height:0;background:var(--surface);
  /* buttons are nowrap by default in this design system; a metric tile's sub-line has to wrap or it
     is clipped by the tile's own overflow:hidden at narrow widths */
  white-space:normal;
  transition:border-color var(--t),box-shadow var(--t),transform var(--t),background var(--t);
}
button.tile:hover{border-color:color-mix(in srgb,var(--tile) 45%,var(--line));box-shadow:var(--shadow-2);transform:translateY(-2px)}
button.tile:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.tile.on{
  border-color:color-mix(in srgb,var(--tile) 55%,var(--line));
  background:color-mix(in srgb,var(--tile) 7%,var(--surface));
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--tile) 22%,transparent),var(--shadow-1);
}
.tile.on::before{opacity:1;width:4px}
/* the segmented period switch that sits in a section heading */
.section-head .metric-period{margin-left:auto;text-transform:none;letter-spacing:0;align-self:center}

/* "this goes somewhere" — shared by linked tiles and by metric tiles that drill into a detail page,
   so there is one affordance for it rather than two that look different. */
a.tile::after,button.tile.drill::after{
  content:"→";position:absolute;top:var(--s3);right:var(--s3);color:var(--muted);
  font-size:var(--fs-base);opacity:0;transform:translateX(-4px);transition:opacity var(--t),transform var(--t);
}
a.tile:hover::after,a.tile:focus-visible::after,
button.tile.drill:hover::after,button.tile.drill:focus-visible::after{opacity:1;transform:none}

.note-item{padding:var(--s2) 0;border-bottom:1px solid var(--line-soft)}
.note-item:last-child{border-bottom:none}
/* A note-item carrying a file: the name and its size on the left, the remove control pinned right.
   A long filename gets an ellipsis rather than pushing the button off the panel. */
.att-row{display:flex;align-items:center;gap:var(--s3)}
.att-name{flex:1;min-width:0}
.att-name>a{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kvrow{
  display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:var(--s2) var(--s3);
  padding:var(--s2) 0;border-bottom:1px solid var(--line-soft);font-size:var(--fs-base);
}
.kvrow:last-child{border-bottom:0}
.kvrow>strong{font-variant-numeric:tabular-nums}
/* Same treatment for a kvrow that navigates — the Signals list on the dashboard. */
button.kvrow-act{
  width:100%;font:inherit;color:inherit;background:transparent;border:0;border-bottom:1px solid var(--line-soft);
  text-align:left;cursor:pointer;transition:background var(--t) var(--ease);
}
button.kvrow-act:hover{background:var(--surface-2)}
button.kvrow-act:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}

/* =============================================================================
   08 · BADGES, TAGS, SCORES
   ========================================================================== */
.badge{
  display:inline-flex;align-items:center;gap:5px;font-size:var(--fs-hint);font-weight:600;
  border-radius:var(--r-full);padding:2px 10px;border:1px solid var(--line);
  background:var(--surface);color:var(--ink2);box-shadow:none;white-space:nowrap;line-height:1.6;
}
.badge::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--muted);flex-shrink:0}
/* Lead statuses. The class name is the stored slug; keep these in step with STATUS_DOT in app.js
   so a dot means the same thing on a badge, a board column and the table's status select.
   `sequenced` is kept as an alias because the invite badge borrows it for its pending colour. */
.badge.new{background:var(--st-new-soft);border-color:transparent;color:color-mix(in srgb,var(--st-new) 62%,var(--ink))}
.badge.new::before{background:var(--st-new)}
.badge.not-contacted::before{background:var(--seq-4)}
.badge.attempted{background:var(--st-attempt-soft);border-color:transparent;color:color-mix(in srgb,var(--st-attempt) 70%,var(--ink))}
.badge.attempted::before{background:var(--st-attempt)}
/* `sequenced` is the invite badge's pending colour, not a lead status — it keeps warning. */
.badge.contacted{background:var(--st-contacted-soft);border-color:transparent;color:color-mix(in srgb,var(--st-contacted) 68%,var(--ink))}
.badge.contacted::before{background:var(--st-contacted)}
/* Written off, both of them: grey, and deliberately the SAME grey — the distinction between junk
   and not-interested is in the word, not the colour, and neither deserves a red alarm. */
.badge.not-interested{color:var(--muted)}
.badge.not-interested::before{background:var(--muted)}
.badge.won{background:var(--good-soft);color:color-mix(in srgb,var(--good) 72%,var(--ink));border-color:color-mix(in srgb,var(--good) 32%,transparent)}
.badge.won::before{background:var(--good)}
.badge.junk,.badge.lost{color:var(--muted)}
.badge.junk::before,.badge.lost::before{background:var(--muted)}
.badge.draft::before,.badge.skipped::before,.badge.idle::before{background:var(--muted)}
.badge.idle{color:var(--muted)}
.badge.approved{background:var(--warning-soft);border-color:transparent;color:color-mix(in srgb,var(--warning) 70%,var(--ink))}
.badge.approved::before{background:var(--warning)}
.badge.sent,.badge.done{background:var(--good-soft);border-color:transparent;color:color-mix(in srgb,var(--good) 70%,var(--ink))}
.badge.sent::before,.badge.done::before{background:var(--good)}
.badge.failed{background:var(--critical-soft);color:var(--critical);border-color:color-mix(in srgb,var(--critical) 30%,transparent)}
.badge.failed::before{background:var(--critical)}
.badge.running{background:var(--warning-soft);color:color-mix(in srgb,var(--warning) 72%,var(--ink));border-color:color-mix(in srgb,var(--warning) 30%,transparent)}
.badge.running::before{background:var(--warning);animation:pulseDot 1.4s ease-in-out infinite}
.badge.off{background:var(--critical-soft);color:var(--critical);border-color:color-mix(in srgb,var(--critical) 26%,transparent)}
.badge.off::before{background:var(--serious)}
@keyframes pulseDot{0%,100%{opacity:1}50%{opacity:.35}}

.tag{
  display:inline-flex;align-items:center;gap:5px;background:var(--surface-2);
  border:1px solid var(--line);border-radius:var(--r-full);padding:2px 10px;
  font-size:var(--fs-hint);font-weight:520;color:var(--ink2);margin:2px 3px 2px 0;
  box-shadow:none;white-space:nowrap;max-width:100%;overflow:hidden;text-overflow:ellipsis;
  transition:background var(--t-fast),color var(--t-fast),border-color var(--t-fast);
}
.chips{display:flex;flex-wrap:wrap;gap:var(--s1)}
.tag.mini{font-size:var(--fs-xs);padding:2px 8px;cursor:pointer;user-select:none}
.tag.mini:hover{background:var(--accent-soft);color:var(--tint-ink);border-color:transparent}
/* A chip that is a link (a task's deal, for instance) keeps the chip's shape rather than picking up
   the underline and accent colour every other anchor gets. */
a.tag{color:var(--ink2);text-decoration:none}
a.tag:hover{color:var(--tint-ink)}
.tag.mini.static{cursor:default}
.tag.mini.static:hover{background:var(--surface-2);color:var(--ink2);border-color:var(--line)}
.tag.auto,.tag.auto-semi{background:var(--accent-soft);color:var(--tint-ink);border-color:transparent;font-weight:600}
.tag.auto-full{background:var(--good-soft);color:color-mix(in srgb,var(--good) 70%,var(--ink));border-color:transparent;font-weight:600}
.tag.auto-manual{background:var(--surface-2);color:var(--muted);border-color:var(--line);font-weight:600}
.tag.soon{background:var(--warning-soft);color:color-mix(in srgb,var(--warning) 72%,var(--ink));border-color:transparent;font-weight:600}
.tag.sev-high{background:var(--critical-soft);color:var(--critical);border-color:transparent;font-weight:600}
.tag.sev-medium{background:var(--warning-soft);color:color-mix(in srgb,var(--warning) 72%,var(--ink));border-color:transparent;font-weight:600}
.tag.net-goal,.tag.net-industry,.tag.net-role{background:var(--surface-2);color:var(--ink2)}
.tag.poweredby,.poweredby{font-size:var(--fs-2xs);color:var(--muted);letter-spacing:.02em}

.score{
  display:inline-flex;align-items:center;justify-content:center;min-width:36px;
  border-radius:var(--r-xs);padding:1px 7px;font-weight:660;font-size:var(--fs-sm);
  font-variant-numeric:tabular-nums;background:var(--accent-soft);color:var(--tint-ink);
}
.verify-ico{
  display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-left:4px;
  font-weight:700;font-size:10px;border-radius:50%;flex-shrink:0;
}
.verify-ico.ok{color:var(--good);background:color-mix(in srgb, var(--good) 16%, transparent)}
.verify-ico.bad{color:var(--critical);background:color-mix(in srgb, var(--critical) 16%, transparent)}
.verify-ico.unk{color:var(--muted);background:color-mix(in srgb, var(--muted) 16%, transparent)}

/* inline status <select> styled as a status pill.
   ONE fixed height for every status, active or not — the pill's colour is the signal, not its
   size. The focus ring is keyboard-only (:focus-visible): after a mouse change the select keeps
   focus, and the old :focus ring sat there glowing and reading as a bigger pill. */
.status-select{
  --dot:var(--muted);width:auto;min-width:118px;border:1px solid transparent;border-radius:var(--r-full);
  padding:0 28px 0 13px;font-weight:620;font-size:var(--fs-sm);text-transform:capitalize;
  height:28px;min-height:28px;max-height:28px;line-height:26px;
  color:color-mix(in srgb, var(--dot) 78%, var(--ink));
  background-color:color-mix(in srgb, var(--dot) 14%, var(--surface));
  background-position:right 9px center;
}
.status-select:hover{background-color:color-mix(in srgb, var(--dot) 22%, var(--surface));border-color:transparent}
.status-select:focus{outline:none;border-color:transparent;box-shadow:none}
.status-select:focus-visible{border-color:var(--dot);box-shadow:0 0 0 3px color-mix(in srgb, var(--dot) 26%, transparent)}

/* =============================================================================
   09 · TABLES
   ========================================================================== */
.table-wrap{
  overflow-x:auto;overflow-y:visible;border-radius:var(--r-md);
  /* scroll-shadow affordance: a soft edge fades in on whichever side still has
     more columns to reach, and clears once you've scrolled all the way there. */
  background:
    linear-gradient(to right, var(--surface) 30%, rgba(255,255,255,0)) 0 0,
    linear-gradient(to left, var(--surface) 30%, rgba(255,255,255,0)) 100% 0,
    radial-gradient(farthest-side at 0 50%, rgba(0,0,0,.13), rgba(0,0,0,0)) 0 0,
    radial-gradient(farthest-side at 100% 50%, rgba(0,0,0,.13), rgba(0,0,0,0)) 100% 0;
  background-repeat:no-repeat;
  background-size:44px 100%, 44px 100%, 14px 100%, 14px 100%;
  background-attachment:local, local, scroll, scroll;
}
table,.data-table,.activity-table{width:100%;border-collapse:separate;border-spacing:0;font-size:var(--fs-base)}
/* Every table header on the platform wears the house dark teal-green with white type — the same
   band the Meetings weekday strip uses, so a header row reads as a header and not as a first, empty
   row of data. One rule: a page that re-styled its own header is how the platform ends up with four
   different tables. */
th,.data-table th,.activity-table th{
  position:sticky;top:0;z-index:var(--z-sticky);
  font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.07em;font-weight:680;
  color:#fff;text-align:left;padding:7px var(--s3);
  background:var(--brand-800);
  border-bottom:1px solid var(--line-2);
  white-space:nowrap;
}
/* The signature editor is somebody's own HTML being edited in place — a table THEY pasted must not
   be repainted in our brand colour. */
.sig-edit th{background:transparent;color:inherit;position:static;text-transform:none;letter-spacing:0}
/* rounded top corners on the first/last header cell of a card-hosted table */
.card .table-wrap th:first-child{border-top-left-radius:var(--r-sm)}
.card .table-wrap th:last-child{border-top-right-radius:var(--r-sm)}
td,.data-table td,.activity-table td{
  padding:8px var(--s3);border-bottom:1px solid var(--line-soft);vertical-align:top;
  transition:background var(--t-fast);overflow-wrap:anywhere;
}
tr:last-child td,.data-table tr:last-child td{border-bottom:0}
tbody tr:hover td,.data-table tr.dt-row:hover td{background:color-mix(in srgb, var(--accent) 5%, transparent)}
/* A row that navigates. The hover tint above already applies; this adds the two things that were
   missing — a pointer, and a focus ring for the keyboard path (role=button + Enter/Space). */
tr.row-act{cursor:pointer}
tr.row-act:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}
.activity-table{font-size:var(--fs-sm)}
.activity-table td{padding:8px var(--s3)}
.activity-table code,.wiz-body code{
  font-size:var(--fs-hint);background:var(--surface-3);border:1px solid var(--line);
  padding:1px 6px;border-radius:5px;white-space:nowrap;
}
.data-table th.sortable{cursor:pointer;user-select:none}
.data-table th.sortable:hover{color:#fff;text-decoration:underline}
/* The sorted column is named by its arrow — on a dark header an accent tint would be less legible,
   not more. */
.data-table th.sortable[aria-sort="ascending"],.data-table th.sortable[aria-sort="descending"]{color:#fff}
.data-table th.sortable[aria-sort="ascending"]::after{content:" ↑"}
.data-table th.sortable[aria-sort="descending"]::after{content:" ↓"}
.data-table .filter-row th{position:static;background:var(--surface);padding-top:var(--s2);padding-bottom:var(--s2)}
.data-table .filter-row input{width:100%;padding:5px 9px;font-size:var(--fs-sm);font-weight:400;border-radius:var(--r-xs);min-height:28px}
.data-table .filter-row input.narrow{width:64px}
.data-table .cell-wrap{min-width:160px;max-width:300px;color:var(--ink2)}
.data-table .overdue,td .overdue{color:var(--critical);font-weight:620}
.data-table button.small{margin:2px 3px 0 0}
.data-table tr.lost-row td{opacity:.55}
.empty-cell{padding:0}
.cell-desc{
  font-size:var(--fs-sm);line-height:var(--lh-snug);margin-top:3px;max-width:340px;
  display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.cell-contact{display:flex;align-items:center;gap:var(--s2);min-width:0}
/* Notes is now an editable cell holding a textarea, not clamped text — and no minimum width, which
   was the one thing still forcing the table wider than its container. */
#leadTable .cell-notes{font-size:var(--fs-sm);line-height:var(--lh-snug);overflow:hidden}
.dt-detail>td{background:var(--surface-2);padding:0}

/* selection / bulk bar */
.bulk-count{font-variant-numeric:tabular-nums}

/* avatars in tables */
.lead-avatar-ring{
  position:relative;display:inline-flex;align-items:center;justify-content:center;
  width:38px;height:38px;min-width:38px;border-radius:50%;padding:2px;flex-shrink:0;
  background:conic-gradient(var(--ring) calc(var(--pct)*1%), var(--line-2) 0);
}
.lead-avatar-ring img{width:100%;height:100%;border-radius:50%;object-fit:cover;display:block;background:var(--surface)}
.lead-avatar-fallback{
  width:100%;height:100%;border-radius:50%;background:var(--surface-3);color:var(--ink2);
  align-items:center;justify-content:center;font-size:var(--fs-sm);font-weight:700;
}
.company-avatar{position:relative;display:inline-flex;width:38px;height:38px;min-width:38px;flex-shrink:0}
.company-logo{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;border-radius:50%;padding:2px;
  background:conic-gradient(from 200deg, color-mix(in srgb, var(--ring) 50%, transparent), var(--ring), color-mix(in srgb, var(--ring) 50%, transparent));
  box-shadow:var(--shadow-1);transition:transform var(--t) var(--ease);
}
.company-avatar:hover .company-logo{transform:scale(1.06)}
.company-logo img{width:100%;height:100%;border-radius:50%;object-fit:cover;display:block;background:var(--surface)}
.company-logo-fallback{width:100%;height:100%;border-radius:50%;background:var(--surface);align-items:center;justify-content:center;font-size:15px}
.company-badge{
  position:absolute;min-width:16px;height:16px;padding:0 3px;border-radius:var(--r-full);
  font-size:8.5px;font-weight:800;line-height:1;display:inline-flex;align-items:center;justify-content:center;
  color:#fff;border:2px solid var(--surface);box-shadow:var(--shadow-1);
}
.company-badge-score{top:-4px;right:-5px}
/* The employee count was a number nobody acted on. A buying signal from Clay is the opposite —
   it is the reason to pick this lead over the one under it, so it takes the badge.
   Signal yellow is its own colour, deliberately not the warning amber: a signal is an opportunity,
   not a problem, and it has to pop out of a scan of forty rows. */
.company-badge-signal{
  bottom:-4px;right:-6px;width:17px;height:17px;padding:0;
  background:linear-gradient(145deg,#ffdd55,#f5a524);
  color:#4a3200;border-color:var(--surface);
  box-shadow:0 0 0 1px rgba(245,165,36,.45),0 1px 3px rgba(245,165,36,.5);
}
.company-badge-signal svg{width:11px;height:11px}
.lead-name-link{
  cursor:pointer;text-decoration:underline;text-decoration-color:transparent;
  text-underline-offset:2px;transition:text-decoration-color var(--t);
}
.lead-name-link:hover,.lead-name-link:focus-visible{text-decoration-color:currentColor}

/* =============================================================================
   10 · FILTER BARS
   ========================================================================== */
/* align-items:center + one shared control height — mixed input/select/button heights made every
   filter row read as slightly broken, which is the kind of thing nobody reports but everyone feels. */
.filters,.filterbar{display:flex;gap:var(--s2);flex-wrap:wrap;margin:0 0 var(--s4);align-items:center}
.filters input,.filters select,.filterbar input,.filterbar select{width:auto;min-height:34px}
.filterbar input[type=search]{flex:1;min-width:220px}
.filterbar{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-md);
  padding:var(--s3);box-shadow:var(--shadow-1);
}
.filterbar.plain{background:transparent;border:0;padding:0;box-shadow:none}

/* =============================================================================
   11 · KANBAN BOARDS
   ========================================================================== */
.board{display:flex;gap:var(--s3);overflow-x:auto;padding-bottom:var(--s2);align-items:flex-start}
.board-col{
  flex:0 0 274px;width:274px;background:var(--surface-2);border:1px solid var(--line);
  border-radius:var(--r-lg);display:flex;flex-direction:column;max-height:74vh;box-shadow:var(--shadow-1);
}
.board-col-head{
  position:sticky;top:0;z-index:1;
  background:color-mix(in srgb, var(--surface-2) 88%, transparent);
  backdrop-filter:blur(12px) saturate(160%);-webkit-backdrop-filter:blur(12px) saturate(160%);
  border-bottom:1px solid var(--line);border-radius:var(--r-lg) var(--r-lg) 0 0;padding:var(--s3);
}
.board-col-title{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s2);
  font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--ink2);
}
.board-col-count{
  font-size:var(--fs-2xs);font-weight:700;color:var(--muted);background:var(--surface);
  border:1px solid var(--line);border-radius:var(--r-full);padding:1px 8px;font-variant-numeric:tabular-nums;
}
.board-col-sum{font-size:var(--fs-hint);color:var(--muted);margin-top:3px;font-variant-numeric:tabular-nums}
.board-col-body{padding:var(--s2);display:flex;flex-direction:column;gap:var(--s2);overflow-y:auto}
.board-card{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-md);
  padding:var(--s3);cursor:pointer;box-shadow:var(--shadow-1);
  transition:border-color var(--t),box-shadow var(--t),transform var(--t);
}
.board-card:hover{border-color:color-mix(in srgb, var(--accent) 40%, var(--line));box-shadow:var(--shadow-2);transform:translateY(-2px)}
.board-card:active{transform:scale(.985);box-shadow:var(--shadow-1)}
.board-card:focus-visible{outline:none;border-color:var(--accent);box-shadow:var(--ring-focus)}
.board-card-title{font-weight:640;font-size:var(--fs-base);color:var(--ink);line-height:var(--lh-tight)}
.board-card-sub{font-size:var(--fs-sm);color:var(--muted);margin-top:3px}
.board-card-meta{display:flex;align-items:center;justify-content:space-between;gap:var(--s2);flex-wrap:wrap;margin-top:var(--s2)}
.board-card select.small{margin-top:var(--s2);padding:5px 9px;font-size:var(--fs-sm);border-radius:var(--r-xs);width:100%}
/* status select + the ⋯ actions chip share the card's last row */
.board-card-foot{display:flex;align-items:center;gap:var(--s2)}
.board-card-foot select.small{flex:1;min-width:0}
.board-card-foot .act-tool{margin-top:var(--s2);flex-shrink:0}
.board-empty{font-size:var(--fs-sm);color:var(--muted);padding:var(--s3) var(--s1);text-align:center}
.board-card[draggable]{cursor:grab}
.board-card.dragging{opacity:.4}
.board-col.drag-over{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-soft) inset}

/* =============================================================================
   12 · LISTS — notifications, tasks, connectors, collections
   ========================================================================== */
.notif-list{display:flex;flex-direction:column;gap:var(--s2);margin-bottom:var(--s4)}
.notif-item{
  display:flex;align-items:center;gap:var(--s3);background:var(--surface);
  border:1px solid var(--line);border-left-width:3px;border-left-color:var(--line);
  border-radius:var(--r-md);padding:var(--s3) var(--s4);text-decoration:none;color:var(--ink);
  box-shadow:var(--shadow-1);transition:border-color var(--t),box-shadow var(--t),transform var(--t);
}
.notif-item:hover{border-color:var(--line-2);box-shadow:var(--shadow-2);transform:translateX(2px);color:var(--ink)}
.notif-item.hot{border-left-color:var(--critical)}
.notif-item.warn{border-left-color:var(--serious)}
.notif-item.info{border-left-color:var(--accent)}
.notif-dot{font-size:11px;flex-shrink:0}
.notif-text{flex:1;font-size:var(--fs-base);min-width:0}
.notif-go{font-size:var(--fs-sm);color:var(--accent);font-weight:620;flex-shrink:0;white-space:nowrap}

.task-list{display:flex;flex-direction:column;gap:var(--s2)}
.task-item{
  display:flex;align-items:center;gap:var(--s3);background:var(--surface);
  border:1px solid var(--line);border-left-width:3px;border-left-color:var(--line);
  border-radius:var(--r-md);padding:var(--s3) var(--s4);box-shadow:var(--shadow-1);
}
.task-item.overdue{border-left-color:var(--critical)}
.task-item.today{border-left-color:var(--warning)}
.task-item.done{opacity:.55}
.task-item.done .task-title{text-decoration:line-through}
/* The done control. A button rather than an 18px checkbox: it writes to the server on press, so it
   should look and read like an action, and it has to be hittable on a phone. Fixed width so a row
   does not reflow when "Complete" becomes "Reopen". */
.task-done{display:inline-flex;align-items:center;gap:6px;flex-shrink:0;width:112px;justify-content:center;
  padding:7px 10px;font-size:var(--fs-sm);font-weight:600;border-radius:8px;cursor:pointer;
  border:1px solid var(--accent);background:var(--accent);color:#fff}
.task-done:hover{filter:brightness(1.08)}
.task-done svg{width:15px;height:15px;flex-shrink:0}
.task-done.is-done{background:transparent;color:var(--muted);border-color:var(--line)}
.task-done.is-done:hover{color:var(--ink);border-color:var(--muted);filter:none}
@media (max-width:640px){.task-done{width:auto}.task-done span{display:none}}
.task-main{flex:1;min-width:0}
.task-title{font-size:var(--fs-base);font-weight:600}
.task-meta{font-size:var(--fs-sm);color:var(--muted);margin-top:2px}
.task-meta .overdue{color:var(--critical);font-weight:620}

/* connector cards */
.conn-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(310px,1fr));gap:var(--s4)}
.conn-card{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:var(--s4);display:flex;flex-direction:column;gap:var(--s2);box-shadow:var(--shadow-1);
  min-width:0;overflow-wrap:anywhere;/* a model id or a URL in a description wraps instead of leaving the card */
  transition:border-color var(--t),box-shadow var(--t),transform var(--t);
}
.conn-card:hover{box-shadow:var(--shadow-2);transform:translateY(-2px)}
.conn-card.on{border-color:color-mix(in srgb,var(--good) 42%,var(--line))}
/* The head is a grid, not one flex row. As a flex row the nowrap pricing chip and the nowrap status
   badge refused to shrink, so the only item that could give — the min-width:0 title — was squeezed to
   ~15px and the connector's own NAME painted straight across the chip and the badge, at every width.
   Rows are explicit instead: icon + name + status on row 1 (the name wraps inside its own track),
   pricing on row 2 under the name. Nothing can be crushed into anything else. */
.conn-head{
  display:grid;grid-template-columns:auto minmax(0,1fr) auto;
  align-items:center;column-gap:var(--s3);row-gap:var(--s1);min-width:0;
}
.conn-head .conn-icon{grid-column:1;grid-row:1}
.conn-head .conn-title{
  grid-column:2;grid-row:1;font-weight:640;font-size:var(--fs-md);
  display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;min-width:0;
}
/* "auto-login"/"Soon" wrap onto the next line of the title rather than being squashed to an
   unreadable 20px stub — they are labels, not filler. */
.conn-head .conn-title .tag{flex:none;margin:0}
.conn-head .badge{grid-column:3;grid-row:1;justify-self:end}
.conn-head .conn-price{grid-column:2/-1;grid-row:2;justify-self:start;margin:0}
.conn-icon{
  display:inline-flex;align-items:center;justify-content:center;width:38px;height:38px;
  border-radius:var(--r-sm);background:#fff;border:1px solid var(--line);
  flex-shrink:0;overflow:hidden;padding:5px;
}
.conn-icon .conn-logo{width:100%;height:100%;object-fit:contain;display:block}
.conn-desc{color:var(--ink2);font-size:var(--fs-base);flex:1;margin:0;line-height:var(--lh-snug)}
/* inline-block, not the .tag inline-flex: text-overflow does nothing to a flex container's anonymous
   text item, so a long price used to be sliced off mid-glyph. The full terms stay in the title. */
.conn-price{display:inline-block;max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:help}
.conn-tags{display:flex;flex-wrap:wrap;gap:var(--s1);margin:2px 0}
.conn-foot{
  display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;
  padding-top:var(--s3);border-top:1px solid var(--line);margin-top:auto;
}
.conn-foot button{margin-top:0}
.conn-foot .switch{margin:0 0 0 auto}
.conn-search{margin:0 0 var(--s4);position:relative;max-width:420px}
.conn-search input{max-width:420px;width:100%}
.conn-suggest{
  position:absolute;left:0;right:0;top:calc(100% + 5px);z-index:var(--z-pop);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-md);
  box-shadow:var(--shadow-2);overflow:hidden;padding:var(--s1);
}
.conn-suggest-row{display:flex;align-items:center;gap:var(--s2);padding:7px var(--s2);border-radius:var(--r-xs);cursor:pointer;min-width:0}
.conn-suggest-row:hover,.conn-suggest-row.active{background:var(--accent-soft)}
.conn-suggest .conn-icon{width:26px;height:26px;border-radius:var(--r-xs);padding:3px}
.conn-suggest-name{font-weight:600;font-size:var(--fs-base);flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.conn-suggest-via{font-size:var(--fs-xs);color:var(--muted);flex-shrink:0}
.conn-suggest-hint{font-size:var(--fs-2xs);color:var(--muted);text-transform:lowercase;flex-shrink:0}
.conn-suggest-hint.ok{color:var(--good)}

/* collection cards */
.coll-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(248px,1fr));gap:var(--s3)}
.coll-card{
  display:flex;flex-direction:column;gap:6px;min-height:196px;padding:var(--s4);
  border:1px solid var(--line);border-radius:var(--r-lg);background:var(--surface);cursor:pointer;
  box-shadow:var(--shadow-1);transition:border-color var(--t),box-shadow var(--t),transform var(--t);
}
.coll-card:hover{border-color:color-mix(in srgb, var(--accent) 40%, var(--line));box-shadow:var(--shadow-2);transform:translateY(-2px)}
.coll-card:focus-visible{outline:none;border-color:var(--accent);box-shadow:var(--ring-focus)}
.coll-card.active{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-soft-2)}
.coll-top{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--s2);min-width:0}
/* Titles are clamped to two lines so a long generated name can't push the metrics
   out of alignment across the grid; the full name is on the element's title. */
.coll-name{
  font-weight:680;font-size:var(--fs-md);color:var(--ink);line-height:var(--lh-tight);
  letter-spacing:-.015em;min-width:0;
  display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.coll-updated{font-size:var(--fs-2xs);white-space:nowrap}
.coll-industry{align-self:flex-start;background:var(--accent-soft);color:var(--tint-ink);border-color:transparent;font-weight:600;white-space:nowrap;margin:0;flex-shrink:0}
.coll-metrics{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap;margin-top:2px}
.coll-total{font-size:32px;font-weight:700;color:var(--ink);line-height:1;font-variant-numeric:tabular-nums;letter-spacing:-.03em}
.coll-count-label{font-size:var(--fs-hint)}
.coll-year{font-size:var(--fs-xs);white-space:nowrap;margin-left:auto}
/* Collection card body: headline count, then coverage meters, then quality.
   (Replaces a flat 2-column grid of nine label/value pairs, where a progress figure,
   three coverage ratios and two metadata strings all looked identical.) */
.coll-src{margin-left:auto;text-transform:lowercase}
.coll-meters{display:flex;flex-direction:column;gap:5px;margin-top:var(--s3)}
.coll-meter{
  /* 78px, not 60: the widest label in use is "Conferences" on the All-events card, and a truncated
     meter label ("Conferen…") is worse than a slightly narrower bar. */
  display:grid;grid-template-columns:78px minmax(0,1fr) auto;gap:var(--s2);align-items:center;
  font-size:var(--fs-xs);color:var(--ink2);
}
.coll-meter .cm-l{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.coll-meter .cm-bar{height:5px;border-radius:var(--r-full);background:var(--surface-3);overflow:hidden}
.coll-meter .cm-bar i{display:block;height:100%;border-radius:var(--r-full);background:var(--accent);transition:width var(--t-slow) var(--ease)}
.coll-meter.good .cm-bar i{background:var(--good)}
.coll-meter .cm-v{font-variant-numeric:tabular-nums;font-weight:620;color:var(--ink);white-space:nowrap}
.coll-meter .cm-v .muted{font-weight:500}
.coll-quality{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s2);flex-wrap:wrap;
  margin-top:var(--s3);padding-top:var(--s2);border-top:1px solid var(--line-soft);font-size:var(--fs-xs);
}
.coll-q{display:inline-flex;align-items:center;gap:5px;color:var(--ink2);min-width:0}
.coll-q .score{min-width:0;padding:1px 6px;font-size:var(--fs-xs)}
.coll-q.on{color:color-mix(in srgb,var(--warning) 74%,var(--ink));font-weight:620}
.coll-next{margin-top:auto;padding-top:var(--s2);border-top:1px solid var(--line);display:flex;flex-direction:column;gap:1px;min-width:0}
.coll-next-label{font-size:var(--fs-2xs);text-transform:uppercase;letter-spacing:.07em;color:var(--muted);font-weight:640}
.coll-next-val{display:flex;flex-direction:column;min-width:0}
.coll-next-name{font-size:var(--fs-sm);font-weight:600;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.coll-next-date{font-size:var(--fs-xs);color:var(--ink2);font-variant-numeric:tabular-nums}
/* Date above, icon row below: with five actions the two no longer compete for one
   line and the last icon stops wrapping onto a row of its own. */
.coll-foot{display:flex;flex-direction:column;align-items:flex-start;gap:6px;margin-top:var(--s2)}
.coll-foot .coll-actions{width:100%;flex-wrap:nowrap}
.coll-actions{display:flex;gap:var(--s1)}
.coll-actions .small{padding:3px 9px;font-size:var(--fs-xs)}
/* The All-leads card is the aggregate, not one collection among many — so it gets its own
   treatment instead of the dashed grey it had, which read as de-emphasised (the same look as an
   archived card). Brand-tinted, with a solid accent edge on the left. */
.coll-card.all{
  align-items:stretch;justify-content:flex-start;gap:var(--s1);
  /* Deliberately deeper than the per-collection tints (which sit at 9% of their own hue): this is
     the aggregate, and at anything near their strength it read as just another collection that
     happened to sit first in the grid. */
  background:linear-gradient(160deg,color-mix(in srgb,var(--accent) 24%,var(--surface)) 0%,color-mix(in srgb,var(--accent) 14%,var(--surface)) 70%);
  border-color:color-mix(in srgb,var(--accent) 55%,var(--line));
  border-left:4px solid var(--accent-dk);
  padding-left:calc(var(--s4) - 3px);
  box-shadow:var(--shadow-2);
}
.coll-card.all:hover{border-color:color-mix(in srgb,var(--accent) 52%,var(--line));border-left-color:var(--accent)}
.coll-card.all.active{box-shadow:0 0 0 2px var(--accent-soft-2),var(--shadow-2)}
.coll-card.all .coll-name{color:var(--tint-ink)}
.coll-card.all .coll-total{color:var(--tint-ink)}
.coll-card.all>*{min-width:0}
/* The split-by-collection list is secondary to the summary above it, so it folds away — the card
   leads with what the numbers are, and the breakdown is there when you want to know where they sit. */
.coll-split{margin-top:var(--s2);border-top:1px solid var(--line);padding-top:var(--s2)}
.coll-split>summary{
  list-style:none;cursor:pointer;font-size:var(--fs-2xs);font-weight:700;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted);display:inline-flex;align-items:center;gap:5px;user-select:none;
}
.coll-split>summary::-webkit-details-marker{display:none}
.coll-split>summary::before{content:"▸";transition:transform var(--t) var(--ease)}
.coll-split[open]>summary::before{transform:rotate(90deg)}
.coll-split>summary:hover{color:var(--ink2)}
.coll-split .coll-breakdown{margin-top:var(--s1);padding-top:0;border-top:0}
/* a per-row signal count inside the All-leads breakdown, so the block reconciles with the metric band */
.coll-breakdown .cb-sig{
  font-style:normal;font-size:var(--fs-2xs);font-weight:640;color:var(--warning);
  font-variant-numeric:tabular-nums;white-space:nowrap;
}
/* rows without a signal count still need the middle track to exist, or their number shifts left */
.coll-breakdown>div>b:nth-child(2){grid-column:3}
/* (dark-mode override removed: --tint-ink is now a light teal that reads fine on --accent-soft,
   so the "all leads" card uses the same tint ink as every other tinted surface) */
/* Every collection card carries its own hue, derived from its name (hueOf) — the same categorical
   colour family as the industry chips, at fixed saturation and lightness so nothing shouts and
   nothing collides with the status palette. The All-leads card keeps the brand accent because it is
   the aggregate, not one collection among many. */
.coll-card.tinted{
  --coll-c:hsl(var(--coll) 52% 46%);
  background:linear-gradient(160deg,color-mix(in srgb,var(--coll-c) 9%,var(--surface)) 0%,var(--surface) 60%);
  border-color:color-mix(in srgb,var(--coll-c) 26%,var(--line));
  border-left:3px solid var(--coll-c);
  padding-left:calc(var(--s4) - 2px);
}
.coll-card.tinted:hover{border-color:color-mix(in srgb,var(--coll-c) 46%,var(--line))}
.coll-card.tinted.active{box-shadow:0 0 0 2px color-mix(in srgb,var(--coll-c) 22%,transparent),var(--shadow-2)}
.coll-card.tinted .coll-name{color:color-mix(in srgb,var(--coll-c) 72%,var(--ink))}
.coll-card.tinted .coll-industry{background:color-mix(in srgb,var(--coll-c) 14%,transparent);color:color-mix(in srgb,var(--coll-c) 78%,var(--ink))}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .coll-card.tinted{--coll-c:hsl(var(--coll) 58% 62%)}
  :root:not([data-theme="light"]) .coll-card.tinted .coll-name{color:color-mix(in srgb,var(--coll-c) 86%,var(--ink))}
}
:root[data-theme="dark"] .coll-card.tinted{--coll-c:hsl(var(--coll) 58% 62%)}
:root[data-theme="dark"] .coll-card.tinted .coll-name{color:color-mix(in srgb,var(--coll-c) 86%,var(--ink))}

/* archived collections — collapsed, and visibly de-emphasised when open */
.coll-archive{margin-top:var(--s4);border-top:1px solid var(--line);padding-top:var(--s3)}
.coll-archive>summary{
  list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:6px;
  font-size:var(--fs-sm);font-weight:620;color:var(--ink2);user-select:none;
}
.coll-archive>summary::-webkit-details-marker{display:none}
.coll-archive>summary::before{content:"▸";color:var(--muted);transition:transform var(--t) var(--ease)}
.coll-archive[open]>summary::before{transform:rotate(90deg)}
.coll-archive>.hint{margin:var(--s1) 0 var(--s3)}
.coll-archive .coll-card{opacity:.72;background:var(--surface-2)}
.coll-archive .coll-card:hover{opacity:1}

/* =============================================================================
   13 · CHARTS & PROGRESS
   ========================================================================== */
.bar-row{display:grid;grid-template-columns:minmax(104px,148px) 1fr 48px;gap:var(--s3);align-items:center;margin-bottom:var(--s2);font-size:var(--fs-base)}
.bar-row .name{color:var(--ink2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bar-track{height:20px;border-radius:var(--r-xs);background:var(--surface-3);position:relative;overflow:hidden}
/* A default fill colour matters: only the Dashboard pipeline sets one inline (per
   stage). Performance's lead funnel sets none, so without this every one of its
   bars painted transparent — a chart of empty tracks. */
.bar-fill{height:100%;border-radius:var(--r-xs);min-width:3px;background:var(--accent);transition:width var(--t-slow) var(--ease)}
.bar-row .val{text-align:right;font-variant-numeric:tabular-nums;color:var(--ink);font-weight:620}
/* The dashboard's pipeline rows are buttons now — a count you can read but not follow is a poster,
   not a tool. Button defaults are reset so they still look exactly like the rows they replaced;
   only hover, focus and the cursor say they are live. */
button.bar-row{
  width:100%;text-align:left;font:inherit;color:inherit;
  background:transparent;border:0;padding:var(--s1) var(--s2);margin-left:calc(var(--s2) * -1);
  border-radius:var(--r-sm);cursor:pointer;
  transition:background var(--t) var(--ease);
}
button.bar-row:hover{background:var(--surface-2)}
button.bar-row:hover .bar-track{background:var(--line-2)}
button.bar-row:focus-visible{outline:2px solid var(--accent);outline-offset:1px}
.bar-foot{margin-top:var(--s3);display:flex;align-items:center;gap:2px;flex-wrap:wrap;font-size:var(--fs-sm)}
/* A count rendered as prose that turns out to be clickable. Underlined on hover only, so the row
   still reads as the quiet footnote it is. */
.linkish{
  background:none;border:0;padding:0;font:inherit;color:var(--muted);cursor:pointer;
  border-radius:var(--r-xs);
}
.linkish:hover{color:var(--ink2);text-decoration:underline}
.linkish:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* The line under the Dashboard's tiles naming what could not be shown for one person. Pulled up
   against the band it belongs to, so it reads as that band's footnote and not as a stray paragraph. */
.own-skip{margin:calc(-1 * var(--s2)) 0 var(--s4);font-size:var(--fs-sm)}

/* The revenue-target band and the monthly bar chart were styled here. Deals came back on 2026-08-19
   WITHOUT targets or quota attainment — money lives in the owner's CRM — so none of these classes has
   been emitted by app.js since. ~45 lines, no markup. */

.step-flow{display:flex;gap:var(--s1);flex-wrap:wrap;margin:var(--s3) 0 var(--s4);align-items:center}
.step-flow span{
  background:var(--accent-soft);color:var(--tint-ink);border-radius:var(--r-sm);
  padding:6px 12px;font-size:var(--fs-sm);font-weight:600;
}
.step-flow.small span{font-size:var(--fs-xs);padding:5px 10px}

/* =============================================================================
   14 · OVERLAYS — dialog, wizard, toast, palette, progress
   ========================================================================== */
dialog{
  border:1px solid var(--line);border-radius:var(--r-xl);background:var(--surface);color:var(--ink);
  padding:var(--s6);width:min(580px,94vw);box-shadow:var(--shadow-3);
  position:fixed;inset:0;margin:auto;max-height:min(92vh,92dvh);overflow:auto;
  animation:dlgIn var(--t-slow) var(--ease) both;
}
dialog::backdrop{background:var(--scrim);backdrop-filter:blur(8px) saturate(130%);animation:fadeIn var(--t-slow) ease both}
@keyframes dlgIn{from{opacity:0;transform:scale(.97) translateY(10px)}to{opacity:1;transform:none}}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}

/* content-heavy popups (the form builder) ask for more room via dialog(html,'wide') */
dialog.wizard.wide{width:min(940px,96vw)}
dialog.wizard{width:min(560px,95vw);padding:0;overflow:hidden;max-height:min(92vh,92dvh);display:flex;flex-direction:column}
.wiz-top{
  display:flex;align-items:center;gap:var(--s3);padding:var(--s4) var(--s5);
  border-bottom:1px solid var(--line);background:var(--surface-2);flex-shrink:0;
}
.wiz-name{font-weight:660;font-size:var(--fs-md);letter-spacing:-.015em}
.wiz-progress{display:flex;align-items:center;gap:var(--s1);margin-top:6px}
.wiz-dot{width:7px;height:7px;border-radius:50%;background:var(--line-2);transition:background var(--t),box-shadow var(--t)}
.wiz-dot.cur{background:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.wiz-dot.done{background:var(--good)}
.wiz-count{font-size:var(--fs-xs);color:var(--muted);margin-left:var(--s1);font-variant-numeric:tabular-nums}
/* ONE dismiss control for every overlay (2026-08-22). It was declared twice with contradictory
   values — a round grey disc at one rule, a hairline square at the next — and rendered a 12px glyph in
   a 30px box at 3.5:1 contrast, which is the "close button" the owner asked to see redesigned.
   It inks itself from `currentColor`, so the same rule works on a white panel and on the dark
   teal-green header bands without a second variant, and the ::after gives it a 44px pointer target
   without a 44px visual box. Red on hover is gone: closing a panel is not destructive, and red is
   this app's delete colour. */
.wiz-x,.bp-x{
  display:inline-flex;align-items:center;justify-content:center;
  width:32px;height:32px;min-height:32px;padding:0;flex-shrink:0;align-self:flex-start;
  border:0;border-radius:var(--r-sm);box-shadow:none;position:relative;
  background:color-mix(in srgb, currentColor 9%, transparent);
  color:inherit;opacity:.75;
  transition:background var(--t) var(--ease),opacity var(--t) var(--ease);
}
.wiz-x::after,.bp-x::after{content:"";position:absolute;inset:-6px}
.wiz-x:hover,.bp-x:hover{background:color-mix(in srgb, currentColor 18%, transparent);opacity:1}
/* A ring that survives both grounds: the outline takes the button's own ink, the halo is its inverse. */
.wiz-x:focus-visible,.bp-x:focus-visible{
  outline:2px solid currentColor;outline-offset:2px;opacity:1;
  box-shadow:0 0 0 4px color-mix(in srgb, currentColor 22%, transparent);
}
.wiz-head{padding:var(--s4) var(--s5) 0;display:flex;align-items:flex-start;gap:var(--s3)}
.wiz-head h3{font-size:var(--fs-lg);margin:0;display:flex;align-items:center;gap:var(--s2);min-width:0}
/* No `order` any more: the button is the last child now, so the DOM order and the visual order agree
   and it is the last thing in the tab sequence rather than the first. */
.wiz-head .wiz-x,.wiz-top .wiz-x{margin-left:auto}
.wiz-steptitle{font-size:var(--fs-lg);font-weight:640;padding:var(--s4) var(--s5) var(--s1);letter-spacing:-.018em}
.wiz-body{padding:var(--s1) var(--s5) var(--s3);overflow-y:auto;flex:1;min-height:0}
dialog:not(.wizard) .wiz-body{padding:0;overflow:visible}
.wiz-body p{color:var(--ink2);font-size:var(--fs-base);margin-bottom:var(--s3)}
.wiz-body form label{margin-bottom:var(--s3)}
.wiz-body .hint{margin:6px 0 0}
.wiz-ol{padding-left:var(--s5);margin:0 0 var(--s3);color:var(--ink2);font-size:var(--fs-base)}
.wiz-ol li{margin-bottom:6px}
.wiz-ol b,.wiz-body b{color:var(--ink);font-weight:620}
.wiz-live{
  display:flex;align-items:center;gap:var(--s2);background:var(--surface-2);
  border:1px solid var(--line);border-radius:var(--r-sm);padding:11px var(--s3);
  font-size:var(--fs-base);color:var(--ink2);margin-top:var(--s2);
}
/* The confirmation that survives the step it was earned on: which instance answered, kept in view
   while you finish the setup that depends on it. */
.wiz-ok{
  display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 var(--s3);
  padding:var(--s2) var(--s3);border-radius:var(--r-sm);
  background:var(--good-soft);color:color-mix(in srgb,var(--good) 74%,var(--ink));
  font-size:var(--fs-sm);
}
.wiz-choice{
  display:block;width:100%;text-align:left;background:var(--surface);color:var(--ink);
  border:1px solid var(--line-2);border-radius:var(--r-md);padding:var(--s3) var(--s4);
  margin-bottom:var(--s2);font:inherit;box-shadow:none;min-height:0;justify-content:flex-start;
  transition:background var(--t-fast),border-color var(--t-fast),box-shadow var(--t-fast);
}
.wiz-choice:hover{background:var(--surface-2);border-color:color-mix(in srgb, var(--accent) 45%, var(--line-2))}
.wiz-choice.sel{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.wiz-choice b{display:inline-flex;align-items:center;gap:var(--s2);font-size:var(--fs-md);font-weight:620}
.wiz-choice .muted{display:block;margin-top:5px;font-size:var(--fs-sm)}
.wiz-choice:disabled{opacity:.45;cursor:not-allowed}
.wiz-choice:disabled:hover{background:var(--surface);border-color:var(--line-2)}
.wiz-opt{border:1px solid var(--line);border-radius:var(--r-md);padding:var(--s3) var(--s4);margin-bottom:var(--s3);background:var(--surface-2)}
.wiz-opt h4{font-size:var(--fs-base);margin-bottom:var(--s2);display:flex;flex-wrap:wrap;align-items:center;gap:var(--s2)}
.wiz-opt .wiz-ol{margin-bottom:var(--s2)}
.wiz-group{border:1px solid var(--line);border-radius:var(--r-md);padding:var(--s3) var(--s4);margin-bottom:var(--s3);background:var(--surface-2)}
.wiz-group>label:last-child,.wiz-group>.formgrid:last-child{margin-bottom:0}
.wiz-group-h{font-size:var(--fs-xs);font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);margin-bottom:var(--s2)}
/* A wiz-group that folds: the summary keeps the group heading's look and gains a caret. */
details.wiz-group>summary.wiz-group-h{cursor:pointer;list-style:none;display:flex;align-items:center;gap:6px}
details.wiz-group>summary.wiz-group-h::-webkit-details-marker{display:none}
details.wiz-group>summary.wiz-group-h::after{content:"";width:6px;height:6px;border-right:2px solid currentColor;border-bottom:2px solid currentColor;
  transform:rotate(-45deg);transition:transform .15s ease;margin-left:auto;flex:none}
details.wiz-group[open]>summary.wiz-group-h::after{transform:rotate(45deg)}
details.wiz-group>summary.wiz-group-h:hover{color:var(--ink)}
details.wiz-group:not([open]){margin-bottom:var(--s2)}
.wiz-note{
  margin:0 var(--s5);padding:10px var(--s3);border-radius:var(--r-sm);font-size:var(--fs-base);
  background:var(--good-soft);color:color-mix(in srgb,var(--good) 72%,var(--ink));
  border:1px solid color-mix(in srgb,var(--good) 30%,transparent);
}
.wiz-note.err{background:var(--critical-soft);color:var(--critical);border-color:color-mix(in srgb,var(--critical) 30%,transparent)}
.wiz-foot{
  /* flex-end so a lone primary action sits right (conventional) instead of stranded on
     the left of a wide band; .wiz-foot-r's auto margin still splits two-part footers. */
  display:flex;align-items:center;justify-content:flex-end;gap:var(--s2);
  padding:var(--s3) var(--s5);border-top:1px solid var(--line);margin-top:var(--s3);
  background:var(--surface-2);flex-shrink:0;flex-wrap:wrap;
}
dialog:not(.wizard) .wiz-foot{margin:var(--s5) calc(var(--s6) * -1) calc(var(--s6) * -1);border-radius:0 0 var(--r-xl) var(--r-xl)}
.wiz-foot-l,.wiz-foot-r{display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap}
.wiz-foot-r{margin-left:auto}
.wiz-foot button{margin:0}

.copyrow{
  display:flex;align-items:center;gap:var(--s2);background:var(--surface-2);
  border:1px solid var(--line);border-radius:var(--r-sm);padding:var(--s2) var(--s3);margin:6px 0 var(--s3);
}
.copyrow-label{font-size:var(--fs-xs);color:var(--muted);text-transform:uppercase;letter-spacing:.07em;font-weight:640;flex-shrink:0}
/* min-height:0 made these 18px tall — they are click-to-select controls, so they get a
   real target height while staying visually borderless. */
.copyrow-val{flex:1;font-family:ui-monospace,Menlo,monospace;font-size:var(--fs-xs);word-break:break-all;background:transparent;border:0;padding:0;min-height:26px}

/* toast */
#toast{
  position:fixed;bottom:var(--s6);right:var(--s6);z-index:var(--z-toast);
  background:var(--n900);color:var(--n0);
  padding:11px var(--s5);border-radius:var(--r-md);font-size:var(--fs-base);font-weight:520;
  box-shadow:var(--shadow-3);max-width:min(440px,90vw);word-break:break-word;overflow-wrap:anywhere;
  opacity:0;transform:translateY(14px) scale(.96);
  transition:opacity var(--t) var(--ease),transform var(--t-slow) var(--ease-spring);
}
#toast.show{opacity:1;transform:none}

/* spinners & button loading dots */
.spinner{
  width:15px;height:15px;border:2px solid var(--line-2);border-top-color:var(--accent);
  border-radius:50%;animation:spin .7s linear infinite;flex-shrink:0;
}
@keyframes spin{to{transform:rotate(360deg)}}
.btn-load-dots{display:inline-flex;align-items:center;gap:4px;margin-left:var(--s2);vertical-align:middle}
.btn-load-dots span{width:5px;height:5px;border-radius:50%;display:inline-block;animation:btnDotWave 1.1s ease-in-out infinite}
.btn-load-dots.on-solid span{background:var(--accent)}
.btn-load-dots.on-light span{background:var(--accent)}
@keyframes btnDotWave{0%,80%,100%{opacity:.25;transform:scale(.6)}40%{opacity:1;transform:scale(1)}}

/* =============================================================================
   15 · COMMAND PALETTE (⌘K)
   ========================================================================== */
.cmdk{
  border:0;background:transparent;padding:0;width:min(620px,94vw);max-height:none;overflow:visible;
  position:fixed;top:14vh;left:50%;transform:translateX(-50%);margin:0;box-shadow:none;
}
.cmdk::backdrop{background:var(--scrim);backdrop-filter:blur(8px) saturate(130%)}
.cmdk-panel{
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-3);overflow:hidden;display:flex;flex-direction:column;max-height:70vh;
}
.cmdk-input-wrap{display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s4);border-bottom:1px solid var(--line)}
.cmdk-input-wrap svg{color:var(--muted);flex-shrink:0}
.cmdk-input{
  border:0;background:transparent;font-size:var(--fs-lg);padding:0;min-height:30px;
  color:var(--ink);width:100%;
}
/* The input's own ring is suppressed because the whole row reads as the field — but SOMETHING has
   to show focus, or a keyboard user opening ⌘K has no idea where they are. The wrapper takes it. */
.cmdk-input:focus{outline:none;box-shadow:none}
.cmdk-input-wrap:focus-within{background:var(--accent-soft)}
.cmdk-input-wrap:focus-within svg{color:var(--accent)}
.cmdk-list{overflow-y:auto;padding:var(--s1);flex:1;min-height:0}
.cmdk-group{font-size:var(--fs-2xs);font-weight:700;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);padding:var(--s3) var(--s3) var(--s1)}
.cmdk-item{
  display:flex;align-items:center;gap:var(--s3);padding:9px var(--s3);border-radius:var(--r-sm);
  cursor:pointer;color:var(--ink2);font-size:var(--fs-base);min-width:0;
}
.cmdk-item .cmdk-ic{display:inline-flex;color:var(--muted);flex-shrink:0}
.cmdk-item .cmdk-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:520}
.cmdk-item .cmdk-meta{font-size:var(--fs-xs);color:var(--muted);flex-shrink:0}
.cmdk-item[aria-selected="true"]{background:var(--accent-soft);color:var(--tint-ink)}
.cmdk-item[aria-selected="true"] .cmdk-ic,.cmdk-item[aria-selected="true"] .cmdk-meta{color:var(--accent)}
.cmdk-empty{padding:var(--s6) var(--s4);text-align:center;color:var(--muted);font-size:var(--fs-base)}
.cmdk-foot{
  display:flex;align-items:center;gap:var(--s4);padding:var(--s2) var(--s4);
  border-top:1px solid var(--line);background:var(--surface-2);font-size:var(--fs-xs);color:var(--muted);flex-wrap:wrap;
}
.cmdk-foot span{display:inline-flex;align-items:center;gap:5px}

/* =============================================================================
   16 · STATES — empty, loading skeleton, error
   ========================================================================== */
.empty-state{
  text-align:center;padding:var(--s8) var(--s4);
  display:flex;flex-direction:column;align-items:center;gap:var(--s2);
}
.empty-state .empty-ic{
  width:46px;height:46px;border-radius:var(--r-md);display:inline-flex;align-items:center;justify-content:center;
  background:var(--surface-3);color:var(--muted);margin-bottom:var(--s1);
}
.empty-state h4{font-size:var(--fs-md);font-weight:620}
.empty-state p{margin:0 0 var(--s3);font-size:var(--fs-base);color:var(--muted);max-width:52ch}
.empty-state>div{display:flex;gap:var(--s2);justify-content:center;flex-wrap:wrap}

/* skeleton loader */
.skel{display:flex;flex-direction:column;gap:var(--s3)}
.skel-line,.skel-block,.skel-tile{
  background:linear-gradient(90deg,var(--surface-3) 25%,color-mix(in srgb,var(--ink) 7%,var(--surface-3)) 37%,var(--surface-3) 63%);
  background-size:400% 100%;animation:shimmer 1.4s ease infinite;border-radius:var(--r-sm);
}
.skel-line{height:12px}
.skel-line.w40{width:40%} .skel-line.w60{width:60%} .skel-line.w25{width:25%}
.skel-tile{height:96px;border-radius:var(--r-lg)}
.skel-block{height:220px;border-radius:var(--r-lg)}
.skel-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(196px,1fr));gap:var(--s3)}
@keyframes shimmer{0%{background-position:100% 50%}100%{background-position:0 50%}}

/* =============================================================================
   17 · PAGE MODULES
   ========================================================================== */
/* — login — */
.login-wrap{
  min-height:100vh;min-height:100dvh;display:grid;grid-template-columns:1fr;
  place-items:center;padding:var(--s5);
  /* The wordmark's own ramp — deep navy into teal — as the entry-hall backdrop. */
  background:
    radial-gradient(1100px 620px at 12% -10%, color-mix(in srgb, var(--brand-500) 26%, transparent), transparent 60%),
    radial-gradient(900px 520px at 100% 108%, color-mix(in srgb, var(--brand-700) 22%, transparent), transparent 60%),
    linear-gradient(160deg, color-mix(in srgb, var(--brand-900) 10%, var(--page)), var(--page) 55%);
}
.login-card{
  /* Glass card: translucent surface + blur, both themes. Falls back to the solid surface where
     backdrop-filter is unsupported — the border and shadow carry the shape either way. */
  background:color-mix(in srgb, var(--surface) 78%, transparent);
  -webkit-backdrop-filter:blur(14px) saturate(1.15);backdrop-filter:blur(14px) saturate(1.15);
  border:1px solid color-mix(in srgb, var(--line) 65%, transparent);border-radius:var(--r-xl);
  padding:var(--s7);width:min(390px,100%);
  box-shadow:var(--shadow-3), inset 0 1px 0 rgba(255,255,255,.09);
}
@supports not (backdrop-filter: blur(1px)){.login-card{background:var(--surface)}}
.login-card .login-mark{
  width:44px;height:44px;border-radius:var(--r-md);margin-bottom:var(--s4);
  display:inline-flex;align-items:center;justify-content:center;
  background:linear-gradient(145deg, var(--brand-400), var(--brand-600));color:#fff;
  box-shadow:0 2px 6px rgba(16,24,40,.24), inset 0 1px 0 rgba(255,255,255,.28);
}
.login-card h1{font-size:var(--fs-2xl);margin-bottom:var(--s1);letter-spacing:-.028em}
.login-card h1 span{
  display:block;font-size:var(--fs-xs);font-weight:660;color:var(--accent);
  letter-spacing:.13em;text-transform:uppercase;margin-top:6px;
}
.login-card .login-sub{font-size:var(--fs-base);color:var(--muted);margin-bottom:var(--s5)}
.login-card label{margin-bottom:var(--s4)}
.login-card input{min-height:38px}
.login-card button[type=submit]{width:100%;margin-top:var(--s1);padding:10px;min-height:40px;font-size:var(--fs-md)}
.login-card .remember{
  display:flex;flex-direction:row;align-items:center;gap:var(--s2);
  font-size:var(--fs-base);margin:var(--s1) 0 var(--s4);cursor:pointer;color:var(--ink2);
}
.login-card .remember input{width:auto;margin:0}
.login-foot{margin-top:var(--s5);padding-top:var(--s4);border-top:1px solid var(--line);font-size:var(--fs-hint);color:var(--muted);text-align:center}

/* — playbook — */
.playbook h3{margin:var(--s6) 0 var(--s2);font-size:var(--fs-lg);letter-spacing:-.018em}
.playbook p,.playbook li{color:var(--ink2);font-size:var(--fs-base);margin-bottom:6px;line-height:var(--lh)}
.playbook ol,.playbook ul{padding-left:var(--s5);margin-bottom:var(--s3)}
.playbook strong{color:var(--ink);font-weight:620}
.pb-toc{
  font-size:var(--fs-sm);line-height:2;background:var(--surface-2);border:1px solid var(--line);
  border-radius:var(--r-md);padding:var(--s3) var(--s4);margin:var(--s3) 0 var(--s5);
  columns:14em;column-gap:var(--s6);
}
.pb-toc a{text-decoration:none;display:block;break-inside:avoid}
.pb-toc a:hover{text-decoration:underline}

/* — Business Network — */
.net-opts{display:flex;flex-direction:column;gap:var(--s2);margin-bottom:var(--s1)}
.net-opts .wiz-choice{margin-bottom:0}
/* nowrap: with the expander, star and avatar all in front of the name, this column wrapped the
   chevron onto its own line at table widths */
.net-org{display:flex;align-items:flex-start;gap:var(--s2);min-width:0;flex-wrap:nowrap}
#netTable th:first-child,#netTable td:first-child{min-width:264px}
.net-org-t{min-width:0}
.net-av{
  flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;
  border-radius:var(--r-sm);background:var(--accent-soft);color:var(--tint-ink);
  font-size:var(--fs-sm);font-weight:700;letter-spacing:.02em;
}
.net-loc{font-size:var(--fs-xs);margin-top:1px}
.net-why{font-size:var(--fs-hint);color:var(--ink2);margin-top:3px;max-width:360px}
.net-exp{
  background:transparent;color:var(--muted);border:0;box-shadow:none;padding:6px var(--s2) 6px var(--s1);
  /* top-aligned with the star and avatar: centred, it floated away from them on a three-line row */
  font-size:var(--fs-base);line-height:1;align-self:flex-start;margin-top:8px;flex-shrink:0;min-height:0;
}
.net-exp:hover{color:var(--accent);background:transparent}
/* the disclosure control is a real chevron now; it rotates rather than swapping glyphs */
.net-exp>svg{width:13px;height:13px;display:block;transition:transform var(--t) var(--ease)}
.net-exp[aria-expanded="true"]>svg{transform:rotate(90deg)}
.net-apply{font-weight:600;font-size:var(--fs-sm);white-space:nowrap;text-decoration:none}
.net-apply:hover{text-decoration:underline}
.net-quick{display:flex;align-items:center;gap:var(--s4);flex-wrap:wrap;margin-bottom:var(--s3)}
.net-goalfilter{display:flex;align-items:center;gap:5px;flex-wrap:wrap}
.net-goalchip{cursor:pointer}
.net-goalchip.on{background:var(--accent-soft);color:var(--tint-ink);border-color:transparent;font-weight:600}
.net-detail{padding:var(--s4) var(--s5) var(--s5) 56px}
.net-detail-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:var(--s3) var(--s5);margin-bottom:var(--s3)}
.net-detail p{font-size:var(--fs-base);color:var(--ink2);margin:2px 0 0}
.net-dl{font-size:var(--fs-2xs);font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);margin-top:var(--s1)}
.net-steps{margin:var(--s1) 0 var(--s3);padding-left:var(--s5);font-size:var(--fs-base);color:var(--ink2)}
.net-steps li{margin-bottom:3px}
.net-why-full{font-size:var(--fs-base);color:var(--ink2);margin:6px 0}
.net-why-full strong{color:var(--ink)}
.net-detail-foot{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;margin-top:var(--s3);padding-top:var(--s3);border-top:1px solid var(--line);font-size:var(--fs-hint)}
.net-future-sum{cursor:pointer;font-weight:640;font-size:var(--fs-md)}
.net-future-list{display:flex;flex-direction:column;gap:var(--s2)}
.net-future-item{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--s3);border:1px solid var(--line);border-radius:var(--r-md);padding:var(--s3) var(--s4);background:var(--surface-2)}
.net-needed{font-size:var(--fs-sm);color:var(--serious);font-weight:600;margin-top:var(--s1)}

/* — Find Leads panel / wizard — */
.mlf-foot{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;margin-top:var(--s5);padding-top:var(--s4);border-top:1px solid var(--line)}
.mlf-foot .spacer{flex:1}
.mlf-foot .hint{font-size:var(--fs-hint);color:var(--muted)}
@keyframes flwIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.flw-step,.flw-reveal{animation:flwIn var(--t) var(--ease)}
.flw-dots{display:flex;gap:6px;margin:2px 0 var(--s4)}
.flw-dots i{width:24px;height:4px;border-radius:2px;background:var(--surface-3);transition:background var(--t)}
.flw-dots i.on{background:var(--accent)}
.flw-q{font-weight:640;font-size:var(--fs-base);margin:var(--s4) 0 var(--s2)}

/* — compact icon actions (collection cards) —
   Square icon buttons instead of a row of text buttons: the same four actions in
   roughly a third of the width, so the card footer stays on one line. Every one
   carries a title + aria-label, since the glyph alone isn't a label. */
.icon-act{
  --act-ink:var(--muted);
  position:relative;display:inline-flex;align-items:center;justify-content:center;
  width:30px;height:30px;min-height:30px;padding:0;margin:0;flex-shrink:0;
  background:var(--surface-2);color:var(--act-ink);border:1px solid var(--line);
  border-radius:var(--r-sm);box-shadow:none;cursor:pointer;
  transition:background var(--t-fast),color var(--t-fast),border-color var(--t-fast);
}
.icon-act svg{width:15px;height:15px;display:block;pointer-events:none}
.icon-act:hover{background:var(--surface-3);color:var(--ink);border-color:var(--line-2)}
.icon-act.danger{background:var(--surface-2);border-color:var(--line)}
.icon-act.danger:hover{background:var(--critical-soft);color:var(--critical);border-color:color-mix(in srgb,var(--critical) 34%,transparent)}
.icon-act:focus-within,.icon-act:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* toggle variant — the checkbox is the control, the box is the affordance */
.icon-act.toggle input{position:absolute;opacity:0;width:100%;height:100%;margin:0;cursor:pointer}
.icon-act.toggle:has(input:checked){background:var(--accent-soft);color:var(--tint-ink);border-color:var(--accent)}
/* select variant — icon shows, the native select sits invisibly on top so it stays a real select */
/* Assign is an ICON, like every other action on this card. It used to carry a visible select
   showing "Assign…", which made one action twice the width of the rest and pushed the row of them
   out of the card. The select is still a real <select> — it is stretched invisibly over the icon,
   so clicking anywhere on the button opens the native list of people. Keyboard and screen readers
   get the select; the eye gets the icon. */
.icon-act.select{width:auto;padding:0;gap:0;position:relative;overflow:hidden}
.icon-act.select svg{margin:0 7px}
.icon-act.select select{
  position:absolute;inset:0;width:100%;height:100%;min-width:0;min-height:0;padding:0;margin:0;
  border:0;background:none;box-shadow:none;color:transparent;
  opacity:0;cursor:pointer;appearance:none;-webkit-appearance:none;
}
/* Focus has to be visible on the BUTTON, since the control carrying it is invisible. */
.icon-act.select:focus-within{background:var(--surface-3);border-color:var(--accent);box-shadow:var(--ring-focus)}
.icon-act.select select:focus{box-shadow:none;outline:none}
/* Every action stays inside the card: one row that wraps within the block rather than spilling. */
.coll-actions{display:flex;gap:5px;align-items:center;flex-wrap:wrap;justify-content:flex-end;min-width:0;max-width:100%}

/* — collapsible "data sources" strip —
   Was a permanently-open row of up to 14 connector chips sitting above the data on
   several pages; now one line that opens on demand. */
details.poweredby{margin:0 0 var(--s3)}
details.poweredby>summary{
  list-style:none;cursor:pointer;display:inline-flex;align-items:center;gap:6px;
  font-size:var(--fs-sm);color:var(--ink2);background:var(--surface-2);
  border:1px solid var(--line);border-radius:var(--r-full);padding:4px 13px;user-select:none;
}
details.poweredby>summary::-webkit-details-marker{display:none}
details.poweredby>summary::after{content:"▾";color:var(--muted);font-size:10px;transition:transform var(--t) var(--ease)}
details.poweredby[open]>summary::after{transform:rotate(180deg)}
details.poweredby>summary:hover{background:var(--surface-3);border-color:var(--line-2)}
.poweredby-chips{display:flex;align-items:center;flex-wrap:wrap;gap:5px;margin-top:var(--s2)}

/* — Leads filter bar: filters and saved views on one row instead of two — */
.leadbar{align-items:center}
.leadbar-sep{width:1px;align-self:stretch;min-height:26px;background:var(--line);margin:0 var(--s1)}
.savedviews{display:inline-flex;align-items:center;gap:5px;flex-wrap:wrap;font-size:var(--fs-sm)}
.savedviews .muted{font-size:var(--fs-xs)}
@media (max-width:900px){.leadbar-sep{display:none}.savedviews{width:100%}}


/* — company brief bubble (Leads 🏢) —
   position:fixed and appended to <body>: the leads table scrolls horizontally, so a
   popover anchored inside it would drift away from its button. */
.brief-pop{
  position:fixed;z-index:var(--z-pop);width:min(360px,calc(100vw - 20px));
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-3);display:flex;flex-direction:column;
  max-height:min(560px,78vh);overflow:hidden;
  transform-origin:top right;animation:notifPopIn var(--t-slow) var(--ease-spring) both;
}
/* Same band as the notifications bubble — the two popovers are the same object at different sizes,
   and letting one go dark while the other stayed grey is how a platform stops looking designed. */
.bp-head{
  display:flex;align-items:center;gap:var(--s2);padding:var(--s3) var(--s4);
  border-bottom:1px solid var(--line);background:var(--brand-800);color:#fff;flex-shrink:0;
}
.bp-head .bp-title strong{color:#fff}
.bp-head .bp-title a,.bp-head .bp-title .muted{color:rgba(255,255,255,.78)}
/* The letter-tile fallback when a company has no logo: white on the band, like the real logo tile. */
.bp-head .bp-logo-fb{background:#fff;color:var(--brand-800)}
.bp-logo{width:32px;height:32px;border-radius:var(--r-sm);object-fit:contain;background:#fff;border:1px solid var(--line);flex-shrink:0}
.bp-logo-fb{display:inline-flex;align-items:center;justify-content:center;background:var(--accent-soft);color:var(--tint-ink);font-weight:700;font-size:var(--fs-md);border-color:transparent}
.bp-title{display:flex;flex-direction:column;min-width:0;flex:1;line-height:1.3}
.bp-title strong{font-size:var(--fs-md);font-weight:650;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bp-title a,.bp-title .muted{font-size:var(--fs-xs);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bp-body{overflow-y:auto;padding:var(--s3) var(--s4) var(--s4);min-height:0}
.bp-sec{
  font-size:var(--fs-2xs);font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);margin:var(--s4) 0 var(--s2);
}
.bp-body>.bp-sec:first-child{margin-top:0}
.bp-what{font-size:var(--fs-sm);line-height:var(--lh);color:var(--ink2);margin:0;white-space:pre-wrap;overflow-wrap:anywhere}
.bp-acts{display:flex;gap:6px;flex-wrap:wrap;margin-top:var(--s2)}
.bp-acts .small{padding:3px 10px;font-size:var(--fs-xs);min-height:26px}
.bp-err{font-size:var(--fs-xs);margin-top:6px;min-height:0}
.bp-row{display:grid;grid-template-columns:92px minmax(0,1fr);gap:var(--s2);padding:3px 0;font-size:var(--fs-sm)}
.bp-k{color:var(--muted)}
.bp-v{color:var(--ink);overflow-wrap:anywhere}
.bp-signal{
  margin-top:var(--s2);font-size:var(--fs-xs);font-weight:600;
  color:color-mix(in srgb,var(--warning) 74%,var(--ink));
  background:var(--warning-soft);border-radius:var(--r-sm);padding:5px 9px;
}
.bp-sugg{list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:6px}
.bp-sugg li{
  display:flex;flex-direction:column;gap:1px;font-size:var(--fs-sm);
  background:var(--surface-2);border:1px solid var(--line);border-left:3px solid var(--accent);
  border-radius:var(--r-sm);padding:7px 10px;
}
.bp-sugg li .muted{font-size:var(--fs-xs);line-height:var(--lh-snug)}
.bp-foot{font-size:var(--fs-2xs);margin-top:var(--s3);line-height:var(--lh-snug)}

/* — Leads: composed cells + Reach slots —
   Secondary lines carry what used to be their own columns (industry under company,
   title under contact), which is what lets the table fit without horizontal scroll. */
.cell-sub{font-size:var(--fs-xs);color:var(--ink2);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cell-age{font-size:var(--fs-xs);white-space:nowrap;font-variant-numeric:tabular-nums}
.reach-cell{display:inline-flex;gap:4px;align-items:center}
.reach{
  position:relative;display:inline-flex;align-items:center;justify-content:center;
  width:28px;height:28px;min-height:28px;padding:0;flex-shrink:0;
  border-radius:var(--r-sm);border:1px solid var(--line);background:var(--surface-2);
  color:var(--muted);box-shadow:none;cursor:pointer;text-decoration:none;
  transition:background var(--t-fast),color var(--t-fast),border-color var(--t-fast);
}
.reach svg{width:15px;height:15px;display:block;pointer-events:none}
.reach:hover{background:var(--surface-3);border-color:var(--line-2)}
.reach.ok{color:var(--good);border-color:color-mix(in srgb,var(--good) 30%,transparent);background:var(--good-soft)}
.reach.bad{color:var(--critical);border-color:color-mix(in srgb,var(--critical) 30%,transparent);background:var(--critical-soft)}
.reach.guess{color:color-mix(in srgb,var(--warning) 78%,var(--ink));border-color:color-mix(in srgb,var(--warning) 30%,transparent);background:var(--warning-soft)}
.reach.unk{color:var(--ink2)}
/* nothing on file, and not fetchable (LinkedIn) — present but visibly inert */
.reach.none{background:transparent;border-style:dashed;color:var(--n400);cursor:default}
.reach.none:hover{background:transparent;border-color:var(--line)}
/* fetchable gap — dashed with a small + badge */
.reach.add{background:transparent;border-style:dashed;color:var(--muted)}
.reach.add:hover{background:var(--accent-soft);border-color:var(--accent);color:var(--tint-ink)}
/* looking one up right now — the button itself lights up and blinks.
   A 28px icon can't carry the sibling dot-wave the wide buttons use: it doubles the width of the
   Reach cell and detaches the feedback from the control that was actually clicked. This keeps the
   signal on the button, and makes it loud — accent fill, accent border, and a halo that breathes.
   The resting state below is already strong on its own, so the global prefers-reduced-motion rule
   (which stops the pulse) still leaves an unmistakably busy control rather than a dead one.
   ~1.05s per cycle, deliberately under 3 flashes/second (WCAG 2.3.1). */
.reach.is-busy{
  border-color:var(--accent);background:var(--accent-soft);color:var(--tint-ink);
  cursor:progress;
  box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 30%,transparent),0 0 12px 2px color-mix(in srgb,var(--accent) 55%,transparent);
  animation:reachBusy 1.05s ease-in-out infinite;
}
/* it is disabled while it works, and the global disabled rule would halve exactly the glow we want seen */
.reach.is-busy:disabled{opacity:1;cursor:progress}
/* the + badge promises "click to find this" — it is already finding it */
.reach.is-busy .reach-plus{display:none}
@keyframes reachBusy{
  0%,100%{
    box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 32%,transparent),0 0 8px 1px color-mix(in srgb,var(--accent) 45%,transparent);
    border-color:var(--accent);opacity:1;
  }
  50%{
    box-shadow:0 0 0 6px color-mix(in srgb,var(--accent) 16%,transparent),0 0 20px 5px color-mix(in srgb,var(--accent) 90%,transparent);
    border-color:color-mix(in srgb,var(--accent) 55%,var(--surface));opacity:.58;
  }
}
.reach-plus{
  position:absolute;right:-3px;bottom:-3px;width:13px;height:13px;border-radius:50%;
  background:var(--accent);color:#fff;display:inline-flex;align-items:center;justify-content:center;
  border:1.5px solid var(--surface);
}
.reach-plus svg{width:8px;height:8px}
/* — lead activity timeline —
   One row per event, icon-led, with the timestamp always visible: the point of the feed is when
   something happened, so the date is never behind a tooltip. */
.hist-feed{display:flex;flex-direction:column;gap:1px}
.hist-row{display:flex;gap:var(--s3);padding:var(--s2) var(--s2) var(--s2) 0;border-bottom:1px solid var(--line-soft)}
.hist-row:last-child{border-bottom:0}
.hist-ic{
  width:26px;height:26px;border-radius:var(--r-sm);flex-shrink:0;margin-top:1px;
  display:inline-flex;align-items:center;justify-content:center;
  background:var(--surface-3);color:var(--ink2);
}
.hist-ic svg{width:14px;height:14px}
.hist-body{min-width:0;flex:1}
.hist-head{display:flex;align-items:baseline;gap:var(--s2);flex-wrap:wrap}
.hist-head>b{font-size:var(--fs-sm);font-weight:620;color:var(--ink)}
.hist-head .muted{font-size:var(--fs-xs);font-variant-numeric:tabular-nums}
.hist-note{font-size:var(--fs-sm);color:var(--ink2);line-height:var(--lh-snug);margin-top:2px;overflow-wrap:anywhere}
.note-meta{font-size:var(--fs-xs);font-variant-numeric:tabular-nums}

/* — grouped dialog form (Add / Edit lead) —
   The lead form was fifteen equal-weight fields in one column: no grouping, no idea which of them
   mattered. Sections give it shape without hiding anything. */
.form-sec{
  border:1px solid var(--line);border-radius:var(--r-md);background:var(--surface-2);
  padding:var(--s3) var(--s3) var(--s2);margin-bottom:var(--s3);
}
.form-sec>h4,.form-sec>summary{
  font-size:var(--fs-2xs);font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  color:var(--ink2);margin:0 0 var(--s2);
}
.form-sec>h4 .muted,.form-sec>summary .muted{letter-spacing:0;text-transform:none;font-weight:520}
.form-sec label{margin-bottom:var(--s2)}
.form-sec>label:last-child,.form-sec .q-row:last-child label{margin-bottom:var(--s1)}
.form-sec input,.form-sec select,.form-sec textarea{background:var(--surface)}
.form-sec .hint{margin:0 0 var(--s1)}
/* "required" reads better than a bare asterisk nobody has a legend for */
.req{
  font-size:var(--fs-2xs);font-weight:640;letter-spacing:.04em;text-transform:uppercase;
  color:var(--accent);margin-left:5px;
}
details.form-sec>summary{cursor:pointer;user-select:none;display:flex;align-items:center;gap:6px}
details.form-sec>summary::-webkit-details-marker{display:none}
details.form-sec>summary::before{content:"▸";transition:transform var(--t) var(--ease);color:var(--muted)}
details.form-sec[open]>summary::before{transform:rotate(90deg)}
.dossier-body{
  white-space:pre-wrap;font-family:inherit;font-size:var(--fs-sm);line-height:var(--lh-normal);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);
  padding:var(--s3);max-height:220px;overflow:auto;margin:0;color:var(--ink2);
}
.lead-notes-feed{max-height:190px;overflow-y:auto;margin-bottom:var(--s2)}
.note-add{display:flex;gap:var(--s2);align-items:flex-start}
.note-add textarea{flex:1;min-width:0;margin:0}
.note-add button{flex-shrink:0;white-space:nowrap}
/* pushes the destructive action away from the confirming one */
.foot-spacer{flex:1}

/* Back sits above the page title: it belongs to the page you are on, not to the title. */
.back-btn{margin-bottom:var(--s2);padding-left:8px}
.back-btn svg{width:14px;height:14px}
.cell-num{font-variant-numeric:tabular-nums}

/* — CSV export picker (Leads → Export) —
   A tick list rather than a dropdown, because you can now export several collections into one file. */
.exp-list{
  display:flex;flex-direction:column;gap:1px;margin:var(--s2) 0 var(--s3);
  max-height:min(46vh,340px);overflow-y:auto;
  border:1px solid var(--line);border-radius:var(--r-md);padding:var(--s1);background:var(--surface-2);
}
.exp-row{
  display:flex;align-items:center;gap:var(--s2);padding:7px var(--s2);border-radius:var(--r-sm);
  cursor:pointer;font-size:var(--fs-sm);color:var(--ink2);margin:0;
}
.exp-row:hover{background:var(--surface-3)}
.exp-row input{width:16px;height:16px;flex-shrink:0;margin:0}
.exp-name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:520}
.exp-row.lead .exp-name{font-weight:640}
.exp-row>b{font-variant-numeric:tabular-nums;color:var(--ink);flex-shrink:0}
/* the aggregate row sits apart from the collections it aggregates */
.exp-row.lead{
  background:var(--accent-soft);color:var(--tint-ink);font-weight:620;
  margin-bottom:var(--s1);border:1px solid var(--accent-ring);
}
.exp-row.lead>b{color:inherit}
.exp-list+.wiz-foot,.exp-list~.wiz-foot{display:flex;align-items:center;justify-content:space-between;gap:var(--s3)}

/* — business network table —
   "What it is" clamps to three lines with the full text on hover, and the row's actions are icons:
   at seven columns of prose the table was unreadable and nothing stood out as clickable. */
.net-concept{
  display:-webkit-box;-webkit-line-clamp:3;line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;
  max-width:34ch;color:var(--ink2);
}
.net-rules{
  display:inline-flex;align-items:center;gap:5px;margin-top:5px;
  font-size:var(--fs-2xs);color:var(--ink2);white-space:nowrap;
}
.net-rules svg{width:12px;height:12px;color:var(--muted);flex-shrink:0}
.net-acts{display:inline-flex;gap:var(--s1)}
.net-acts .icon-act{width:28px;height:28px;min-height:28px}
.net-acts .icon-act svg{width:14px;height:14px}

/* — form branding (lead-magnet builder) — */
.lm-brand{display:grid;grid-template-columns:auto 1fr;gap:var(--s3) var(--s4);align-items:start}
.lm-logo-box{
  width:132px;height:76px;border:1px dashed var(--line-2);border-radius:var(--r-md);
  background:var(--surface-2);display:flex;align-items:center;justify-content:center;padding:var(--s2);
}
.lm-logo-box img{max-width:100%;max-height:100%;object-fit:contain}
.lm-brand-ctl{display:flex;flex-direction:column;gap:var(--s2);align-items:flex-start;min-width:0}
/* the file input itself is unstyleable across browsers, so it's hidden behind its own label */
.lm-file input[type=file]{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.lm-file{display:flex;flex-direction:column;gap:4px;margin:0;cursor:pointer}
.lm-file .btn-like{
  display:inline-flex;align-items:center;gap:6px;align-self:flex-start;
  padding:7px 14px;border:1px solid var(--line-2);border-radius:var(--r-sm);
  background:var(--surface);font-size:var(--fs-base);font-weight:560;color:var(--ink2);
}
.lm-file:hover .btn-like{border-color:var(--accent);color:var(--tint-ink)}
.lm-file .btn-like svg{width:14px;height:14px}
.lm-file input:focus-visible+.btn-like{outline:2px solid var(--accent);outline-offset:2px}
.lm-swatches{grid-column:1/-1;display:flex;gap:var(--s4);flex-wrap:wrap}
.lm-swatch{display:flex;flex-direction:column;gap:4px;margin:0;font-size:var(--fs-sm);font-weight:560}
.lm-swatch.fixed{color:var(--ink2)}
.lm-swatch-fixed{
  display:inline-block;width:64px;height:32px;border:1px solid var(--line-2);border-radius:var(--r-sm);
}
.lm-swatch input[type=color]{
  width:64px;height:32px;padding:2px;border:1px solid var(--line-2);border-radius:var(--r-sm);
  background:var(--surface);cursor:pointer;
}
.lm-swatch .hint{margin:0}
/* the preview iframe is the real public page, so it gets a real viewport rather than a thumbnail */
.lm-preview{border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden;background:var(--surface-2)}
.lm-preview iframe{display:block;width:100%;height:min(70vh,620px);border:0}
@media (max-width:640px){
  .lm-brand{grid-template-columns:1fr}
}

/* — newsletter brand & email design —
   The template picker is a .net-seg whose buttons stack a pure-CSS thumbnail over their label. No
   image assets: three PNGs of three email shells is three PNGs that go stale the first time the
   renderer changes, and these are drawn from the same two colours the emails are. */
.nlt-seg{flex-wrap:wrap;padding:4px}
.nlt-seg button{
  display:flex;flex-direction:column;align-items:center;gap:5px;padding:9px 12px;
  max-width:170px;text-align:center;line-height:1.35;
}
.nlt-seg button[disabled]{opacity:.55;cursor:default}
.nlt-lb{font-weight:inherit}
.nlt-sub{font-size:var(--fs-2xs);color:var(--ink2);font-weight:460;display:block}
.nlt-th{
  position:relative;display:flex;align-items:center;justify-content:center;
  width:52px;height:38px;border:1px solid var(--line);background:var(--surface);overflow:hidden;
}
/* card — white card on grey, accent hairline across the top of it */
/* flat — full-bleed block with the rule centred underneath it */
/* editorial — a serif A over a heavy rule */

.nlb-cols{display:flex;gap:var(--s5) var(--s6);flex-wrap:wrap}
.nlb-col{display:flex;flex-direction:column;gap:5px;margin:0;min-width:260px;font-size:var(--fs-sm);font-weight:560}
.nlb-col .hint{margin:0}
.nlb-colrow{display:flex;align-items:center;gap:var(--s2)}
.nlb-colrow input[type=color]{
  width:46px;height:34px;padding:2px;border:1px solid var(--line-2);border-radius:var(--r-sm);
  background:var(--surface);cursor:pointer;
}
.nlb-hex{width:104px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;text-transform:lowercase}
.nlb-chiprow{display:flex}
/* the sample the main colour actually has to carry: white label on a real button */
.nlb-chip{
  display:inline-block;padding:9px 20px;border-radius:6px;color:#fff;
  font-size:var(--fs-md);font-weight:600;letter-spacing:.01em;
}
/* advisory, never blocking — a contrast warning does not stop the brand being saved */
.nlb-warn{
  margin:0;font-size:var(--fs-sm);font-weight:520;color:var(--warning);
  background:var(--warning-soft);border-radius:var(--r-sm);padding:7px 10px;
}
.nlb-preview{border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden;background:var(--surface-2);max-width:520px}
.nlb-preview iframe{display:block;width:100%;height:min(66vh,600px);border:0;background:#fff}
/* the editor's read-only reminder of where the colours and the logo come from */
.nlb-strip{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;margin-top:var(--s4);font-size:var(--fs-sm)}
.nlb-sw{width:22px;height:22px;border-radius:var(--r-xs);border:1px solid var(--line-2)}
.nlb-striplogo{height:22px;width:auto;max-width:120px;object-fit:contain}

/* a note in the filter bar when the table is showing a capped slice of a bigger result */

/* — business network favourites — */
.net-tabs{margin:var(--s2) 0 var(--s3)}
.net-tabs button{font-weight:560}
.net-tabs .net-tab-n{
  display:inline-block;margin-left:6px;padding:0 6px;border-radius:var(--r-full);
  background:var(--accent-soft);color:var(--tint-ink);font-size:var(--fs-2xs);font-weight:700;
  font-variant-numeric:tabular-nums;
}
.net-tabs button.on .net-tab-n{background:var(--accent);color:var(--ink-invert)}
.net-star{margin-top:3px;
  background:transparent;border:0;box-shadow:none;padding:0;min-height:0;flex-shrink:0;
  width:24px;height:24px;display:inline-flex;align-items:center;justify-content:center;
  color:var(--muted);border-radius:var(--r-sm);
}
.net-star svg{width:16px;height:16px}
.net-star:hover{background:var(--warning-soft);color:var(--warning)}
.net-star.on{color:var(--warning)}
.net-star.on svg{fill:currentColor}
.empty-state .net-star,.empty-ic svg{width:20px;height:20px}

/* — bulk-selection toolbar (Leads, Deals) —
   Was a .card.banner with inline padding, which read as another notice rather than "you are in
   selection mode". Accent-tinted, its own component, and its controls hug their content: the bar
   is a toolbar sitting outside .filterbar, so without this the global select{width:100%} made each
   dropdown claim the whole row and the toolbar stacked one control per line. */
.bulk-bar{
  display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;
  padding:var(--s3) var(--s4);margin-bottom:var(--s3);
  background:var(--accent-soft);border:1px solid var(--accent-ring);
  border-radius:var(--r-lg);box-shadow:var(--shadow-1);
}
.bulk-lead{display:flex;align-items:center;gap:var(--s2);min-width:0}
.bulk-ic{
  width:22px;height:22px;border-radius:var(--r-full);flex-shrink:0;
  background:var(--accent);color:var(--ink-invert);
  display:inline-flex;align-items:center;justify-content:center;
}
.bulk-ic svg{width:13px;height:13px}
.bulk-txt{display:flex;flex-direction:column;gap:0;min-width:0}
.bulk-count{font-size:var(--fs-base);font-weight:640;color:var(--tint-ink);white-space:nowrap}
.bulk-scope{font-size:var(--fs-2xs);color:var(--ink2);line-height:var(--lh-snug)}
.bulk-scope:empty{display:none}
.bulk-actions{display:flex;gap:var(--s2);flex-wrap:wrap;align-items:center;margin-left:auto}
.bulk-bar select,.bulk-bar input{width:auto;min-width:126px}
/* select + Apply read as one control instead of six loose buttons */
.bulk-pair{display:inline-flex;align-items:center;gap:var(--s1)}
.bulk-pair>select,.bulk-pair>input{border-top-right-radius:0;border-bottom-right-radius:0}
.bulk-pair>button{border-top-left-radius:0;border-bottom-left-radius:0;margin-left:-1px}
.bulk-sep{width:1px;align-self:stretch;min-height:22px;background:var(--accent-ring)}
@media (max-width:760px){
  .bulk-actions{margin-left:0;width:100%}
  .bulk-bar select,.bulk-bar input{min-width:0;flex:1 1 120px}
  .bulk-pair{flex:1 1 200px}
}

/* — activity chips (what has already been done to this lead) —
   Glyph identifies the channel/object, tone identifies the state. They live under the status
   select rather than in a ninth column: same question ("how is this doing"), and the table has
   no width left for another column. */
.lead-acts{display:flex;flex-wrap:wrap;gap:3px;margin-top:5px;max-width:112px}
.act-chip{
  --act:var(--accent);
  width:20px;height:20px;border-radius:var(--r-xs);flex-shrink:0;
  display:inline-flex;align-items:center;justify-content:center;
  color:var(--act);background:color-mix(in srgb,var(--act) 15%,transparent);
  border:1px solid color-mix(in srgb,var(--act) 30%,transparent);
}
.act-chip svg{width:12px;height:12px}
/* On touch, the ⋯ tool chip is the ONLY way into draft/call/timeline actions — a 20px target
   fails the finger. Uplift the actionable chips (not the read-only state ones) on coarse pointers. */
@media (pointer:coarse){
  .act-tool{width:28px;height:28px}
  .act-tool svg{width:15px;height:15px}
}
/* Three states, three readings, because they are three different situations:
   drafted  — written, waiting on a human. Plain white, outlined: nothing has happened yet.
   approved — cleared to go, sitting in the queue. Amber, filled: about to happen.
   sent     — the channel's own colour, filled. It happened.
   A failed attempt still overrides all of them in critical red. */
.act-chip.draft{background:var(--surface);border-style:solid;border-color:var(--line-2);color:var(--ink2);filter:none}
.act-chip.ready{--act:var(--warning)}
/* legacy alias — older payloads sent "pending" for anything not yet out */
.act-chip.wait{background:transparent;border-style:dashed;color:var(--muted);border-color:var(--line-2)}
/* never contacted this way: visible, but plainly not a thing that happened */
.act-chip.off{background:var(--surface-2);border-color:var(--line);color:var(--n400);filter:grayscale(1)}
:root[data-theme="dark"] .act-chip.off{color:var(--n600)}
.act-chip.bad{--act:var(--critical)}
/* Already dealt with — sent, approved, done. Legible, but deliberately quiet: only a draft is
   waiting on the reader, so only a draft earns the colour and the click. */
.act-chip.done-quiet{background:var(--surface-2);border-color:var(--line);color:var(--muted)}
/* A drafted message: the one chip that goes somewhere (click → the queue), but visually NEUTRAL —
   colour on this column means "outreach actually went out", and a draft hasn't (owner's rule,
   2026-08-15). Same 20×20 box as the sibling spans: the app-wide button rule's min-height:34px
   was stretching this one taller, so every button default it inherits is zeroed here. */
.act-chip.draft-live{
  min-height:0;min-width:0;box-shadow:none;transform:none;
  padding:0;margin:0;box-sizing:border-box;cursor:pointer;
  font:inherit;line-height:1;appearance:none;
  color:var(--ink2);background:var(--surface);
  border:1px solid var(--line-2);
}
.act-chip.draft-live:hover{border-color:var(--accent);color:var(--accent);background:var(--surface)}
.act-chip.draft-live:active{transform:none}
.act-chip.draft-live:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* Row tools (brief / prep / ⋯) — the second chip row under the channel chips in the Status
   column. Same 20×20 box and quiet-until-hover language as the draft chip: these are actions,
   so they never carry state colour. */
.lead-tools{margin-top:4px}
.act-chip.act-tool{
  min-height:0;min-width:0;box-shadow:none;transform:none;
  padding:0;margin:0;box-sizing:border-box;cursor:pointer;
  font:inherit;line-height:1;appearance:none;
  color:var(--ink2);background:var(--surface);
  border:1px solid var(--line-2);
}
.act-chip.act-tool:hover{border-color:var(--accent);color:var(--accent);background:var(--surface)}
.act-chip.act-tool:active{transform:none}
.act-chip.act-tool:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* The message a jump landed on — held long enough to find, then released. */
.oq-item.oq-focus{
  border-color:var(--accent);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 26%,transparent);
  animation:oqFocusIn .5s ease-out;
}
@keyframes oqFocusIn{ from{box-shadow:0 0 0 10px color-mix(in srgb,var(--accent) 0%,transparent)} }
/* Per-message jumps under a bell notification. */
.notif-acts{display:flex;flex-direction:column;gap:4px;padding:2px 34px 4px 14px}
.notif-act{
  display:flex;align-items:baseline;gap:8px;width:100%;text-align:left;
  padding:6px 9px;border-radius:var(--r-sm);border:1px solid var(--line);
  background:var(--surface-2);cursor:pointer;font-size:var(--fs-hint);
}
.notif-act:hover{border-color:var(--accent);background:var(--accent-soft)}
.notif-act .na-who{font-weight:650;color:var(--ink);white-space:nowrap}
.notif-act .na-what{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.notif-act .na-go{color:var(--accent);font-weight:650;white-space:nowrap}
.notif-act-more{padding:2px 9px;font-size:var(--fs-hint);color:var(--accent)}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .act-chip{background:color-mix(in srgb,var(--act) 24%,transparent)}
}
:root[data-theme="dark"] .act-chip{background:color-mix(in srgb,var(--act) 24%,transparent)}

/* Column budget for the composed table. Company/Contact get the room; Reach, Status and the row
   actions are pinned to their content so Notes absorbs the remaining width.
   Everything has to fit WITHOUT horizontal scrolling — a table you have to drag sideways hides
   exactly the columns you were trying to compare. Three things bought the width back without
   dropping a single feature: the four row actions became a 2x2 block instead of one long row, the
   activity chips moved onto their own line under the status select, and the two text columns lost
   their generous minimums (they wrap now, which is what the sub-lines already did). */
/* table-layout:fixed is what actually guarantees it: the columns are budgeted as a share of the
   width available, so no cell's content can push the table wider than its container. Everything
   wraps instead. */
/* calc() rather than 100%: sub-pixel column rounding was leaving the table one pixel wider than its
   wrapper, which is enough for a scrollbar to appear and for the whole point of this to be lost. */
#leadTable{table-layout:fixed;width:calc(100% - 1px);max-width:100%;box-sizing:border-box}
#leadTable td{overflow-wrap:anywhere}
#leadTable th:nth-child(1),#leadTable td:nth-child(1){width:32px}
#leadTable th:nth-child(2),#leadTable td:nth-child(2){width:23%}
#leadTable th:nth-child(3),#leadTable td:nth-child(3){width:18%}
#leadTable th:nth-child(4),#leadTable td:nth-child(4){width:120px}
#leadTable th:nth-child(5),#leadTable td:nth-child(5){width:138px}
#leadTable th:nth-child(6),#leadTable td:nth-child(6){width:auto}
#leadTable th:nth-child(7),#leadTable td:nth-child(7){width:72px}
/* 2 x 2 rather than four in a line: same four actions, a third of the width. */
.rowacts{display:grid;grid-template-columns:repeat(2,1fr);gap:2px;justify-items:center}
.rowacts .icon-btn{margin:0;min-width:28px;padding-left:2px;padding-right:2px}
#leadTable .cell-notes{max-width:none;vertical-align:middle}
/* A status is a BADGE that happens to be changeable, so it is sized to the word it is showing.
   width:100% made every row carry a full-column-wide bar of flat colour: the pill shape was lost,
   short statuses like "New" and "Won" were mostly empty space, and the eye had nothing to lock on
   to when scanning the column. Sized to content, with a ceiling so the longest option
   ("Junk / Not relevant") cannot widen the column — its full text is readable in the open list. */
#leadTable .status-select{
  /* field-sizing is the only way a native <select> sizes to the SELECTED option — width:auto sizes
     it to the longest one, so every pill came out the width of "Junk / Not relevant" regardless of
     what it said. Where it is unsupported the rule is ignored and the uniform pill remains, which
     is still far better than the full-column bar this replaced. */
  field-sizing:content;
  /* No ceiling any more: the table shows the SHORT status words now ("Not interested", not
     "Junk / Not relevant" — the full wording is swapped in as the list opens), and the longest of
     them fits in less room than the old ceiling clipped it to. Capping it here only produced
     "Not Interes…" in a column with space to spare. */
  width:auto;min-width:0;max-width:none;padding-right:24px;font-size:var(--fs-sm);
  text-overflow:ellipsis;
}
/* The cell holds the pill, the CRM sub-line and the channel chips, so it stacks them rather than
   letting the pill be stretched by whatever sits beneath it. */
#leadTable td:has(> .status-select){white-space:normal}
/* Notes edit in place. One row at rest so the table stays compact, three on focus so a real note is
   writable, and a brief green edge on save — the only feedback a silent PUT can honestly give. */
.note-inline{
  width:100%;margin:0;padding:6px 8px;font:inherit;font-size:var(--fs-sm);line-height:var(--lh-snug);
  border:1px solid transparent;border-radius:var(--r-sm);background:transparent;color:var(--ink2);
  resize:none;overflow:hidden;transition:border-color var(--t),background var(--t),box-shadow var(--t);
}
.note-inline:hover{border-color:var(--line);background:var(--surface-2)}
.note-inline:focus{
  outline:none;border-color:var(--accent);background:var(--surface);color:var(--ink);
  box-shadow:var(--ring-focus);overflow:auto;
}
.note-inline.saved{border-color:var(--good);box-shadow:0 0 0 3px color-mix(in srgb,var(--good) 20%,transparent)}
.note-inline::placeholder{color:var(--n400)}
#leadTable td{vertical-align:middle}
#leadTable .reach{width:26px;height:26px;min-height:26px}
#leadTable .reach svg{width:14px;height:14px}
/* The notes slot is the Notes column's stand-in on narrow screens only. */
.reach.note{display:none}
/* Under ~1300px the sidebar leaves too little room for eight rich columns, so Notes
   folds into an icon in the Reach cell (tooltip + click-to-copy keeps the text
   reachable) instead of the whole table scrolling sideways. */
@media (max-width:1080px){
  #leadTable th:nth-child(6),#leadTable td:nth-child(6){display:none}
  .reach.note{display:inline-flex}
  /* tighter gutters and controls buy back the remaining width without hiding anything */
  #leadTable th,#leadTable td{padding-left:8px;padding-right:8px}
  #leadTable .status-select{min-width:0;width:auto;max-width:100%;padding-right:22px}
  #leadTable .reach{width:26px;height:26px;min-height:26px}
  #leadTable .icon-btn{min-width:26px;padding-left:4px;padding-right:4px}
  #leadTable .cell-sub{font-size:var(--fs-2xs)}
}

/* — action menus (⋯) —
   List-height rows instead of full-width .wiz-choice blocks, so a ten-action menu is a
   short grouped list rather than a stack of buttons taller than the viewport. */
.menu-sub{font-size:var(--fs-sm);margin:calc(var(--s1) * -1) 0 var(--s3)}
/* Anchored variant: the same .menu-list rows in a bubble that grows out of the ⋯ button,
   matching the notification bell's "cloud". position:fixed because the button sits inside
   .table-wrap, an overflow:auto scroller that would otherwise clip it. */
.act-pop{
  position:fixed;z-index:var(--z-pop);width:min(280px,calc(100vw - 16px));
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-lg);
  box-shadow:var(--shadow-3);
  animation:notifPopIn var(--t-slow) var(--ease-spring) both;
}
/* the scroller is the inner box: on the outer one, overflow:auto would clip the pointer */
.act-pop-in{
  padding:var(--s2);max-height:min(74vh,540px);
  overflow-y:auto;overscroll-behavior:contain;border-radius:inherit;
}
/* pointer — two stacked squares so the 1px border reads as continuous, like .notif-pop */
.act-pop::before,.act-pop::after{
  content:"";position:absolute;top:-7px;left:var(--arrow);margin-left:-6px;
  width:12px;height:12px;background:var(--surface);transform:rotate(45deg);
}
.act-pop::before{border:1px solid var(--line);border-right:0;border-bottom:0}
.act-pop::after{top:-5px}
.act-pop.up::before,.act-pop.up::after{top:auto;bottom:-7px;border:1px solid var(--line);border-left:0;border-top:0}
.act-pop.up::after{bottom:-5px;border:0}
.act-pop-head{
  display:flex;flex-direction:column;gap:1px;padding:var(--s1) var(--s2) var(--s2);
  border-bottom:1px solid var(--line);margin-bottom:var(--s1);
}
.act-pop-head b{font-size:var(--fs-sm);font-weight:640;line-height:var(--lh-snug);overflow-wrap:anywhere}
.act-pop-head .muted{font-size:var(--fs-xs);overflow-wrap:anywhere}
.act-pop .menu-list{margin:0;gap:0}
.act-pop .menu-label{padding:var(--s2) var(--s2) 2px}
.act-pop .menu-row{padding:7px var(--s2)}
/* a hint wraps here rather than being cut off -- these read "already on a newsletter", and a
   clipped half-sentence is worse than two lines */
.act-pop .menu-txt{white-space:normal}
.act-pop .menu-txt .hint{white-space:normal;line-height:var(--lh-snug)}
.menu-list{display:flex;flex-direction:column;gap:1px;margin:0 calc(var(--s2) * -1)}
.menu-label{
  font-size:var(--fs-2xs);font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);padding:var(--s3) var(--s2) var(--s1);
}
.menu-list>.menu-label:first-child{padding-top:0}
.menu-row{
  display:flex;align-items:center;gap:var(--s3);width:100%;text-align:left;
  background:transparent;border:1px solid transparent;box-shadow:none;color:var(--ink);
  border-radius:var(--r-sm);padding:9px var(--s2);min-height:40px;font-weight:500;
  justify-content:flex-start;
}
.menu-row:hover:not(:disabled){background:var(--surface-3);border-color:var(--line)}
.menu-row:disabled{opacity:1;cursor:not-allowed;color:var(--muted)}
.menu-row:disabled .menu-ic{opacity:.4}
.menu-row.danger{color:var(--critical)}
.menu-row.danger:hover:not(:disabled){background:var(--critical-soft);border-color:color-mix(in srgb,var(--critical) 26%,transparent)}
.menu-ic{display:inline-flex;align-items:center;justify-content:center;width:20px;flex-shrink:0;color:var(--muted)}
.menu-ic svg{width:16px;height:16px}
.menu-row:hover:not(:disabled) .menu-ic{color:var(--accent)}
.menu-txt{display:flex;flex-direction:column;gap:1px;min-width:0}
.menu-txt>b{font-weight:560;font-size:var(--fs-base)}
.menu-txt .hint{font-size:var(--fs-xs);margin:0}

/* — Outreach queue —
   Replaces a bare grey status line and a run of inline-styled flex rows. */
.oq-status{
  display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r-md);
  padding:9px var(--s4);margin:0 0 var(--s4);font-size:var(--fs-sm);color:var(--ink2);
}
.oq-status .oq-dot{width:8px;height:8px;border-radius:50%;background:var(--muted);flex-shrink:0}
.oq-status.on{background:var(--good-soft);border-color:color-mix(in srgb,var(--good) 26%,transparent)}
.oq-status.on .oq-dot{background:var(--good);animation:pulseDot 1.8s ease-in-out infinite}
.oq-status strong{color:var(--ink)}
.oq-queued{margin-left:auto;font-size:var(--fs-xs);color:var(--muted);white-space:nowrap}
.oq-when{font-size:var(--fs-xs);white-space:nowrap;flex-shrink:0}
/* channel chip carries its icon inline with the label */
.tag.chan{display:inline-flex;align-items:center;gap:5px}
.tag.chan svg{width:12px;height:12px;flex-shrink:0}
.oq-acts{display:flex;gap:var(--s2);flex-wrap:wrap;align-items:center;margin-top:var(--s3);padding-top:var(--s3);border-top:1px solid var(--line-soft)}
/* — outreach queue items —
   Collapsed by default (drafts and failures open), so a queue of twenty reads as a list you can scan
   instead of twenty stacked editors. */
/* — the queue reads by colour before it reads by word —
   Every item carries a 3px status rail on its left edge, the same device the metric tiles use, so a
   queue of twenty answers "what is waiting on me?" by shape alone. A DRAFT takes the brand accent:
   it is the one state that is waiting on a person, and the accent is the app's own "this is yours to
   do" colour (the same one the rail, the active nav item and the primary button use). Approved is
   amber — cleared, about to leave, nothing to do. Sent is green and deliberately the quietest.
   Failed is the only one that also tints its whole summary, because it is the only one that is wrong. */
.oq-item{padding:0;overflow:hidden;position:relative;--oq:var(--line-2)}
.oq-item::before{
  content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--oq);
  border-radius:var(--r-lg) 0 0 var(--r-lg);
}
/* The draft card also borrows the accent for its border and its badge, so a draft is identifiable
   from the rail, the wash, the border and the status pill — four quiet signals rather than one loud
   one, which is what keeps a queue of twenty calm while still being instantly sortable by eye. */
.oq-draft{--oq:var(--accent);border-color:color-mix(in srgb,var(--accent) 34%,var(--line))}
.oq-draft .badge{background:var(--accent-soft);border-color:color-mix(in srgb,var(--accent) 30%,transparent);color:var(--tint-ink)}
.oq-draft .badge::before{background:var(--accent)}
.oq-approved{--oq:var(--warning)}
.oq-sent,.oq-done{--oq:var(--good)}
.oq-failed{--oq:var(--critical)}
.oq-skipped{--oq:var(--line-2);opacity:.72}
/* A DRAFT is the only row you have to do something about, so its header takes the house dark
   teal-green outright (2026-08-22) — the same band the table headers and the calendar weekday strip
   wear. It was a 7% accent wash, which grouped the drafts but did not lead the page. Everything
   inside it is recoloured for the dark ground; the status rail on the left edge and the pills keep
   their own colours, so "draft" is still readable by shape as well as by band. */
.oq-draft>.oq-sum{background:var(--brand-800);color:#fff}
.oq-draft[open]>.oq-sum{background:var(--brand-800)}
.oq-draft>.oq-sum:hover{background:var(--brand-900)}
.oq-draft>.oq-sum .oq-lead{color:#fff}
.oq-draft>.oq-sum .muted{color:rgba(255,255,255,.78)}
/* The chevron is drawn from two borders, so it needs its own line — `color` does not reach it. */
.oq-draft>.oq-sum::after{border-right-color:rgba(255,255,255,.85);border-bottom-color:rgba(255,255,255,.85)}
.oq-failed>.oq-sum{background:color-mix(in srgb,var(--critical) 5%,transparent)}
.oq-failed[open]>.oq-sum{background:color-mix(in srgb,var(--critical) 7%,var(--surface-2))}
/* the pale FAILED tint needs more presence on a dark surface to survive at all; the draft header is
   a solid brand band in both themes and needs no boost. */
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .oq-failed>.oq-sum{background:color-mix(in srgb,var(--critical) 12%,transparent)}
}
:root[data-theme="dark"] .oq-failed>.oq-sum{background:color-mix(in srgb,var(--critical) 12%,transparent)}
.oq-sum{
  display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s4) var(--s3) calc(var(--s4) + 4px);
  cursor:pointer;list-style:none;user-select:none;
}
.oq-sum::-webkit-details-marker{display:none}
.oq-sum:hover{background:var(--surface-2)}
.oq-item[open]>.oq-sum{border-bottom:1px solid var(--line);background:var(--surface-2)}
/* AFTER the generic open rule, not before it: both selectors weigh the same, so the later one wins
   and an expanded draft was dropping back to grey the moment it was opened. The header keeps the
   band open or closed; the body below stays light because it holds the editor. */
.oq-draft[open]>.oq-sum{background:var(--brand-800);color:#fff;border-bottom-color:transparent}
.oq-main{display:flex;flex-direction:column;gap:1px;min-width:0;flex:1}
.oq-line1{display:flex;align-items:baseline;gap:6px;min-width:0;flex-wrap:wrap}
/* The lead is the subject of every row in this queue, so it gets one colour everywhere — the same
   brand-tinted ink the All-leads card uses — and the same scored avatar it has on the Leads page.
   Before this the company sat in body ink among five other body-ink strings and you had to read the
   row to find out who it was about. */
.oq-line1>strong.oq-lead{font-size:var(--fs-md);font-weight:660;color:var(--tint-ink)}
.oq-sum .lead-avatar-ring{width:34px;height:34px;min-width:34px}
.oq-line1 .muted{font-size:var(--fs-sm)}
.oq-line2{font-size:var(--fs-sm);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.oq-tags{display:flex;align-items:center;gap:5px;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end}
.oq-tags .tag,.oq-tags .badge{margin:0}
.oq-body{padding:var(--s3) var(--s4) var(--s4)}
.oq-body>label{margin-bottom:var(--s3)}
.oq-body .oq-acts{margin-top:var(--s2)}
/* a chevron so it reads as expandable without adding a second control */
.oq-sum::after{
  content:"";width:7px;height:7px;flex-shrink:0;
  border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);
  transform:rotate(-45deg);transition:transform var(--t) var(--ease);
}
.oq-item[open]>.oq-sum::after{transform:rotate(45deg)}
@media (max-width:820px){
  .oq-tags{width:100%;justify-content:flex-start;order:3}
  .oq-sum{flex-wrap:wrap}
  .oq-when{order:2}
}

/* — outreach channel tabs —
   The channel used to be a filter chip and an icon on every row. It is now the page you are on:
   each channel sends as a different identity and reports a different thing back, so the row itself
   no longer has to say which one it is. */
/* scrolls rather than wrapping on a phone — three channels don't fit on 390px */
.oq-tabs{margin:0 0 var(--s4);max-width:100%;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;flex-wrap:nowrap}
.oq-tabs::-webkit-scrollbar{display:none}
.oq-tabs button{flex:0 0 auto}
.oq-tabs button{display:inline-flex;align-items:center;gap:7px}
/* A channel that cannot send cannot be opened either (2026-08-22). It still shows — the tab is how you
   learn the channel exists and why it is shut — but it reads as unavailable and does not respond. */
/* The filters currently applied, each removable on its own — "Clear filters" as the only exit meant
   dropping all four to look at one. */
/* The auto-send switch sits inline on the status bar, so it must not take the switch-row's own
   block layout and margins. */
.oq-status .oq-auto{margin:0 0 0 auto;display:inline-flex;align-items:center;gap:8px;font-size:var(--fs-sm);white-space:nowrap}
.oq-status .oq-auto+.oq-queued{margin-left:var(--s3)}
/* The filter pattern that replaced the filter bars (2026-08-22): a search box and a Filters button in
   the page header, the rest behind them. */
.head-search{width:min(260px,42vw);min-width:150px}
.fchip-n{display:inline-flex;align-items:center;justify-content:center;min-width:17px;height:17px;padding:0 5px;
  border-radius:var(--r-full);background:var(--accent);color:#fff;font-size:var(--fs-2xs);font-weight:700;margin-left:4px}
/* One row per filter: its name on the left, its control on the right, every row the same shape. A
   bare ddSingle() select carries its own name in the "Status: all" option, so it stands alone and is
   right-aligned to line up with the labelled rows beside it. */
.fdlg{display:flex;flex-direction:column;gap:var(--s2)}
.fdlg label.inline,.fdlg>label:not(.switch-row){
  /* label.inline is a COLUMN elsewhere (a caption over a control in a toolbar); in this panel every
     row is name-left / control-right, so the direction is overridden rather than a new class invented. */
  display:flex;flex-direction:row;align-items:center;justify-content:space-between;gap:var(--s3);
  margin:0;font-size:var(--fs-base);color:var(--ink2);
}
.fdlg label.inline select,.fdlg label.inline input,
.fdlg>label:not(.switch-row) select,.fdlg>label:not(.switch-row) input{
  width:58%;max-width:58%;min-width:0;flex:0 0 58%;margin-top:0;
}
.fdlg>select{width:58%;align-self:flex-end}
.fdlg .switch-row{margin:var(--s1) 0 0}
.fdlg .wiz-foot{margin-top:var(--s3);padding:var(--s3) 0 0;border-top:1px solid var(--line)}
/* NESTED HEADERS (2026-08-24, owner's ask). `.tablehead` is the outer band; the table header row and
   the calendar's weekday strip sit directly under it and are the inner one, so they take brand-700 —
   one step lighter, same hue. Scoped to the ADJACENT case on purpose: a table that is not under a
   card band is the only header there is, and stays the full-strength colour. */
.tablehead + .table-wrap th,
.tablehead + .table-wrap .data-table thead th,
.tablehead ~ .mt-grid .mt-head{background:var(--brand-700)}
/* The calendar strip is a sibling of the band rather than a child of a table-wrap. */
.mt-card .tablehead ~ .mt-grid .mt-head{background:var(--brand-700)}

/* Anything focusable on one of the dark header bands: the accent focus ring is ~1.9:1 against
   --brand-800, which is a WCAG 2.4.11 failure. White ring, white halo. */
.tablehead :focus-visible,.notif-pop-head :focus-visible,.bp-head :focus-visible{
  outline-color:#fff;box-shadow:0 0 0 4px rgba(255,255,255,.28);
}
/* The refresh and Clear controls in the notifications bubble kept their light-ground ink when that
   header went dark — ~1.3:1 and ~2.1:1 respectively, i.e. invisible and nearly so. */
.notif-pop-head .tb-icon,.notif-pop-head .notif-clear{color:#fff}
/* The bubbles' own dismiss sits at the end of the band, like the dialogs'. */
.notif-pop-head .wiz-x{margin-left:6px;align-self:center}
.notif-pop-head .notif-pop-count+.wiz-x{margin-left:auto}
.notif-pop-head .tb-icon:hover,.notif-pop-head .notif-clear:hover{background:rgba(255,255,255,.18);color:#fff}
/* Who a form is shared with, under its title. */
.lm-shared{font-size:var(--fs-xs);margin:-2px 0 6px}
.oq-chips{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin:0 0 var(--s3)}
.oq-chips .tag.mini{cursor:pointer}
.oq-tabs button[disabled]{opacity:.6;cursor:not-allowed}
.oq-tabs button[disabled]:hover{background:transparent}
.oq-tabs button svg{width:15px;height:15px}
.oq-tab-n:empty{display:none}
.oq-tab-n{
  min-width:18px;padding:0 5px;border-radius:var(--r-full);background:var(--warning-soft);
  color:var(--warning);font-size:var(--fs-xs);font-weight:660;line-height:17px;text-align:center;
}
/* A channel this user cannot send on. The tab still opens — the card inside it says what to do — so
   the pill is the only thing carrying the state. Its hover state is pinned to the same values as its
   resting one: it lives inside a button, and neither the colour nor the size may shift when that
   button is hovered or pressed. Both tones come from the theme's own critical pair, so it is legible
   light and dark without a second palette. */
.tag.mini.static.oq-off,.tag.mini.static.oq-off:hover{
  background:var(--critical-soft);color:var(--critical);
  border-color:color-mix(in srgb,var(--critical) 30%,transparent);
  font-size:var(--fs-2xs);font-weight:620;padding:1px 6px;
}
/* who this channel sends as — the addresses and accounts that used to only reveal
   themselves after something had already gone out */
.oq-senders{
  display:flex;flex-wrap:wrap;gap:var(--s3) var(--s6);align-items:flex-start;
  padding:var(--s3) var(--s4);margin-bottom:var(--s4);
}
.oq-id{display:flex;flex-direction:column;gap:1px;min-width:0}
.oq-id .muted{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.04em}
.oq-id strong{font-size:var(--fs-sm);font-weight:600;word-break:break-word}
/* Manage/Change/Edit read as links, not buttons — they navigate, they don't act. `button` is used
   for the ones that open an editor in place, so the global button styling has to be undone. */
.oq-idlink{
  font-size:var(--fs-xs);margin-left:6px;font-weight:500;display:inline-block;padding:5px 0;
  background:none;border:0;box-shadow:none;min-height:0;color:var(--accent);cursor:pointer;
  text-decoration:underline;text-decoration-color:transparent;text-underline-offset:2px;
  transition:text-decoration-color var(--t);
}
.oq-idlink:hover{background:none;text-decoration-color:currentColor;filter:none;transform:none}
.oq-senders-off{justify-content:space-between;align-items:center}
.oq-senders-off p{margin:2px 0 0;font-size:var(--fs-sm)}
/* — first-run channel setup —
   One row per channel: what it is, whether it is connected (the same .conn-chip the sender card
   uses) and the one button that connects it. */
.onb-rows{display:flex;flex-direction:column;gap:var(--s2);margin:var(--s3) 0}
.onb-row{
  display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;
  padding:var(--s3);background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r-sm);
}
.onb-chan{display:inline-flex;align-items:center;gap:var(--s2);min-width:104px}
.onb-chan svg{width:18px;height:18px;flex:0 0 auto}
.onb-state{display:inline-flex;align-items:center;gap:var(--s2);flex:1 1 12ch;min-width:0;font-size:var(--fs-sm)}
/* The chip is a fixed label, the reason beside it is the part that reflows — without this the two
   words in "Not connected" wrapped and the chip grew over the sentence next to it. */
.onb-state .conn-chip{flex:0 0 auto;white-space:nowrap}
.onb-state .muted{min-width:0;overflow-wrap:anywhere}
.onb-row button{margin-left:auto;flex:0 0 auto}
.onb .wiz-note{margin:0}
/* the "How to connect X" links under the per-lead channel picker */
.onb-inline{display:flex;flex-wrap:wrap;gap:var(--s4);margin:var(--s3) 0 0}
/* addressing block inside an open item */
.oq-addr{
  display:flex;flex-wrap:wrap;gap:var(--s2) var(--s5);
  padding:var(--s2) var(--s3);margin-bottom:var(--s3);
  background:var(--surface-2);border:1px solid var(--line-soft);border-radius:var(--r-sm);
}
.oq-addr>div{display:flex;flex-direction:column;gap:1px;min-width:0}
.oq-addr .muted{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.04em}
.oq-addr strong{font-size:var(--fs-sm);font-weight:600;word-break:break-word}
.oq-addr .err{font-size:var(--fs-xs);margin-left:6px}
.oq-sig{margin:calc(var(--s1) * -1) 0 var(--s3)}
.oq-sig .muted{font-size:var(--fs-xs)}
.oq-sig pre{
  margin:3px 0 0;padding:var(--s2) var(--s3);white-space:pre-wrap;font:inherit;
  font-size:var(--fs-sm);color:var(--ink2);background:var(--surface-2);
  border-left:2px solid var(--line);border-radius:0 var(--r-sm) var(--r-sm) 0;
}
.oq-hint{font-size:var(--fs-sm);margin:calc(var(--s1) * -1) 0 var(--s3)}
/* sent → received → read. Steps are buttons because LinkedIn invitations never report a
   receipt, and whoever saw the reply knows more than the API does. */
.oq-dlv{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;margin-bottom:var(--s3)}
.oq-dlv>.muted:first-of-type{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.04em}
.oq-dlv-steps{display:inline-flex;gap:2px;padding:2px;background:var(--surface-3);border:1px solid var(--line);border-radius:var(--r-full)}
.oq-dlv-step{
  background:transparent;border:0;box-shadow:none;color:var(--muted);
  padding:3px 12px;border-radius:var(--r-full);font-size:var(--fs-xs);font-weight:560;min-height:24px;
}
.oq-dlv-step:hover{background:color-mix(in srgb,var(--ink) 6%,transparent);color:var(--ink)}
.oq-dlv-step.on{background:var(--good-soft);color:var(--good);font-weight:660}
.oq-dlv-note{font-size:var(--fs-xs);flex:1;min-width:140px;text-transform:none;letter-spacing:0}
@media (max-width:560px){ .oq-senders{gap:var(--s3)} }

/* — lead magnets / newsletter — */
/* form-field builder rows: contained and aligned, rather than bare inputs floating in
   a flex row with inline widths */
.lm-frow{
  display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin-bottom:6px;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);padding:6px 8px;
}
.lm-frow.locked{background:var(--surface-2);border-style:dashed}
.lm-f-label{flex:2;min-width:150px}
.lm-f-type{width:auto;min-width:118px;flex:0 0 auto}
/* Choices sit on their own line: a comma list is long, and squeezing it into the control row pushed
   the remove button onto a line by itself. flex-basis:100% forces the wrap deliberately. */
.lm-f-opts{flex:0 0 100%;display:flex;align-items:center;gap:6px;margin:2px 0 0}
.lm-f-opts-l{
  font-size:var(--fs-2xs);font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);flex-shrink:0;padding-left:26px;
}
.lm-f-opts input{flex:1;min-width:0}
.lm-f-req{
  display:flex;align-items:center;gap:5px;margin:0;font-size:var(--fs-xs);
  white-space:nowrap;color:var(--ink2);flex-shrink:0;
}
.lm-f-req input{margin:0}
.lm-f-lock{font-size:var(--fs-2xs);color:var(--muted);white-space:nowrap;flex-shrink:0;padding:0 4px}
.lm-frow>.icon-act{width:28px;height:28px;min-height:28px}
.lm-frow>.icon-act svg{width:12px;height:12px}
.tw-region{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;font-size:var(--fs-sm);color:var(--ink2)}

/* =============================================================================
   18 · RESPONSIVE
   ========================================================================== */
@media (max-width:1180px){
  main{padding:var(--s5) var(--s5) var(--s8)}
}
@media (max-width:980px){
  #app{grid-template-columns:minmax(0,1fr);grid-template-areas:"topbar" "main"}
  aside{
    position:fixed;top:0;left:0;height:100vh;height:100dvh;width:272px;z-index:var(--z-side);
    transform:translateX(-100%);transition:transform var(--t-slow) var(--ease);
    box-shadow:var(--shadow-3);padding-top:var(--s3);background:var(--surface);
  }
  #app.nav-open aside{transform:translateX(0)}
  #app.rail aside{width:272px}
  #app.rail aside nav a{justify-content:flex-start;padding:7px var(--s3);margin:0 var(--s1)}
  #app.rail aside nav a>span:not(.nav-badge),#app.rail aside nav a .tag{display:inline}
  #app.rail aside nav a::after{display:none}
  #app.rail .nav-group-h{justify-content:space-between;padding:var(--s4) var(--s3) var(--s1);pointer-events:auto}
  #app.rail .nav-group-h>span{display:inline-flex}
  #app.rail .nav-group-h::after{display:none}
  #app.rail .nav-group-chev{display:block}
  .nav-toggle{
    display:inline-flex;align-items:center;justify-content:center;
    width:34px;height:34px;min-height:34px;padding:0;font-size:17px;flex-shrink:0;
    background:transparent;color:var(--ink2);border:1px solid transparent;box-shadow:none;border-radius:var(--r-sm);
  }
  .nav-toggle:hover{background:color-mix(in srgb, var(--ink) 7%, transparent);color:var(--ink)}
  .side-foot{display:none}
  #app::after{
    content:"";position:fixed;inset:0;background:var(--scrim);opacity:0;pointer-events:none;
    transition:opacity var(--t-slow);z-index:var(--z-scrim);
  }
  #app.nav-open::after{opacity:1;pointer-events:auto}
  main{padding:var(--s5) var(--s4) var(--s8)}
  .crumbs{display:none}
}
@media (max-width:720px){
  :root{--topbar-h:48px} /* still a step DOWN from the 52px desktop bar — 54 predated the compact pass */
  main{padding:var(--s4) var(--s3) var(--s7)}
  .pagehead{align-items:flex-start;gap:var(--s3)}
  .pagehead h2{font-size:var(--fs-xl)}
  .pagehead .actions{width:100%}
  .grid2{grid-template-columns:1fr}
  .tiles{grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:var(--s2)}
  .tile{padding:var(--s3) var(--s3) var(--s3) var(--s4)}
  .tile .n{font-size:var(--fs-2xl)}
  .tb-user .tb-username{display:none}
  .tb-word span{display:none}
  .pb-toc{columns:1}
  .card{padding:var(--s4);border-radius:var(--r-md)}
  dialog{padding:var(--s5);width:min(560px,96vw);border-radius:var(--r-lg)}
  dialog:not(.wizard) .wiz-foot{margin:var(--s4) calc(var(--s5) * -1) calc(var(--s5) * -1);border-radius:0 0 var(--r-lg) var(--r-lg)}
  .wiz-top,.wiz-foot{padding-left:var(--s4);padding-right:var(--s4)}
  .wiz-body,.wiz-steptitle,.wiz-head{padding-left:var(--s4);padding-right:var(--s4)}
  .wiz-note{margin:0 var(--s4)}
  #toast{left:var(--s3);right:var(--s3);bottom:var(--s3);max-width:none}
}
@media (max-width:720px){
  /* Filter dropdowns sit part-way across the bar, so a left-anchored panel runs
     off the right edge on a phone. Anchor them to the trigger's right instead. */
  .dd-panel{left:auto;right:0;max-width:calc(100vw - 32px)}
}
@media (max-width:560px){
  .formgrid,.q-row{grid-template-columns:1fr}
  .coll-grid,.conn-grid{grid-template-columns:1fr}
  .board-col{flex-basis:84vw;width:84vw}
}

/* Business Network table collapses to cards on narrow screens */
@media (max-width:760px){
  #netTable thead .filter-row{display:none}
  #netTable,#netTable tbody,#netTable tr.dt-row,#netTable tr.dt-row td{display:block;width:100%}
  #netTable thead{position:absolute;left:-9999px}
  #netTable tr.dt-row{border:1px solid var(--line);border-radius:var(--r-md);margin-bottom:var(--s2);padding:6px var(--s1);background:var(--surface)}
  #netTable tr.dt-row td{border-bottom:0;padding:6px var(--s3)}
  #netTable tr.dt-row td.cell-wrap{max-width:none}
  .net-detail{padding-left:var(--s4)}
}

/* =============================================================================
   19 · PRINT & REDUCED MOTION
   ========================================================================== */
@media print{
  .topbar,aside,.pagehead .actions,.net-quick,.filter-row,.net-exp,.card.banner button,
  .page-progress,#toast,.side-foot{display:none!important}
  #app{display:block}
  main{max-width:none;padding:0}
  .card{break-inside:avoid;border-color:#ccc;box-shadow:none}
  .dt-detail{display:none!important}
  th{position:static}
}
@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}
}


/* =============================================================================
   20 · SETTINGS — grouped rail + pane
   ========================================================================== */
.set-layout{display:grid;grid-template-columns:216px minmax(0,1fr);gap:var(--s6);align-items:start}
.set-rail{
  display:flex;flex-direction:column;gap:1px;position:sticky;top:calc(var(--topbar-h) + var(--s5));
  background:transparent;border:0;padding:0;max-height:calc(100vh - var(--topbar-h) - var(--s8));overflow-y:auto;
}
.set-rail-label{
  font-size:var(--fs-2xs);font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);padding:var(--s4) var(--s3) var(--s1);
}
.set-rail>.set-rail-label:first-child{padding-top:0}
.set-rail .set-pill{
  position:relative;flex:0 0 auto;justify-content:flex-start;text-align:left;
  border-radius:var(--r-sm);padding:8px var(--s3);font-size:var(--fs-base);min-height:34px;
  color:var(--ink2);background:transparent;box-shadow:none;font-weight:500;
}
.set-rail .set-pill:hover{background:color-mix(in srgb, var(--ink) 6%, transparent);color:var(--ink)}
.set-rail .set-pill.on{background:var(--accent-soft);color:var(--tint-ink);font-weight:640;box-shadow:none}
.set-rail .set-pill.on::before{
  content:"";position:absolute;left:calc(var(--s1) * -1);top:50%;transform:translateY(-50%);
  width:3px;height:18px;border-radius:0 3px 3px 0;background:var(--accent);
}
.set-sec-h{font-size:var(--fs-xl);font-weight:650;letter-spacing:-.02em;margin-bottom:var(--s1);display:flex;align-items:center;gap:var(--s2)}
.set-sec-ic{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:var(--r-sm);
  background:var(--accent-soft);color:var(--accent)}
.set-sec-ic svg{width:15px;height:15px}
.set-pane .set-intro{margin:0 0 var(--s5);max-width:78ch}
/* Rail furniture: a filter box, per-pill glyphs, and an amber unsaved-changes dot. */
.set-filter{
  margin:0 0 var(--s2);padding:6px 10px;font-size:var(--fs-sm);min-height:30px;
  border-radius:var(--r-sm);background:var(--surface);border:1px solid var(--line);
}
.set-pill-ic{display:inline-flex;width:15px;height:15px;margin-right:8px;color:var(--muted);flex:0 0 auto}
.set-pill-ic svg{width:15px;height:15px}
.set-rail .set-pill.on .set-pill-ic{color:var(--accent)}
.set-pill-dot{display:none;width:7px;height:7px;border-radius:50%;background:var(--warning);margin-left:auto;flex:0 0 auto}
.set-rail .set-pill.dirty .set-pill-dot{display:inline-block}
/* Switching tabs: content arrives, it doesn't teleport. Honors the global reduced-motion override. */
.set-sec:not([hidden]){animation:setSecIn var(--t) var(--ease)}
@keyframes setSecIn{from{opacity:.4;transform:translateY(4px)}to{opacity:1;transform:none}}
@media (max-width:980px){
  .set-layout{grid-template-columns:minmax(0,1fr);gap:var(--s4)}
  .set-rail{
    position:static;max-height:none;flex-direction:row;flex-wrap:nowrap;overflow-x:auto;
    gap:2px;padding:3px;background:var(--surface-3);border:1px solid var(--line);border-radius:var(--r-full);
    scrollbar-width:none;
  }
  .set-rail::-webkit-scrollbar{display:none}
  .set-rail-label{display:none}
  .set-rail .set-pill{border-radius:var(--r-full);padding:6px 14px;white-space:nowrap}
  .set-rail .set-pill.on{background:var(--surface);color:var(--ink);box-shadow:var(--shadow-1)}
  .set-rail .set-pill.on::before{display:none}
}

/* grouped integrations: a heading per purpose, hidden when its cards are filtered out */
.conn-cat{margin-bottom:var(--s6)}
.conn-cat>.section-head{margin-top:0}
.conn-cat>.section-head .muted{
  font-size:var(--fs-xs);font-weight:700;background:var(--surface-3);border-radius:var(--r-full);
  padding:1px 8px;letter-spacing:0;
}

/* =============================================================================
   21 · TARGET SIZE + FINAL ICON UNIFICATION
   ========================================================================== */
/* Every close/remove control now renders an SVG rather than a ✕ glyph, so they need
   a box instead of a font size. */
.wiz-x>svg,.bp-x>svg{width:16px;height:16px;display:block}
.notif-x>svg,.sv-x>svg{width:13px;height:13px;display:block}
.icon-btn-dots>svg{width:18px;height:18px}
.icon-btn-dots{padding-top:0;letter-spacing:0}

/* Saved-view delete was 19x18 — under a comfortable target. Now a real 24px control,
   and it no longer inherits link underline behaviour. */
.sv-x{
  display:inline-flex;align-items:center;justify-content:center;
  width:22px;height:22px;margin-left:2px;border-radius:var(--r-xs);
  color:var(--muted);text-decoration:none;flex-shrink:0;
}
.sv-x:hover{background:var(--critical-soft);color:var(--critical)}

/* <details> toggles are controls, not text: they were rendering 19–22px tall. WCAG 2.2
   target size wants 24. (The 16px checkboxes are left alone deliberately — table cell
   padding leaves ~36px between adjacent ones, which meets the spacing exception.) */
summary{min-height:26px;display:flex;align-items:center;gap:5px}
.dd summary{min-height:32px}
details.poweredby>summary{min-height:26px}
.coll-archive>summary,.notif-minor>summary{min-height:26px}
summary>svg{width:14px;height:14px;flex-shrink:0}

/* =============================================================================
   22 · LEAD MAGNETS
   ========================================================================== */
.lm-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(330px,1fr));gap:var(--s4)}
.lm-card{margin-bottom:0;display:flex;flex-direction:column;gap:var(--s2)}
/* A paused form reads as dormant before you find the switch — same idiom as .lm-frow.locked. */
.lm-card.paused{border-style:dashed;background:var(--surface-2)}
.lm-card.paused .lm-head{background:color-mix(in srgb,var(--brand-800) 88%,var(--ink))}
.badge.live{background:var(--good-soft);color:color-mix(in srgb,var(--good) 72%,var(--ink));border-color:color-mix(in srgb,var(--good) 32%,transparent)}
.badge.live::before{background:var(--good)}
.badge.paused{color:var(--muted)}
.badge.paused::before{background:var(--muted)}
/* A form's title wears the house band like every other card header (2026-08-24). Negative margins
   pull it to the card's edges — .card pads by --s5 — and the top corners follow the card's radius. */
.lm-head{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s2);min-width:0;
  background:var(--brand-800);color:#fff;padding:10px var(--s5);
  margin:calc(var(--s5) * -1) calc(var(--s5) * -1) var(--s2);
  border-radius:calc(var(--r-lg) - 1px) calc(var(--r-lg) - 1px) 0 0;
}
.lm-head h3{margin:0;font-size:var(--fs-md);font-weight:700;color:#fff;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lm-head .badge{flex-shrink:0}
/* Live and Paused have to read AGAINST the band: the light-ground pills are ~2:1 on brand-800. Live
   keeps its green as a solid dot on a white pill; paused stays quiet, in white at 70%. */
.lm-head .badge.live{background:#fff;color:color-mix(in srgb,var(--good) 78%,#0b2b1c);border-color:transparent}
.lm-head .badge.live::before{background:var(--good)}
.lm-head .badge.paused{background:rgba(255,255,255,.16);color:#fff;border-color:rgba(255,255,255,.34)}
.lm-head .badge.paused::before{background:rgba(255,255,255,.8)}
.lm-teaser{
  font-size:var(--fs-sm);color:var(--ink2);margin:0;line-height:var(--lh-snug);
  display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
/* Only shown when a form overrides the account-wide sender — a quiet note, not a badge, because
   the common case is the default and that needs no explanation. */
.lm-from-note{
  display:flex;align-items:center;gap:6px;margin:0;
  font-size:var(--fs-xs);color:var(--muted);min-width:0;
}

/* response count is the page's primary read — a number worth clicking, not a ghost button */
.lm-count{
  align-self:flex-start;background:var(--accent-soft);color:var(--tint-ink);border:1px solid transparent;
  box-shadow:none;font-size:var(--fs-sm);font-weight:520;padding:4px 11px;min-height:28px;border-radius:var(--r-full);
}
.lm-count strong{font-weight:700;font-variant-numeric:tabular-nums}
.lm-count:hover{background:var(--accent-soft-2);color:var(--tint-ink)}
.lm-count .muted{font-size:var(--fs-xs)}
.lm-link{margin:0}
.lm-link .copyrow-val{color:var(--ink2)}
.lm-foot{
  display:flex;align-items:center;justify-content:space-between;gap:var(--s2);flex-wrap:wrap;
  margin-top:auto;padding-top:var(--s3);border-top:1px solid var(--line-soft);
}
.lm-foot .switch-row{margin:0;font-size:var(--fs-sm)}
.lm-foot-r{display:flex;align-items:center;gap:var(--s2)}
.lm-warn>div{display:flex;flex-direction:column;gap:3px;min-width:0}

/* In dialog() popups the footer sits inside the scrolling .wiz-body (runWizard keeps it
   as a sibling instead). On a long form — the lead-magnet editor is ~1000px — that put
   the primary action below the fold. Pin it to the bottom of the scroll area so Save is
   always reachable without hunting for it. */
dialog.wizard .wiz-body>.wiz-foot{
  position:sticky;bottom:calc(var(--s3) * -1);z-index:2;
  margin-left:calc(var(--s5) * -1);margin-right:calc(var(--s5) * -1);
  margin-bottom:calc(var(--s3) * -1);
  border-top:1px solid var(--line);
  background:color-mix(in srgb, var(--surface-2) 94%, transparent);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
}
@media (max-width:720px){
  dialog.wizard .wiz-body>.wiz-foot{margin-left:calc(var(--s4) * -1);margin-right:calc(var(--s4) * -1)}
}

/* — Data Enrich — */
.en-card{max-width:820px}
/* The tags that say where the answer came from ride in the band, so they take the band's ink. */
.en-src{display:inline-flex;align-items:center;gap:5px;flex-wrap:wrap;justify-content:flex-end}
.tablehead .tag,.tablehead .tag.auto-full{background:rgba(255,255,255,.16);color:#fff;border-color:rgba(255,255,255,.3)}
/* "Who" / "Where" inside a banded card are the INNER headers here — tinted, not another dark slab. */
.en-card .wiz-group-h{
  background:var(--accent-soft);color:var(--tint-ink);
  padding:5px var(--s3);border-radius:var(--r-xs);margin-bottom:var(--s3);
}
.en-card .wiz-group:last-of-type{margin-bottom:0}


/* inline "open in a new tab" links: the icon rides with the text */
.ext-link{display:inline-flex;align-items:center;gap:4px;white-space:nowrap}
.ext-link svg{width:11px;height:11px;flex-shrink:0;opacity:.8}

/* — Events table column budget —
   Category and Location fold into the Event and When cells, so six columns carry what
   eight did and the table stops scrolling sideways. */
.ev-name{min-width:220px;max-width:340px}
.ev-name>strong{display:block}
.ev-meta{display:flex;align-items:center;gap:5px;flex-wrap:wrap;margin-top:4px}
.ev-meta .tag{margin:0}
.ev-when{min-width:150px;white-space:nowrap}
.ev-when>div+div{white-space:normal;font-size:var(--fs-xs);margin-top:2px}
.ev-acts{width:1%}
.ev-acts .icon-btn{min-width:30px}
/* Interested star — quiet until active (same rule as .act-chip.draft-live: colored only when on). */
.ev-int.on{color:var(--accent);border-color:var(--accent)}
.ev-int.on svg{fill:currentColor}
/* Under ~1300px the sidebar leaves too little room; tighten gutters and floors rather
   than let the table scroll sideways. */
@media (max-width:1300px){
  .ev-name{min-width:180px;max-width:260px}
  .ev-when{min-width:120px}
  #evtTable th,#evtTable td,.data-table th,.data-table td{padding-left:8px;padding-right:8px}
  .ev-acts .icon-btn{min-width:26px;padding-left:4px;padding-right:4px}
  .cell-desc{-webkit-line-clamp:1;line-clamp:1}
  .ev-name{min-width:160px;max-width:230px}
  .ev-meta{gap:4px}
  .ev-meta .tag.mini{font-size:var(--fs-2xs);padding:1px 6px}
  .ev-when{min-width:106px;font-size:var(--fs-sm)}
}

/* — board columns tinted by stage —
   The tint comes from --stage, set per column from the same STATUS_DOT palette the status
   pills and badges use, so a colour carries one meaning app-wide. Applied to the column's
   top rule and its title only: enough to tell the columns apart while scanning across,
   without colouring the cards and drowning the status badges sitting on them. */
.board-col{--stage:var(--seq-3);border-top:3px solid var(--stage)}
.board-col-head{background:color-mix(in srgb, var(--stage) 9%, var(--surface-2))}
.board-col-title>span:first-child{color:color-mix(in srgb, var(--stage) 72%, var(--ink))}
.board-col-count{
  background:color-mix(in srgb, var(--stage) 16%, var(--surface));
  border-color:color-mix(in srgb, var(--stage) 30%, transparent);
  color:color-mix(in srgb, var(--stage) 74%, var(--ink));
}
.board-col.drag-over{border-color:var(--stage);box-shadow:0 0 0 2px color-mix(in srgb, var(--stage) 26%, transparent) inset}

/* =============================================================================
   23 · LEAD-MAGNET FORM BUILDER
   ========================================================================== */
/* flex, not grid: as a grid this picked up extra implicit tracks and dropped the canvas
   into the 186px column. Flex sizes the two panes explicitly and can't do that. */
.fb{display:flex;gap:var(--s3);align-items:flex-start}
.fb>.fb-pal{flex:0 0 186px;width:186px}
.fb>.fb-canvas{flex:1 1 auto;min-width:0}
.fb-pal{
  display:flex;flex-direction:column;gap:4px;padding:var(--s2);
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r-md);
  position:sticky;top:0;
  /* The global aside{} sidebar rule hands every <aside> z-index:var(--z-side) (45), which put this
     palette ABOVE the dialog's sticky footer (z-index:2) — covering the Cancel button mid-scroll
     and stealing its clicks. Pin it under the footer. */
  z-index:1;
}
.fb-pal-h{
  font-size:var(--fs-2xs);font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);padding:2px 4px var(--s1);
}
.fb-pal-item{
  display:flex;align-items:center;gap:var(--s2);justify-content:flex-start;width:100%;
  background:var(--surface);border:1px solid var(--line);box-shadow:none;color:var(--ink2);
  border-radius:var(--r-sm);padding:6px 9px;min-height:32px;font-size:var(--fs-sm);font-weight:500;
  cursor:grab;
}
.fb-pal-item:hover{background:var(--accent-soft);border-color:var(--accent);color:var(--tint-ink)}
.fb-pal-item:active{cursor:grabbing}
.fb-pal-ic{display:inline-flex;color:var(--muted);flex-shrink:0}
.fb-pal-ic svg{width:14px;height:14px}
.fb-pal-item:hover .fb-pal-ic{color:var(--accent)}
.fb-pal-note{font-size:var(--fs-2xs);color:var(--muted);margin:var(--s2) 4px 0;line-height:var(--lh-snug)}
.fb-canvas{
  display:flex;flex-direction:column;gap:6px;min-height:150px;
  border:1px dashed var(--line-2);border-radius:var(--r-md);padding:var(--s2);
  background:var(--surface-2);
}
.fb-grip{display:inline-flex;width:14px;color:var(--n400);cursor:grab;flex-shrink:0}
.fb-grip svg{width:14px;height:14px}
.lm-frow.locked .fb-grip{cursor:default}
.fb-tic{display:inline-flex;color:var(--muted);flex-shrink:0}
.fb-tic svg{width:14px;height:14px}
.lm-frow[draggable="true"]{cursor:grab}
.lm-frow.dragging{opacity:.4}
.lm-frow.drop-at{border-color:var(--accent);box-shadow:0 -2px 0 0 var(--accent)}
.lm-f-req.switch-row{margin:0;gap:6px}
.lm-f-req .switch{width:34px;height:20px}
.lm-f-req .switch span::before{width:14px;height:14px}
.lm-f-req .switch input:checked+span::before{transform:translateX(14px)}
.fb-resp{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);flex-wrap:wrap}
.fb-resp strong{font-size:var(--fs-lg);font-variant-numeric:tabular-nums}
@media (max-width:720px){
  /* .fb is a FLEX row — the grid-template-columns that used to be here did nothing at all, so the
     186px palette stayed pinned beside a canvas squeezed to nothing. Stack them instead. */
  .fb{flex-direction:column}
  .fb>.fb-pal{flex:0 0 auto;width:100%}
  .fb-pal{position:static;flex-direction:row;flex-wrap:wrap}
  .fb-pal-h,.fb-pal-note{width:100%}
  .fb-pal-item{width:auto}
}

/* Connected Microsoft mailboxes in the integration wizard. One row per mailbox, its last sync
   state beside it, so a mailbox that has quietly stopped syncing is visible without opening it. */
.ms-list{display:flex;flex-direction:column;gap:2px;margin:var(--s3) 0}
.ms-row{
  display:flex;align-items:center;gap:var(--s3);padding:var(--s2) var(--s3);
  border:1px solid var(--line);border-radius:var(--r-sm);background:var(--surface-2);
}
.ms-mail{display:flex;align-items:center;gap:6px;min-width:0;flex:1;font-size:var(--fs-sm);font-weight:560}
.ms-mail svg{width:14px;height:14px;flex-shrink:0;color:var(--muted)}
.ms-mail{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ms-when{font-size:var(--fs-xs);flex-shrink:0}
/* Whose calendar it is, shown only when it is not yours — an admin looking at everyone's. */
.ms-owner{font-size:var(--fs-2xs);flex-shrink:0;background:var(--surface-3);border-radius:var(--r-full);padding:1px 8px}
.ms-acts{display:flex;gap:var(--s2);margin-top:var(--s3);flex-wrap:wrap}
@media (max-width:560px){
  .ms-row{flex-wrap:wrap}
  .ms-mail{flex:1 1 100%}
}

/* Per-collection breakdown inside the All-leads card */
/* Sits inside the card like every other block: full width of the content box, with long
   names ellipsised so a row can never widen the card past its padding. Same hairline and
   label rhythm as .kvrow. */
.coll-breakdown{
  display:flex;flex-direction:column;gap:1px;width:100%;min-width:0;
  margin-top:auto;padding-top:var(--s2);border-top:1px solid var(--line);
  font-size:var(--fs-xs);
}
.coll-breakdown>div{
  display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:var(--s2);align-items:baseline;
  color:var(--ink2);padding:2px 0;
}
.coll-breakdown>div+div{border-top:1px solid var(--line-soft)}
.coll-breakdown span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.coll-breakdown b{font-variant-numeric:tabular-nums;color:var(--ink);font-weight:620}
.coll-breakdown .uncoll{color:var(--muted)}
.coll-breakdown .uncoll b{color:var(--muted)}

/* Industry chip — categorical, not status. Fixed saturation/lightness keeps these visibly
   a different family from the green/amber/red status palette, so the two don't get confused. */
.ind-chip{
  display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  padding:1px 8px;border-radius:var(--r-full);font-size:var(--fs-2xs);font-weight:620;
  background:hsl(var(--ind) 62% 93%);color:hsl(var(--ind) 55% 30%);
  border:1px solid hsl(var(--ind) 55% 84%);
}
:root[data-theme="dark"] .ind-chip{background:hsl(var(--ind) 40% 18%);color:hsl(var(--ind) 65% 78%);border-color:hsl(var(--ind) 35% 30%)}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]) .ind-chip{background:hsl(var(--ind) 40% 18%);color:hsl(var(--ind) 65% 78%);border-color:hsl(var(--ind) 35% 30%)}
}

/* Newsletter: the add-unsubscriber field needs a usable width without an inline style */
/* Add-leads picker (newsletter editor): a scrollable tick-list that reads like the audience table */
.nl-picklist{max-height:320px;overflow-y:auto;border:1px solid var(--line);border-radius:var(--r-sm);padding:4px}
.nl-pick{display:flex;align-items:center;gap:10px;padding:7px 10px;border-radius:var(--r-xs);cursor:pointer;border:0;margin:0}
.nl-pick:hover{background:var(--surface-2)}
.nl-pick input{flex:0 0 auto}
.nl-pick-who{display:flex;flex-direction:column;min-width:0}
.nl-pick-who .muted{font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.nl-unsub-input{min-width:240px;flex:0 1 320px}

/* — dashboard insight card —
   Reads as sentences, not tiles: each line is a fact plus what to do about it, linked to the list
   it names. The channel strip underneath answers "which one is landing" in one glance. */
.ins-card .ins-list{list-style:none;margin:0 0 var(--s3);padding:0;display:flex;flex-direction:column;gap:2px}
.ins-list li{display:flex;align-items:center;gap:9px;padding:var(--s2) 0;border-bottom:1px solid var(--line-soft);font-size:var(--fs-base)}
.ins-list li:last-child{border-bottom:0}
.ins-list a{color:var(--ink);text-decoration:none;display:block;flex:1;min-height:24px;line-height:1.55}
.ins-list a:hover{color:var(--accent)}
.ins-list li::before{content:"";flex:0 0 auto;width:6px;height:6px;border-radius:50%;background:var(--muted)}
.ins-list li.ins-warning::before{background:var(--warning)}
.ins-list li.ins-good::before{background:var(--good)}
.ins-chans{display:flex;flex-wrap:wrap;gap:var(--s2)}
.ins-chan{
  flex:1 1 160px;display:flex;flex-direction:column;gap:1px;
  padding:var(--s2) var(--s3);background:var(--surface-2);
  border:1px solid var(--line-soft);border-radius:var(--r-sm);
}
.ins-chan-h{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.04em;color:var(--ink2)}
.ins-chan-n{font-size:var(--fs-lg);font-weight:660;line-height:1.15}
.ins-chan-n .muted{font-size:var(--fs-sm);font-weight:400}
.ins-chan .muted{font-size:var(--fs-xs)}

/* — lead-magnet responses table —
   Every form asks for something different, so the columns after Reach are whatever that form
   defined. Free-text answers are clamped to one line (full text in the title) rather than letting
   one long paragraph set the height of every row. */
.lm-resp .lm-reach{white-space:nowrap}
.lm-resp .lm-reach a{
  display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;
  border-radius:var(--r-sm);color:var(--ink2);background:var(--surface-2);border:1px solid var(--line-soft);
}
.lm-resp .lm-reach a:hover{color:var(--accent);border-color:var(--accent)}
.lm-resp .lm-reach svg{width:14px;height:14px}
.lm-resp .lm-reach .cell-sub{max-width:190px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.lm-ans{display:inline-block;max-width:230px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}
/* a response already in the pipeline has no checkbox — this says why, in its place */
.lm-inpipe{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;color:var(--good)}
.lm-inpipe svg{width:14px;height:14px}

/* — email signature composer —
   contentEditable with a toolbar, so a signature pasted out of Outlook keeps its own markup and can
   then be edited here. The editor is styled like an email body, not like a form field: what you see
   is what lands in the inbox. */
.sig-wrap{border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden;background:var(--surface)}
.sig-tools{
  display:flex;flex-wrap:wrap;align-items:center;gap:3px;padding:6px;
  background:var(--surface-2);border-bottom:1px solid var(--line);
}
.sig-b{
  min-width:30px;height:28px;padding:0 7px;background:transparent;border:0;box-shadow:none;
  color:var(--ink2);font-size:var(--fs-base);line-height:1;border-radius:var(--r-sm);
}
.sig-b:hover{background:color-mix(in srgb,var(--ink) 8%,transparent);color:var(--ink)}
.sig-sel{width:auto;min-width:74px;height:28px;padding:0 22px 0 8px;font-size:var(--fs-sm);margin:0}
.sig-sep{width:1px;height:18px;background:var(--line);margin:0 4px}
.sig-colour{position:relative;display:inline-flex;align-items:center;justify-content:center;width:30px;height:28px;border-radius:var(--r-sm);cursor:pointer;color:var(--ink2);margin:0}
.sig-colour:hover{background:color-mix(in srgb,var(--ink) 8%,transparent)}
.sig-colour svg{width:15px;height:15px;pointer-events:none}
.sig-colour input{position:absolute;inset:0;opacity:0;width:100%;height:100%;padding:0;margin:0;border:0;cursor:pointer}
.sig-edit{
  min-height:160px;max-height:420px;overflow-y:auto;padding:var(--s4);
  line-height:1.55;color:var(--ink);background:var(--surface);
}
.sig-edit:focus{outline:none;box-shadow:inset 0 0 0 2px color-mix(in srgb,var(--accent) 28%,transparent)}
.sig-edit:empty::before{content:attr(data-placeholder);color:var(--muted)}
.sig-edit img{max-width:100%;height:auto}
.sig-edit table{border-collapse:collapse}
.sig-edit a{color:var(--accent)}
.sig-foot{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;padding:var(--s3) var(--s4);border-top:1px solid var(--line);background:var(--surface-2)}
.sig-foot .muted{font-size:var(--fs-xs);flex:1;min-width:180px}
/* the signature preview in the queue renders the real thing, so it needs email-body styling
   rather than the app's own */
.oq-sig-html{
  margin-top:3px;padding:var(--s2) var(--s3);background:var(--surface-2);
  border-left:2px solid var(--line);border-radius:0 var(--r-sm) var(--r-sm) 0;
  font-size:var(--fs-sm);line-height:1.5;color:var(--ink2);overflow-x:auto;
}
.oq-sig-html img{max-width:100%;height:auto}
.oq-sig-html table{border-collapse:collapse}

/* — connection status chips (Outreach sender cards) —
   Two meanings only, same as everywhere: ok / needs attention. "Unchecked" is deliberately its own
   amber state rather than a green guess — claiming a domain is verified when the provider never
   answered is worse than saying nothing. */
.conn-chip{
  display:inline-flex;align-items:center;gap:5px;padding:2px 8px;border-radius:var(--r-full);
  font-size:var(--fs-xs);font-weight:560;border:1px solid var(--line);color:var(--ink2);background:var(--surface-2);
}
.conn-chip .conn-dot{width:6px;height:6px;border-radius:50%;background:var(--muted)}
.conn-chip.ok{background:var(--good-soft);border-color:color-mix(in srgb,var(--good) 30%,transparent);color:var(--good)}
.conn-chip.ok .conn-dot{background:var(--good)}
.conn-chip.wait{background:var(--warning-soft);border-color:color-mix(in srgb,var(--warning) 30%,transparent);color:var(--warning)}
.conn-chip.wait .conn-dot{background:var(--warning)}
.conn-chip.bad{background:var(--critical-soft);border-color:color-mix(in srgb,var(--critical) 30%,transparent);color:var(--critical)}
.conn-chip.bad .conn-dot{background:var(--critical)}
.oq-idmeta{display:flex;align-items:center;gap:7px;flex-wrap:wrap;margin-top:3px}
.oq-idmeta .muted{font-size:var(--fs-xs);text-transform:none;letter-spacing:0}
.oq-idlink.warn{color:var(--warning);font-weight:600}
.oq-senders{gap:var(--s4) var(--s6)}
.oq-dates{display:inline-flex;align-items:center;gap:6px}
.oq-dates input{width:auto}
/* the channel tabs carry the providers' own marks, which are full colour */
.oq-tabs button svg{width:16px;height:16px;border-radius:3px}

/* — settings: per-tab save bar —
   A settings tab can hold several cards, each with its own Save. It was easy to change three things
   and walk away having saved one. This appears the moment anything in the tab is edited and saves
   the whole tab; the per-card buttons still work for anyone who prefers them. */
.set-savebar{
  position:sticky;bottom:0;z-index:5;display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;
  margin-top:var(--s4);padding:var(--s3) var(--s4);
  background:var(--surface);border:1px solid color-mix(in srgb,var(--warning) 40%,var(--line));
  border-radius:var(--r-md);box-shadow:var(--shadow-2);
}
.set-savebar .set-dirty{flex:1;min-width:150px;font-size:var(--fs-sm);font-weight:560;color:var(--warning)}
.set-savebar .set-dirty::before{content:"";display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--warning);margin-right:8px;vertical-align:middle}

/* — settings groups —
   Every tab is a short stack of titled groups: what the group is for on one line, its fields, and
   its own Save in a footer. Consistent shape everywhere means the Save button is always in the same
   place, rather than sometimes under a field and sometimes after a paragraph. */
.set-group{display:flex;flex-direction:column;gap:var(--s3)}
.set-group-h{display:flex;flex-direction:column;gap:3px}
.set-group-h h3{margin:0}
.set-group-h .muted{margin:0;font-size:var(--fs-sm);line-height:var(--lh-snug);max-width:78ch}
.set-group>label,.set-group>.formgrid,.set-group>textarea,.set-group>p{margin:0}
.set-group-f{
  display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;
  padding-top:var(--s3);border-top:1px solid var(--line-soft);
}
.set-group-f .muted{font-size:var(--fs-xs)}
.set-group-note{margin-left:auto;text-align:right}
/* ICP's groups sit in the two-column grid; the wide ones span it */
#icpForm .set-group:nth-child(n+3){grid-column:1/-1}

/* — the Dashboard's global date filter —
   It sits in the page head because it governs the whole page: every number below it answers for
   that window, which is the thing the old two-hardcoded-sections layout could never say. */
.date-filter{margin:0}
.date-filter select{min-width:150px}
.pagehead .actions .oq-dates{margin-left:var(--s2)}

/* — newsletter editor —
   Blocks are repeatable items inside one card, not nested cards: a card inside a card doubled every
   border, shadow and radius for no gain. The grip arms the drag, the same rule the form builder
   uses, so a drag can never start from inside a field you were selecting text in. */
.nl-block{
  border:1px solid var(--line);border-radius:var(--r-md);padding:var(--s3);
  background:var(--surface);margin-bottom:var(--s2);
}
.nl-block:hover{border-color:var(--line-2)}
.nl-block[draggable="true"]{cursor:grabbing}
.nl-bhead{display:flex;align-items:center;gap:var(--s2);margin-bottom:var(--s2);flex-wrap:wrap}
.nl-bhead>strong{font-size:var(--fs-xs);text-transform:uppercase;letter-spacing:.06em;color:var(--ink2)}
.nl-bhead>.muted{font-size:var(--fs-xs);flex:1;min-width:120px}
.nl-grip{display:inline-flex;width:18px;height:18px;color:var(--muted);cursor:grab;flex-shrink:0}
.nl-grip svg{width:100%;height:100%}
.nl-bacts{display:inline-flex;gap:2px;flex-shrink:0}
.nl-add{display:flex;flex-wrap:wrap;gap:var(--s2);margin-top:var(--s3);padding-top:var(--s3);border-top:1px solid var(--line-soft)}
/* a banner that carries a consequence, not just information */
.card.banner.warn{border-color:color-mix(in srgb,var(--warning) 45%,var(--line));background:var(--warning-soft)}
.card.banner.warn p{margin:0}
.banner-acts{display:flex;gap:var(--s2);flex-wrap:wrap;margin-top:var(--s3)}

/* — collection signal controls —
   Watching arms a collection; the spark button is what actually spends a Clay credit, so it only
   exists on cards that are armed. Yellow, like the signal badge it produces. */
.icon-act.sig{color:#b8860b}
.icon-act.sig:hover{background:color-mix(in srgb,#f5a524 16%,transparent);color:#8a6100;border-color:color-mix(in srgb,#f5a524 45%,transparent)}
.icon-act.sig svg{width:15px;height:15px}
.coll-sigline{
  display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap;
  font-size:var(--fs-xs);margin:0 0 var(--s3);
}
.coll-sigline .small{margin:0}
/* the inline "connect this" link is a control, not prose — give it a real target size */
.coll-sigline a{display:inline-block;padding:4px 0}
/* a gated control still reads, it just can't be pressed — and its tooltip says what would change that */
button[aria-disabled="true"],.icon-act[disabled]{cursor:not-allowed}
/* the signature editor's own table affordances — contentEditable gives you none */
.sig-edit td,.sig-edit th{border:1px dashed transparent;min-width:24px}
.sig-edit:focus td,.sig-edit:focus th{border-color:color-mix(in srgb,var(--accent) 22%,transparent)}

/* — one table component, everywhere —
   The Leads table is the reference: a header that reads as a label rather than a heading, rows that
   respond to the pointer, muted sub-lines under the primary value, ages that never wrap, and an
   empty state that says what to do rather than "no data". These rules give every other table on the
   platform the same behaviour without each page re-styling its own. */
.data-table thead th{
  font-size:var(--fs-2xs);font-weight:700;letter-spacing:.07em;text-transform:uppercase;
  color:#fff;white-space:nowrap;
}
.data-table tbody tr:hover{background:var(--surface-2)}
.data-table .cell-sub{font-size:var(--fs-xs);color:var(--muted);margin-top:2px}
.data-table .cell-age{white-space:nowrap;font-size:var(--fs-xs)}
.data-table td.nowrap,.data-table th.nowrap{white-space:nowrap}
.data-table .empty-cell{padding:var(--s6) var(--s4)}
.data-table .rowacts{justify-items:end}
/* Settings' own tables were the last three with no shared class at all. */
.set-table th.set-perm-h{text-align:center;font-size:var(--fs-2xs);min-width:64px;white-space:normal;line-height:1.2}
.set-table td{vertical-align:middle}
/* the activity log keeps its denser type, everything else it now shares */
.activity-table{font-size:var(--fs-sm)}

/* — rich message body (Outreach queue) —
   Calibri 11pt, because that is what actually leaves the building: the body and the signature are
   one letter, so the editor writes in the same face and size the recipient will read. */
.rte{
  font-family:Calibri,"Segoe UI",Helvetica,Arial,sans-serif;font-size:14.7px;line-height:1.5;
  color:var(--ink);background:var(--surface);
}
.oq-body-rte{
  min-height:120px;max-height:340px;overflow-y:auto;padding:var(--s3);
  border:1px solid var(--line);border-top:0;border-radius:0 0 var(--r-sm) var(--r-sm);
}
.oq-body-rte:focus{outline:none;box-shadow:inset 0 0 0 2px color-mix(in srgb,var(--accent) 26%,transparent)}
.rte-tools{border:1px solid var(--line);border-radius:var(--r-sm) var(--r-sm) 0 0;margin-top:6px}
.oq-body-rte a{color:var(--accent)}
/* the signature composer writes in the same face for the same reason */
.sig-edit{font-family:Calibri,"Segoe UI",Helvetica,Arial,sans-serif;font-size:14.7px}
/* ideas are suggestions, not alarms: same rows, folded away, and never counted in the bell */
.notif-ideas>summary{color:var(--accent)}
.notif-ideas .notif-item{border-left:2px solid color-mix(in srgb,var(--accent) 35%,transparent)}

/* — loading status —
   The chrome never goes away and the content underneath stays put; this strip says what is being
   fetched right now, and the main area dims rather than blanking. A page that blanks to grey bars
   on every navigation feels like a reload even when it isn't one. */
.page-progress{
  position:sticky;top:0;z-index:calc(var(--z-pop) - 1);
  display:flex;align-items:center;gap:var(--s2);
  padding:5px var(--s5);background:var(--surface);border-bottom:1px solid var(--line);
  font-size:var(--fs-xs);color:var(--ink2);
}
.pp-bar{
  position:relative;flex:0 0 74px;height:3px;border-radius:2px;overflow:hidden;
  background:color-mix(in srgb,var(--accent) 18%,transparent);
}
.pp-bar::after{
  content:"";position:absolute;inset:0 auto 0 0;width:40%;border-radius:2px;background:var(--accent);
  animation:ppSlide 1.05s var(--ease) infinite;
}
@keyframes ppSlide{0%{left:-40%}100%{left:100%}}
.pp-text{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#main.is-loading{opacity:.55;transition:opacity var(--t)}
#main{transition:opacity var(--t)}
@media (prefers-reduced-motion:reduce){ .pp-bar::after{animation:none;width:100%} }

/* — a metric broken down inside its own tile —
   Three compartments, each divided by a rule in that channel's brand colour. The point is to read
   three numbers at a glance rather than parse a sentence; the colours match the Outreach tabs, so
   the same colour means the same channel wherever you are. */
.tile-parts{display:flex;margin-top:var(--s3);padding-top:var(--s2);border-top:1px solid var(--line-soft)}
.tile-part{
  flex:1;min-width:0;display:flex;flex-direction:column;gap:1px;
  padding-left:9px;border-left:2px solid var(--part);
}
.tile-part:first-child{padding-left:8px}
.tile-part b{font-size:var(--fs-md);font-weight:680;line-height:1.1;font-variant-numeric:tabular-nums;color:var(--ink)}
.tile-part i{
  font-style:normal;font-size:var(--fs-2xs);font-weight:640;letter-spacing:.04em;text-transform:uppercase;
  color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.tile-part-ic{display:inline-flex;width:13px;height:13px;border-radius:3px;overflow:hidden;margin-top:2px}
.tile-part-ic svg{width:100%;height:100%;display:block}
.tile .tile-parts{padding-right:44px}
@media (max-width:520px){ .tile .tile-parts{padding-right:0} }
/* visually hidden, still announced — the compartment shows a brand mark, screen readers get the word */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}


/* =============================================================================
   Lead form — phone control, source editor
   ========================================================================== */
/* Country code + number as one field. The code is select-only on purpose: a dial code that can be
   typed is a dial code that gets typed wrong ("00971", "+9715"), and every downstream match on the
   number then fails silently. */
/* Wraps rather than squeezes. The country select needs room to show a country NAME — that is what
   makes the list usable — so on a narrow form it takes its own line instead of both controls
   shrinking until neither can be read. */
.phone-field{display:flex;flex-wrap:nowrap;gap:6px;align-items:center;min-width:0}
.phone-field .phone-num{flex:1 1 120px;min-width:0;font-variant-numeric:tabular-nums}

.login-help{margin:10px 0 0;text-align:center}
.login-help .linkish{font-size:var(--fs-sm)}

/* ---------- ICP editor ----------
   Chip lists in place of newline-separated textareas: countable at a glance, removable one at a
   time, and de-duplicated as you go. */
.icp-lists{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:var(--s4)}
.chip-label{display:block;font-size:var(--fs-sm);font-weight:600;margin-bottom:6px;color:var(--ink2)}
.chipset{display:flex;flex-direction:column;gap:6px;min-width:0}
.chip-list{
  display:flex;flex-wrap:wrap;gap:5px;align-content:flex-start;
  min-height:64px;max-height:180px;overflow-y:auto;
  padding:7px;border:1px solid var(--line-2);border-radius:var(--r-sm);background:var(--surface);
}
.chip{
  display:inline-flex;align-items:center;gap:4px;max-width:100%;
  padding:3px 4px 3px 9px;border-radius:var(--r-full);
  background:var(--accent-soft);color:var(--tint-ink);
  font-size:var(--fs-xs);font-weight:560;line-height:1.5;
}
.chip>button{
  display:inline-flex;align-items:center;justify-content:center;
  width:16px;height:16px;min-height:0;padding:0;flex-shrink:0;
  border:0;border-radius:50%;background:transparent;color:inherit;opacity:.65;box-shadow:none;
}
.chip>button:hover{opacity:1;background:color-mix(in srgb,var(--accent) 24%,transparent)}
.chip>button svg{width:11px;height:11px}
.chip-add{display:flex;gap:6px}
.chip-add input{flex:1;min-width:0}
/* The count is the whole point of chips over a textarea — and an empty list is a real warning,
   because scoring silently uses nothing. */
.chip-count{font-size:var(--fs-2xs);margin:0}
.chip-count.empty{color:var(--warning)}
.icp-gap{border-color:color-mix(in srgb,var(--warning) 40%,transparent)}

/* What each part of the score is worth, so the threshold below is a decision rather than a guess. */
.fit-scale{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px}
.fit-scale span{
  font-size:var(--fs-2xs);color:var(--muted);background:var(--surface-2);
  border:1px solid var(--line);border-radius:var(--r-full);padding:2px 9px;
}
.fit-scale b{color:var(--ink2)}
.fit-row{display:flex;align-items:center;gap:var(--s3)}
.fit-row input[type=range]{flex:1;min-width:0}
.fit-val{
  flex:0 0 auto;min-width:44px;text-align:center;font-variant-numeric:tabular-nums;font-weight:700;
  background:var(--accent-soft);color:var(--tint-ink);border-radius:var(--r-full);padding:3px 10px;
}
#fitNote{margin-top:8px}
#fitNote.warn{color:var(--warning)}

/* Services as two real fields per row, not a pipe-delimited line. */
.svc-rows{display:flex;flex-direction:column;gap:6px}
.svc-row{display:grid;grid-template-columns:minmax(120px,1fr) minmax(160px,2fr) auto;gap:6px;align-items:center}
@media (max-width:560px){ .svc-row{grid-template-columns:1fr auto} .svc-row .svc-desc{grid-column:1/-1} }

/* Activity log: the person on top, the login they signed in with underneath. The login stays
   because it is what the audit row actually records and what older rows are keyed on. */
.act-who{display:block;font-weight:560}
.act-login{display:block;font-size:var(--fs-2xs);line-height:1.4}

/* Country picker. A button showing flag + dial code, opening a searchable list — see phoneField()
   in app.js for why this cannot be a native <select>. Same control the public lead-magnet form
   uses, so the interaction is identical wherever a phone number is typed. */
.dialpick{position:relative;flex:0 0 auto}
.dialbtn{
  display:inline-flex;align-items:center;gap:6px;cursor:pointer;
  /* Same box model as the input beside it — padding, border and LINE-HEIGHT — so the two halves
     are the same height. Matching only the padding left the button 2px short, because its content
     is a flag glyph rather than a line of text. */
  min-height:34px;padding:7px 9px 7px 10px;line-height:1.5;
  background:var(--surface);color:var(--ink);
  border:1px solid var(--line-2);border-radius:var(--r-sm);
  font:inherit;font-variant-numeric:tabular-nums;white-space:nowrap;
}
/* `button:hover` is (0,1,1) and beats a bare `.dialbtn`, so without restating the background here
   the control turned solid accent the moment the pointer touched it — it has to keep looking like
   the input it sits beside, not like a submit button. */
.dialbtn:hover{background:var(--surface-2);border-color:color-mix(in srgb, var(--ink) 24%, var(--line-2))}
.dialbtn:focus-visible{outline:none;border-color:var(--accent);box-shadow:var(--ring-focus)}
/* Same reason: the shared button rules nudge on press and cast a shadow. This is a field, not a
   button that submits something. */
.dialbtn,.dialbtn:hover,.dialbtn:active{box-shadow:none}
.dialbtn:active{transform:none}
.dialflag{font-size:17px;line-height:1}
.dialnum{font-weight:560}
/* The chevron, drawn rather than shipped as an icon — it is 6px of geometry. */
.dialcar{
  width:0;height:0;margin-left:1px;
  border-left:4px solid transparent;border-right:4px solid transparent;
  border-top:5px solid var(--muted);
}
.dialbtn[aria-expanded="true"] .dialcar{transform:rotate(180deg)}

.dialpop{
  position:absolute;top:calc(100% + 5px);left:0;z-index:var(--z-pop);
  width:clamp(240px,78vw,320px);
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);
  box-shadow:var(--shadow-3);padding:var(--s2);
}
.diallist{list-style:none;margin:0;padding:0;max-height:280px;overflow-y:auto;outline:none}
.diallist li{
  display:flex;align-items:center;gap:8px;padding:6px 8px;border-radius:var(--r-xs);
  cursor:pointer;font-size:var(--fs-sm);
}
.diallist li:hover,.diallist li.active{background:var(--accent-soft);color:var(--tint-ink)}
.diallist li.on{font-weight:650}
/* The list holds focus (it is the thing arrow keys drive), so the active row carries a ring rather
   than relying on the hover tint alone — otherwise there is no visible cursor at all. */
.diallist:focus-visible li.active{box-shadow:inset 0 0 0 2px var(--accent)}
.diallist .f{flex:0 0 auto;font-size:16px;line-height:1}
/* Name takes the slack, code is pinned right — the layout the whole control is for. */
.diallist .n{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.diallist .c{flex:0 0 auto;color:var(--muted);font-variant-numeric:tabular-nums}
.diallist li:hover .c,.diallist li.active .c{color:inherit}
@media (max-width:560px){ .dialpop{width:min(300px,86vw)} }

.src-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:6px}
.src-row{display:flex;gap:6px;align-items:center}
.src-row .src-name{flex:1;min-width:0}
.src-empty{padding:4px 0}
.src-add{display:flex;gap:6px;margin-top:10px}
.src-add input{flex:1;min-width:0}
.src-builtin{display:flex;flex-wrap:wrap;gap:6px}

/* Icon + label buttons (the outreach queue's Approve / Send / Skip). The glyph carries the meaning
   at a glance; the word stays because an icon-only row of three actions is a guessing game. */
.btn-ic{display:inline-flex;align-items:center;gap:6px}
.btn-ic svg{width:14px;height:14px;flex-shrink:0}

/* The signature note doubles as the failure message for adding an image, so it has to beat the
   .muted colour it normally carries — a red warning rendered grey is not a warning. */
#sigNote.err{color:var(--critical);font-weight:600}

/* =============================================================================
   Live LLM status — collapsed into the topbar (2026-08-17): one icon per
   connected provider next to the bell, its dot carrying health at a glance;
   clicking an icon opens the full card as a bubble reusing .notif-pop.
   ========================================================================== */
.llm-anchor{position:relative;flex-shrink:0;display:flex;align-items:center}
/* One tight, evenly-spaced button cluster: s1 between the AI icons, and the bell pulled in to the
   same s1 (offsetting the topbar's s3 flex gap — only while the AI anchor is actually showing). */
.llm-icons{display:flex;align-items:center;gap:var(--s1)}
.llm-anchor:not([hidden])+.notif-anchor{margin-left:calc(var(--s1) - var(--s3))}
.llm-tb svg{width:18px;height:18px;display:block}
.llm-pop-ic{display:inline-flex;color:var(--muted);flex-shrink:0}
.llm-pop-ic svg{width:16px;height:16px}
/* Top-right, where the bell's badge sits — one place on a topbar icon means "state of this button",
   and two different corners for the same idea is what made it read as decoration. */
.llm-tb-dot{
  position:absolute;top:-3px;right:-3px;width:9px;height:9px;border-radius:50%;
  background:var(--n400);box-shadow:0 0 0 2px var(--bg);
}
.llm-tb-dot.good{background:var(--good)}
.llm-tb-dot.warning{background:var(--warning)}
.llm-tb-dot.critical{background:var(--critical)}
.llm-tb-dot.muted{background:var(--n400)}
/* Three states, readable without opening anything: the one answering the next call, the ones standing
   by behind it, and the ones the router is skipping. */
.llm-tb.next{color:var(--accent)}
.llm-tb.next::after{
  content:"";position:absolute;inset:2px;border-radius:var(--r-xs);pointer-events:none;
  box-shadow:0 0 0 1.5px color-mix(in srgb,var(--accent) 55%,transparent);
  background:color-mix(in srgb,var(--accent) 10%,transparent);
}
.llm-tb.standby{opacity:.8}
/* Out of the chain: dimmed AND desaturated, so it does not read as merely "further down the list". */
.llm-tb.paused{opacity:.5;filter:grayscale(1)}
/* The fallback order, in the bubble. The head of the chain is the one answering now. */
.llm-chain{margin:0;padding:var(--s1) var(--s3) 0;font-size:var(--fs-xs);line-height:1.7}
.llm-chain b{font-weight:650}
.llm-chain b.on{color:var(--accent)}
.llm-tb[aria-expanded="true"]{background:color-mix(in srgb, var(--ink) 9%, transparent)}
.llm-pop{width:min(300px,calc(100vw - 24px))}
.llm-pop .notif-pop-head .llm-state{margin-left:auto}
.llm-pop .llm-state.ok{background:var(--good-soft);color:color-mix(in srgb,var(--good) 72%,var(--ink))}
.llm-pop-body{padding:var(--s2)}
.llm-pop .llm-card{border:0}
.llm-pop .llm-none{padding:0 var(--s3) var(--s2);margin:0}
@media (max-width:560px){
  /* inherits .notif-pop's fixed placement; keep the fixed left/right sizing, not the 300px width */
  .llm-pop{width:auto}
  .llm-icons .llm-tb{width:29px;height:29px;min-height:29px}
}
.llm-card{
  border:1px solid var(--line);border-radius:var(--r-sm);padding:var(--s2) var(--s3);
  background:var(--surface);min-width:0;
}
/* The one that will actually answer the next call — the single most useful fact here. */
.llm-card.next{border-color:var(--accent);box-shadow:0 0 0 2px color-mix(in srgb,var(--accent) 16%,transparent)}
.llm-card.capped,.llm-card.off{opacity:.72}
.llm-top{display:flex;align-items:center;gap:6px;min-width:0;flex-wrap:wrap}
.llm-name{font-size:var(--fs-sm);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.llm-next{
  margin-left:auto;font-size:var(--fs-2xs);font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  color:var(--accent);background:var(--accent-soft);border-radius:var(--r-full);padding:1px 7px;flex-shrink:0;
}
.llm-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;background:var(--muted)}
.llm-dot.good{background:var(--good)}
.llm-dot.warning{background:var(--warning)}
.llm-dot.critical{background:var(--critical)}
.llm-dot.muted{background:var(--n400)}
.llm-model{font-size:var(--fs-2xs);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-top:1px}
.llm-bar{height:4px;border-radius:var(--r-full);background:var(--surface-3);margin:6px 0 4px;overflow:hidden}
.llm-bar>i{display:block;height:100%;background:var(--accent);border-radius:inherit}
.llm-card.capped .llm-bar>i{background:var(--critical)}
.llm-card.resting .llm-bar>i{background:var(--warning)}
/* One figure per row since each line carries used AND left — two nowrap spans forced onto one
   line is what made them overlap. Wrapping stays allowed for narrow cards. */
.llm-figs{display:flex;flex-wrap:wrap;justify-content:flex-start;gap:2px var(--s2);font-size:var(--fs-2xs);min-width:0}
.llm-left{font-weight:650}
/* The state in words, for the cases where a provider is NOT answering. Tinted to match its dot, but
   the words are what carry the meaning — the colour only reinforces it. */
.llm-state{
  font-size:var(--fs-2xs);font-weight:650;line-height:1.5;white-space:nowrap;
  padding:1px 7px;border-radius:var(--r-full);
  background:var(--surface-3);color:var(--ink2);
}
.llm-state.warning{background:var(--warning-soft);color:color-mix(in srgb,var(--warning) 72%,var(--ink))}
.llm-state.critical{background:var(--critical-soft);color:color-mix(in srgb,var(--critical) 72%,var(--ink))}
.llm-state.muted{background:var(--surface-3);color:var(--muted)}
.llm-money{color:var(--ink2);font-weight:600}
.llm-figs .muted{white-space:nowrap}
/* Why a provider is not being used. The whole reason this panel exists is that silence here
   used to be indistinguishable from working. */
.llm-why{font-size:var(--fs-2xs);margin-top:4px;line-height:1.35}
.llm-none{font-size:var(--fs-sm);color:var(--muted);margin:var(--s2) 0 0}


/* =============================================================================
   Channel-native composers (Outreach queue)
   A draft is easier to judge when it looks like the thing that will land. The only literal colours
   in this section are the three channel brand hues — a channel's own colour is the one thing a
   design token cannot supply. Everything else comes off the ramp, so both themes follow.
   ========================================================================== */

/* — email: an Outlook-style field stack — */
.oc{
  --oc-blue:#0F6CBD;
  margin-bottom:var(--s3);overflow:hidden;
  background:var(--surface);border:1px solid var(--line);border-radius:var(--r-sm);
}
.oc-row{
  display:grid;grid-template-columns:74px minmax(0,1fr) auto;align-items:center;gap:var(--s2);
  min-height:34px;padding:0 var(--s3);border-bottom:1px solid var(--line);
}
.oc-lbl{margin:0;padding:0;line-height:1;font-size:var(--fs-xs);font-weight:520;letter-spacing:.02em;color:var(--muted)}
.oc-val{
  display:flex;align-items:center;flex-wrap:wrap;gap:6px;min-width:0;padding:7px 0;
  font-family:Calibri,"Segoe UI",Helvetica,Arial,sans-serif;font-size:14.7px;color:var(--ink);word-break:break-word;
}
.oc-val .err{font-size:var(--fs-xs);margin:0}
.oc-pill{
  display:inline-flex;align-items:center;max-width:100%;padding:2px 9px;border-radius:var(--r-full);
  font-size:var(--fs-sm);color:var(--ink);
  background:color-mix(in srgb,var(--oc-blue) 10%,transparent);
  border:1px solid color-mix(in srgb,var(--oc-blue) 24%,transparent);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.oc-in{
  width:100%;min-height:0;padding:7px 0;background:transparent;border:0;border-radius:0;box-shadow:none;
  font-family:Calibri,"Segoe UI",Helvetica,Arial,sans-serif;font-size:14.7px;color:var(--ink);
}
.oc-in:hover:not(:disabled){border:0;background:color-mix(in srgb,var(--ink) 3%,transparent)}
.oc-in:focus{outline:none;border:0;box-shadow:inset 0 -2px 0 var(--oc-blue);background:color-mix(in srgb,var(--oc-blue) 5%,transparent)}
.oc-row-subject{border-bottom:1px solid var(--line)}
.oc-subj{font-weight:600}
.oc-note{margin:5px var(--s3) 0;font-size:var(--fs-2xs);color:var(--muted)}
.oc .rte-tools{margin:var(--s2) 0 0;border-left:0;border-right:0;border-radius:0}
.oc .oq-body-rte{min-height:200px;max-height:420px;padding:var(--s4) var(--s3);background:var(--surface);border:0;border-radius:0}
.oc .oq-body-rte:focus{box-shadow:inset 3px 0 0 var(--oc-blue)}
.oc .oq-sig{margin:0;padding:0 var(--s3) var(--s3)}
.oc .oq-sig .muted{font-size:var(--fs-2xs);text-transform:uppercase;letter-spacing:.04em}
.oc .oq-sig-html,.oc .oq-sig pre{background:transparent;border-left:2px solid color-mix(in srgb,var(--oc-blue) 30%,transparent)}
.oc .oq-hint{margin:0;padding:0 var(--s3) var(--s3);font-size:var(--fs-xs)}
@media (max-width:560px){
  .oc-row{grid-template-columns:60px minmax(0,1fr);row-gap:0}
}

/* — LinkedIn: avatar-led, rounder, one blue button, and a live cap — */
.oq-item[data-chan="linkedin"]{ --li:#0A66C2; --li-ink:#0A66C2; --li-on:#fff; }
.li-head{
  display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s4);margin-bottom:var(--s2);
  background:var(--surface-2);border:1px solid color-mix(in srgb,var(--li-ink) 22%,var(--line));border-radius:var(--r-md);
}
.li-head .lead-avatar-ring{width:48px;height:48px;min-width:48px}
.li-who{display:flex;flex-direction:column;gap:1px;min-width:0;flex:1}
.li-name{font-size:var(--fs-lg);font-weight:660;color:var(--ink);min-width:0;overflow-wrap:anywhere}
.li-name a{color:inherit;text-decoration:none}
.li-name a:hover{color:var(--li-ink);text-decoration:underline;text-underline-offset:2px}
.li-headline{font-size:var(--fs-sm);color:var(--ink2)}
.li-co{font-size:var(--fs-xs);color:var(--muted)}
.li-from{margin:0 0 var(--s3);font-size:var(--fs-xs);color:var(--muted)}
.li-from strong{color:var(--ink2);font-weight:600}
.li-note{
  position:relative;margin-bottom:var(--s3);padding:var(--s3) var(--s4) var(--s2);
  background:var(--surface);border:1px solid color-mix(in srgb,var(--li-ink) 22%,var(--line-2));border-radius:var(--r-md);
}
.li-note:focus-within{border-color:var(--li-ink);box-shadow:0 0 0 3px color-mix(in srgb,var(--li-ink) 22%,transparent)}
.li-note-lbl{display:block;margin:0;font-size:var(--fs-xs);font-weight:600;text-transform:uppercase;letter-spacing:.04em;color:var(--muted)}
.li-note textarea{
  margin:2px 0 0;padding:0;min-height:104px;width:100%;background:transparent;border:0;border-radius:0;
  box-shadow:none;line-height:1.5;color:var(--ink);resize:vertical;
}
.li-note textarea:hover:not(:disabled),.li-note textarea:focus{background:transparent;border:0;outline:none;box-shadow:none}
.li-note-foot{display:flex;align-items:center;gap:var(--s3);margin-top:var(--s2);padding-top:var(--s2);border-top:1px solid var(--line)}
.li-note-hint{font-size:var(--fs-xs);color:var(--muted);flex:1;min-width:0}
.li-count{
  padding:2px 9px;border-radius:var(--r-full);white-space:nowrap;font-size:var(--fs-xs);font-weight:600;
  font-variant-numeric:tabular-nums;color:var(--muted);background:var(--surface-2);border:1px solid var(--line);
}
.li-note.over{border-color:var(--critical)}
.li-note.over .li-count{color:var(--critical);background:var(--critical-soft);border-color:color-mix(in srgb,var(--critical) 34%,transparent)}
.li-over{margin:var(--s2) 0 0;font-size:var(--fs-xs);color:var(--critical)}
.li-over[hidden]{display:none}
.oq-item[data-chan="linkedin"] .oq-acts button,
.oq-item[data-chan="linkedin"] .oq-acts a.small{border-radius:var(--r-full);padding:6px 16px;min-height:32px;font-weight:600}
.oq-item[data-chan="linkedin"] .oq-acts button:not(.ghost){background:var(--li);border-color:var(--li);color:var(--li-on);box-shadow:none}
.oq-item[data-chan="linkedin"] .oq-acts button:not(.ghost):hover:not(:disabled){
  background:color-mix(in srgb,var(--li) 86%,var(--ink));border-color:color-mix(in srgb,var(--li) 86%,var(--ink));
}
.oq-item[data-chan="linkedin"] .oq-acts button.ghost,
.oq-item[data-chan="linkedin"] .oq-acts a.ghost{
  background:transparent;color:var(--li-ink);font-weight:600;box-shadow:none;
  border-color:color-mix(in srgb,var(--li-ink) 42%,transparent);
}

/* — WhatsApp: the thread it will become. Backdrop is a CSS weave, never an image file. — */
.wa-chat{
  --wa-green:#25D366; --wa-read:#53BDEB;
  --wa-out:color-mix(in srgb,var(--wa-green) 20%,var(--surface));
  --wa-paper:color-mix(in srgb,var(--wa-green) 5%,var(--surface-2));
  border:1px solid var(--line);border-radius:var(--r-md);overflow:hidden;margin-bottom:var(--s3);
}
.wa-head{display:flex;align-items:center;gap:var(--s2);padding:var(--s2) var(--s3);background:var(--surface-2);border-bottom:1px solid var(--line)}
.wa-head .lead-avatar-ring{width:32px;height:32px;min-width:32px}
.wa-who{display:flex;flex-direction:column;min-width:0;flex:1}
.wa-who strong{font-size:var(--fs-sm);font-weight:640;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wa-who>span{font-size:var(--fs-xs);color:var(--muted);font-variant-numeric:tabular-nums}
.wa-from{font-size:var(--fs-2xs);color:var(--muted);white-space:nowrap;text-transform:uppercase;letter-spacing:.04em;flex-shrink:0}
.wa-thread{
  display:flex;flex-direction:column;align-items:flex-end;gap:var(--s2);
  padding:var(--s4) var(--s4) var(--s4) var(--s3);min-height:96px;background-color:var(--wa-paper);
  background-image:
    radial-gradient(circle at 50% 50%, color-mix(in srgb,var(--ink) 6%,transparent) 0 1px, transparent 1.5px),
    repeating-linear-gradient(45deg, transparent 0 10px, color-mix(in srgb,var(--ink) 3%,transparent) 10px 11px),
    repeating-linear-gradient(135deg, transparent 0 10px, color-mix(in srgb,var(--ink) 3%,transparent) 10px 11px);
  background-size:20px 20px,auto,auto;
}
.wa-day{
  align-self:center;padding:3px 10px;border-radius:var(--r-full);font-size:var(--fs-2xs);font-weight:640;
  color:var(--ink2);background:color-mix(in srgb,var(--surface) 84%,transparent);
}
.wa-bubble{
  position:relative;max-width:min(560px,86%);padding:6px 10px;background:var(--wa-out);color:var(--ink);
  border-radius:var(--r-md) 0 var(--r-md) var(--r-md);font-size:var(--fs-md);line-height:1.42;
}
.wa-bubble::after{content:"";position:absolute;top:0;right:-7px;width:0;height:0;border-left:8px solid var(--wa-out);border-bottom:9px solid transparent}
.wa-text{margin:0;white-space:pre-wrap;overflow-wrap:anywhere}
/* Reserves the tail of the last line so the stamp tucks INSIDE the bubble instead of colliding
   with the final word. Sized for "12:00 PM" plus a double tick plus breathing room. */
.wa-text::after{content:"";display:inline-block;width:80px}
.wa-text:empty::before{content:"No message yet";opacity:.55;font-style:italic}
.wa-stamp{
  position:absolute;right:9px;bottom:4px;display:inline-flex;align-items:center;gap:4px;
  font-size:var(--fs-2xs);font-variant-numeric:tabular-nums;user-select:none;color:color-mix(in srgb,var(--ink) 50%,transparent);
}
.wa-ticks{display:inline-flex;align-items:center}
.wa-ticks svg{width:16px;height:11px;display:block}
.wa-ticks svg.wa-clock{width:11px;height:11px}
.wa-ticks.wa-read{color:var(--wa-read)}
.wa-ticks.wa-fail{color:var(--critical)}
.wa-ticks.wa-wait{opacity:.7}
.wa-composer{display:flex;align-items:flex-end;gap:var(--s2);padding:var(--s2) var(--s3);background:var(--surface-2);border-top:1px solid var(--line)}
.wa-input{
  flex:1;width:auto;min-width:0;margin:0;min-height:38px;max-height:160px;resize:none;overflow-y:auto;
  padding:9px var(--s4);border-radius:var(--r-full);background:var(--surface);border:1px solid var(--line-2);line-height:1.4;
}
.wa-input:focus{border-color:var(--wa-green);box-shadow:0 0 0 3px color-mix(in srgb,var(--wa-green) 22%,transparent)}
.wa-send{flex:0 0 auto;width:38px;height:38px;min-height:38px;padding:0;border:0;border-radius:var(--r-full);background:var(--wa-green);color:#fff}
.wa-send svg{width:17px;height:17px;transform:translateX(-1px)}
.wa-send:hover:not(:disabled){background:color-mix(in srgb,var(--wa-green) 84%,var(--ink))}
.wa-send:disabled{background:var(--surface-3);color:var(--muted);opacity:1}
@media (max-width:560px){ .wa-from{display:none} .wa-bubble{max-width:92%} }

/* Dark mode for all three. Each brand hue is carried toward the ink rather than swapped for another
   colour: #0F6CBD and #0A66C2 cannot hold text on a dark surface, and WhatsApp's own dark bubble is
   a deep teal-green, not a pale mint. */
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .oc{--oc-blue:color-mix(in srgb,#0F6CBD 46%,var(--ink))}
  :root:not([data-theme="light"]) .oc-in:hover:not(:disabled){background:color-mix(in srgb,var(--ink) 6%,transparent)}
  :root:not([data-theme="light"]) .oc-pill{background:color-mix(in srgb,var(--oc-blue) 18%,transparent)}
  :root:not([data-theme="light"]) .oq-item[data-chan="linkedin"]{
    --li:color-mix(in srgb,#0A66C2 46%,#fff); --li-ink:color-mix(in srgb,#0A66C2 46%,#fff); --li-on:var(--ink-invert);
  }
  :root:not([data-theme="light"]) .wa-chat{
    --wa-out:color-mix(in srgb,var(--wa-green) 30%,#04120e);
    --wa-paper:color-mix(in srgb,var(--wa-green) 4%,var(--surface-2));
  }
  :root:not([data-theme="light"]) .wa-stamp{color:color-mix(in srgb,var(--ink) 62%,transparent)}
  :root:not([data-theme="light"]) .wa-day{background:color-mix(in srgb,var(--surface-3) 88%,transparent)}
}
:root[data-theme="dark"] .oc{--oc-blue:color-mix(in srgb,#0F6CBD 46%,var(--ink))}
:root[data-theme="dark"] .oc-in:hover:not(:disabled){background:color-mix(in srgb,var(--ink) 6%,transparent)}
:root[data-theme="dark"] .oc-pill{background:color-mix(in srgb,var(--oc-blue) 18%,transparent)}
:root[data-theme="dark"] .oq-item[data-chan="linkedin"]{
  --li:color-mix(in srgb,#0A66C2 46%,#fff); --li-ink:color-mix(in srgb,#0A66C2 46%,#fff); --li-on:var(--ink-invert);
}
:root[data-theme="dark"] .wa-chat{
  --wa-out:color-mix(in srgb,var(--wa-green) 30%,#04120e);
  --wa-paper:color-mix(in srgb,var(--wa-green) 4%,var(--surface-2));
}
:root[data-theme="dark"] .wa-stamp{color:color-mix(in srgb,var(--ink) 62%,transparent)}
:root[data-theme="dark"] .wa-day{background:color-mix(in srgb,var(--surface-3) 88%,transparent)}

/* A toast that carries an action needs room for it, and the button has to read as clickable against
   the toast's inverted surface. */
#toast.has-action{display:inline-flex;align-items:center;gap:var(--s3)}
.toast-act{
  flex-shrink:0;padding:3px 10px;min-height:26px;font-size:var(--fs-sm);font-weight:650;
  color:var(--page);background:color-mix(in srgb,var(--page) 22%,transparent);
  border:1px solid color-mix(in srgb,var(--page) 45%,transparent);border-radius:var(--r-full);
}
.toast-act:hover{background:color-mix(in srgb,var(--page) 34%,transparent);border-color:var(--page)}
.toast-act:focus-visible{outline:2px solid var(--page);outline-offset:2px}

/* =============================================================================
   A/B/C variants — badge, matrix, and the picker's extra button
   ========================================================================== */
.vbadge{
  display:inline-flex;align-items:center;justify-content:center;min-width:19px;height:19px;padding:0 5px;
  border-radius:var(--r-xs);font-size:var(--fs-2xs);font-weight:800;letter-spacing:.02em;flex-shrink:0;
  background:var(--surface-3);color:var(--ink2);border:1px solid var(--line);
}
/* Three distinct hues so a variant is recognisable at a glance in a long queue — from the sequential
   ramp, not new colours, so they stay in the platform's palette and follow the theme. */
.vbadge.vA{background:color-mix(in srgb,var(--seq-5) 20%,transparent);color:var(--seq-7);border-color:color-mix(in srgb,var(--seq-5) 38%,transparent)}
.vbadge.vB{background:color-mix(in srgb,var(--warning) 18%,transparent);color:color-mix(in srgb,var(--warning) 72%,var(--ink));border-color:color-mix(in srgb,var(--warning) 34%,transparent)}
.vbadge.vC{background:color-mix(in srgb,var(--good) 18%,transparent);color:color-mix(in srgb,var(--good) 72%,var(--ink));border-color:color-mix(in srgb,var(--good) 34%,transparent)}
.badge.replied{background:var(--good-soft);color:color-mix(in srgb,var(--good) 72%,var(--ink));border-color:color-mix(in srgb,var(--good) 32%,transparent)}
.badge.replied::before{background:var(--good)}
/* the Mark-replied button, once it is on */
.oq-acts .btn-ic.on{background:var(--good-soft);border-color:color-mix(in srgb,var(--good) 34%,transparent);color:color-mix(in srgb,var(--good) 74%,var(--ink))}

.abc-card{margin-bottom:var(--s4)}
.abc-grid{display:grid;grid-template-columns:minmax(0,1fr) 56px 66px 62px minmax(120px,1.1fr);gap:var(--s2) var(--s3);align-items:center}
/* Seven columns once clicks + meetings joined the matrix. */
.abc-grid.abc-grid-6{grid-template-columns:minmax(0,1fr) 48px 74px 74px 56px 64px minmax(110px,1fr)}
.abc-h{font-size:var(--fs-2xs);text-transform:uppercase;letter-spacing:.05em;color:var(--muted);font-weight:650}
.abc-h.abc-rate,.abc-grid>.abc-n{text-align:right}
.abc-name{display:flex;align-items:center;gap:var(--s2);min-width:0;font-size:var(--fs-sm)}
.abc-name span:last-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.abc-n{font-variant-numeric:tabular-nums;font-size:var(--fs-sm);color:var(--ink2)}
.abc-rate{display:flex;align-items:center;justify-content:flex-end;gap:var(--s2);font-variant-numeric:tabular-nums}
.abc-bar{flex:1;max-width:110px;height:6px;border-radius:var(--r-full);background:var(--surface-3);overflow:hidden}
.abc-bar>i{display:block;height:100%;background:var(--seq-5);border-radius:inherit}
/* 184px of fixed columns plus a 120px floor on the rate column puts a hard 352px minimum on this
   grid, which overflows its card on a phone. Tighten the numbers and drop the bar — the percentage
   beside it says the same thing, and a number that fits beats a bar that does not. */
@media (max-width:560px){
  .abc-grid{grid-template-columns:minmax(0,1fr) 40px 50px 48px minmax(52px,auto);gap:var(--s2)}
  .abc-grid.abc-grid-6{grid-template-columns:minmax(0,1fr) 36px 52px 52px 44px 48px minmax(48px,auto)}
  .abc-bar{display:none}
}
/* Only the CONFIRMED winner is coloured as one — an early leader is drawn in the neutral ramp. */
.abc-bar>i.win{background:var(--good)}
.abc-verdict{margin:var(--s3) 0 0;font-size:var(--fs-sm)}
/* Header row on each approach's editor card: the letter chip ties the wording to its row in the
   matrix above, and the mini stat line keeps the numbers next to what's being edited. */
.abc-ed-h{display:flex;align-items:center;gap:var(--s2);margin-bottom:var(--s2);flex-wrap:wrap}
.abc-ed-stats{font-size:var(--fs-xs);font-variant-numeric:tabular-nums}
.abc-empty p{margin:var(--s2) 0 0;font-size:var(--fs-sm);line-height:1.5}

/* Meeting-link switch — same strip treatment as Rephrase below it, on every channel. The URL is
   allowed to shrink and ellipsis rather than wrap: a booking address is long, and a two-line link
   pushes the actions around every time a draft repaints. */
.bk-bar{display:flex;align-items:center;flex-wrap:wrap;gap:var(--s2);margin:var(--s3) 0 0;padding-top:var(--s3);border-top:1px dashed var(--line)}
.bk-tick{display:inline-flex;align-items:center;gap:6px;font-size:var(--fs-sm);font-weight:600;cursor:pointer;flex-shrink:0}
.bk-tick input{cursor:pointer;accent-color:var(--accent)}
.bk-tick:has(input:disabled){cursor:default;color:var(--muted)}
.bk-tick:has(input:disabled) input{cursor:default}
.bk-url{flex:1 1 0;min-width:0;font-size:var(--fs-xs);font-family:var(--mono,ui-monospace,monospace);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bk-off{flex:1 1 0;min-width:0;font-size:var(--fs-xs)}
.bk-note{flex:1 1 100%;font-size:var(--fs-xs);margin-top:2px}
.bk-note.err{color:var(--critical);font-weight:600}

/* Rephrase strip — sits between the message and the actions, on every channel. */
.rp-bar{display:flex;align-items:center;flex-wrap:wrap;gap:var(--s2);margin:var(--s3) 0 0;padding-top:var(--s3);border-top:1px dashed var(--line)}
.rp-lbl{font-size:var(--fs-xs);color:var(--muted);font-weight:650;text-transform:uppercase;letter-spacing:.04em}
.rp-btn{display:inline-flex;align-items:center;gap:6px;font-size:var(--fs-sm)}
.rp-btn.on{border-color:var(--accent);background:var(--accent-soft);color:var(--tint-ink)}
.rp-note{flex:1 1 100%;font-size:var(--fs-xs);margin-top:2px}
.rp-note.err{color:var(--critical);font-weight:600}

/* =============================================================================
   Meetings — month grid + next-up list
   ========================================================================== */
.mt-card{margin-bottom:var(--s4)}
.mt-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:1px;background:var(--line);border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden}
/* Weekday strip in the house dark teal-green with white type — it reads as the grid's header rather
   than as a first, empty row of cells. Same token in dark mode: it is already a dark surface, and a
   lighter header there would invert the hierarchy. */
.mt-head{background:var(--brand-800);padding:6px 8px;font-size:var(--fs-2xs);font-weight:800;text-transform:uppercase;letter-spacing:.05em;color:#fff;text-align:center}
.mt-cell{background:var(--surface);min-height:92px;padding:5px 6px;display:flex;flex-direction:column;gap:3px;min-width:0}
/* Days from the neighbouring months are present for shape, not for reading. */
.mt-cell.other{background:var(--surface-2)}
.mt-cell.other .mt-daynum{color:var(--n400)}
.mt-cell.today{box-shadow:inset 0 0 0 2px var(--accent)}
/* Today's number sits in a filled red disc — the rectangle around the cell stays, it answers
   "which cell" while the disc answers "which date" at a glance. Fixed size so a 1-digit and a
   2-digit date are the same circle. */
.mt-cell.today .mt-daynum{align-self:flex-start;display:inline-flex;align-items:center;justify-content:center;
  min-width:18px;height:18px;padding:0 4px;border-radius:999px;background:var(--critical);color:#fff;font-weight:800}
.mt-daynum{font-size:var(--fs-2xs);font-weight:650;color:var(--ink2);line-height:1}
.mt-chip{
  display:block;width:100%;text-align:left;padding:2px 6px;border-radius:var(--r-xs);
  font-size:var(--fs-2xs);line-height:1.35;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  background:var(--accent-soft);color:var(--tint-ink);border:1px solid transparent;min-height:0;
}
/* A chip is a <button>, so the global button:hover paints it var(--accent-dk) — every variant's
   resting text color is dark, so hover must go white or the label vanishes. .mt-grid prefix so
   this outranks the .mt-chip.pending/.ev/.cancelled color declarations below. */
.mt-grid .mt-chip:hover{border-color:var(--accent);color:#fff}
.mt-chip .mt-t{font-variant-numeric:tabular-nums;font-weight:700;opacity:.75;margin-right:3px}
.mt-chip.pending{background:var(--warning-soft);color:color-mix(in srgb,var(--warning) 72%,var(--ink))}
/* Events calendar rides the same grid; a chip is quiet unless starred (colored only when active),
   and past events dim the same way .ev-past table rows do. */
.mt-chip.ev{background:var(--surface-3);color:var(--ink2)}
.mt-chip.ev.int{background:var(--accent-soft);color:var(--tint-ink);border-color:var(--accent)}
.mt-chip.ev.past{opacity:.55}
/* A cancelled booking stays visible and struck through — it explains a gap in the day. */
.mt-chip.cancelled{background:var(--surface-3);color:var(--muted);text-decoration:line-through}
.mt-more{font-size:var(--fs-2xs)}
@media (max-width:820px){
  .mt-cell{min-height:64px}
  .mt-chip .mt-t{display:none}
}

/* =============================================================================
   Settings — 12-hour send-window range, and the anti-spam channel cards
   ========================================================================== */
.timerange{display:flex;align-items:flex-end;gap:var(--s3);flex-wrap:wrap}
.tr-part{flex:1 1 160px;min-width:0;margin:0}
.tr-arrow{padding-bottom:10px;color:var(--muted);font-size:var(--fs-lg)}
.tr-sel{min-width:130px}
/* Which weekdays sending is allowed — pill checkboxes, one per day. */
.dayrow{display:flex;gap:var(--s2);flex-wrap:wrap;margin:var(--s3) 0}
.daychk{
  display:inline-flex;align-items:center;gap:6px;margin:0;cursor:pointer;
  font-size:var(--fs-sm);font-weight:560;color:var(--ink2);
  border:1px solid var(--line);border-radius:var(--r-full);padding:4px 12px;background:var(--surface);
}
.daychk:hover{border-color:var(--accent)}
.daychk:has(input:checked){background:var(--accent-soft);border-color:color-mix(in srgb,var(--accent) 40%,transparent);color:var(--tint-ink)}
.daychk input{margin:0;accent-color:var(--accent)}

/* The whole sending policy in one line above the channel cards. */
.as-summary{margin:0 0 var(--s3);font-size:var(--fs-sm)}
.as-chan-h{display:flex;align-items:center;gap:var(--s2)}
.as-chan-dot{width:9px;height:9px;border-radius:50%;background:var(--oc,var(--muted));flex:0 0 auto}
.as-caps{margin-bottom:var(--s3)}
.as-idh{margin:var(--s4) 0 var(--s2);font-size:var(--fs-sm);text-transform:uppercase;letter-spacing:.05em;color:var(--muted)}
/* The rotation pool itself: one editable row per sending identity, its cap, what it has used today
   and an un-park button when it is sitting in cooldown. */
.as-pool{margin:0 0 var(--s3)}
.as-pool .data-table input:not([type="checkbox"]){width:100%;min-width:110px}
.as-pool .data-table td{vertical-align:middle}
.as-pool-acts{display:flex;gap:var(--s2);align-items:center;flex-wrap:wrap;margin-top:var(--s2)}
.as-rules{list-style:none;margin:0 0 var(--s2);padding:0;display:flex;flex-direction:column;gap:1px;
  border:1px solid var(--line);border-radius:var(--r-sm);overflow:hidden;background:var(--line)}
.as-rule{display:flex;align-items:flex-start;gap:var(--s2);padding:8px var(--s3);background:var(--surface);font-size:var(--fs-sm)}
.as-rule-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;margin-top:6px;background:var(--muted)}
.as-rule.on .as-rule-dot{background:var(--good)}
.as-rule.part .as-rule-dot{background:var(--warning)}
.as-rule.off .as-rule-dot{background:var(--n400)}
.as-rule-txt{flex:1;min-width:0;line-height:1.45}
/* Why a rule is not enforced. The whole value of listing it is saying this out loud — a toggle that
   looks active while nothing checks it is worse than not showing the rule. */
.as-rule-why{display:block;font-size:var(--fs-xs);color:var(--muted);margin-top:2px}
.as-rule-state{flex-shrink:0;font-size:var(--fs-2xs);font-weight:700;text-transform:uppercase;letter-spacing:.04em;
  padding:2px 8px;border-radius:var(--r-full);background:var(--surface-2);color:var(--muted);white-space:nowrap}
.as-rule.on .as-rule-state{background:var(--good-soft);color:color-mix(in srgb,var(--good) 72%,var(--ink))}
.as-rule.part .as-rule-state{background:var(--warning-soft);color:color-mix(in srgb,var(--warning) 74%,var(--ink))}
@media (max-width:640px){
  .as-rule{flex-wrap:wrap}
  .as-rule-state{margin-left:16px}
}

/* =============================================================================
   Notification pop-up — three tiers, nothing folded away
   ========================================================================== */
.notif-tier-h{
  display:flex;align-items:center;gap:6px;
  padding:8px 12px 4px;font-size:var(--fs-2xs);font-weight:750;
  text-transform:uppercase;letter-spacing:.05em;color:var(--muted);
  position:sticky;top:0;background:var(--surface);z-index:1;
}
.notif-tier-n{
  margin-left:auto;font-variant-numeric:tabular-nums;padding:1px 7px;border-radius:var(--r-full);
  background:var(--surface-3);color:var(--ink2);font-weight:700;
}
.notif-tier-h.alarm{color:var(--critical)}
.notif-tier-h.alarm .notif-tier-n{background:var(--critical-soft);color:var(--critical)}
.notif-tier-h.warning{color:color-mix(in srgb,var(--warning) 78%,var(--ink))}
.notif-tier-h.warning .notif-tier-n{background:var(--warning-soft);color:color-mix(in srgb,var(--warning) 78%,var(--ink))}
.notif-tier-h.reminder{color:var(--accent)}
.notif-tier-h.reminder .notif-tier-n{background:var(--accent-soft);color:var(--accent)}

/* The left rail is the tier, so severity reads before the words do. */
.notif-item.n-alarm{border-left-color:var(--critical);background:color-mix(in srgb,var(--critical) 5%,var(--surface))}
.notif-item.n-warning{border-left-color:var(--warning)}
.notif-item.n-reminder{border-left-color:var(--accent)}
/* Only the alarm tier moves. If everything pulses, nothing is urgent. */
.notif-row.tier-alarm .notif-dot{animation:notifPulse 1.6s ease-in-out infinite}
@keyframes notifPulse{ 0%,100%{transform:scale(1);opacity:1} 50%{transform:scale(1.18);opacity:.65} }
/* Long text is summarised to fit; the full sentence is on the row's tooltip. */
.notif-text{display:block;line-height:1.4;overflow-wrap:anywhere}
.notif-pop-body{max-height:min(70vh,560px);overflow-y:auto}

/* Locked sender rows — someone else's personal identity, shown but not editable. */

/* Micro-interactions (compact pass): a felt press on every button, a soft lift on interactive
   cards. Both honour prefers-reduced-motion via the global override further up. */
button:not(:disabled):active,.btn:not(:disabled):active{transform:translateY(1px)}
.conn-card{transition:border-color var(--t),box-shadow var(--t),transform var(--t)}
.conn-card:hover{border-color:color-mix(in srgb, var(--accent) 30%, var(--line));box-shadow:var(--shadow-2);transform:translateY(-1px)}

/* — Sources pages polish (2026-08-15) — */
/* Past events stay for context but read as history. */
.ev-past td{opacity:.55}
.ev-past:hover td{opacity:.8}
/* Group divider between upcoming and past — a label, not a row, so it must not read as data. */
.ev-divider td{
  padding:14px 12px 6px;font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);border-bottom:1px solid var(--line);background:transparent;
}
/* Two-line prose clamp with the full text on the title tooltip — used by dense table cells. */
.clamp2{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* Due-date chips shared by Events and Tenders. */
.tag.due-warn{background:var(--warning-soft);color:var(--warning)}
.tag.due-past{background:var(--surface-3);color:var(--muted)}
/* Data Enrich: form and result side by side once there's room — the result used to land
   below the fold, which read as "nothing happened". */
.en-layout{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--s5);align-items:start}
@media (min-width:1080px){.en-layout{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}}
.en-layout>.card,.en-result>.card{margin-bottom:0}
.en-result{position:sticky;top:calc(var(--topbar-h) + var(--s5))}
.en-placeholder{border-style:dashed;background:transparent;box-shadow:none}
.en-placeholder p{margin:0;font-size:var(--fs-sm);line-height:var(--lh)}
.en-copy{font:inherit;color:inherit;background:none;border:0;padding:0;cursor:copy;text-align:right}
.en-copy:hover{color:var(--accent);text-decoration:underline;text-underline-offset:2px}

/* — Draft-outreach channel buttons: one per platform, in the platform's own colour — */
.outreach-chan-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s3)}
@media (max-width:560px){.outreach-chan-grid{grid-template-columns:minmax(0,1fr)}}
.outreach-chan{
  --oc:var(--accent);
  display:flex;flex-direction:column;align-items:center;gap:6px;min-height:0;
  padding:var(--s4) var(--s3);border-radius:var(--r-md);cursor:pointer;text-align:center;
  background:color-mix(in srgb, var(--oc) 9%, var(--surface));
  border:1px solid color-mix(in srgb, var(--oc) 32%, var(--line));
  color:var(--ink);font:inherit;white-space:normal;
  transition:background var(--t),border-color var(--t),transform var(--t);
}
.outreach-chan:hover:not(:disabled){background:color-mix(in srgb, var(--oc) 16%, var(--surface));border-color:var(--oc);transform:translateY(-1px)}
.outreach-chan:disabled{opacity:.45;cursor:not-allowed}
.outreach-chan b{font-size:var(--fs-md)}
.outreach-chan .oc-ic{display:inline-flex;width:30px;height:30px;align-items:center;justify-content:center;
  border-radius:var(--r-sm);background:color-mix(in srgb, var(--oc) 16%, transparent);color:var(--oc)}
.outreach-chan .oc-ic svg{width:17px;height:17px}
.outreach-chan .oc-why{font-size:var(--fs-xs);color:var(--muted);overflow-wrap:anywhere}
/* Channel colours are one vocabulary app-wide: the picker buttons and the anti-spam channel
   headers read the same --oc, so the classes are generic rather than scoped to the picker. */
/* Playbook: sticky jump-nav + section anchors. scroll-margin keeps a jumped-to heading clear of
   the sticky bar instead of underneath it. */
.pb-nav{position:sticky;top:0;z-index:5;display:flex;align-items:center;gap:6px;flex-wrap:wrap;
  padding:10px 12px;margin:0 0 var(--s3);background:var(--surface);border:1px solid var(--line);
  border-radius:var(--r-md);box-shadow:var(--shadow-1);
  /* 26 sections is 26 chips. Sticky + unbounded would cover most of a phone screen, so cap it and
     let the chips scroll inside their own bar. */
  max-height:38vh;overflow:auto}
.pb-nav .pb-find{min-height:30px;width:200px;flex:1 1 160px}
.pb-jump{cursor:pointer;text-decoration:none}
.pb-jump:hover{border-color:var(--accent);color:var(--accent)}
.pb-sec{scroll-margin-top:64px;display:block;border-top:1px solid var(--line)}
.pb-sec:first-of-type{border-top:0}
.pb-sec>summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:8px}
.pb-sec>summary::-webkit-details-marker{display:none}
.pb-sec>summary::after{content:"";width:7px;height:7px;border-right:2px solid var(--muted);border-bottom:2px solid var(--muted);
  transform:rotate(-45deg);transition:transform .15s ease;margin-left:auto;flex:none}
.pb-sec[open]>summary::after{transform:rotate(45deg)}
.pb-sec>summary:hover h3{color:var(--accent)}
/* Spinning state for icon buttons that are waiting on a round-trip (calendar re-sync). Only the
   svg turns — spinning the whole button would wobble its border. */
.icon-btn.spin svg{animation:icospin 1s linear infinite}
@keyframes icospin{to{transform:rotate(360deg)}}
/* Composer autosave flag — visible only for a beat after a save lands. */
.oq-savedflag{opacity:0;transition:opacity .25s ease;color:var(--good);border-color:color-mix(in srgb,var(--good) 40%,transparent)}
.oq-savedflag.show{opacity:1}
/* Approve/Skip confirmation: the message being acted on, as a compact card. */
.conf-msg{display:flex;align-items:flex-start;gap:10px;padding:10px 12px;margin:0 0 12px;
  background:var(--surface-2);border:1px solid var(--line);border-radius:var(--r-sm)}
.conf-msg .conf-chan{flex:0 0 auto;margin-top:1px;color:var(--oc);border-color:color-mix(in srgb,var(--oc) 40%,transparent)}
.conf-msg-who{min-width:0}
.conf-subj{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12.5px;margin-top:2px}
.conf-what{font-size:13.5px;line-height:1.55;color:var(--ink2);margin:0 0 10px}
.conf-again{margin:0 0 4px;font-size:12.5px}
.oc-email{--oc:var(--accent)}
.oc-wa{--oc:#25d366}
.oc-li{--oc:#0a66c2}
/* LinkedIn's brand blue is too dark to read on a dark surface — lighten it there. */
:root[data-theme="dark"] .oc-li{--oc:#5c9dd8}
@media (prefers-color-scheme:dark){ :root:not([data-theme="light"]) .oc-li{--oc:#5c9dd8} }

/* — signature editor: Word-style image selection + corner resize handle — */
.sig-img-sel{outline:2px solid var(--accent);outline-offset:1px}
.sig-img-handle{
  position:absolute;width:14px;height:14px;z-index:6;cursor:nwse-resize;
  background:var(--surface);border:2px solid var(--accent);border-radius:3px;
  box-shadow:var(--shadow-1);
}
.sig-tools .sig-b svg{width:15px;height:15px;display:block}
.sig-sel-size{width:64px;min-width:64px}

/* =============================================================================
   24 · PHONE PASS (≤640px / ≤480px) — 2026-08-15
   The phone user triages — approve/skip drafts, check leads, glance at the
   dashboard — more than they author. Everything here is additive on top of the
   980px drawer and the 720/560px blocks above, so desktop cannot regress.
   ========================================================================== */
@media (max-width:640px){
  /* The page itself must never pan sideways. Anything that accidentally overflows
     is clipped at the root; wide content is expected to scroll inside its own
     box (.table-wrap, .board, .oq-tabs) instead. clip, not hidden: hidden would
     turn the body into a scroll container and break position:sticky above it. */
  html,body{overflow-x:clip}

  /* Tables scroll INSIDE the wrap rather than crushing six-plus columns into
     375px. The floor forces the wrap (already overflow-x:auto) to take over.
     #netTable is excluded — it restacks into cards at ≤760px above, and a
     min-width would drag those cards back out to a scroll. */
  .table-wrap{-webkit-overflow-scrolling:touch}
  .table-wrap>table:not(#netTable){min-width:600px}
  /* The select-all/row checkboxes stay put while the row scrolls under them, so
     bulk triage doesn't mean scrolling back for every tick. Solid backgrounds
     because the row slides beneath; the id also outranks the row-hover tint,
     which this one cell deliberately gives up. */
  #leadTable th:first-child{left:0;z-index:calc(var(--z-sticky) + 1)}
  #leadTable td:first-child{position:sticky;left:0;z-index:1;background:var(--surface)}

  /* Touch targets in the triage flows only: 40px where a thumb does the work.
     Dense-info chips (.act-chip, 20px) are deliberately left alone — they are
     read, not pressed, and the one live draft chip opens fine via its row. */
  .pagehead .actions button,.pagehead .actions a,
  .filterbar input,.filterbar select,.filterbar button,
  .filters input,.filters select,
  .oq-acts button,.oq-acts a.small,.oq-acts a.ghost,
  .bulk-actions button,.bulk-bar select,.bulk-bar input,
  .wiz-foot button{min-height:40px}
  /* the queue's Approve / Skip / Send share the row's width instead of huddling left */
  .oq-acts>button,.oq-acts>a{flex:1 1 auto}
  /* status pill and row icons get a real target without leaving the leads table's
     budget — the table scrolls now, so the extra pixels cost nothing */
  .status-select{height:34px;min-height:34px;max-height:34px;line-height:32px}
  #leadTable .reach{width:32px;height:32px;min-height:32px}
  .rowacts .icon-btn{min-width:34px;min-height:34px}
}

@media (max-width:480px){
  /* Metric tiles: two per row, always. auto-fit already lands on two at 375px,
     but one long label could collapse it to a single unreadable column — pin it. */
  .tiles{grid-template-columns:repeat(2,minmax(0,1fr))}

  /* Filter bars: each control takes the full row. Half-width selects beside a
     half-width search read as broken at this width, and full-width is the
     native-form convention a thumb expects. */
  .filters input,.filters select,
  .filterbar input,.filterbar select{width:100%}
  .filterbar input[type=search]{min-width:0}
  .filterbar .dd,.filterbar .dd summary{width:100%}
  .filterbar .dd summary{justify-content:space-between}

  /* Dialogs and wizards go full-bleed: at 375px the 4vw gutter around a dialog
     is dead space that costs form width, and edge-to-edge is what a phone sheet
     looks like. Height is capped with the internal scroll the base rule already
     has; .wiz-foot stays sticky inside it, so the buttons stay reachable. */
  dialog{width:100vw;max-width:100vw;max-height:100dvh;border-radius:0;border-left:0;border-right:0}
  dialog.wizard,dialog.wizard.wide{width:100vw}
  dialog:not(.wizard) .wiz-foot{border-radius:0}
}

/* Newsletter membership for one lead. Rows are labels wrapping their own checkbox so the whole row
   is the hit target; a locked row keeps its checked state visible but greys out, because "already
   sent" is information the reader needs, not a row to hide. */
.nlm-list{display:flex;flex-direction:column;gap:2px;max-height:46vh;overflow:auto;margin:4px 0 10px}
.nlm-row{display:flex;align-items:flex-start;gap:10px;padding:9px 10px;border-radius:8px;cursor:pointer;margin:0}
.nlm-row:hover{background:var(--panel)}
.nlm-row input{margin-top:2px;width:16px;height:16px;flex-shrink:0}
.nlm-main{display:flex;flex-direction:column;min-width:0}
.nlm-subj{font-weight:600;font-size:var(--fs-base);overflow-wrap:anywhere}
.nlm-meta{font-size:var(--fs-sm);margin-top:1px}
.nlm-row.is-locked{cursor:default;opacity:.6}
.nlm-row.is-locked:hover{background:transparent}

/* Five-minute time picker: an hour list and a minute list that only holds 00, 05 … 55. Two selects
   rather than one 288-entry list of every time in the day — nobody scrolls that. */
.time-pick{display:inline-flex;align-items:center;gap:4px}
.time-pick select{min-width:68px;padding-right:6px}
.tp-sep{color:var(--muted);font-weight:600}

/* The bell's count badge. The shared .nav-badge is sized for a sidebar row; on a 34px icon button it
   covered a third of the bell and read as a blob rather than a count. Smaller, and nudged to the
   corner with a ring in the topbar colour so it still separates from the icon behind it. */
.tb-icon .nav-badge{
  top:-3px;right:-3px;min-width:15px;height:15px;padding:0 4px;font-size:10px;line-height:1;
  box-shadow:0 0 0 2px var(--bg);
}
