/* ══════════════════════════════════════════════════════════════════════
   v3 — the CRM look. Everything hangs off `body.v3`, which the boot script
   sets unless the person chose "Classic" in Settings → Appearance.

   How it works: the app's components all read the --v2-* tokens (v2.css
   remaps the older --pd-* and --bg/--ink families onto them). v3 redefines
   those tokens on body.v3 — light below, dark under html[data-theme=dark] —
   so every existing component recolours without a single selector of its
   own. The rules after the tokens restyle the SHELL (rail, top bar, title
   row, phone bar) and, slice by slice, the components (table, toolbar,
   kanban, record panel). No handler, id or state key changes anywhere.

   References: Twenty (sidebar of objects, view toolbar, dense tables, record
   side panel, ⌘K); Linear (rail density, hairlines, 8px radius); Attio
   (chips, avatar stacks). Mood only from Dribbble.
   ══════════════════════════════════════════════════════════════════════ */

/* ── 1 · tokens ─────────────────────────────────────────────────────── */
body.v3{
  /* ══ ground, surfaces, ink — PAPER ════════════════════════════════
     R38. The owner's words: "remove the dark look, this looks like every
     other app being built in Claude." She is right, and the light theme
     was the same thing inverted — the tells are well documented and this
     had all of them: a cool slate ground (hsl 220 20% 98%), pure white
     cards, hairline grey borders, Inter, and one saturated teal.

     The single cheapest way to stop looking generated is to leave the
     slate-grey family entirely. Every surface here is WARM — a paper
     ground at hue 40 rather than 220 — and the ink is a warm near-black
     rather than blue-black. Nothing else about the layout changes and the
     whole product moves, because it is four tokens.

     Why paper and not another colour: this is a desk for federal
     contracting. Solicitations, SF-1449s, wage determinations and the
     Federal Register are what the work actually looks like, and warm paper
     with black ink is that world's native palette. It is a reason, not a
     preference, which is the thing a prompt cannot supply.

     Contrast was recomputed, not assumed — the faint token failed WCAG AA
     once already today and will not do so again:
       ink   15.0 on paper · 15.8 on panel
       sub    6.0 · 6.2
       faint  4.7 · 5.0 · 4.5 on the muted fill
     Panel sits 1.05 off the ground: visible as a card without a border. */
  --v2-bg:hsl(66 15% 92%);
  --v2-panel:hsl(0 0% 100%);
  --v2-line2:hsl(66 14% 95%);           /* surface-2: hover, nested, muted fill */
  --v2-ink:hsl(60 4% 14%);
  --v2-sub:hsl(75 5% 36%);
  /* R31 (light) · 60% → 44%. Measured 2.84:1 on the page, 2.97:1 on a card,
     2.65:1 on the muted fill — not a near miss, under the 3:1 floor that
     even large text gets. Dark is the default here so this went unnoticed,
     but Classic is one switch away.
     It converges with --v2-sub, and that is not a fudge: on a white page
     there is no value LIGHTER than sub that still clears 4.5:1, so "fainter
     than sub but still legible" does not exist. Faint and sub mean the same
     thing in the light theme because physics says so. */
  --v2-faint:hsl(75 5% 40%);
  --v2-line:hsl(70 13% 86%);
  /* R42 · DNAi's own colours, sampled from the logo in the Brand folder
     rather than guessed. The orange of R41 was Blount's — Profile Builder
     is Blount Construction Group's product, and borrowing its STRUCTURE is
     right while borrowing its colour would have put another company's
     brand on this desk.
     Sampled: deep blue #180CC0, periwinkle #786CE4, cyan #0CF0E4.
     Measured, they divide the work by ground, which is unusually tidy:
       deep blue  white-on 11.34 · on canvas 9.79 · on the dark rail 1.57
       cyan       on the dark rail 12.34 · unusable on light
       periwinkle fails as text everywhere (4.15 / 3.58) — decoration only
     So the canvas takes the deep blue and the rail takes the cyan. The
     brand supplies a colour for each, and neither is the teal the old
     theme used, which was not in the logo at all.
     (Superseded: One accent. Still the brand's teal family — this is DNAi's colour and
     it is on the wordmark — but taken deep and desaturated so it reads as
     printed ink rather than the neon cyan every generated app ships with.
     White on it is 8.2:1, so a primary button is legible without a shout. */
  --v2-accent:hsl(244 88% 40%);
  --v2-accent-ink:hsl(244 85% 36%);
  --v2-accent-soft:hsl(244 70% 95%);
  --v2-accent-line:hsl(244 45% 82%);
  /* semantic */
  --v2-ok:hsl(150 60% 28%);   --v2-ok-soft:hsl(150 55% 94%);  --v2-ok-dot:hsl(150 60% 42%);
  --v2-warn:hsl(32 85% 32%);  --v2-warn-soft:hsl(38 90% 94%); --v2-warn-dot:hsl(36 90% 50%);
  --v2-bad:hsl(0 65% 42%);    --v2-bad-soft:hsl(0 70% 96%);   --v2-bad-dot:hsl(0 72% 52%);
  --v2-info:hsl(221 70% 45%); --v2-info-soft:hsl(221 80% 96%);--v2-info-dot:hsl(221 85% 60%);
  /* shape, depth, type scale */
  --v2-r-control:6px; --v2-r-surface:10px; --v2-r-overlay:12px;
  --v2-shadow-overlay:0 12px 32px hsl(222 30% 11% / .14);
  --v3-shadow-1:0 1px 2px hsl(222 30% 11% / .06);
  --v3-shadow-2:0 8px 24px hsl(222 30% 11% / .12);
  /* The type scale that actually reaches the screen. v3.css loads after
     v2.css, so THESE seven values win and v2.css's are never seen — a trap
     that cost two bugs in one afternoon: --v2-faint fixed in the losing
     file, and a round-13 commit message quoting v2's numbers as if they
     were the app's. --v2-t-small was the only step v3 never listed, so it
     fell through from v2's :root and worked by luck. It is explicit now.
     Check 8 in check-css.mjs fails any token defined twice with different
     values and no comment saying which wins. */
  --v2-t-label:11px; --v2-t-small:12px; --v2-t-body:13px; --v2-t-entity:14px;
  --v2-t-title:16px; --v2-t-say:20px; --v2-t-display:24px;
  /* --on-bright is the ink that sits ON the accent — chips, badges, the
     filter count, the "N closed" pill, eight places in all. It was defined
     once, near-black, when the accent was a light teal that a dark ink read
     well against. R3 made the accent a deep brand blue and left this
     behind, so every one of those eight became 1.57:1. White measures
     11.34:1 on it. Nothing here is a preference; both numbers are the
     reason. */
  --on-bright:#fff;
  --v3-rail:240px; --v3-rail-min:56px; --v3-top:52px;
  --v3-ease:cubic-bezier(.2,.8,.2,1);
  color-scheme:light;
}
html[data-theme="dark"] body.v3{
  /* The dark theme keeps the cyan accent, which wants a dark ink. */
  --on-bright:hsl(220 14% 10%);
  --v2-bg:hsl(222 40% 7%);             /* blue-black, never #000 */
  --v2-panel:hsl(221 36% 11%);
  --v2-line2:hsl(220 30% 15%);
  --v2-ink:hsl(210 25% 93%);
  --v2-sub:hsl(215 16% 70%);
  /* R31 · 50% → 55%. This is the definition that WINS — v3.css loads after
     v2.css, so the matching token in v2.css never reaches the screen, and
     my first attempt at this fix went into the losing file. Measured on the
     live app across nine rooms: 454 text nodes failed WCAG AA and eleven
     colour/class pairs caused all of them; this token caused most.
     At 50% it is 4.58:1 on the page ground — a pass — but 4.24:1 on a panel
     and 3.80:1 on the muted fill, and almost everything in this app sits on
     one of those two. 55% clears 4.5:1 on all three. */
  --v2-faint:hsl(215 12% 55%);
  --v2-line:hsl(218 22% 20%);
  --v2-accent:hsl(176 70% 55%);
  --v2-accent-ink:hsl(176 80% 72%);
  --v2-accent-soft:hsl(178 50% 14%);
  --v2-accent-line:hsl(178 45% 26%);
  --v2-ok:hsl(152 55% 66%);   --v2-ok-soft:hsl(156 40% 13%);  --v2-ok-dot:hsl(152 55% 55%);
  --v2-warn:hsl(38 85% 70%);  --v2-warn-soft:hsl(35 45% 14%); --v2-warn-dot:hsl(38 84% 62%);
  --v2-bad:hsl(355 88% 76%);  --v2-bad-soft:hsl(353 40% 15%); --v2-bad-dot:hsl(355 80% 68%);
  --v2-info:hsl(212 90% 74%); --v2-info-soft:hsl(214 45% 15%);--v2-info-dot:hsl(212 88% 66%);
  --v2-shadow-overlay:0 16px 48px hsl(222 60% 2% / .7);
  --v3-shadow-1:0 1px 2px hsl(222 60% 2% / .5);
  --v3-shadow-2:0 8px 24px hsl(222 60% 2% / .6);
  color-scheme:dark;
}
/* the families index.html and legacy.css still read */
body.v3{
  --bg:var(--v2-bg); --panel:var(--v2-panel); --shell:var(--v2-panel);
  --ink:var(--v2-ink); --sub:var(--v2-sub); --faint:var(--v2-faint);
  --line:var(--v2-line); --line2:var(--v2-line2);
  --accent:var(--v2-accent); --accent-soft:var(--v2-accent-soft);
  --r:var(--v2-r-surface);
}
body.v3{background:var(--v2-bg);color:var(--v2-ink);font-size:var(--v2-t-body)}
body.v3 h1,body.v3 h2,body.v3 h3,body.v3 h4{font-family:var(--v2-sans);letter-spacing:-.01em;font-weight:600}
body.v3 .ttl,body.v3 .v2-pagehead h2{font-family:var(--v2-sans)}
body.v3 :focus-visible{outline:2px solid var(--v2-accent);outline-offset:1px;border-radius:var(--v2-r-control)}
@media (prefers-reduced-motion:reduce){body.v3 *{transition-duration:0s!important;animation-duration:0s!important}}

/* ── 2 · the rail ───────────────────────────────────────────────────── */
body.v3 .app{grid-template-columns:var(--v3-rail) minmax(0,1fr);transition:grid-template-columns var(--v2-mid) var(--v3-ease)}
body.v3 .app > aside{padding:var(--v2-s3) var(--v2-s2) var(--v2-s3);gap:0;background:var(--v2-panel);border-right:1px solid var(--v2-line);position:sticky;top:0;height:100vh;overflow-y:auto;overflow-x:hidden;scrollbar-width:thin}
body.v3 .brand{padding:var(--v2-s1) var(--v2-s2) var(--v2-s3);display:flex;align-items:center;gap:var(--v2-s2);line-height:1.1}
body.v3 .brand-n{font:800 var(--v2-t-entity)/1 var(--v2-sans);letter-spacing:-.02em}
body.v3 .brand-tag{font-size:var(--v2-t-label);letter-spacing:.06em;color:var(--v2-faint);text-transform:uppercase;margin:0}
body.v3 .navlbl{font-size:var(--v2-t-label);letter-spacing:.07em;text-transform:uppercase;color:var(--v2-faint);margin:var(--v2-s3) var(--v2-s2) var(--v2-s1);font-weight:600}
body.v3 .navitem{display:flex;align-items:center;gap:var(--v2-s2);padding:var(--v2-s1h) var(--v2-s2);min-height:32px;border-radius:8px;font-size:var(--v2-t-body);font-weight:500;color:var(--v2-sub);border:0;background:none;width:100%;text-align:left;transition:background var(--v2-fast) var(--v3-ease),color var(--v2-fast) var(--v3-ease)}
body.v3 .navitem:hover{background:var(--v2-line2);color:var(--v2-ink)}
body.v3 .navitem.on{background:var(--v2-line2);color:var(--v2-ink);font-weight:600;box-shadow:none}
body.v3 .navitem i{width:16px;height:16px;flex:0 0 16px;display:grid;place-items:center;color:inherit;opacity:.85}
body.v3 .navitem i svg{width:16px;height:16px}
body.v3 .navitem .ct{margin-left:auto;font-size:var(--v2-t-label);font-weight:600;color:var(--v2-faint);background:none;padding:0;min-width:0}
body.v3 .navitem.navchild{padding-left:var(--v2-s6)}
body.v3 #arenas .navitem{font-size:var(--v2-t-small);min-height:28px}
body.v3 .app > aside .foot{margin-top:auto}
body.v3 .rail-tg{position:static;width:28px;height:28px;border-radius:8px;border:1px solid var(--v2-line);background:var(--v2-panel);color:var(--v2-sub);font-size:var(--v2-t-entity);order:99;margin:var(--v2-s3) 0 0 auto}
body.v3 .rail-tg:hover{color:var(--v2-ink);background:var(--v2-line2)}
body.v3 #rail-open{display:none!important}
/* collapsed = an icon rail, not a hidden one */
body.v3.rail-off .app{grid-template-columns:var(--v3-rail-min) minmax(0,1fr)}
body.v3.rail-off aside{display:flex!important;padding:var(--v2-s3) var(--v2-s2) var(--v2-s3);width:auto}
body.v3.rail-off .brand{justify-content:center;padding:var(--v2-s1) 0 var(--v2-s3)}
body.v3.rail-off .brand-tag,body.v3.rail-off .navlbl,body.v3.rail-off .navitem .ct,body.v3.rail-off #arenas-lbl{display:none}
body.v3.rail-off .navitem{font-size:0;gap:0;justify-content:center;padding:var(--v2-s2) 0;min-height:36px}
body.v3.rail-off .navitem i{width:18px;height:18px;flex-basis:18px}
body.v3.rail-off .navitem i svg{width:18px;height:18px}
body.v3.rail-off .navitem.navchild{padding-left:0}
body.v3.rail-off #arenas{display:none}
body.v3.rail-off .rail-tg{margin:var(--v2-s3) auto 0;transform:rotate(180deg)}
body.v3.rail-off .utility{padding-left:0}
body.v3.rail-off .app>main{grid-column:2}

/* ── 3 · the top bar and the title row ───────────────────────────────── */
body.v3 .top{background:var(--v2-bg)!important;border-bottom:0!important;padding:0 var(--v2-s5) 0!important;position:static!important}
body.v3 .utility{height:var(--v3-top);padding:0;margin:0 -var(--v2-s5);padding:0 var(--v2-s5);border-bottom:1px solid var(--v2-line);background:var(--v2-panel);gap:var(--v2-s3);position:sticky;top:0;z-index:30}
body.v3 .crumb{font-size:var(--v2-t-small);color:var(--v2-sub);gap:var(--v2-s1h)}
body.v3 .crumb b{color:var(--v2-ink);font-weight:600}
body.v3 .crumb .crumb-l{color:var(--v2-sub)}
body.v3 .crumb span{color:var(--v2-faint)}
body.v3 .usearch{height:32px;width:min(360px,34vw);border-radius:8px;background:var(--v2-bg);border:1px solid var(--v2-line);padding:0 var(--v2-s2);gap:var(--v2-s2)}
body.v3 .usearch:focus-within{border-color:var(--v2-accent);box-shadow:0 0 0 3px var(--v2-accent-soft)}
body.v3 .usearch input{font-size:var(--v2-t-body)}
body.v3 .usearch kbd{font:500 var(--v2-t-label)/1 var(--v2-mono);color:var(--v2-faint);border:1px solid var(--v2-line);border-radius:4px;padding:var(--v2-s0) var(--v2-s1);white-space:nowrap}
body.v3 .uav{height:32px;padding:0 var(--v2-s2) 0 var(--v2-s0);border-radius:999px;border-color:transparent;color:var(--v2-ink);font-size:var(--v2-t-small)}
body.v3 .uav:hover{background:var(--v2-line2);border-color:transparent}
body.v3 .uav-i{width:26px;height:26px;flex-basis:26px;font-size:var(--v2-t-label);background:var(--v2-accent-soft);color:var(--v2-accent-ink)}
body.v3 .v3-ib{height:32px;width:32px;display:grid;place-items:center;border:1px solid transparent;border-radius:8px;background:none;color:var(--v2-sub);cursor:pointer}
body.v3 .v3-ib:hover{background:var(--v2-line2);color:var(--v2-ink)}
body.v3 .v3-ib svg{width:16px;height:16px}
body.v3 .v3-new{height:32px;display:inline-flex;align-items:center;gap:var(--v2-s1h);padding:0 var(--v2-s3) 0 var(--v2-s2);border:0;border-radius:8px;background:var(--v2-accent);color:#fff;font:600 var(--v2-t-body) var(--v2-sans);cursor:pointer;white-space:nowrap;box-shadow:var(--v3-shadow-1)}
html[data-theme="dark"] body.v3 .v3-new{color:hsl(222 40% 7%)}
body.v3 .v3-new:hover{filter:brightness(1.06)}
body.v3 .v3-new svg{width:14px;height:14px}
body.v3 .v3-menu{position:absolute;top:calc(100% + 6px);right:0;min-width:220px;background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:10px;box-shadow:var(--v3-shadow-2);padding:var(--v2-s1h);z-index:60}
body.v3 .v3-menu button{display:flex;align-items:center;gap:var(--v2-s2);width:100%;padding:var(--v2-s2) var(--v2-s2);border:0;background:none;border-radius:7px;font:500 var(--v2-t-body) var(--v2-sans);color:var(--v2-ink);text-align:left;cursor:pointer}
body.v3 .v3-menu button:hover{background:var(--v2-line2)}
body.v3 .v3-menu button small{margin-left:auto;color:var(--v2-faint);font-size:var(--v2-t-label)}
body.v3 .v3-menu .v3-mh{font-size:var(--v2-t-label);letter-spacing:.06em;text-transform:uppercase;color:var(--v2-faint);padding:var(--v2-s1h) var(--v2-s2) var(--v2-s0);font-weight:600}
body.v3 .v3-newwrap{position:relative}
body.v3 .uav-menu{border-radius:10px;box-shadow:var(--v3-shadow-2);border:1px solid var(--v2-line)}
/* the title row: name, meta, actions — one line, 48px */
body.v3 .toprow{align-items:center;gap:var(--v2-s3);padding:var(--v2-s3) 0 var(--v2-s1h);flex-wrap:nowrap}
body.v3 .ttl{font-size:var(--v2-t-say);font-weight:700;letter-spacing:-.02em;line-height:1.2}
body.v3 .ttl-date,body.v3 .ttl-sub,body.v3 .topacts,body.v3 #tabs{display:none!important}
body.v3 .wrap{padding:var(--v2-s2) var(--v2-s5) 90px}
/* GovCon's own action row (Refresh · + Intake · sign out) moved into the top bar */
body.v3 .pd-navrow.actions-only{display:none!important}
body.v3 .v2-pagehead{margin:0 0 var(--v2-s3);padding:0;min-height:36px;display:flex;align-items:center;gap:var(--v2-s3);flex-wrap:wrap}
body.v3 .v2-pagehead h2{font-size:var(--v2-t-title);font-weight:600;margin:0}
body.v3 .v2-pagehead .meta{color:var(--v2-faint);font-size:var(--v2-t-small)}
/* the planner's wrong-coloured action buttons, wherever they still appear */
body.v3 .frictionbtn,body.v3 .capbtn{border:1px solid var(--v2-line);background:var(--v2-panel);color:var(--v2-ink);box-shadow:none}
body.v3 .newbtn{background:var(--v2-accent);color:#fff;box-shadow:none}

/* ── 4 · surfaces, buttons, chips, tabs: one rule each ───────────────── */
body.v3 .v2-block,body.v3 .pd-panel,body.v3 .stat,body.v3 .card,body.v3 .ccph-setup,body.v3 .st-card,body.v3 .today-num,body.v3 .ops-col,body.v3 .src2-card,body.v3 .ma-card{
  background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:var(--v2-r-surface);box-shadow:none}
body.v3 .pd-btn{border-radius:8px;font-weight:500;font-size:var(--v2-t-body);min-height:32px;padding:0 var(--v2-s3);border:1px solid var(--v2-line);background:var(--v2-panel);color:var(--v2-ink);box-shadow:none;transition:background var(--v2-fast) var(--v3-ease)}
body.v3 .pd-btn:hover{background:var(--v2-line2)}
body.v3 .pd-btn:not(.ghost):not(.sm):not(.danger),body.v3 .pd-btn.primary{background:var(--v2-accent);border-color:var(--v2-accent);color:#fff}
html[data-theme="dark"] body.v3 .pd-btn:not(.ghost):not(.sm):not(.danger){color:hsl(222 40% 7%)}
body.v3 .pd-btn:not(.ghost):not(.sm):not(.danger):hover{filter:brightness(1.06);background:var(--v2-accent)}
body.v3 .pd-btn.sm{min-height:28px;padding:0 var(--v2-s2);font-size:var(--v2-t-small)}
body.v3 .pd-btn.ghost{background:transparent;border-color:var(--v2-line)}
body.v3 .pd-btn.ghost:hover{background:var(--v2-line2)}
body.v3 .pd-linkbtn{color:var(--v2-accent-ink);font-weight:500}
body.v3 .pd-chip,body.v3 .dh2-chip,body.v3 .v2-ntype,body.v3 .find-srctag,body.v3 .ccph-chip{border-radius:999px;font-size:var(--v2-t-label);font-weight:500;padding:var(--v2-s0) var(--v2-s2);border:1px solid var(--v2-line);background:var(--v2-line2);color:var(--v2-sub)}
body.v3 .pd-chip.ok{background:var(--v2-ok-soft);color:var(--v2-ok);border-color:transparent}
body.v3 .pd-seg{background:var(--v2-line2);border:1px solid var(--v2-line);border-radius:8px;padding:var(--v2-s0);gap:0}
body.v3 .pd-seg button{border-radius:6px;padding:var(--v2-s1) var(--v2-s2);font-size:var(--v2-t-small);font-weight:500;color:var(--v2-sub);background:none;border:0;min-height:26px}
body.v3 .pd-seg button.on{background:var(--v2-panel);color:var(--v2-ink);box-shadow:var(--v3-shadow-1)}
/* secondary tabs: one style everywhere (room tabs, sub-tabs, card tabs) */
body.v3 .pd-subtabs2,body.v3 .pd-dtabs,body.v3 .pd-srctabs,body.v3 .bt-roomnav{display:flex;gap:var(--v2-s0);border-bottom:1px solid var(--v2-line);margin:0 0 var(--v2-s3);padding:0;overflow-x:auto;scrollbar-width:none;flex-wrap:nowrap;background:none;border-radius:0;box-shadow:none}
body.v3 .pd-subtabs2::-webkit-scrollbar,body.v3 .pd-dtabs::-webkit-scrollbar,body.v3 .pd-srctabs::-webkit-scrollbar{display:none}
body.v3 .pd-subtabs2 button,body.v3 .pd-dtabs button,body.v3 .pd-srctabs button,body.v3 .bt-roomnav button{flex:0 0 auto;display:inline-flex;align-items:center;gap:var(--v2-s1h);padding:var(--v2-s2) var(--v2-s2);margin-bottom:-var(--v2-s0);border:0;border-bottom:2px solid transparent;border-radius:0;background:none;font:500 var(--v2-t-body) var(--v2-sans);color:var(--v2-sub);white-space:nowrap;min-height:36px;box-shadow:none}
body.v3 .pd-subtabs2 button:hover,body.v3 .pd-dtabs button:hover,body.v3 .pd-srctabs button:hover,body.v3 .bt-roomnav button:hover{color:var(--v2-ink);background:none}
body.v3 .pd-subtabs2 button.on,body.v3 .pd-dtabs button.on,body.v3 .pd-srctabs button.on,body.v3 .bt-roomnav button.on{color:var(--v2-ink);font-weight:600;border-bottom-color:var(--v2-accent);background:none}
body.v3 .pd-srctabs button i{width:14px;height:14px;opacity:.7}
body.v3 .pd-srctabs button i svg{width:14px;height:14px}
body.v3 .pd-tabn{background:var(--v2-line2);color:var(--v2-sub);border-radius:999px;font-size:var(--v2-t-label);font-weight:600;padding:var(--v2-s0) var(--v2-s1h);min-width:18px;text-align:center}
body.v3 .pd-tabn.red{background:var(--v2-bad-soft);color:var(--v2-bad)}
body.v3 input,body.v3 select,body.v3 textarea{border-radius:var(--v2-r-control);border:1px solid var(--v2-line);background:var(--v2-panel);color:var(--v2-ink);font-family:var(--v2-sans)}
body.v3 input:focus,body.v3 select:focus,body.v3 textarea:focus{border-color:var(--v2-accent);box-shadow:0 0 0 3px var(--v2-accent-soft);outline:none}
body.v3 .pd-note,body.v3 .pd-hint{color:var(--v2-sub);font-size:var(--v2-t-small)}
body.v3 .pd-modal,body.v3 dialog{border-radius:var(--v2-r-overlay);border:1px solid var(--v2-line);box-shadow:var(--v2-shadow-overlay)}
/* the three floating controls on desktop: one quiet corner */
body.v3 .fb-fab{width:36px;height:36px;font-size:var(--v2-t-title);border:1px solid var(--v2-line);background:var(--v2-panel);color:var(--v2-sub);box-shadow:var(--v3-shadow-1)}
body.v3 .ccph-pill{padding:var(--v2-s1h) var(--v2-s3);border-radius:999px;background:var(--v2-panel);border:1px solid var(--v2-line);color:var(--v2-ink);box-shadow:var(--v3-shadow-1);font-size:var(--v2-t-small)}
body.v3 .ccph-pill svg{color:var(--v2-ok-dot)}

/* ── 5 · iPad: the rail is icons by default (set by shell-nav) ────────── */
@media (min-width:861px) and (max-width:1279px){
  body.v3 .usearch{width:min(260px,30vw)}
}

/* ── 6 · phone ───────────────────────────────────────────────────────── */
@media (max-width:860px){
  body.v3 .app{grid-template-columns:minmax(0,1fr)}
  /* the rail is the off-canvas drawer here (mobile.css) — never in the grid */
  body.v3 .app > aside{position:fixed;height:auto;top:0;bottom:0}
  body.v3.rail-off aside{display:flex!important;width:min(78vw,320px);padding:var(--v2-s3)}
  body.v3.rail-off .app{grid-template-columns:minmax(0,1fr)}
  body.v3.rail-off .app>main{grid-column:1}
  body.v3.rail-off .navitem{font-size:var(--v2-t-entity);justify-content:flex-start;gap:var(--v2-s3);padding:var(--v2-s3)}
  body.v3 .rail-tg{display:none}
  body.v3 .top{padding:0 var(--v2-s4) 0!important}
  body.v3 .utility{margin:0 -var(--v2-s4);padding:0 var(--v2-s2) 0 var(--v2-s1h);height:48px;gap:var(--v2-s1h)}
  body.v3 .utility .crumb{display:none}
  body.v3 .usearch{width:auto;flex:1;height:34px}
  body.v3 .usearch kbd{display:none}
  body.v3 .v3-new span{display:none}
  body.v3 .v3-new{padding:0;width:34px;height:34px;justify-content:center}
  body.v3 .v3-refresh{display:none}
  body.v3 .toprow{padding:var(--v2-s2) 0 var(--v2-s1)}
  body.v3 .ttl{font-size:var(--v2-t-title)}
  body.v3 .wrap{padding:6px 16px calc(96px + env(safe-area-inset-bottom,0px))}
  body.v3 .v2-pagehead h2{font-size:var(--v2-t-entity)}
  /* no floating buttons on the phone: the toolbar has "+", More has help, the phone shows only on a call */
  body.v3 #ma-fab,body.v3 .fab,body.v3 .qadd,body.v3 .fb-fab,body.v3 .ccph-pill{display:none!important}
  body.v3 .fb-panel{bottom:calc(84px + env(safe-area-inset-bottom,0px))}
  body.v3 #cc-stale{bottom:calc(84px + env(safe-area-inset-bottom,0px))}
  /* the bottom bar: five flat items, no frosted pill */
  body.v3 nav.bottom{left:0;right:0;bottom:0;border-radius:0;margin:0;padding:6px 6px calc(6px + env(safe-area-inset-bottom,0px));background:var(--v2-panel);border-top:1px solid var(--v2-line);box-shadow:none;backdrop-filter:none}
  body.v3 nav.bottom button{border-radius:10px;gap:var(--v2-s0);padding:var(--v2-s1h) var(--v2-s0);font-size:var(--v2-t-label);font-weight:500;color:var(--v2-sub);min-height:48px}
  body.v3 nav.bottom button i svg{width:22px;height:22px}
  body.v3 nav.bottom button.on{background:none;color:var(--v2-accent-ink);font-weight:600}
  body.v3 nav.bottom button.on i{color:var(--v2-accent)}
  /* More: the app grid, flat */
  body.v3 #mapps{padding-bottom:calc(90px + env(safe-area-inset-bottom,0px))}
  body.v3 #mapps .ma-head h1{font:700 var(--v2-t-say)/1.2 var(--v2-sans);margin:var(--v2-s3) var(--v2-s0) var(--v2-s2)}
  body.v3 #mapps .ma-card{border-radius:12px;padding:var(--v2-s3)}
  body.v3 #mapps .ma-ic{width:48px;height:48px;border-radius:12px;background:var(--v2-line2);color:var(--v2-ink)}
  body.v3 #mapps .ma-ic svg{width:22px;height:22px}
  body.v3 #mapps .ma-app span:last-child{font-size:var(--v2-t-label)}
  /* tab rows scroll sideways instead of wrapping */
  body.v3 .pd-subtabs2,body.v3 .pd-dtabs,body.v3 .pd-srctabs,body.v3 .bt-roomnav{flex-wrap:nowrap;overflow-x:auto}
  /* R18 · the same row on a phone, allowed to wrap */
  body.v3 .today-nums{gap:var(--v2-s1h)}
  body.v3 .today-num{padding:var(--v2-s1) var(--v2-s2)}
}

/* ── 7 · slice 2: one table, one toolbar ─────────────────────────────── */
/* Every list in the app on one table rule: hairlines, 36px rows, uppercase
   11px headers, hover, tabular numbers, the first text column carries the
   identity. Classes listed are every <table class> the renderers emit. */
body.v3 .sope-score,body.v3 .pd-table,body.v3 .find-table,body.v3 .src2-table,body.v3 .pt2-table,body.v3 .v2-table,body.v3 .bt-t,body.v3 .prc-t,body.v3 .sq-table,body.v3 .pd-gtable,body.v3 .intel-table{
  width:100%;border-collapse:separate;border-spacing:0;font-size:var(--v2-t-body);background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:10px;overflow:hidden;color:var(--v2-ink)}
body.v3 .sope-score th,body.v3 .pd-table th,body.v3 .find-table th,body.v3 .src2-table th,body.v3 .pt2-table th,body.v3 .v2-table th,body.v3 .bt-t th,body.v3 .prc-t th,body.v3 .sq-table th,body.v3 .pd-gtable th{
  position:sticky;top:0;z-index:2;text-align:left;font:600 var(--v2-t-label)/1.2 var(--v2-sans);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint);padding:var(--v2-s2) var(--v2-s3);background:var(--v2-panel);border-bottom:1px solid var(--v2-line);white-space:nowrap}
body.v3 .sope-score td,body.v3 .pd-table td,body.v3 .find-table td,body.v3 .src2-table td,body.v3 .pt2-table td,body.v3 .v2-table td,body.v3 .bt-t td,body.v3 .prc-t td,body.v3 .sq-table td,body.v3 .pd-gtable td{
  padding:var(--v2-s2) var(--v2-s3);border-bottom:1px solid var(--v2-line2);vertical-align:middle;line-height:1.35;color:var(--v2-ink);font-size:var(--v2-t-body);background:transparent}
body.v3 .sope-score tbody tr:last-child td,body.v3 .pd-table tbody:last-child tr:last-child td,body.v3 .find-table tbody tr:last-child td,body.v3 .pt2-table tr:last-child td,body.v3 .v2-table tr:last-child td{border-bottom:0}
body.v3 .sope-score tbody tr:hover td,body.v3 .pd-table tr:hover td,body.v3 .find-table tbody tr:hover td,body.v3 .pt2-table tbody tr:hover td,body.v3 .v2-table tbody tr:hover td,body.v3 .bt-t tbody tr:hover td{background:var(--v2-line2)}
body.v3 .pd-table tr[onclick],body.v3 .sope-score tr[onclick],body.v3 .pt2-table tr[onclick]{cursor:pointer}
body.v3 .pd-table .pd-grouprow td{background:var(--v2-bg);font:600 var(--v2-t-label)/1.2 var(--v2-sans);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-sub);padding:var(--v2-s2) var(--v2-s3)}
body.v3 .pd-table .pd-grouprow .pd-n{color:var(--v2-faint);font-weight:500;margin-left:var(--v2-s1h)}
body.v3 .pd-table .pd-td-t,body.v3 .find-table td b,body.v3 .sope-score td b{font-weight:600;color:var(--v2-ink)}
body.v3 .pd-table .pd-td-t{max-width:420px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
body.v3 td.num,body.v3 .find-due,body.v3 .pd-table td:nth-child(6),body.v3 .pd-table td:nth-child(7){font-variant-numeric:tabular-nums}
body.v3 .pd-table td:nth-child(n+3),body.v3 .find-table td:nth-child(3){color:var(--v2-sub)}
body.v3 .pd-table td:nth-child(n+3):empty::before{content:"–";color:var(--v2-faint)}
body.v3 .sope-scorewrap,body.v3 .pd-tablewrap,body.v3 .pt2-tablewrap,body.v3 .find-list{overflow-x:auto;margin:0;border:0;background:none;scrollbar-width:thin}
body.v3 .pd-srchead{display:flex;align-items:baseline;gap:var(--v2-s2);padding:0 0 var(--v2-s2);font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .pd-srchead b{color:var(--v2-ink);font-size:var(--v2-t-body)}
body.v3 .find-table td a{color:var(--v2-ink);text-decoration:none}
body.v3 .find-table td a:hover{color:var(--v2-accent-ink);text-decoration:underline}
/* R16 · Urgency is a property of the ROW's date, so it is carried by the
   cell, not by a `tr.hot` wrapper that also means "within five days".
   This list is sorted soonest-first, so a five-day threshold paints the
   whole first screen red every single day — true, and useless, which is
   the same shape as OVERDUE on 588 of 618 task cards. Red stops at
   tomorrow. The rules are scoped past `tr.hot` because that selector
   carries four classes and would otherwise keep winning. */
body.v3 .find-table .find-due{color:var(--v2-sub);font-weight:600}
body.v3 .find-table .find-due.near{color:var(--v2-ink)}
body.v3 .find-table .find-due.soon{color:var(--v2-bad)}
body.v3 .find-table .find-due i{color:var(--v2-faint);font-style:normal;font-weight:500}
body.v3 .find-table .find-due.soon i{color:var(--v2-bad)}
body.v3 .find-srctag{font-size:var(--v2-t-label);padding:var(--v2-s0) var(--v2-s1h)}
body.v3 .find-srctag.sam{background:var(--v2-accent-soft);color:var(--v2-accent-ink);border-color:transparent}
body.v3 .find-srctag.tx_esbd{background:var(--v2-warn-soft);color:var(--v2-warn);border-color:transparent}
body.v3 .find-srctag.opengov{background:var(--v2-info-soft);color:var(--v2-info);border-color:transparent}
body.v3 .find-srctag.alerts{background:var(--v2-line2);color:var(--v2-sub);border-color:transparent}
/* the view toolbar: view selector · filters · hint */
body.v3 .v3-toolbar{display:flex;align-items:center;gap:var(--v2-s2);flex-wrap:wrap;margin:0 0 var(--v2-s2);min-height:36px}
body.v3 .v3-view{display:inline-flex;align-items:center;gap:var(--v2-s1h);height:32px;padding:0 var(--v2-s1h) 0 var(--v2-s2);border:1px solid var(--v2-line);border-radius:8px;background:var(--v2-panel);font-weight:600;font-size:var(--v2-t-body);color:var(--v2-ink)}
body.v3 .v3-view i{width:14px;height:14px;color:var(--v2-sub)}
body.v3 .v3-view i svg{width:14px;height:14px}
body.v3 .v3-view select{border:0;background:transparent;font:600 var(--v2-t-body) var(--v2-sans);color:var(--v2-ink);padding:0 var(--v2-s1);height:30px;cursor:pointer;box-shadow:none}
body.v3 .v3-view select:focus{box-shadow:none}
body.v3 .v3-tbhint{color:var(--v2-faint);font-size:var(--v2-t-small);flex:1 1 320px;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
body.v3 .v3-feedwarn{border:1px solid var(--v2-warn-dot);color:var(--v2-warn);background:var(--v2-warn-soft);border-radius:999px;font:600 var(--v2-t-label) var(--v2-sans);padding:var(--v2-s1) var(--v2-s2);cursor:pointer}
body.v3 .pd-feedhealth{margin:0 0 var(--v2-s2)}
/* filter rows everywhere become one quiet toolbar row */
body.v3 .pd-filters,body.v3 .pd-views,body.v3 .find-bar,body.v3 .pd-srcbar,body.v3 .src2-bar,body.v3 .ibx-lh,body.v3 .bt-filters{display:flex;flex-wrap:wrap;align-items:center;gap:var(--v2-s1h);margin:0 0 var(--v2-s2);padding:0;background:none;border:0;box-shadow:none}
body.v3 .pd-filters select,body.v3 .pd-srcbar select,body.v3 .src2-bar select,body.v3 .find-bar select{height:30px;border-radius:8px;border:1px solid var(--v2-line);background:var(--v2-panel);font:500 var(--v2-t-small) var(--v2-sans);color:var(--v2-ink);padding:0 var(--v2-s5) 0 var(--v2-s2);max-width:220px}
body.v3 .pd-filters .sep{display:none}
body.v3 .pd-filters .pd-chip,body.v3 .pd-views .pd-chip,body.v3 .ibx-chips button,body.v3 .find-src{height:28px;display:inline-flex;align-items:center;padding:0 var(--v2-s2);border-radius:999px;border:1px solid var(--v2-line);background:var(--v2-panel);color:var(--v2-sub);font:500 var(--v2-t-small) var(--v2-sans);cursor:pointer;opacity:1}
body.v3 .pd-filters .pd-chip.on,body.v3 .pd-views .pd-chip.on,body.v3 .ibx-chips button.on,body.v3 .find-src.on{background:var(--v2-accent-soft);border-color:var(--v2-accent-line);color:var(--v2-accent-ink);font-weight:600}
body.v3 .find-src:not(.on){opacity:.75}
body.v3 .find-src b{margin-left:var(--v2-s1);font-weight:600}
body.v3 .pd-clearf{border:0;background:none;color:var(--v2-accent-ink);font:500 var(--v2-t-small) var(--v2-sans);cursor:pointer}
body.v3 .find-bar .pd-srcf{display:flex;align-items:center;gap:var(--v2-s1h)}
body.v3 .find-bar .pd-srcf label{font-size:var(--v2-t-label);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint);font-weight:600}
body.v3 .find-bar .pd-srcf.grow{flex:1 1 260px}
body.v3 .find-bar input{height:30px;border-radius:8px;font-size:var(--v2-t-body);padding:0 var(--v2-s2)}
body.v3 .find-hint{margin:0 0 var(--v2-s2);font-size:var(--v2-t-small);color:var(--v2-faint)}
body.v3 .src2-layout{gap:var(--v2-s4)}
body.v3 .src2-bar .src2-f span{font-size:var(--v2-t-label);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint);font-weight:600}
/* ── phone: the two big tables become card lists ── */
@media (max-width:860px){
  body.v3 .find-table,body.v3 .pd-table{border:0;background:none;border-radius:0}
  body.v3 .find-table thead,body.v3 .pd-table thead{display:none}
  body.v3 .find-table,body.v3 .find-table tbody,body.v3 .find-table tr,body.v3 .find-table td,
  body.v3 .pd-table,body.v3 .pd-table tbody,body.v3 .pd-table tr,body.v3 .pd-table td{display:block;width:100%}
  body.v3 .find-table tr,body.v3 .pd-table tr:not(.pd-grouprow){border:1px solid var(--v2-line);border-radius:10px;background:var(--v2-panel);padding:var(--v2-s2) var(--v2-s3);margin:0 0 var(--v2-s2);position:relative}
  body.v3 .find-table td,body.v3 .pd-table td{border:0;padding:var(--v2-s0) 0;font-size:var(--v2-t-small);color:var(--v2-sub)}
  body.v3 .find-table td:nth-child(1){position:absolute;top:10px;right:10px;width:auto}
  body.v3 .find-table td:nth-child(2){padding-right:88px;font-size:var(--v2-t-entity)}
  body.v3 .find-table td:nth-child(2) b{display:block;color:var(--v2-ink)}
  body.v3 .find-table td:nth-child(5){padding-top:var(--v2-s2)}
  body.v3 .find-table td:nth-child(5) .pd-btn{width:100%}
  body.v3 .find-due i{display:inline;margin-left:var(--v2-s1h)}
  body.v3 .pd-table .pd-grouprow td{padding:var(--v2-s3) 0 var(--v2-s1h);background:none}
  body.v3 .pd-table td:nth-child(1){position:absolute;top:10px;right:10px;width:auto}
  body.v3 .pd-table td:nth-child(2){padding-right:60px;font-size:var(--v2-t-entity);color:var(--v2-ink);max-width:none}
  body.v3 .pd-table td:nth-child(3)::before{content:"Agency · "}
  body.v3 .pd-table td:nth-child(4)::before{content:"Set-aside · "}
  body.v3 .pd-table td:nth-child(5)::before{content:"Due · "}
  body.v3 .pd-table td:nth-child(n+6){display:none}
  body.v3 .pd-table td:nth-child(n+3)::before{color:var(--v2-faint)}
  body.v3 .v3-tbhint{display:none}
  body.v3 .v3-toolbar{margin-bottom:var(--v2-s2)}
}

/* ── 8 · slice 3: the board ─────────────────────────────────────────── */
/* KPI tiles → one 36px stat strip (four numbers inline, still clickable) */
body.v3 .ops-kpis{display:flex;flex-wrap:wrap;gap:var(--v2-s1);margin:0 0 var(--v2-s2);padding:0;background:none;border:0}
body.v3 .ops-kpi{display:inline-flex;align-items:center;gap:var(--v2-s2);padding:0 var(--v2-s2);height:30px;border:1px solid var(--v2-line);border-radius:8px;background:var(--v2-panel);box-shadow:none;cursor:pointer;color:var(--v2-sub);font:500 var(--v2-t-small) var(--v2-sans)}
body.v3 .ops-kpi:hover{background:var(--v2-line2)}
body.v3 .ops-kpi[aria-pressed="true"]{border-color:var(--v2-accent-line);background:var(--v2-accent-soft);color:var(--v2-accent-ink)}
body.v3 .ops-kpi .ops-kpi-ic{display:none}
body.v3 .ops-kpi .ops-kpi-b{display:flex;flex-direction:row-reverse;align-items:center;gap:var(--v2-s1h)}
body.v3 .ops-kpi .ops-kpi-l{font-size:var(--v2-t-small);letter-spacing:0;text-transform:none;color:inherit;font-weight:500}
body.v3 .ops-kpi b{font-size:var(--v2-t-body);font-weight:700;color:var(--v2-ink);font-variant-numeric:tabular-nums}
body.v3 .ops-kpi b.live{color:var(--v2-ink)}
body.v3 .ops-kpi .ops-kpi-s{display:none}
/* the filter toolbar */
body.v3 .v3-filterbtn{display:inline-flex;align-items:center;gap:var(--v2-s1h);height:30px;padding:0 var(--v2-s2);border:1px solid var(--v2-line);border-radius:8px;background:var(--v2-panel);font:500 var(--v2-t-small) var(--v2-sans);color:var(--v2-ink);cursor:pointer}
body.v3 .v3-filterbtn svg{width:14px;height:14px;color:var(--v2-sub)}
body.v3 .v3-filterbtn.on{border-color:var(--v2-accent-line);background:var(--v2-accent-soft);color:var(--v2-accent-ink)}
body.v3 .v3-fchip i{font-style:normal;margin-left:var(--v2-s1);color:var(--v2-faint)}
body.v3 .v3-fsel{margin:-var(--v2-s1) 0 var(--v2-s2)}
body.v3 .ops-hidden{margin:0 0 var(--v2-s2);font-size:var(--v2-t-small)}
/* lanes: quiet columns on the ground, cards are the panels */
body.v3 .ops-boardwrap.lanes{margin-top:var(--v2-s1)}
body.v3 .ops-lanes .ops-col,body.v3 .ops-board2 .ops-col{background:var(--v2-line2);border:0;border-radius:12px;padding:0}
body.v3 .ops-colh{padding:var(--v2-s2) var(--v2-s3) var(--v2-s1h);gap:var(--v2-s2)}
body.v3 .ops-colh b{font-size:var(--v2-t-body);font-weight:600;color:var(--v2-ink)}
body.v3 .ops-colh .ops-n{margin-left:auto;font-size:var(--v2-t-label);font-weight:600;color:var(--v2-sub);background:var(--v2-panel);border-radius:999px;padding:var(--v2-s0) var(--v2-s1h);border:1px solid var(--v2-line)}
body.v3 .ops-colh .ops-sop{font-size:var(--v2-t-label);border:0;background:none;color:var(--v2-faint)}
body.v3 .ops-cards{padding:var(--v2-s1) var(--v2-s2) var(--v2-s2);gap:var(--v2-s2)}
body.v3 .ops-lanestage{padding:var(--v2-s2) var(--v2-s1) var(--v2-s0);border-top:0;font-size:var(--v2-t-label)}
body.v3 .ops-lanestage:first-child{padding-top:var(--v2-s0)}
body.v3 .ops-empty{color:var(--v2-faint)}
body.v3 .ops-empty i{display:none}
body.v3 .ops-empty b{font-weight:500;font-size:var(--v2-t-small)}
body.v3 .ops-empty span{font-size:var(--v2-t-label)}
body.v3 .ops-lanefoot{margin-top:var(--v2-s2)}
body.v3 .ops-nudge{width:28px;height:28px;border-radius:8px;border:1px solid var(--v2-line);background:var(--v2-panel);color:var(--v2-sub);box-shadow:var(--v3-shadow-1)}
/* the card: title, due, agency, estimate + who. Four facts, the rest on open. */
body.v3 .pd-card{padding:var(--v2-s2) var(--v2-s3);border-radius:10px;border:1px solid var(--v2-line);background:var(--v2-panel);box-shadow:var(--v3-shadow-1);gap:var(--v2-s1)}
body.v3 .pd-card:hover{border-color:var(--v2-accent-line);box-shadow:var(--v3-shadow-2)}
body.v3 .pd-card::before{display:none}
body.v3 .pd-card .pd-card-top{display:flex;align-items:center;gap:var(--v2-s1h);margin:0 0 var(--v2-s1)}
body.v3 .pd-card .pd-dl{font:600 var(--v2-t-label)/1 var(--v2-mono);padding:var(--v2-s0) var(--v2-s1h);border-radius:999px;background:var(--v2-line2);color:var(--v2-sub)}
body.v3 .pd-card .pd-dl.red{background:var(--v2-bad-soft);color:var(--v2-bad)}
body.v3 .pd-card .pd-dl.amber{background:var(--v2-warn-soft);color:var(--v2-warn)}
body.v3 .pd-card .pd-dl.green{background:var(--v2-ok-soft);color:var(--v2-ok)}
body.v3 .pd-card .pd-sa{font-size:var(--v2-t-label);padding:var(--v2-s0) var(--v2-s1h);border-radius:999px;background:var(--v2-line2);color:var(--v2-sub);border:0}
body.v3 .pd-card .pd-sa.held{background:var(--v2-accent-soft);color:var(--v2-accent-ink)}
body.v3 .pd-card .pd-review{font-size:var(--v2-t-label)}
body.v3 .pd-card .pd-card-t{font:600 var(--v2-t-body)/1.35 var(--v2-sans);color:var(--v2-ink);margin:0;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
body.v3 .pd-card .v2-ntype{display:none}
body.v3 .pd-card .pd-card-m{font-size:var(--v2-t-label);color:var(--v2-sub);margin:var(--v2-s0) 0 0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
body.v3 .pd-card .pd-card-sol{display:none}
body.v3 .pd-card .pd-card-due{display:none}
body.v3 .pd-card .sope-cardhint{display:none}
body.v3 .pd-card .pd-card-f{display:flex;align-items:center;gap:var(--v2-s2);margin:var(--v2-s2) 0 0;padding:var(--v2-s1h) 0 0;border-top:1px solid var(--v2-line2);font-size:var(--v2-t-label);color:var(--v2-sub)}
body.v3 .pd-card .pd-ct{display:inline-flex;align-items:center;gap:var(--v2-s0)}
body.v3 .pd-card .pd-ct i svg{width:12px;height:12px}
body.v3 .pd-card .pd-ct.red{color:var(--v2-bad)}
body.v3 .pd-card .pd-val{margin-left:auto;font:600 var(--v2-t-small) var(--v2-mono);color:var(--v2-ink);font-variant-numeric:tabular-nums}
body.v3 .pd-card .pd-who{display:inline-flex;align-items:center;gap:var(--v2-s1);margin-left:0}
body.v3 .pd-card .pd-who .pd-av{width:20px;height:20px;border-radius:50%;font-size:var(--v2-t-label);font-weight:700;display:grid;place-items:center;background:var(--who,var(--v2-line));color:var(--who-ink,#fff)}
body.v3 .pd-card .pd-who em{display:none}
body.v3 .pd-card .pd-who:not(.has) .pd-av{background:var(--v2-line2);color:var(--v2-faint);border:1px dashed var(--v2-line)}
body.v3 .pd-card .pd-warn{font-size:var(--v2-t-label);color:var(--v2-warn);margin:var(--v2-s1) 0 0}
body.v3 .pd-card[data-who]{border-left:3px solid var(--who);box-shadow:var(--v3-shadow-1)}
/* the red card rule, kept exactly */
body.v3 .pd-card.pd-urgent{background:var(--v2-bad-soft);border-color:var(--v2-bad-dot)}
body.v3 .pd-card.pd-urgent .pd-card-t{color:var(--v2-bad)}
html[data-theme="dark"] body.v3 .pd-card.pd-urgent{background:color-mix(in srgb,hsl(0 72% 52%) 18%,var(--v2-panel))}
body.v3 .ops-draghint{font-size:var(--v2-t-label);color:var(--v2-faint)}
/* the pipeline head: name · count · Board | List | Outreach */
body.v3 .v2-pagehead .pd-seg{margin-left:var(--v2-s1)}
@media (max-width:860px){
  body.v3 .ops-kpis{display:none}
  body.v3 .ops-lanes{scroll-snap-type:x mandatory;gap:var(--v2-s3);padding:0 0 var(--v2-s1)}
  body.v3 .ops-lanes .ops-col{flex:0 0 calc(100vw - 32px);min-width:0;scroll-snap-align:start}
  body.v3 .ops-nudge{display:none!important}
  body.v3 .v3-boardbar{overflow-x:auto;flex-wrap:nowrap;scrollbar-width:none;margin:0 -var(--v2-s4) var(--v2-s2);padding:0 var(--v2-s4)}
  body.v3 .v3-boardbar::-webkit-scrollbar{display:none}
  body.v3 .v3-boardbar .pd-chip,body.v3 .v3-filterbtn{flex:0 0 auto;white-space:nowrap}
}

/* slice 3 polish */
body.v3 .pd-card .pd-card-sep{display:none}
body.v3 .pd-card .pd-who{background:none;border:0;padding:0;flex:0 0 auto;box-shadow:none;border-radius:0}
body.v3 .pd-card .pd-val{font:500 var(--v2-t-label) var(--v2-mono);color:var(--v2-sub)}
body.v3 .pd-boardhead h2{display:none}
body.v3 .pd-boardhead .meta{font-size:var(--v2-t-body);color:var(--v2-sub)}
body.v3 .ops-lanes .ops-col{min-width:208px;flex:1 1 0}
body.v3 .ops-board2:not(.ops-lanes) .ops-col{flex:0 0 260px}

/* ── 9 · slice 4: the record ─────────────────────────────────────────── */
body.v3 .v3-under{pointer-events:none;user-select:none}
body.v3 .v3-scrim{position:fixed;inset:0;z-index:40;background:hsl(222 30% 11% / .22)}
body.v3 .v3-scrim.v3-in{animation:v3fade .18s var(--v3-ease)}
html[data-theme="dark"] body.v3 .v3-scrim{background:hsl(222 60% 2% / .5)}
body.v3 .v3-panel{position:fixed;top:0;right:0;bottom:0;z-index:41;width:min(800px,78vw);background:var(--v2-panel);border-left:1px solid var(--v2-line);box-shadow:var(--v2-shadow-overlay);overflow-y:auto;overscroll-behavior:contain;padding:0 var(--v2-s5) var(--v2-s7)}
body.v3 .v3-panel.v3-in{animation:v3slide .18s var(--v3-ease)}
@keyframes v3slide{from{transform:translateX(24px);opacity:0}to{transform:none;opacity:1}}
@keyframes v3fade{from{opacity:0}to{opacity:1}}
body.v3 .v3-panelbar{position:sticky;top:0;z-index:3;display:flex;align-items:center;gap:var(--v2-s2);height:44px;margin:0 -var(--v2-s5) var(--v2-s1);padding:0 var(--v2-s3);background:var(--v2-panel);border-bottom:1px solid var(--v2-line)}
body.v3 .v3-panelcrumb{font-size:var(--v2-t-small);color:var(--v2-sub);font-weight:500}
body.v3 .v3-panel .dh2-back{display:none}
body.v3 .v3-panel .pd-detail{margin:0}
body.v3 .v3-panel .pd-dh.dh2{padding-top:var(--v2-s2)}
/* the record header, everywhere: one row of actions, a 20px title, one chips row, the tabs */
body.v3 .pd-dh.dh2{background:none;border-bottom:0;padding:0}
body.v3 .dh2-top{gap:var(--v2-s2);margin:0 0 var(--v2-s2)}
body.v3 .dh2-back{height:30px;padding:0 var(--v2-s2);border-radius:8px;font-size:var(--v2-t-small)}
body.v3 .dh2-acts .pd-btn{min-height:30px;font-size:var(--v2-t-small);padding:0 var(--v2-s2)}
body.v3 .dh2-acts .pd-btn.ghost{border-color:var(--v2-line)}
body.v3 .dh2-acts .dh2-ai{background:var(--v2-accent);border-color:var(--v2-accent);color:#fff}
html[data-theme="dark"] body.v3 .dh2-acts .dh2-ai{color:hsl(222 40% 7%)}
body.v3 .dh2-title{font:700 var(--v2-t-say)/1.25 var(--v2-sans);letter-spacing:-.02em;margin:var(--v2-s1) 0 var(--v2-s0);color:var(--v2-ink)}
body.v3 .dh2-meta{font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .dh2-chips{gap:var(--v2-s1h);margin:var(--v2-s2) 0 var(--v2-s0)}
body.v3 .dh2-chip{height:26px;display:inline-flex;align-items:center;gap:var(--v2-s1);padding:0 var(--v2-s2);font-size:var(--v2-t-small)}
body.v3 .dh2-chip.stage{background:var(--v2-panel);border:1px solid var(--v2-line);color:var(--v2-ink)}
body.v3 .dh2-chip.stage .pd-stagesel{font:600 var(--v2-t-small) var(--v2-sans);border:0;background:transparent;box-shadow:none;padding:0 var(--v2-s0);height:auto}
body.v3 .dh2-chip.due.warn{background:var(--v2-warn-soft);color:var(--v2-warn);border-color:transparent}
body.v3 .dh2-chip.due.bad{background:var(--v2-bad-soft);color:var(--v2-bad);border-color:transparent}
body.v3 .dh2-chip.type{background:var(--v2-line2)}
body.v3 .pd-dtabs{margin-top:var(--v2-s2)}
body.v3 .v2-metacards{display:none}
body.v3 .pd-dbody{padding-top:var(--v2-s1)}
body.v3 .v2-block{padding:var(--v2-s3) var(--v2-s4);margin:0 0 var(--v2-s3)}
body.v3 .v2-block h4{font-size:var(--v2-t-entity);font-weight:600;margin:0 0 var(--v2-s2)}
body.v3 .v2-block h4 .v2-hsub{font-weight:400;color:var(--v2-faint);font-size:var(--v2-t-small)}
/* R23 · The measure, restored.
   v2.css sets .v2-prose to max-width:70ch — a real decision, made once and
   then overridden 1,750 lines later by a rule that widened it to 120ch.
   The result on the notice summary, the single longest and most-read block
   in this app: 98 characters per line across 2,378 characters with no
   break. That is the paragraph somebody reads to decide whether to bid, and
   it was set at roughly a third again past the width the eye can track
   without losing the line.

   `ch` is the width of the ZERO glyph, not of an average character, and in
   Plus Jakarta Sans the figures are wide: one ch is 9.5px where the average
   character is 7.3px. So 70ch was never 70 characters and 72ch measured 94.
   55ch measures 72 — checked on the rendered page, not assumed from the
   unit. The leading opens with it, because a long measure and tight leading
   fail together. */
body.v3 .v2-prose{font-size:var(--v2-t-body);line-height:1.62;max-width:55ch}
body.v3 .v2-five li span{color:var(--v2-faint)}
body.v3 .crumb b{max-width:320px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:inline-block;vertical-align:bottom}
/* the whisper strip and the Ask AI drawer keep their place */
body.v3 .gr.gr-slim{margin:var(--v2-s2) 0 var(--v2-s3)}
@media (max-width:1279px){
  body.v3 .dh2-title{font-size:var(--v2-t-title)}
}
@media (max-width:860px){
  body.v3 .dh2-top{flex-wrap:wrap}
  body.v3 .dh2-acts{gap:var(--v2-s1h)}
  body.v3 .dh2-acts .pd-btn span,body.v3 .dh2-acts .pd-btn.ghost:not(.dh2-kebab){font-size:var(--v2-t-small)}
  body.v3 .dh2-title{font-size:var(--v2-t-title)}
  body.v3 .pd-dtabs{position:sticky;top:48px;z-index:5;background:var(--v2-bg);margin:var(--v2-s2) -var(--v2-s4) var(--v2-s2);padding:0 var(--v2-s4)}
}

/* ── 10 · slice 5: Today, Decisions & escalations, The numbers ──────── */
/* R18 · three numbers, not three billboards.
   This band was `repeat(auto-fit,minmax(160px,1fr))`, so on a 1434px page
   it became three 473×69 buttons holding eighteen characters between
   them — about 99,000 square pixels to say "15 / 2 / 10", directly above
   the only list on this screen that says what to do next. They are
   content-width pills on one line now: the figures are still the first
   thing you see and still the same three buttons, 37px further up. */
body.v3 .today-nums{display:flex;flex-wrap:wrap;grid-template-columns:none;
  gap:var(--v2-s2);margin:0 0 var(--v2-s3)}
body.v3 .today-num{flex:0 0 auto;flex-direction:row;align-items:baseline;
  padding:var(--v2-s1h) var(--v2-s3);border-radius:var(--v2-r-full);gap:var(--v2-s1h)}
body.v3 .today-num b{font:700 var(--v2-t-say)/1.1 var(--v2-sans);letter-spacing:-.02em;font-variant-numeric:tabular-nums}
body.v3 .today-num span{font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .today-num.hot{border-color:var(--v2-bad-dot);background:var(--v2-bad-soft)}
body.v3 .today-num.hot b{color:var(--v2-bad)}
body.v3 .today-num.warn{border-color:var(--v2-warn-dot)}
body.v3 .today-sec{margin:0 0 var(--v2-s4)}
/* V18 · Today's section headings join the house style.
   Every other GovCon room marks a section with a small uppercase label —
   READY TO CALL, DECISIONS REQUIRED, STANDARD OPERATING PROCEDURES,
   WAITING FOR YOUR SIGN-OFF. Today, which is the room people land in,
   used bold sentence case in body size, so its headings read as
   statements rather than as the dividers they are, and they competed
   with the card titles directly beneath them. */
body.v3 .today-sec h3{font:600 var(--v2-t-small)/1.2 var(--v2-sans);letter-spacing:.04em;
  text-transform:uppercase;color:var(--v2-sub);margin:0 0 var(--v2-s2)}
body.v3 .today-sec h3 .v2-hsub{font-weight:400;color:var(--v2-faint);font-size:var(--v2-t-small)}
/* rows read as a list, not stacked cards */
body.v3 .today-row{margin:0;border-radius:0;border:0;border-bottom:1px solid var(--v2-line2);border-left:3px solid var(--stage,var(--v2-line));background:var(--v2-panel);padding:var(--v2-s2) var(--v2-s2) var(--v2-s2) var(--v2-s3);min-height:48px}
body.v3 .today-sec .today-row:first-of-type{border-radius:10px 10px 0 0;border-top:1px solid var(--v2-line)}
body.v3 .today-sec .today-row:last-of-type{border-radius:0 0 10px 10px;border-bottom:1px solid var(--v2-line)}
body.v3 .today-sec .today-row{border-right:1px solid var(--v2-line)}
body.v3 .today-row:hover{background:var(--v2-line2)}
body.v3 .today-row.red{background:var(--v2-bad-soft);border-left-color:var(--v2-bad-dot)}
body.v3 .today-open{gap:var(--v2-s0)}
body.v3 .today-open b{font-size:var(--v2-t-body);font-weight:600}
body.v3 .today-open span{font-size:var(--v2-t-small)}
body.v3 .today-open small{font-size:var(--v2-t-small);color:var(--v2-faint)}
body.v3 .today-row .pd-btn{min-height:28px;font-size:var(--v2-t-small);flex:0 0 auto}
body.v3 .today-foot{font-size:var(--v2-t-small);color:var(--v2-faint)}
/* the greeting row becomes the room's own small head */
body.v3 .v2-pagehead .pd-btn{min-height:28px}
/* Decisions & escalations, The numbers, My Work: the SOP engine's blocks on the surface rule */
body.v3 .sope-sec,body.v3 .sope-reviews,body.v3 .sope-fold,body.v3 .sope-pack{background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:10px;padding:var(--v2-s3) var(--v2-s3);box-shadow:none}
body.v3 .sope-sec-h{font:600 var(--v2-t-small)/1.2 var(--v2-sans);letter-spacing:.04em;text-transform:uppercase;color:var(--v2-sub);margin:0 0 var(--v2-s2);display:flex;align-items:center;gap:var(--v2-s1h)}
body.v3 .sope-sec-h b{color:var(--v2-ink);background:var(--v2-line2);border-radius:999px;padding:var(--v2-s0) var(--v2-s1h);font-size:var(--v2-t-label)}
body.v3 .sope-ic{width:14px;height:14px;color:var(--v2-faint)}
body.v3 .sope-ic svg{width:14px;height:14px}
body.v3 .sope-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:var(--v2-s3)}
body.v3 .sope-row,body.v3 .sope-work,body.v3 .sope-review,body.v3 .sope-flag,body.v3 .sope-esc{border:0;border-bottom:1px solid var(--v2-line2);border-radius:0;background:none;padding:var(--v2-s2) var(--v2-s0);margin:0}
body.v3 .sope-row:last-child,body.v3 .sope-work:last-child,body.v3 .sope-review:last-child{border-bottom:0}
body.v3 .sope-row:hover{background:var(--v2-line2)}
body.v3 .sope-row-t{font-size:var(--v2-t-body);font-weight:600;color:var(--v2-ink)}
body.v3 .sope-row-m{font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .sope-note{font-size:var(--v2-t-small);color:var(--v2-faint)}
body.v3 .sope-zero{font-size:var(--v2-t-small);color:var(--v2-faint);padding:var(--v2-s1h) var(--v2-s0)}
/* V4 · The week's four figures are a row of figures, not four cards.
   minmax(200px,1fr) inside a 300px column gives one card per row, so the
   four counts of this week's work stacked into four bordered boxes running
   the height of the panel — four frames, four borders and 240px of height
   to carry four numbers that belong side by side and want comparing. They
   are a 2x2 of plain figures now, inside the one panel that already frames
   them. */
body.v3 .sope-stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--v2-s3) var(--v2-s2);margin:0 0 var(--v2-s3)}
body.v3 .sope-stats>*{background:none;border:0;border-radius:0;padding:0;
  display:flex;flex-direction:column;align-items:flex-start;gap:var(--v2-s0)}
body.v3 .sope-stats>* b{font:700 var(--v2-t-display)/1 var(--v2-sans);
  letter-spacing:-.02em;font-variant-numeric:tabular-nums}
body.v3 .sope-stats>* span{font-size:var(--v2-t-label);color:var(--v2-sub)}
body.v3 .sope-fold summary{font-size:var(--v2-t-body);font-weight:600;color:var(--v2-ink);cursor:pointer}
body.v3 .sope-item{padding:var(--v2-s1h) var(--v2-s0);border-bottom:1px solid var(--v2-line2);font-size:var(--v2-t-body)}
body.v3 .sope-tick{color:var(--v2-ok-dot)}
body.v3 .sope-rag{width:8px;height:8px;border-radius:50%;display:inline-block}
body.v3 .sope-reg,body.v3 .sope-portal-list{border:1px solid var(--v2-line);border-radius:10px;background:var(--v2-panel);padding:var(--v2-s3) var(--v2-s3);margin:0 0 var(--v2-s3)}
/* the Dashboard's What's new: a compact feed, 2-line bodies, the rest on click */
body.v3 .ob-wn{border:1px solid var(--v2-line);border-radius:10px;background:var(--v2-panel);box-shadow:none}
body.v3 .ob-wnl{max-height:360px;overflow-y:auto;scrollbar-width:thin}
body.v3 .ob-wn .ob-how{font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .ob-wn .ob-badge{background:var(--v2-accent-soft);color:var(--v2-accent-ink);border:0}

/* ── 11 · slice 6: Outreach — inbox, queue, follow-ups, tracker, calls, phone ── */
body.v3 .ibx{gap:var(--v2-s3);min-height:560px}
body.v3 .ibx-list{border-radius:10px;padding:0;gap:0;overflow-y:auto;overflow-x:hidden;max-height:calc(100vh - 140px)}
body.v3 .ibx-lh{padding:var(--v2-s2) var(--v2-s2) var(--v2-s1h);margin:0;border-bottom:1px solid var(--v2-line);gap:var(--v2-s1h)}
body.v3 .ibx-chips{display:flex;gap:var(--v2-s1);flex-wrap:wrap}
body.v3 .ibx-lh .pd-btn{min-height:26px;font-size:var(--v2-t-small);padding:0 var(--v2-s2)}
body.v3 .ibx-sync{font-size:var(--v2-t-label);color:var(--v2-faint);flex-basis:100%}
body.v3 .ibx-item{border-radius:0;border:0;border-bottom:1px solid var(--v2-line2);padding:var(--v2-s2) var(--v2-s3);gap:var(--v2-s0)}
body.v3 .ibx-item:hover{background:var(--v2-line2)}
body.v3 .ibx-item.on{background:var(--v2-accent-soft);border-color:transparent}
body.v3 .ibx-item.unread .ibx-ir b{font-weight:700}
body.v3 .ibx-ir b{font-size:var(--v2-t-body)}
body.v3 .ibx-ir small{font-size:var(--v2-t-label);color:var(--v2-faint)}
body.v3 .ibx-sj{font-size:var(--v2-t-small);color:var(--v2-ink)}
body.v3 .ibx-unfiled{font-size:var(--v2-t-label);color:var(--v2-warn)}
body.v3 .ibx-thread,body.v3 .ibx-none{border:1px solid var(--v2-line);border-radius:10px;background:var(--v2-panel)}
body.v3 .ibx-th{border-bottom:1px solid var(--v2-line);padding:var(--v2-s3) var(--v2-s3)}
body.v3 .ibx-m{border-radius:10px;border:1px solid var(--v2-line2);background:var(--v2-bg);padding:var(--v2-s2) var(--v2-s3);font-size:var(--v2-t-body)}
body.v3 .ibx-compose{border-top:1px solid var(--v2-line);padding:var(--v2-s2) var(--v2-s3)}
body.v3 .ibx-none{display:grid;place-items:center;color:var(--v2-faint);font-size:var(--v2-t-body);text-align:center;padding:var(--v2-s6)}
body.v3 .ibx-none b{color:var(--v2-sub);font-weight:600}
/* call queue */
body.v3 .call-queue,body.v3 .call-list{background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:10px;padding:var(--v2-s3) var(--v2-s3)}
body.v3 .call-queue-h{font:600 var(--v2-t-small)/1.2 var(--v2-sans);letter-spacing:.04em;text-transform:uppercase;color:var(--v2-sub);margin:0 0 var(--v2-s2)}
body.v3 .call-row{border:0;border-bottom:1px solid var(--v2-line2);border-radius:0;padding:var(--v2-s2) var(--v2-s0);background:none}
body.v3 .call-row:last-child{border-bottom:0}
body.v3 .call-row-t{font-size:var(--v2-t-body);font-weight:600}
/* bid tracker and quotes */
body.v3 .bt-body{padding:0;background:none;border:0}
body.v3 .bt-month{font:600 var(--v2-t-small)/1.2 var(--v2-sans);letter-spacing:.04em;text-transform:uppercase;color:var(--v2-sub);margin:var(--v2-s3) 0 var(--v2-s1h)}
body.v3 .bt-month:first-child{margin-top:0}
body.v3 .bt-seg{background:var(--v2-line2);border:1px solid var(--v2-line);border-radius:8px;padding:var(--v2-s0)}
body.v3 .bt-seg button{border-radius:6px;font-size:var(--v2-t-small);padding:var(--v2-s1) var(--v2-s2);border:0;background:none;color:var(--v2-sub)}
body.v3 .bt-seg button.on{background:var(--v2-panel);color:var(--v2-ink);box-shadow:var(--v3-shadow-1)}
body.v3 .bt-chip{border-radius:999px;font-size:var(--v2-t-label);padding:var(--v2-s0) var(--v2-s1h);background:var(--v2-line2);color:var(--v2-sub);border:0}
body.v3 .bt-due{font-size:var(--v2-t-small);color:var(--v2-sub);font-variant-numeric:tabular-nums}
body.v3 .bt-dim{color:var(--v2-faint)}
body.v3 .bt-note{font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .pd-tip,body.v3 .ob-tip{border:1px solid var(--v2-line);border-left:3px solid var(--v2-accent);background:var(--v2-panel);border-radius:10px;padding:var(--v2-s2) var(--v2-s3);font-size:var(--v2-t-small);color:var(--v2-sub)}
/* calls: the recents list */
body.v3 .ios-seg{background:var(--v2-line2);border:1px solid var(--v2-line);border-radius:8px;padding:var(--v2-s0)}
body.v3 .ios-seg button{border-radius:6px;font-size:var(--v2-t-small);font-weight:500;color:var(--v2-sub);border:0;background:none;padding:var(--v2-s1) var(--v2-s3)}
body.v3 .ios-seg button.on{background:var(--v2-panel);color:var(--v2-ink);box-shadow:var(--v3-shadow-1)}
body.v3 .ios-list{border:1px solid var(--v2-line);border-radius:10px;background:var(--v2-panel);overflow:hidden}
body.v3 .ios-row{border-bottom:1px solid var(--v2-line2);padding:0}
body.v3 .ios-row:last-child{border-bottom:0}
body.v3 .ios-main{padding:var(--v2-s2) var(--v2-s3);gap:var(--v2-s2)}
body.v3 .ios-who b{font-size:var(--v2-t-body);font-weight:600}
body.v3 .ios-who small{font-size:var(--v2-t-label);color:var(--v2-faint)}
body.v3 .ios-when{font-size:var(--v2-t-small);color:var(--v2-faint);font-variant-numeric:tabular-nums}
body.v3 .ios-row.miss .ios-who b{color:var(--v2-bad)}
body.v3 .ccph-h{font:600 var(--v2-t-title)/1.2 var(--v2-sans);letter-spacing:-.01em}
body.v3 .ccph-num{font-size:var(--v2-t-small);color:var(--v2-faint)}
body.v3 .ccph-empty{color:var(--v2-faint);font-size:var(--v2-t-small);padding:var(--v2-s3)}
/* phone setup: the stepper and the forwarding card */
body.v3 .ccph-setup{max-width:none;padding:var(--v2-s3) var(--v2-s4);margin:0 0 var(--v2-s3)}
body.v3 .ccph-setup-h h3{font-size:var(--v2-t-entity);font-weight:600}
body.v3 .ccph-steps{gap:var(--v2-s2);margin:var(--v2-s2) 0}
body.v3 .ccph-steps li{display:flex;gap:var(--v2-s2);align-items:flex-start;font-size:var(--v2-t-body)}
body.v3 .ccph-dotn{width:22px;height:22px;border-radius:50%;display:grid;place-items:center;font-size:var(--v2-t-label);font-weight:700;background:var(--v2-line2);color:var(--v2-sub);flex:0 0 22px}
body.v3 .ccph-steps li.ok .ccph-dotn{background:var(--v2-ok-soft);color:var(--v2-ok)}
body.v3 .ccph-steps li small{display:block;color:var(--v2-faint);font-size:var(--v2-t-small)}
body.v3 .ccph-chip.ok{background:var(--v2-ok-soft);color:var(--v2-ok);border-color:transparent}
body.v3 .ccph-chip.warn{background:var(--v2-warn-soft);color:var(--v2-warn);border-color:transparent}
body.v3 .ccph-chip.bad{background:var(--v2-bad-soft);color:var(--v2-bad);border-color:transparent}
body.v3 .ccph-setup-f{border-top:1px solid var(--v2-line2);padding-top:var(--v2-s2)}
body.v3 .ccph-fwd-row input[type=tel]{height:30px}
@media (max-width:860px){
  body.v3 .ibx{grid-template-columns:1fr;min-height:0}
  body.v3 .ibx-list{max-height:none}
  body.v3 .ibx-thread{margin-top:var(--v2-s2)}
  body.v3 .ibx-none{display:none}
}

/* ── 12 · slices 7–9: Company · Planner · Settings & Integrations ──── */
/* generic panels and section titles used by these rooms */
body.v3 .pd-panel,body.v3 .nw-block,body.v3 .intel-sec,body.v3 .pt2-pcard,body.v3 .cx-card,body.v3 .pcard,body.v3 .fmcard,body.v3 .bx,body.v3 .quad,body.v3 .ig-pl,body.v3 .ig-okbox{
  background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:10px;box-shadow:none;padding:var(--v2-s3) var(--v2-s4)}
body.v3 .pd-panel h4,body.v3 .nw-block h4,body.v3 .intel-sec h3,body.v3 .cx-cardh,body.v3 .pchead,body.v3 .bx-h,body.v3 .st-cardh,body.v3 .ig-h3{font:600 var(--v2-t-entity)/1.3 var(--v2-sans);letter-spacing:-.01em;color:var(--v2-ink)}
body.v3 .sectitle,body.v3 .st-lbl,body.v3 .ig-h5,body.v3 .pd-facts-k,body.v3 .intel-meta,body.v3 .pt2-vl,body.v3 .cx-muted.lbl{font:600 var(--v2-t-label)/1.2 var(--v2-sans);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint)}
body.v3 .pnote,body.v3 .st-sub,body.v3 .st-dim,body.v3 .ig-desc,body.v3 .ig-sub,body.v3 .cx-muted,body.v3 .v2-compmeta{color:var(--v2-sub);font-size:var(--v2-t-small)}
/* KPI tiles on Portals, Money, the Dashboard, Settings → Company */
body.v3 .statrow,body.v3 .st-grid4,body.v3 .st-grid3,body.v3 .pt2-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:var(--v2-s2);margin:0 0 var(--v2-s3)}
body.v3 .stat,body.v3 .st-n,body.v3 .cx-stat{background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:10px;padding:var(--v2-s3) var(--v2-s3);box-shadow:none}
body.v3 .stat b,body.v3 .stat .n,body.v3 .st-n b,body.v3 .cx-stat b{font:700 var(--v2-t-say)/1.1 var(--v2-sans);letter-spacing:-.02em;font-variant-numeric:tabular-nums;color:var(--v2-ink)}
body.v3 .stat .k,body.v3 .stat small,body.v3 .st-n span,body.v3 .cx-stat span{font-size:var(--v2-t-small);color:var(--v2-sub)}
/* chips, pills, segmented in these rooms */
body.v3 .chip,body.v3 .fm-chip,body.v3 .goalchip,body.v3 .st-pill,body.v3 .ig-badge,body.v3 .cx-chip,body.v3 .cx-badge,body.v3 .pt2-pri,body.v3 .ig-chips span{border-radius:999px;font-size:var(--v2-t-label);font-weight:500;padding:var(--v2-s0) var(--v2-s2);border:1px solid var(--v2-line);background:var(--v2-line2);color:var(--v2-sub)}
body.v3 .chip.on,body.v3 .fm-chip.on,body.v3 .st-pill.on{background:var(--v2-accent-soft);border-color:var(--v2-accent-line);color:var(--v2-accent-ink);font-weight:600}
body.v3 .st-seg,body.v3 .cx-sq,body.v3 .ig-filter,body.v3 .tr-seg{background:var(--v2-line2);border:1px solid var(--v2-line);border-radius:8px;padding:var(--v2-s0);display:inline-flex;gap:0}
body.v3 .st-seg button,body.v3 .cx-sq button,body.v3 .ig-filter button,body.v3 .tr-seg button{border-radius:6px;font:500 var(--v2-t-small) var(--v2-sans);color:var(--v2-sub);border:0;background:none;padding:var(--v2-s1) var(--v2-s2);min-height:26px}
body.v3 .st-seg button.on,body.v3 .cx-sq button.on,body.v3 .ig-filter button.on,body.v3 .tr-seg button.on{background:var(--v2-panel);color:var(--v2-ink);box-shadow:var(--v3-shadow-1)}
/* Company → Library */
body.v3 .pb-libh{font:600 var(--v2-t-small)/1.2 var(--v2-sans);letter-spacing:.04em;text-transform:uppercase;color:var(--v2-sub);margin:var(--v2-s3) 0 var(--v2-s1h)}
body.v3 .pb-libgrp{margin:0 0 var(--v2-s3)}
body.v3 .v2-libsearch input{height:32px}
body.v3 .pb-libtable td{padding:var(--v2-s1h) var(--v2-s3)}
/* Company → Portals */
body.v3 .pt2-vrow{border-bottom:1px solid var(--v2-line2);padding:var(--v2-s2) 0;display:flex;align-items:center;gap:var(--v2-s2)}
body.v3 .pt2-pri{font-size:var(--v2-t-label);letter-spacing:.04em;text-transform:uppercase}
body.v3 .pt2-pri.high{background:var(--v2-bad-soft);color:var(--v2-bad);border-color:transparent}
body.v3 .pt2-dot{width:8px;height:8px;border-radius:50%;display:inline-block}
/* Company → Network: the side panel's tabs and facts */
body.v3 .pd-pick{border-radius:8px}
body.v3 .pd-facts-k{margin-top:var(--v2-s2)}
/* Company → Forecasting */
body.v3 .intel-bar{display:flex;flex-wrap:wrap;gap:var(--v2-s2);align-items:flex-end;margin:0 0 var(--v2-s2);padding:0;background:none;border:0}
body.v3 .intel-scroll{max-height:none;overflow:visible}
/* Company → Comps */
body.v3 .cmp-form,body.v3 .comps-form{border-left:0}
/* Planner → Dashboard, My Tasks, Projects, Week, RICE, Money, Delivery */
body.v3 .pgrid,body.v3 .cards{gap:var(--v2-s2)}
body.v3 .card,body.v3 .pcard{padding:var(--v2-s3) var(--v2-s3);border-radius:10px;border:1px solid var(--v2-line);background:var(--v2-panel);box-shadow:var(--v3-shadow-1)}
body.v3 .card:hover,body.v3 .pcard:hover{border-color:var(--v2-accent-line);box-shadow:var(--v3-shadow-2)}
body.v3 .card .t,body.v3 .pcard .t{font:600 var(--v2-t-body)/1.35 var(--v2-sans);color:var(--v2-ink)}
body.v3 .card .meta,body.v3 .pcard .meta{font-size:var(--v2-t-label);color:var(--v2-sub)}
body.v3 .emptycol{color:var(--v2-faint);font-size:var(--v2-t-small);border:1px dashed var(--v2-line);border-radius:10px;padding:var(--v2-s3);text-align:center;background:none}
/* R20 · Projects gets the treatment R2 gave the rest of the app.
   The screen carried 101 bordered surfaces: thirteen project cards, each
   holding a bordered .pj-rows box, each holding three bordered .pj-row
   boxes, each holding a bordered copy button. Four frames deep to show
   one file path. The card keeps its border because it IS the object; what
   is inside it is separated by a rule and some air, which is what .bud-row
   two rules below has been doing on the Money page all along. */
/* R26 · The panel takes focus when it opens, so it must not draw a focus
   ring for that — the ring belongs to things you Tab to, and a region you
   were moved into is not one of them. Screen readers still announce it,
   because the region and its label are what they read, not the outline. */
body.v3 #pd-detail:focus{outline:none}
/* V17 · One meaning for colour in a row.
   "Sourcing Subs · 4d left · Daysha Blount" ran three colours across one
   line: grey for the stage, amber for the time left, and a per-person tint
   for the name. So colour meant urgency AND identity in the same sentence,
   and a reader scanning for what is late had to keep deciding which kind
   of coloured word they had just landed on.
   Urgency keeps colour, because urgency is the question this screen
   answers. The name keeps its weight — it is still the second thing you
   look for — and gives up its tint. Who owns a card is already carried by
   the tinted disc on the board, where it is a mark rather than a word
   competing with a deadline. */
body.v3 .today-who{color:var(--v2-ink);font-weight:600}
/* V16 · The actions sit beside the title, not above it.
   The card header ran: a row of four buttons and a menu, THEN the title of
   the thing they act on, then the identifiers, then the chips. You were
   offered "Re-pull SAM", "Ask AI" and "Email CO" before you had been told
   which solicitation you were looking at — and on a 198-card board, which
   one it is is the first thing you need.
   A two-column grid puts the title and its identifiers first in the
   reading order and the actions on the same line, right. Below 1100px it
   falls back to the stack, because squeezing five controls next to a
   seventy-character title helps nobody. */
@media (min-width:1100px){
  body.v3 .pd-dh.dh2{display:grid;grid-template-columns:minmax(0,1fr) auto;
    grid-template-areas:"title acts" "meta acts" "chips chips" "tabs tabs";
    column-gap:var(--v2-s4);align-items:start}
  body.v3 .pd-dh.dh2 > .dh2-top{grid-area:acts;justify-content:flex-end;margin:0}
  body.v3 .pd-dh.dh2 > .dh2-title{grid-area:title}
  body.v3 .pd-dh.dh2 > .dh2-meta{grid-area:meta}
  body.v3 .pd-dh.dh2 > .dh2-chips{grid-area:chips}
  body.v3 .pd-dh.dh2 > .pd-dtabs{grid-area:tabs}
}
/* V13 · Forecasting's four tiles join the other seventeen.
   The GovCon desk had FOUR designs for "a number with a label that filters
   a list": the Action Center's eight, Portals' five, Today's pills, and
   these — number first, in display type, label under it. Same object, same
   job, four readings. V3 and V8 settled the first two; this is the last.
   The markup is <b>, <strong>, <span> in that order, so grid areas place
   them without touching the renderer. */
body.v3 .intel-tiles > button{display:grid;grid-template-columns:minmax(0,1fr) auto;
  grid-template-areas:"l n" "s n";align-items:center;column-gap:var(--v2-s3);text-align:left}
body.v3 .intel-tiles > button strong{grid-area:l;align-self:end}
body.v3 .intel-tiles > button span{grid-area:s;align-self:start}
body.v3 .intel-tiles > button b{grid-area:n;justify-self:end;font-size:var(--v2-t-display);
  line-height:1;font-variant-numeric:tabular-nums}
/* V12 · The sticky strip carries the card's name, so it has to behave like
   a label that might be long. */
body.v3 .v3-panelcrumb{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .v3-panelcrumb b{color:var(--v2-ink);font-family:var(--v2-mono);font-size:var(--v2-t-label)}
/* V11 · A filter that would return nothing does not stand level with one
   that has two waiting. Four chips above the board, all the same weight,
   two of them reading 0 — so the eye spends the same effort on "Emails not
   sent: none" as on "Quote gap: 2", every time it crosses that row. The
   markup already distinguishes them: the count carries .live only when it
   is non-zero. */
body.v3 .ops-kpi:has(b:not(.live)){opacity:.62}
body.v3 .ops-kpi:has(b:not(.live)):hover,
body.v3 .ops-kpi:has(b:not(.live)):focus-visible,
body.v3 .ops-kpi[aria-pressed="true"]{opacity:1}
/* V10 · Orientation folds away; the count line stays. */
body.v3 .find-about{margin:0 0 var(--v2-s2)}
body.v3 .find-about > summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;
  gap:var(--v2-s1h);font-size:var(--v2-t-label);letter-spacing:.04em;text-transform:uppercase;
  color:var(--v2-sub);padding:var(--v2-s1) 0}
body.v3 .find-about > summary::-webkit-details-marker{display:none}
body.v3 .find-about > summary::before{content:"▸";color:var(--v2-faint);transform:scale(.8)}
body.v3 .find-about[open] > summary::before{content:"▾"}
body.v3 .find-about > summary:hover{color:var(--v2-ink)}
body.v3 .find-about .find-hint{margin:var(--v2-s1) 0 0}
/* V8 · Portals' five tiles take the shape the other eight already use.
   A GovCon desk had three tile designs: the Action Center's eight (now one
   shape), Today's figure pills, and this — icon, then number ABOVE its own
   label. Same object, same job, a different reading in each room, so the
   eye re-learns the layout every time it changes room.
   Label first, number right, detail under. No markup moved: the span holds
   <b>, <em>, <small> in that order and grid areas put them where they read
   best. */
body.v3 .pt2-stat{align-items:center}
body.v3 .pt2-stat > span{display:grid;grid-template-columns:minmax(0,1fr) auto;
  grid-template-areas:"l n" "s n";align-items:center;column-gap:var(--v2-s3);width:100%}
body.v3 .pt2-stat em{grid-area:l;align-self:end;font-style:normal}
body.v3 .pt2-stat small{grid-area:s;align-self:start}
body.v3 .pt2-stat b{grid-area:n;justify-self:end;font-size:var(--v2-t-display);line-height:1;
  font-variant-numeric:tabular-nums}
/* V7 · The Network's five lists use the app's own tab idiom.
   They were a boxed segmented control stretched to the full width, five
   equal fifths with the labels floating in the middle of each — directly
   under the room tab row, which is compact, left-aligned and underlined.
   Two tab idioms stacked on one screen, the lower one shouting. It is the
   same row as the one above it now, so the eye reads a hierarchy instead of
   two competing bars, and the count keeps its weight because the count is
   the reason to look. */
body.v3 .net-tabs{display:flex;grid-template-columns:none;border:0;border-bottom:1px solid var(--v2-line);
  border-radius:0;gap:var(--v2-s1);overflow-x:auto;scrollbar-width:thin;margin-bottom:var(--v2-s3)}
body.v3 .net-tabs button{flex:0 0 auto;justify-content:flex-start;border-right:0;
  padding:var(--v2-s2) var(--v2-s3);border-bottom:2px solid transparent;border-radius:0}
body.v3 .net-tabs button.on{background:none;box-shadow:none;color:var(--v2-ink);
  border-bottom-color:var(--v2-accent);font-weight:650}
/* V3 · Label first, number right, one line of detail, the whole tile is the
   button. A tile reading zero steps back rather than disappearing: knowing a
   queue is clear is worth seeing, but it should not shout as loudly as the
   one with ten in it. */
body.v3 .ops-stat{grid-template-columns:auto minmax(0,1fr) auto;
  grid-template-areas:"ic l n" "ic s n";align-items:center;column-gap:var(--v2-s3)}
body.v3 .ops-stat-l{grid-area:l;align-self:end}
body.v3 .ops-stat-s{grid-area:s;align-self:start}
body.v3 .ops-stat b{grid-area:n;justify-self:end;font-size:var(--v2-t-display);line-height:1}
body.v3 .ops-stat-go{display:none}
body.v3 .ops-stat.quiet{background:none}
body.v3 .ops-stat.quiet b{color:var(--v2-faint)}
body.v3 .ops-stat.quiet .ops-stat-l{color:var(--v2-sub)}
/* V2 · The quiet sign-off line. */
body.v3 .sope-reviews.quiet{display:flex;align-items:baseline;gap:var(--v2-s2);flex-wrap:wrap;
  padding:var(--v2-s2) var(--v2-s3);background:none;border:0;border-top:1px solid var(--v2-line)}
body.v3 .sope-reviews.quiet .sope-sec-h{margin:0}
body.v3 .sope-reviews.quiet .sope-note{margin:0}
/* V1 · A section with nothing in it is a line at the back of the grid. */
body.v3 .sope-sec.empty{order:2;padding:var(--v2-s2) var(--v2-s3);background:none;
  border-style:dashed;align-self:start}
body.v3 .sope-sec.empty .sope-sec-h{margin:0}
body.v3 .sope-sec.empty .sope-zero{padding:var(--v2-s0) 0 0;font-size:var(--v2-t-label)}
/* Sign in with Google — Google's own brand rules ask for their mark on a
   plain surface with their wordmark spelled out, so this is a quiet button
   beside ours rather than a second coloured one competing with it. */
body.v3 .cc-or{display:flex;align-items:center;gap:var(--v2-s2);margin:var(--v2-s3) 0;
  color:var(--v2-faint);font-size:var(--v2-t-label);letter-spacing:.06em;text-transform:uppercase}
body.v3 .cc-or::before,body.v3 .cc-or::after{content:"";flex:1;height:1px;background:var(--v2-line)}
body.v3 .cc-google{display:flex;align-items:center;justify-content:center;gap:var(--v2-s2);
  width:100%;box-sizing:border-box;min-height:40px;padding:0 var(--v2-s3);
  border:1px solid var(--v2-line);border-radius:var(--v2-r-control);background:var(--v2-panel);
  color:var(--v2-ink);font:600 var(--v2-t-body)/1 var(--v2-sans);text-decoration:none}
body.v3 .cc-google:hover{border-color:var(--v2-accent-line);background:var(--v2-line2)}
body.v3 .cc-google:focus-visible{outline:2px solid var(--v2-accent);outline-offset:2px}
body.v3 .cc-google svg{flex:0 0 auto}
/* R28 · Configuration stands apart from the queues it sits beside. */
body.v3 .bt-roomnav .bt-navsp{flex:0 0 auto;width:1px;align-self:stretch;
  margin:var(--v2-s1) var(--v2-s2);background:var(--v2-line)}
body.v3 .bt-roomnav button.quiet{color:var(--v2-faint)}
body.v3 .bt-roomnav button.quiet.on{color:var(--v2-ink)}
/* R25 · 176 boxes that all mean "you may type here".
   The budget tracker gives every cell a bordered white input on a white
   panel: 216 controls on one page, and because every single one is framed,
   the frame says nothing. A row of numbers you are reading looks exactly
   like a row of numbers you are editing, and the eye has to parse a grid
   of boxes before it can find a figure.
   The values read as text until you reach for them. Hovering a ROW frames
   that row's cells — so "what can I edit here" is answered by moving the
   mouse down the table, which is also how you were going to find the row
   you wanted. Focus takes the accent, as everywhere else. */
body.v3 .bg-table .bg-in{border-color:transparent;background:none}
body.v3 .bg-table .bg-row:hover .bg-in{border-color:var(--v2-line);background:var(--v2-panel)}
body.v3 .bg-table .bg-in:hover{border-color:var(--v2-accent-line)}
body.v3 .bg-table .bg-in:focus{border-color:var(--v2-accent);background:var(--v2-panel);outline:none}
/* R21 · The prior-award candidates are a list, so they read as a list.
   Twenty of them, each in its own bordered, rounded, margin-separated
   box, stacked inside a panel that is itself inside a panel — the same
   boxes-in-boxes R2 took out of the rest of the app and R20 took out of
   Projects. This is the view somebody prices a bid against; twenty frames
   make it look like twenty unrelated objects instead of one comparison.
   The selected one keeps its fill, because that is a state, not a frame. */
body.v3 .pd-incrow{border:0;border-top:1px solid var(--v2-line2);border-radius:0;
  margin-bottom:0;padding:var(--v2-s2) var(--v2-s3) var(--v2-s2) 0}
body.v3 .pd-inclist > .pd-incrow:first-child{border-top:0}
body.v3 .pd-incrow.on{background:var(--v2-accent-soft);border-radius:var(--v2-r-control);
  padding-left:var(--v2-s2);border-top-color:transparent}
body.v3 .pj-rows{display:grid;gap:0;margin-top:var(--v2-s2);border:0;background:none;padding:0}
body.v3 .pj-row{border:0;border-top:1px solid var(--v2-line2);border-radius:0;
  background:none;padding:var(--v2-s2) 0;box-shadow:none}
body.v3 .pj-rows > .pj-row:first-child{border-top:0;padding-top:0}
/* The copy button is an affordance on a row, not an object of its own.
   It takes its frame when you reach for it. */
body.v3 .pj-copy{border-color:transparent;background:none}
body.v3 .pj-row:hover .pj-copy,body.v3 .pj-copy:hover,body.v3 .pj-copy:focus-visible{
  border-color:var(--v2-line);background:var(--v2-panel)}
body.v3 .pj-name{font:600 var(--v2-t-entity) var(--v2-sans)}
body.v3 .pj-k{font:500 var(--v2-t-small) var(--v2-sans);color:var(--v2-sub)}
body.v3 .bud-row{border-bottom:1px solid var(--v2-line2);padding:var(--v2-s1h) 0;font-size:var(--v2-t-body)}
body.v3 .bud-k{color:var(--v2-sub)}
body.v3 .bud-v{font-variant-numeric:tabular-nums;font-weight:600}
body.v3 .bud-paid{color:var(--v2-ok)}
body.v3 .ricehint{font-size:var(--v2-t-small);color:var(--v2-sub);background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:10px;padding:var(--v2-s2) var(--v2-s3)}
/* CFA desk */
body.v3 .cx-btn{border-radius:8px;font:500 var(--v2-t-small) var(--v2-sans);min-height:30px;padding:0 var(--v2-s2);border:1px solid var(--v2-line);background:var(--v2-panel);color:var(--v2-ink);box-shadow:none}
body.v3 .cx-btn.primary,body.v3 .cx-btn.go,body.v3 .cx-btn.dark{background:var(--v2-accent);border-color:var(--v2-accent);color:#fff}
body.v3 .cx-btnrow{gap:var(--v2-s1h)}
body.v3 .cx-toolbar{gap:var(--v2-s2);flex-wrap:wrap}
body.v3 .cx-sel,body.v3 .cx-inp{height:30px;border-radius:8px;font-size:var(--v2-t-small)}
body.v3 .cx-table th{font:600 var(--v2-t-label)/1.2 var(--v2-sans);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint);padding:var(--v2-s2) var(--v2-s3);border-bottom:1px solid var(--v2-line)}
body.v3 .cx-table td{padding:var(--v2-s2) var(--v2-s3);border-bottom:1px solid var(--v2-line2);font-size:var(--v2-t-body)}
body.v3 .cx-mnav b,body.v3 .cfa-mnav b{font:600 var(--v2-t-entity) var(--v2-sans)}
body.v3 .cx-warnline{border-radius:10px;font-size:var(--v2-t-small)}
/* Settings & Integrations: the settings-page pattern */
body.v3 .st-card{background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:10px;padding:var(--v2-s4) var(--v2-s4);box-shadow:none;margin:0 0 var(--v2-s3)}
body.v3 .st-card h3{font:600 var(--v2-t-entity)/1.3 var(--v2-sans);margin:0 0 var(--v2-s0)}
body.v3 .st-line{border-color:var(--v2-line2)}
body.v3 .st-f input,body.v3 .st-f select,body.v3 .st-f textarea{height:32px;font-size:var(--v2-t-body)}
body.v3 .st-f textarea{height:auto}
body.v3 .st-table th{font:600 var(--v2-t-label)/1.2 var(--v2-sans);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint)}
body.v3 .st-table td{font-size:var(--v2-t-body);border-bottom:1px solid var(--v2-line2);padding:var(--v2-s2) var(--v2-s2)}
body.v3 .st-step{border:1px solid var(--v2-line);border-radius:10px;background:var(--v2-panel)}
body.v3 .st-tip,body.v3 .ig-okbox{font-size:var(--v2-t-small);border-left:3px solid var(--v2-accent)}
body.v3 .st-act{display:flex;gap:var(--v2-s2);justify-content:flex-end;align-items:center}
body.v3 .st-themes{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:var(--v2-s2)}
body.v3 .st-theme{border:1px solid var(--v2-line);border-radius:10px;background:var(--v2-panel);padding:var(--v2-s3);text-align:left}
body.v3 .st-theme.on{border-color:var(--v2-accent);box-shadow:0 0 0 3px var(--v2-accent-soft)}
body.v3 .ig-svch{display:flex;align-items:center;gap:var(--v2-s2)}
body.v3 .ig-dot{width:8px;height:8px;border-radius:50%}
body.v3 .ig-code{font:var(--v2-t-small) var(--v2-mono);background:var(--v2-line2);border-radius:6px;padding:var(--v2-s0) var(--v2-s1h)}
body.v3 .ig-state{font-size:var(--v2-t-label)}
/* the Settings / Integrations top tab strips (icons + label) → secondary tabs */
body.v3 .st-tabs,body.v3 .ig-tabs,body.v3 .st-nav{display:flex;gap:var(--v2-s0);border-bottom:1px solid var(--v2-line);margin:0 0 var(--v2-s3);overflow-x:auto;scrollbar-width:none;background:none;border-radius:0;padding:0;box-shadow:none}
body.v3 .st-tabs button,body.v3 .ig-tabs button,body.v3 .st-nav button{flex:0 0 auto;display:inline-flex;align-items:center;gap:var(--v2-s1h);padding:var(--v2-s2) var(--v2-s2);margin-bottom:-var(--v2-s0);border:0;border-bottom:2px solid transparent;border-radius:0;background:none;font:500 var(--v2-t-body) var(--v2-sans);color:var(--v2-sub);white-space:nowrap;box-shadow:none}
body.v3 .st-tabs button.on,body.v3 .ig-tabs button.on,body.v3 .st-nav button.on{color:var(--v2-ink);font-weight:600;border-bottom-color:var(--v2-accent);background:none}
body.v3 .st-tabs button svg,body.v3 .ig-tabs button svg{width:14px;height:14px;opacity:.7}
body.v3 .st-subtabs,body.v3 .ig-subtabs{display:flex;gap:var(--v2-s1);margin:0 0 var(--v2-s3);flex-wrap:wrap}
body.v3 .st-subtabs button,body.v3 .ig-subtabs button{height:28px;padding:0 var(--v2-s2);border-radius:999px;border:1px solid var(--v2-line);background:var(--v2-panel);color:var(--v2-sub);font:500 var(--v2-t-small) var(--v2-sans)}
body.v3 .st-subtabs button.on,body.v3 .ig-subtabs button.on{background:var(--v2-accent-soft);border-color:var(--v2-accent-line);color:var(--v2-accent-ink);font-weight:600}
/* sticky save bars sit above the phone bar */
@media (max-width:860px){
  body.v3 .st-save,body.v3 .st-foot,body.v3 .st-act.sticky{bottom:calc(72px + env(safe-area-inset-bottom,0px))}
  body.v3 .statrow,body.v3 .st-grid4,body.v3 .st-grid3{grid-template-columns:repeat(2,1fr)}
  body.v3 .cx-toolbar{overflow-x:auto;flex-wrap:nowrap;scrollbar-width:none;margin:0 -var(--v2-s4);padding:0 var(--v2-s4)}
}

/* ── 13 · slice 10: sign-in, agreements, onboarding, tours ───────────── */
body.v3 #cc-auth{background:var(--v2-bg)}
body.v3 .cc-authbox{background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:14px;box-shadow:var(--v3-shadow-2);padding:var(--v2-s5) var(--v2-s5) var(--v2-s5);max-width:420px}
/* The sign-in card is the first thing anyone sees of this company, and
   until now it showed no mark at all — just a heading, which the v3 rule
   `h1{text-transform:uppercase}` was rendering as "DNAI COMMAND CENTER".
   Our name has a lowercase i. Uppercasing it spells it wrong, on the one
   screen that greets people who are not yet signed in.

   So: the real lockup above, and the heading back in its own case. The
   mark says who we are, the heading says what this is — which is why the
   two together are not the doubling the rail had. */
body.v3 .cc-authbox::before{content:"";display:block;width:132px;height:58px;
  margin:0 0 var(--v2-s3);
  background:url("/brand/dnai-logo.png") left center/contain no-repeat}
body.v3 .cc-authbox h1,body.v3 .cc-authbox h2{font:700 var(--v2-t-say)/1.2 var(--v2-display);letter-spacing:-.02em;margin:0 0 var(--v2-s1);text-transform:none}
body.v3 .cc-authnote{font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .cc-authbox .pd-f input{height:38px;font-size:var(--v2-t-entity)}
body.v3 .cc-authgo{height:38px;border-radius:8px;background:var(--v2-accent);color:#fff;border:0;font:600 var(--v2-t-entity) var(--v2-sans);width:100%}
body.v3 .cc-invstep{border:1px solid var(--v2-line);border-radius:10px;background:var(--v2-panel);padding:var(--v2-s3) var(--v2-s3)}
body.v3 .cc-invn{width:24px;height:24px;border-radius:50%;background:var(--v2-accent-soft);color:var(--v2-accent-ink);font-weight:700;font-size:var(--v2-t-small);display:grid;place-items:center}
body.v3 .cc-switch{border-radius:999px}
body.v3 .ob-modal{border-radius:14px;border:1px solid var(--v2-line);box-shadow:var(--v2-shadow-overlay);background:var(--v2-panel)}
body.v3 /* R32 · white on the accent measured 1.68:1 — the worst contrast left in
   the app after round 15, and on a button the owner is meant to press.
   --v2-accent is a bright teal in both themes; white text on it is
   almost invisible. --v2-bg is the page ground, near-black in dark and
   near-white in light, so it inverts correctly with the theme instead
   of being right in one of them. */
.ob-cta{border-radius:8px;background:var(--v2-accent);color:var(--v2-bg);border:0;font-weight:600}
body.v3 .ob-link{color:var(--v2-accent-ink)}
body.v3 .ob-tip{border-radius:12px;border:1px solid var(--v2-line);box-shadow:var(--v3-shadow-2);background:var(--v2-panel)}
body.v3 .tour-list{display:grid;gap:var(--v2-s2)}
body.v3 .tour-row{border:1px solid var(--v2-line);border-radius:10px;background:var(--v2-panel);padding:var(--v2-s2) var(--v2-s3)}
body.v3 .tour-rt{font:600 var(--v2-t-body) var(--v2-sans)}
body.v3 .tour-dots i{background:var(--v2-line)}
body.v3 .tour-dots i.on{background:var(--v2-accent)}
body.v3 .tour-k{font-size:var(--v2-t-label);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint)}

/* inbox sort */
body.v3 .ibx-sort{display:inline-flex;align-items:center;gap:var(--v2-s1h);margin-left:auto;font-size:var(--v2-t-label);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint);font-weight:600}
body.v3 .ibx-sort select{height:26px;font:500 var(--v2-t-small) var(--v2-sans);border-radius:6px;padding:0 var(--v2-s5) 0 var(--v2-s2);letter-spacing:0;text-transform:none}

/* inbox: re-file a conversation or one message */
body.v3 .ibx-opp{display:flex;flex-wrap:wrap;align-items:center;gap:var(--v2-s2);padding:var(--v2-s2) var(--v2-s3);border-bottom:1px solid var(--v2-line);font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .ibx-opp a{color:var(--v2-accent-ink);font-weight:600}
body.v3 .ibx-refile{display:inline-flex;align-items:center;gap:var(--v2-s1h);margin-left:auto;font-size:var(--v2-t-label);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint);font-weight:600}
body.v3 .ibx-refile select,body.v3 .ibx-opp select{height:26px;font:500 var(--v2-t-small) var(--v2-sans);border-radius:6px;padding:0 var(--v2-s5) 0 var(--v2-s2);max-width:320px;letter-spacing:0;text-transform:none}
body.v3 .ibx-mfile{display:none;margin:var(--v2-s0) 0 0}
body.v3 .ibx-m:hover .ibx-mfile,body.v3 .ibx-m:focus-within .ibx-mfile{display:block}
body.v3 .ibx-mfile select{height:22px;font:500 var(--v2-t-label) var(--v2-sans);border-radius:5px;padding:0 var(--v2-s4) 0 var(--v2-s1h);color:var(--v2-sub);background:transparent;border-color:transparent;max-width:260px}
body.v3 .ibx-mfile select:hover{border-color:var(--v2-line);background:var(--v2-panel)}
body.v3 .ibx-mopp{display:block;font-size:var(--v2-t-label);color:var(--v2-accent-ink)}
@media (max-width:860px){body.v3 .ibx-mfile{display:block}}

/* inbox compose: send as · send later · the queue */
body.v3 .ibx-cf{display:flex;flex-wrap:wrap;align-items:center;gap:var(--v2-s2)}
body.v3 .ibx-as,body.v3 .ibx-later{display:inline-flex;align-items:center;gap:var(--v2-s1h);font-size:var(--v2-t-label);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint);font-weight:600}
body.v3 .ibx-as select,body.v3 .ibx-later input{height:28px;font:500 var(--v2-t-small) var(--v2-sans);border-radius:6px;padding:0 var(--v2-s2);letter-spacing:0;text-transform:none;color:var(--v2-ink)}
body.v3 .ibx-queued{display:grid;gap:var(--v2-s1h);margin:0 0 var(--v2-s2)}
body.v3 .ibx-q1{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--v2-s2);font-size:var(--v2-t-small);border:1px dashed var(--v2-line);border-radius:8px;padding:var(--v2-s1h) var(--v2-s2);color:var(--v2-sub)}
body.v3 .ibx-q1 span{font-weight:600;color:var(--v2-ink)}
body.v3 .ibx-q1.failed span{color:var(--v2-bad)}
body.v3 .ibx-q1 em{font-style:normal;color:var(--v2-sub);flex:1 1 200px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── Dialer on a call: draggable header, one-line bar (Mark, 17 Oct) ── */
body.v3 .ccph-top{cursor:move;user-select:none;touch-action:none}
body.v3 .ccph-top button{cursor:pointer}
body.v3 .ccph-mini{display:flex;align-items:center;gap:var(--v2-s2);padding:var(--v2-s1h) var(--v2-s2) var(--v2-s1h) var(--v2-s2);background:var(--v2-panel);color:var(--v2-ink);border:1px solid var(--v2-line);border-radius:999px;box-shadow:var(--v2-shadow-overlay);cursor:move;user-select:none;touch-action:none;max-width:min(520px,calc(100vw - 32px))}
body.v3 .ccph-mini b{font-size:var(--v2-t-body);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
body.v3 .ccph-mini .ccph-t{font-variant-numeric:tabular-nums;font-size:var(--v2-t-small)}
body.v3 .ccph-mb{border:1px solid var(--v2-line);background:var(--v2-line2);color:var(--v2-ink);border-radius:999px;padding:var(--v2-s1) var(--v2-s2);font:600 var(--v2-t-small) var(--v2-sans);cursor:pointer;flex:none}
body.v3 .ccph-mb.no{background:#ff3b30;border-color:#ff3b30;color:#fff;width:28px;padding:var(--v2-s1) 0;font-size:var(--v2-t-entity);line-height:1}
@media (max-width:860px){body.v3 #ccph:has(.ccph-mini){inset:auto 12px calc(90px + env(safe-area-inset-bottom,0px)) 12px;z-index:950}body.v3 .ccph-mini{cursor:default}}

/* ── Notes during a call ── */
body.v3 .ccph-panel{height:auto;max-height:calc(100vh - 32px)}
body.v3 .ccph-note{display:flex;flex-direction:column;gap:var(--v2-s1h);padding:var(--v2-s2) var(--v2-s3) var(--v2-s3);border-top:1px solid var(--v2-line)}
body.v3 .ccph-note textarea{width:100%;resize:vertical;min-height:52px;font:400 var(--v2-t-body) var(--v2-sans);padding:var(--v2-s2) var(--v2-s2);border:1px solid var(--v2-line);border-radius:6px;background:var(--v2-bg);color:var(--v2-ink)}
body.v3 .ccph-nfor,body.v3 .ccph-nhint{font-size:var(--v2-t-label);color:var(--v2-sub)}
body.v3 .ccph-nfor b{color:var(--v2-ink);font-weight:600}
body.v3 .ccph-nsel{font-size:var(--v2-t-small);padding:var(--v2-s1) var(--v2-s2);max-width:100%}
body.v3 .ccph-nrow{display:flex;align-items:center;justify-content:space-between;gap:var(--v2-s2)}
body.v3 .ccph-note.compact{border-top:0;margin-top:var(--v2-s1h);padding:var(--v2-s2) var(--v2-s3);background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:10px;box-shadow:var(--v2-shadow-overlay);width:min(520px,calc(100vw - 32px))}
body.v3 .ccph-note.compact .ccph-nhint{display:none}
body.v3 .ccph-mb.on{background:var(--v2-accent-soft);border-color:var(--v2-accent-line);color:var(--v2-accent-ink)}

/* ── Card email window: Send later ── */
body.v3 .em-sendcol{display:flex;flex-direction:column;align-items:flex-end;gap:var(--v2-s1h)}
body.v3 .em-later{display:inline-flex;align-items:center;gap:var(--v2-s1h);font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .em-later input{font-size:var(--v2-t-small);padding:var(--v2-s1) var(--v2-s1h);border:1px solid var(--v2-line);border-radius:6px;background:var(--v2-bg);color:var(--v2-ink)}
body.v3 .em-clear{border:0;background:none;color:var(--v2-sub);font-size:var(--v2-t-title);line-height:1;cursor:pointer;padding:0 var(--v2-s1)}
@media (max-width:640px){body.v3 .em-sendcol{align-items:stretch}body.v3 .em-later{justify-content:space-between}}

/* ── Inbox views: Inbox · Sent · Responses · Scheduled · All ── */
body.v3 .ibx-views{display:flex;gap:var(--v2-s0);padding:var(--v2-s2) var(--v2-s3) 0;border-bottom:1px solid var(--v2-line)}
body.v3 .ibx-views button{position:relative;border:0;background:none;padding:var(--v2-s1h) var(--v2-s2) var(--v2-s2);font:500 var(--v2-t-body) var(--v2-sans);color:var(--v2-sub);cursor:pointer;border-radius:6px 6px 0 0}
body.v3 .ibx-views button:hover{color:var(--v2-ink);background:var(--v2-line2)}
body.v3 .ibx-views button.on{color:var(--v2-ink);font-weight:600;box-shadow:inset 0 -2px 0 var(--v2-accent)}
body.v3 .ibx-views button i{font-style:normal;font-size:var(--v2-t-label);color:var(--v2-sub);background:var(--v2-line2);border-radius:999px;padding:0 var(--v2-s1h);margin-left:var(--v2-s0)}
body.v3 .ibx-views button.on i{background:var(--v2-accent-soft);color:var(--v2-accent-ink)}
body.v3 .ibx-sched{cursor:default}
body.v3 .ibx-sched.failed .ibx-ir small{color:var(--v2-bad)}
body.v3 .ibx-sacts{display:flex;gap:var(--v2-s3);margin-top:var(--v2-s1)}
@media (max-width:640px){body.v3 .ibx-views{overflow-x:auto;padding-left:var(--v2-s2)}body.v3 .ibx-views button{white-space:nowrap}}

body.v3 .ibx-mailbox{display:flex;align-items:center;gap:var(--v2-s2);padding:var(--v2-s2) var(--v2-s3) 0;font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .ibx-mailbox select{font-size:var(--v2-t-small);padding:var(--v2-s1) var(--v2-s2);max-width:100%}

/* ── Inbox header, cut down: views row + one filter row ── */
body.v3 .ibx-views{align-items:center}
body.v3 .ibx-views select.ibx-mailbox{margin-left:auto;margin-bottom:var(--v2-s1h);height:26px;font:500 var(--v2-t-small) var(--v2-sans);border:1px solid var(--v2-line);border-radius:6px;background:var(--v2-panel);color:var(--v2-ink);padding:0 var(--v2-s5) 0 var(--v2-s2);max-width:120px}
body.v3 .ibx-fbar{display:flex;align-items:center;gap:var(--v2-s1h);padding:var(--v2-s2) var(--v2-s2);border-bottom:1px solid var(--v2-line)}
body.v3 .ibx-fbar .ibx-chips{flex:1;min-width:0;flex-wrap:nowrap;overflow-x:auto}
body.v3 .ibx-fbar .ibx-chips button{height:26px;padding:0 var(--v2-s2);font-size:var(--v2-t-small);white-space:nowrap}
body.v3 .ibx-sortsel{height:26px;font:500 var(--v2-t-small) var(--v2-sans);border:1px solid var(--v2-line);border-radius:6px;background:var(--v2-panel);color:var(--v2-sub);padding:0 var(--v2-s4) 0 var(--v2-s2);max-width:118px}
body.v3 .ibx-refresh{width:26px;height:26px;flex:none}
body.v3 .ibx-refresh svg{width:15px;height:15px}
body.v3 .ibx-refresh.busy svg{animation:ibx-spin 1s linear infinite}
@keyframes ibx-spin{to{transform:rotate(360deg)}}
body.v3 .ibx-sync{flex-basis:auto;padding:var(--v2-s1h) var(--v2-s3)}
body.v3 .ibx-fileall{align-self:flex-start;margin:var(--v2-s1h) var(--v2-s3) 0;font-size:var(--v2-t-small)}
@media (max-width:640px){body.v3 .ibx-views select.ibx-mailbox{max-width:96px}}

/* ── Whose mailbox: its own row, pills ── */
body.v3 .ibx-mbrow{display:flex;align-items:center;gap:var(--v2-s1);padding:var(--v2-s2) var(--v2-s2) 0;font-size:var(--v2-t-label);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint);font-weight:600}
body.v3 .ibx-mbrow span{margin-right:var(--v2-s1)}
body.v3 .ibx-mbrow button{height:24px;padding:0 var(--v2-s2);border-radius:999px;border:1px solid var(--v2-line);background:var(--v2-panel);color:var(--v2-sub);font:500 var(--v2-t-small) var(--v2-sans);letter-spacing:0;text-transform:none;cursor:pointer}
body.v3 .ibx-mbrow button.on{background:var(--v2-accent-soft);border-color:var(--v2-accent-line);color:var(--v2-accent-ink);font-weight:600}

/* ── Card → Outreach: who has been reached ── */
body.v3 .ccph-who td small{display:block;color:var(--v2-sub);font-size:var(--v2-t-label)}
body.v3 .ccph-who td.ccph-note{max-width:320px;font-size:var(--v2-t-small);line-height:1.35;white-space:normal}
body.v3 .ccph-who tr.quiet td{color:var(--v2-sub)}
body.v3 .ccph-nocand{font-size:var(--v2-t-label);color:var(--v2-faint)}
body.v3 .ccph-notyet{margin-top:var(--v2-s2)}
body.v3 .ccph-notyet summary{cursor:pointer;font-size:var(--v2-t-small);color:var(--v2-sub);padding:var(--v2-s1h) 0}
body.v3 .ccph-h small{display:block;font:400 var(--v2-t-small) var(--v2-sans);letter-spacing:0;margin-top:var(--v2-s0)}

/* ── Pipeline → Calendar: meetings before the bid ── */
body.v3 .mt-wrap{display:flex;flex-direction:column;gap:var(--v2-s3)}
body.v3 .mt-top{display:flex;flex-wrap:wrap;align-items:center;gap:var(--v2-s2)}
body.v3 .mt-top b{font-size:var(--v2-t-entity)}
body.v3 .mt-top small{display:block;margin-top:var(--v2-s0)}
body.v3 .mt-toggle{display:inline-flex;align-items:center;gap:var(--v2-s1h);font-size:var(--v2-t-small);color:var(--v2-sub)}
body.v3 .mt-body{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);gap:var(--v2-s4);align-items:start}
@media (max-width:1100px){body.v3 .mt-body{grid-template-columns:1fr}}
body.v3 .mt-month{background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:10px;padding:var(--v2-s3)}
body.v3 .mt-mhead{display:flex;align-items:center;gap:var(--v2-s2);margin-bottom:var(--v2-s2)}
body.v3 .mt-mhead b{font-size:var(--v2-t-entity);min-width:150px;text-align:center}
body.v3 .mt-grid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:var(--v2-s1)}
body.v3 .mt-wd{font:600 var(--v2-t-label) var(--v2-sans);letter-spacing:.05em;text-transform:uppercase;color:var(--v2-faint);text-align:center;padding:var(--v2-s0) 0}
body.v3 .mt-cell{min-height:84px;border:1px solid var(--v2-line2);border-radius:6px;padding:var(--v2-s1);display:flex;flex-direction:column;gap:var(--v2-s0);min-width:0}
body.v3 .mt-cell.empty{border:0}
body.v3 .mt-cell.past{opacity:.55}
body.v3 .mt-cell.today{border-color:var(--v2-accent);box-shadow:inset 0 0 0 1px var(--v2-accent)}
body.v3 .mt-n{font:600 var(--v2-t-label) var(--v2-sans);color:var(--v2-sub);font-variant-numeric:tabular-nums}
body.v3 .mt-chip{display:block;width:100%;text-align:left;border:0;border-left:3px solid var(--v2-line);background:var(--v2-line2);color:var(--v2-ink);border-radius:4px;padding:var(--v2-s0) var(--v2-s1);font:500 var(--v2-t-label)/1.3 var(--v2-sans);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer}
body.v3 .mt-chip.info{border-left-color:var(--v2-info,var(--v2-accent))}
body.v3 .mt-chip.warn{border-left-color:var(--v2-warn)}
body.v3 .mt-chip.ok{border-left-color:var(--v2-ok-dot)}
body.v3 .mt-chip.must{font-weight:700}
body.v3 .mt-more{font-size:var(--v2-t-label);color:var(--v2-faint)}
body.v3 .mt-agenda{display:flex;flex-direction:column;gap:var(--v2-s3)}
body.v3 .mt-day{background:var(--v2-panel);border:1px solid var(--v2-line);border-radius:10px;padding:var(--v2-s2) var(--v2-s3)}
body.v3 .mt-day.past{opacity:.6}
body.v3 .mt-dayh{display:flex;align-items:baseline;justify-content:space-between;gap:var(--v2-s2);padding-bottom:var(--v2-s1h);border-bottom:1px solid var(--v2-line2)}
body.v3 .mt-dayh small{color:var(--v2-sub);font-size:var(--v2-t-small)}
body.v3 .mt-row{display:grid;grid-template-columns:110px minmax(0,1fr);gap:var(--v2-s2);padding:var(--v2-s2) 0;border-bottom:1px solid var(--v2-line2)}
body.v3 .mt-row:last-child{border-bottom:0}
body.v3 .mt-when{font:600 var(--v2-t-small) var(--v2-sans);font-variant-numeric:tabular-nums;color:var(--v2-ink)}
body.v3 .mt-line{display:flex;flex-wrap:wrap;align-items:center;gap:var(--v2-s1h)}
body.v3 .mt-kind{font:600 var(--v2-t-label) var(--v2-sans);padding:var(--v2-s0) var(--v2-s2);border-radius:999px;background:var(--v2-line2);color:var(--v2-sub)}
body.v3 .mt-kind.info{background:var(--v2-accent-soft);color:var(--v2-accent-ink)}
body.v3 .mt-kind.warn{background:var(--v2-warn-soft,var(--v2-line2));color:var(--v2-warn)}
body.v3 .mt-kind.ok{background:var(--v2-ok-soft,var(--v2-line2));color:var(--v2-ok)}
body.v3 .mt-must{font:700 var(--v2-t-label) var(--v2-sans);letter-spacing:.04em;text-transform:uppercase;color:var(--v2-bad);border:1px solid var(--v2-bad);border-radius:999px;padding:0 var(--v2-s1h)}
body.v3 .mt-title{font-weight:600;text-align:left}
body.v3 .mt-detail{margin:var(--v2-s1) 0;font-size:var(--v2-t-small);line-height:1.4;color:var(--v2-sub)}
body.v3 .mt-undated summary{cursor:pointer;font-size:var(--v2-t-small);color:var(--v2-sub);padding:var(--v2-s1h) 0}
@media (max-width:640px){body.v3 .mt-cell{min-height:52px}body.v3 .mt-chip{font-size:0;height:6px;padding:0}body.v3 .mt-row{grid-template-columns:1fr}}

/* Inbox: compose a new email (not only a reply) */
body.v3 .ibx-composebtn.on{background:var(--v2-accent-soft);color:var(--v2-accent-ink)}
body.v3 .ibx-cform{display:flex;flex-direction:column;gap:var(--v2-s2);padding:var(--v2-s3) var(--v2-s3)}
body.v3 .ibx-cform label{display:grid;grid-template-columns:84px 1fr;align-items:center;gap:var(--v2-s2);font-size:var(--v2-t-body)}
body.v3 .ibx-cform label > span{color:var(--v2-sub);font-size:var(--v2-t-label);text-transform:uppercase;letter-spacing:.06em}
body.v3 .ibx-cform textarea{min-height:200px;resize:vertical;font:inherit;padding:var(--v2-s2) var(--v2-s2);border:1px solid var(--v2-line);border-radius:var(--v2-r-control);background:var(--v2-bg);color:var(--v2-ink)}
body.v3 .ibx-cform .ibx-cf{display:flex;align-items:center;gap:var(--v2-s2);flex-wrap:wrap}
body.v3 .ibx-cform .ibx-cf .sp{flex:1}

/* Inbox header, cleaned up: one line of views, one line of mailbox pills, one line of filters — nothing stacks or overlaps */
body.v3 .ibx-views{flex-wrap:nowrap;overflow-x:auto;overflow-y:hidden;gap:0;padding:var(--v2-s1h) var(--v2-s2) 0;scrollbar-width:none}
body.v3 .ibx-views::-webkit-scrollbar{display:none}
body.v3 .ibx-views button{display:inline-flex;align-items:center;gap:var(--v2-s1);white-space:nowrap;padding:var(--v2-s1h) var(--v2-s2) var(--v2-s2);font-size:var(--v2-t-small);line-height:1}
body.v3 .ibx-views button i{font-size:var(--v2-t-label);padding:0 var(--v2-s1);line-height:16px}
body.v3 .ibx-mbrow{flex-wrap:wrap;row-gap:var(--v2-s1);padding:var(--v2-s1h) var(--v2-s2) 0}
body.v3 .ibx-fbar{flex-wrap:wrap;row-gap:var(--v2-s1h);padding:var(--v2-s1h) var(--v2-s2) var(--v2-s2)}
body.v3 .ibx-fbar .ibx-chips{flex:1 1 140px}
body.v3 .ibx-sortsel{max-width:112px}
body.v3 .ibx-composebtn{height:26px;padding:0 var(--v2-s2);font-size:var(--v2-t-small);white-space:nowrap}
body.v3 .ibx-composebtn.on{background:var(--v2-accent-soft);color:var(--v2-accent-ink)}
body.v3 .ibx-none{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:var(--v2-s1h)}
/* Sub-to-prime */
body.v3 .sp-page{display:flex;flex-direction:column;gap:var(--v2-s3)}
body.v3 .sp-table td small{display:block;color:var(--v2-sub);font-size:var(--v2-t-label)}
body.v3 .sp-table .sp-act{display:flex;gap:var(--v2-s1h);align-items:center;flex-wrap:wrap;justify-content:flex-end}
body.v3 .sp-win{color:var(--v2-ok)}
body.v3 .sp-wait{color:var(--v2-sub)}
body.v3 tr.sp-awarded td{background:var(--v2-ok-soft)}
/* Inbox header, second pass: the view tabs WRAP instead of scrolling (a scrolling row clipped its own text); Compose is an icon beside refresh so the filter line stays one line */
body.v3 .ibx-views{flex-wrap:wrap;overflow:visible;row-gap:0;padding:var(--v2-s1h) var(--v2-s2) 0}
body.v3 .ibx-views button{padding:var(--v2-s1h) var(--v2-s1h) var(--v2-s2)}
body.v3 .ibx-composebtn{width:28px;height:26px;padding:0;display:inline-flex;align-items:center;justify-content:center;font-size:var(--v2-t-entity);border-radius:6px}

/* Activity rows open what they describe */
body.v3 .pd-actrow.go{cursor:pointer;border-radius:8px;transition:background var(--v2-fast)}
body.v3 .pd-actrow.go:hover{background:var(--v2-line2)}
body.v3 .pd-actrow.go:focus-visible{outline:2px solid var(--v2-accent);outline-offset:1px}
body.v3 .pd-actgo{font-size:var(--v2-t-label);color:var(--v2-sub);white-space:nowrap;opacity:0;transition:opacity var(--v2-fast);margin-right:var(--v2-s1)}
body.v3 .pd-actrow.go:hover .pd-actgo{opacity:1}
body.v3 .pd-actrow:not(.open) .pd-actextra{display:none}
body.v3 .pd-actrow.open .pd-actextra{display:block}
body.v3 .ccph-who tr.focus td{background:var(--v2-accent-soft);box-shadow:inset 3px 0 0 var(--v2-accent)}
body.v3 .ccph-row.focus{background:var(--v2-accent-soft);box-shadow:inset 3px 0 0 var(--v2-accent);border-radius:8px}

/* ══ R20 · One status signal ════════════════════════════════════════
   Measured on the live site before writing this: .st-pill.warm ("Onboarding")
   and .st-pill.ok ("Active") both computed to rgb(27,34,50) on rgb(166,176,191)
   — the SAME grey. The rule above at "body.v3 .chip,…,body.v3 .st-pill,…"
   sets background and colour at (0,2,1), which outranks v2.css's .st-pill.ok
   at (0,2,0). So the app was writing the status tone into the markup and then
   silently discarding it: two different states, one appearance.

   That is worse than having no colour at all. A reader who has learned that
   colour means something here is being told these two rows are alike.

   This restores the tone and, while it is at it, makes every status read the
   way Jarvis reads: a lit dot, then the state in a small uppercase letterspaced
   word. The research is blunt about why the dot matters — status must be
   colour PLUS a mark, never colour alone, or it disappears for anyone who
   cannot separate the hues.

   ── what is deliberately NOT included ──────────────────────────────
   `.chip` stays as it is. An arena chip ("govcon", "agency") is a CATEGORY,
   not a state, and it already carries its own colour meaningfully. Folding
   categories into the status system would make eight arenas look like eight
   severities. `.st-pill.on` and `.chip.on` are a SELECTED filter, also not a
   state, and are left alone below. */
body.v3 .st-pill,body.v3 .ppl-st,body.v3 .ig-badge{
  display:inline-flex;align-items:center;gap:var(--v2-s1h);
  font-size:var(--v2-t-label);font-weight:600;letter-spacing:.05em;
  text-transform:uppercase;padding:var(--v2-s0) var(--v2-s2);border-radius:999px;
  border:1px solid transparent;white-space:nowrap}
/* The dot. ::before so no markup anywhere has to change for it to appear. */
body.v3 .st-pill::before,body.v3 .ppl-st::before,body.v3 .ig-badge::before{
  content:"";width:6px;height:6px;border-radius:999px;flex:0 0 auto;
  background:currentColor;opacity:.9}
/* Tone, at a specificity that beats the flattening rule above. */
body.v3 .st-pill.ok,body.v3 .ppl-st.ok,body.v3 .ig-badge.ok,
body.v3 .st-pill.active,body.v3 .ppl-st.active{
  background:var(--v2-ok-soft);color:var(--v2-ok);border-color:var(--v2-ok-line)}
body.v3 .st-pill.warn,body.v3 .ppl-st.warn,body.v3 .ig-badge.warn{
  background:var(--v2-warn-soft);color:var(--v2-warn);border-color:var(--v2-warn-line)}
body.v3 .st-pill.bad,body.v3 .ppl-st.bad,body.v3 .ig-badge.bad{
  background:var(--v2-bad-soft);color:var(--v2-bad);border-color:var(--v2-bad-line)}
body.v3 .st-pill.acc,body.v3 .ppl-st.acc,body.v3 .ig-badge.acc{
  background:var(--v2-accent-soft);color:var(--v2-accent-ink);
  border-color:var(--v2-accent-line)}
/* The live one gets Jarvis's halo — the same ring as .jv-orb. */
body.v3 .st-pill.ok::before,body.v3 .ppl-st.active::before{
  box-shadow:0 0 0 3px var(--v2-ok-soft)}
/* A selected filter is not a status: no dot, no shouting. */
body.v3 .st-pill.on::before,body.v3 .chip.on::before{content:none}
body.v3 .st-pill.on{text-transform:none;letter-spacing:0}

/* ══ R21 · What's new folds ═════════════════════════════════════════
   42 unread entries, each rendering its whole paragraph, on the screen the
   owner opens every morning. A wall of prose is not read, it is scrolled
   past — which makes the feature worthless however carefully the entries
   are written. Title, date and the entry's own first sentence; the rest on
   a click. Nothing removed. */
/* NOT overflow:hidden. .ob-wnl is display:grid, and overflow:hidden on a
   grid item zeroes its automatic minimum size — every row collapsed to 2px
   and the whole changelog rendered as 42 blank lines on the live Dashboard.
   Measured: gridTemplateRows came back "2px 2px 2px …" while the button
   inside each row was 59px tall and clipped. The corners are kept round by
   matching the radius on the button instead. */
body.v3 .ob-wnl li{padding:0}
body.v3 .ob-wnt{border-radius:inherit}
body.v3 .ob-wnt{display:flex;align-items:baseline;gap:var(--v2-s2);width:100%;
  text-align:left;background:none;border:0;cursor:pointer;color:inherit;
  font:inherit;padding:var(--v2-s2) var(--v2-s3)}
body.v3 .ob-wnt:hover{background:var(--v2-line2)}
body.v3 .ob-wnt:focus-visible{outline:2px solid var(--v2-accent);outline-offset:-2px}
body.v3 .ob-wnti{flex:1;min-width:0;display:grid;gap:var(--v2-s0)}
body.v3 .ob-wnti b{font-size:var(--v2-t-entity);line-height:1.35;color:var(--v2-ink)}
body.v3 .ob-wnlede{font-size:var(--v2-t-small);line-height:1.45;color:var(--v2-sub);
  overflow:hidden;text-overflow:ellipsis;display:-webkit-box;
  -webkit-line-clamp:2;-webkit-box-orient:vertical}
body.v3 .ob-wnt small{color:var(--v2-sub);font-size:var(--v2-t-small);white-space:nowrap;
  font-variant-numeric:tabular-nums}
/* The chevron, drawn rather than typed, so it rotates. */
body.v3 .ob-wnx{width:7px;height:7px;flex:0 0 auto;border-right:1.5px solid var(--v2-sub);
  border-bottom:1.5px solid var(--v2-sub);transform:rotate(-45deg);
  transition:transform var(--v2-mid) var(--v3-ease,var(--v2-ease));align-self:center}
body.v3 .ob-wnl li.open .ob-wnx{transform:rotate(45deg)}
body.v3 .ob-wnb{padding:0 var(--v2-s3) var(--v2-s3);display:grid;gap:var(--v2-s1h)}
body.v3 .ob-wnb p{margin:0;font-size:var(--v2-t-body);line-height:1.55;color:var(--v2-sub)}
body.v3 .ob-wnl li.open{background:var(--v2-bg)}
@media (prefers-reduced-motion:reduce){body.v3 .ob-wnx{transition:none}}

/* ══ R22 · Documents fold ═══════════════════════════════════════════
   The record's Paperwork block measured 966px of a 2,772px page — the
   single biggest thing between the owner and the hours she came for. Each
   document carried a five-button status row, an upload control and two
   date fields whether or not anything needed doing to it.

   Shut, a document is one line: name, status, expiry. Open, it is exactly
   what it was. The ones that WANT something — required, asked for, or
   inside 90 days of expiry — open themselves, because a task folded away
   is a task nobody does. */
body.v3 .ppl-doc > .ppl-doc-h{display:flex;align-items:baseline;gap:var(--v2-s2);
  width:100%;text-align:left;background:none;border:0;color:inherit;font:inherit;
  cursor:pointer;padding:var(--v2-s2) var(--v2-s2);border-radius:var(--v2-r-control)}
body.v3 .ppl-doc > .ppl-doc-h:hover{background:var(--v2-line2)}
body.v3 .ppl-doc > .ppl-doc-h:focus-visible{outline:2px solid var(--v2-accent);
  outline-offset:-2px}
body.v3 .ppl-doc > .ppl-doc-h .sp{flex:1}
body.v3 .ppl-doc.shut{padding:0}
body.v3 .ppl-doc-x{width:7px;height:7px;flex:0 0 auto;align-self:center;
  border-right:1.5px solid var(--v2-sub);border-bottom:1.5px solid var(--v2-sub);
  transform:rotate(-45deg);transition:transform var(--v2-mid) var(--v3-ease,var(--v2-ease))}
body.v3 .ppl-doc.open .ppl-doc-x{transform:rotate(45deg)}
/* The document's state joins the one status signal (R20). */
body.v3 .ppl-dst{display:inline-flex;align-items:center;gap:var(--v2-s1h);
  font-size:var(--v2-t-label);font-weight:600;letter-spacing:.05em;
  text-transform:uppercase;padding:var(--v2-s0) var(--v2-s2);border-radius:999px;
  border:1px solid transparent;white-space:nowrap;
  background:var(--v2-line2);color:var(--v2-sub)}
body.v3 .ppl-dst::before{content:"";width:6px;height:6px;border-radius:999px;
  flex:0 0 auto;background:currentColor;opacity:.9}
body.v3 .ppl-dst.ok{background:var(--v2-ok-soft);color:var(--v2-ok);
  border-color:var(--v2-ok-line)}
body.v3 .ppl-dst.ok::before{box-shadow:0 0 0 3px var(--v2-ok-soft)}
body.v3 .ppl-dst.warn{background:var(--v2-warn-soft);color:var(--v2-warn);
  border-color:var(--v2-warn-line)}
body.v3 .ppl-dst.bad{background:var(--v2-bad-soft);color:var(--v2-bad);
  border-color:var(--v2-bad-line)}
@media (prefers-reduced-motion:reduce){body.v3 .ppl-doc-x{transition:none}}

/* ══ R23 · Finger-sized on a finger-sized screen ════════════════════
   Measured at 375px on the person record: 16 interactive controls under
   32px tall — the document status buttons at 26px, the contents rail at
   30px. Both platform guidelines put the floor at 44px (iOS) / 48dp
   (Android), and the gap is not pedantry: a 26px target between two other
   26px targets is how you mark a document "Not needed" while meaning
   "On file".

   Only on coarse pointers. A mouse is precise and a desktop screen is
   expensive, so nothing here changes what the owner sees on her laptop —
   this is the one case where the phone should be LESS dense, not more.

   min-height rather than padding so the text stays optically centred, and
   gap rather than margin so rows that wrap do not collide. */
@media (pointer:coarse){
  body.v3 .ppl-doc-a button,
  body.v3 .ppl-doc-a .ppl-up,
  body.v3 .ppl-rail button,
  body.v3 .ts-weeks button,
  body.v3 .wks-pid,
  body.v3 .pd-btn.sm,
  body.v3 .pd-linkbtn,
  body.v3 .ob-link,
  body.v3 .ibx-chips button,
  body.v3 .pd-pick button,
  body.v3 .st-seg button{
    min-height:44px;display:inline-flex;align-items:center;justify-content:center}
  body.v3 .ppl-doc-a{gap:var(--v2-s2)}
  body.v3 .ppl-doc > .ppl-doc-h,body.v3 .ob-wnt{min-height:48px}
  /* A link rendered as a button in a sentence must not become a 44px block
     in the middle of a paragraph — only the standalone ones grow. */
  body.v3 p .pd-linkbtn,body.v3 .pd-hint .pd-linkbtn,
  body.v3 .ts-what + .pd-linkbtn{min-height:0;display:inline}
}

/* ══ R24 · The board stops giving the dead equal billing ════════════
   Measured on the live board: six lanes at 231px each. New held 12
   pursuits, Sourcing 4, Quoting 0, Pricing 0, Submitting 0 — and Closed
   held 182. Ninety-two per cent of the cards sat in one sixth of the
   width, and three lanes with nothing in them were each as wide as the
   archive.

   That is the hierarchy exactly inverted. The live lanes are a workspace:
   things move through them and that is where the day's work is. Closed is
   a REFERENCE — you look things up in it, you do not work in it. Space and
   contrast should say which is which, and they were saying the opposite.

   So the archive narrows and quietens, the live lanes take the width back,
   and nothing is hidden: every closed card is still there, still
   scrollable, still a drop target. This is hierarchy by spacing, which is
   what the research says to reach for before borders and colour. */
body.v3 .ops-lanes .ops-col[data-terminal="1"]{
  flex:0 0 184px;min-width:184px;background:transparent;
  border:1px dashed var(--v2-line)}
body.v3 .ops-lanes .ops-col[data-terminal="1"] .ops-colh b{color:var(--v2-sub)}
body.v3 .ops-lanes .ops-col[data-terminal="1"] .ops-card{opacity:.72}
body.v3 .ops-lanes .ops-col[data-terminal="1"] .ops-card:hover,
body.v3 .ops-lanes .ops-col[data-terminal="1"]:focus-within .ops-card{opacity:1}
body.v3 .ops-lanes .ops-col:not([data-terminal="1"]){min-width:228px}
/* A dashed archive beside a solid workspace is the whole point; it must not
   look like a drop target that is refusing you, so the drag state is loud. */
body.v3 .ops-lanes .ops-col[data-terminal="1"].droptarget{
  border-style:solid;border-color:var(--v2-accent);background:var(--v2-accent-soft)}
@media (max-width:860px){
  body.v3 .ops-lanes .ops-col[data-terminal="1"]{flex:0 0 calc(100vw - 32px);
    min-width:0;border-style:solid}
}

/* ══ R25 · A passed deadline reads as one ═══════════════════════════
   Measured on the live call queue: "overdue by 2 days" and "closes in 5
   days" were both rgb(166,176,191) at weight 600 — the same grey, the same
   weight, in the same sentence position. One of those is a problem and the
   other is a Tuesday.

   Four bands, because three would lie by omission: overdue, today, inside
   three days, and everything further out (which stays plain, because most
   deadlines are fine and colouring them all is the same as colouring none).
   Tone plus a word, never tone alone — the words already said it, they just
   were not allowed to sound like it. */
body.v3 .dl{font-weight:600}
body.v3 .dl.over{color:var(--v2-bad)}
body.v3 .dl.today{color:var(--v2-warn)}
body.v3 .dl.soon{color:var(--v2-warn)}
body.v3 .dl.none{color:var(--v2-faint);font-weight:400;font-style:italic}

/* ══ R27 · The rail reports, not just points ════════════════════════
   A contents page that lists only headings still makes you go and look.
   With a note, the top of the record answers the question the owner
   actually arrived with — "has he logged any hours?" — without scrolling
   at all. The notes come from the sections themselves, so the rail cannot
   claim something the section does not say. */
body.v3 .ppl-rail button em{font-style:normal;font-weight:500;letter-spacing:0;
  text-transform:none;color:var(--v2-faint);font-variant-numeric:tabular-nums}
body.v3 .ppl-rail button[aria-current="true"] em{color:var(--v2-sub)}
body.v3 .ppl-rail button > span{letter-spacing:.05em}

/* ══ R33 · faint text on a selected row ════════════════════════════
   --v2-faint is tuned against the three neutral surfaces — ground, panel
   and muted fill — and clears 4.5:1 on all of them. A SELECTED row is a
   fourth surface it was never measured against: accent-soft, which is a
   tealish fill, and faint lands on it at 3.74:1.
   Rather than lighten the token everywhere for one state, faint steps up
   to sub inside a selected row. Selection already carries its own signal
   (the fill, the accent border); the quiet text does not also need to be
   quiet there. */
body.v3 .on .faint,
body.v3 .on .pd-hint,
body.v3 [aria-selected="true"] .faint,
/* The table variants carry their own .faint rule at `body.v2 <table> td
   .faint`, which is MORE specific than `body.v3 .on .faint` — three classes
   plus two elements beats three classes plus one. The first version of this
   fix shipped and changed nothing for exactly that reason; measured again
   and it was still 3.74. Matching their shape is the honest answer, not
   stacking a class on itself to win on a technicality. */
body.v3 .pt2-table tr.on td .faint,
body.v3 .net-table tr.on td .faint,
body.v3 .intel-table tr.on td .faint{color:var(--v2-sub)}

/* ══ R34 · dismiss the getting-started list ════════════════════════
   Two of the owner's five steps can never tick — she built the thing — so
   the list could never complete and never went away. Hidden per person,
   not deleted: the next hire needs it on their first morning. */
body.v3 .ob-x{margin-left:var(--v2-s2);width:26px;height:26px;flex:0 0 auto;
  border:0;border-radius:var(--v2-r-full);background:none;color:var(--v2-faint);
  font-size:var(--v2-t-entity);line-height:1;cursor:pointer;
  transition:color var(--v2-fast) var(--v2-ease),background-color var(--v2-fast) var(--v2-ease)}
body.v3 .ob-x:hover{background:var(--v2-line2);color:var(--v2-ink)}
body.v3 .ob-x:focus-visible{outline:2px solid var(--v2-accent);outline-offset:1px}
@media (pointer:coarse){body.v3 .ob-x{width:44px;height:44px}}

/* ══ R35 · Sources sought ══════════════════════════════════════════
   The quotes column says "asked, none in yet" rather than showing a zero.
   A zero on a dashboard reads as a failure; at this stage it is the
   expected and correct state, and the row should not look like a problem
   for being in it. */
body.v3 .ss-page{display:flex;flex-direction:column;gap:var(--v2-s3)}
body.v3 .ss-table td small{display:block;color:var(--v2-faint);
  font-size:var(--v2-t-label);margin-top:2px}
body.v3 .ss-early{color:var(--v2-sub);font-style:italic}
body.v3 .ss-act{white-space:nowrap;text-align:right}
body.v3 .ss-act .pd-linkbtn{margin-left:var(--v2-s2)}

/* ══ R36 · the sources-sought chip, beside the stage ════════════════
   The owner looked for this in the stage dropdown, because that is where
   you go to move a card. It lived on a separate Pipeline tab — the right
   place to see the list, the wrong place to put something on it. */
body.v3 .ss-chip{cursor:pointer;border:1px dashed var(--v2-line);
  background:none;color:var(--v2-sub);font:inherit;
  font-size:var(--v2-t-label);font-weight:600;
  transition:border-color var(--v2-fast) var(--v2-ease),color var(--v2-fast) var(--v2-ease)}
body.v3 .ss-chip:hover{border-color:var(--v2-accent);color:var(--v2-ink)}
body.v3 .ss-chip.on{border-style:solid;border-color:var(--v2-accent-line);
  background:var(--v2-accent-soft);color:var(--v2-accent-ink)}
body.v3 .ss-chip:focus-visible{outline:2px solid var(--v2-accent);outline-offset:1px}

/* ══ B1 · The board's controls are one row ═══════════════════════════
   Counters, filter button, quick filters and the "hidden" note used to be
   four stacked rows, pushing the first card to 29% of the screen height.
   They share a line now and wrap only when the screen forces it. */
body.v2 .ops-chrome{display:flex;flex-wrap:wrap;align-items:center;gap:var(--v2-s2) var(--v2-s4);margin:0 0 var(--v2-s3)}
body.v2 .ops-chrome>.ops-kpis,body.v2 .ops-chrome>.v3-boardbar{margin:0;flex:0 1 auto}
body.v2 .ops-chrome>.v3-fsel{flex:0 0 100%;margin:0}
body.v2 .ops-chrome>.ops-hidden{margin:0 0 0 auto;font-size:var(--t-sm)}

/* ══ B2 · Lanes size to their work ═══════════════════════════════════
   Six equal columns gave an empty Quoting the same width as a New lane
   holding eleven cards. Lanes with cards share the space (cards read in two
   lines instead of four); an empty lane folds to a slim tab. */
@media (min-width:861px){
body.v2 .ops-lanes .ops-lane{flex:1 1 280px;max-width:380px;min-width:240px}
body.v2 .ops-lanes .ops-lane[data-terminal="1"]{flex:0 0 200px;max-width:200px;min-width:200px}
body.v2 .ops-lanes .ops-lane.is-empty{flex:0 0 52px;min-width:52px;max-width:52px;
  transition:flex-basis var(--v2-fast),min-width var(--v2-fast),max-width var(--v2-fast)}
body.v2 .ops-lane.is-empty .ops-colh{flex-direction:column;align-items:center;gap:var(--v2-s2);padding:var(--v2-s3) 0;height:100%}
body.v2 .ops-lane.is-empty .ops-colh b,body.v2 .ops-lane.is-empty .ops-n{margin:0}
body.v2 .ops-lane.is-empty .ops-colh b{writing-mode:vertical-rl}
body.v2 .ops-lane.is-empty .ops-cards{display:none}
/* While a card is being dragged every lane opens, so the target is big and says what the lane is for. */
body.pd-dragging.v2 .ops-lanes .ops-lane.is-empty{flex:0 0 200px;min-width:200px;max-width:200px}
body.pd-dragging.v2 .ops-lane.is-empty .ops-colh{flex-direction:row;height:auto;padding:var(--v2-s2) var(--v2-s3)}
body.pd-dragging.v2 .ops-lane.is-empty .ops-colh b{writing-mode:horizontal-tb}
body.pd-dragging.v2 .ops-lane.is-empty .ops-cards{display:flex}
}
/* Phones keep the one-lane-per-screen swipe layout above: an empty lane there is a full screen that says what it is for. */

/* ══ B4 · The archive reads as a list ════════════════════════════════
   Forty full cards of No-Bid pursuits filled the Closed lane and told
   nobody anything. They are one line each now; Won and Lost keep their
   full cards because those are outcomes worth reading. */
body.v2 .pd-card.pd-row{padding:var(--v2-s1h) var(--v2-s2);border-color:transparent;background:transparent;border-radius:var(--v2-r-control,6px)}
body.v2 .pd-card.pd-row:hover{background:var(--v2-raised,var(--v2-panel));border-color:var(--v2-line);transform:none;box-shadow:none}
body.v2 .pd-card.pd-row .pd-card-t{font-weight:500;font-size:var(--t-sm);line-height:1.3;color:var(--v2-sub);
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1;overflow:hidden}
body.v2 .pd-card.pd-row:hover .pd-card-t{color:var(--v2-ink)}
body.v2 .ops-lane[data-terminal="1"] .ops-cards{gap:var(--v2-s0)}
html[data-theme] body.v2 .pd-card.pd-row{border-color:transparent;box-shadow:none}
html[data-theme] body.v2 .pd-card.pd-row:hover{border-color:var(--v2-line)}

/* ══ B5 · The board is one screen ════════════════════════════════════
   Lanes were as tall as their longest column (826px for eleven cards), so
   the page scrolled to reach the bottom of a lane. opsFit() sets --ops-fit to
   the room under the controls; every lane then scrolls inside itself. */
@media (min-width:861px){
  body.v2 .ops-boardwrap.lanes .ops-lanes{height:var(--ops-fit,70vh);align-items:stretch}
  body.v2 .ops-boardwrap.lanes .ops-lane{display:flex;flex-direction:column;min-height:0}
  body.v2 .ops-boardwrap.lanes .ops-lane .ops-colh{flex:0 0 auto}
  body.v2 .ops-boardwrap.lanes .ops-lane .ops-cards{flex:1 1 auto;min-height:0;overflow-y:auto}
}

/* ══ B6 · Phones: one lane per screen, with a tab strip ═══════════════
   The phone rule that was meant to make each lane a full screen was beaten
   by a later desktop rule (min-width:208px; flex:1 1 0), so a phone showed
   a lane and a half at 228px with no way to tell what was beyond it. The
   lanes are near full width again, and a strip names and counts them. */
.ops-lanetabs{display:none}
@media (max-width:860px){
  body.v3 .ops-lanes .ops-col:not([data-terminal="1"]),
  body.v3 .ops-lanes .ops-col[data-terminal="1"],
  body.v2 .ops-lanes .ops-col{flex:0 0 calc(100% - 28px);min-width:0;max-width:none;scroll-snap-align:start}
}

/* ══ B7 · Tablets: the same strip, two lanes to a screen ══════════════
   At 860-1000px the sidebar leaves ~530px, so the board showed two lanes and
   a scrollbar, with the rest unnamed. The strip names every lane and counts
   it; lanes snap two to a screen. */
@media (max-width:1000px){
  body.v2 .ops-lanetabs{display:flex;gap:var(--v2-s1);overflow-x:auto;scrollbar-width:none;margin:0 calc(var(--v2-s4) * -1) var(--v2-s2);padding:0 var(--v2-s4);
    position:sticky;top:0;z-index:5;background:var(--v2-bg);padding-block:var(--v2-s1h)}
  body.v2 .ops-lanetabs::-webkit-scrollbar{display:none}
  body.v2 .ops-lanetab{flex:0 0 auto;display:inline-flex;align-items:center;gap:var(--v2-s1h);min-height:36px;padding:0 var(--v2-s3);
    border:1px solid var(--v2-line);border-radius:var(--v2-r-full);background:transparent;color:var(--v2-sub);
    font:600 var(--v2-t-body) var(--v2-sans,inherit);cursor:pointer}
  body.v2 .ops-lanetab b{font-family:var(--v2-mono);font-variant-numeric:tabular-nums;font-weight:600}
  body.v2 .ops-lanetab.zero{opacity:.55}
  body.v2 .ops-lanetab.on{background:var(--v2-accent-soft);border-color:var(--v2-accent);color:var(--v2-accent-ink);opacity:1}
}
@media (min-width:861px) and (max-width:1000px){
  body.v2 .ops-lanes{scroll-snap-type:x proximity}
  body.v2 .ops-lanes .ops-lane:not(.is-empty){flex:0 0 calc(50% - 6px);max-width:none;min-width:0;scroll-snap-align:start}
}

/* ══ R37 · a locked key tells you where to change it ═══════════════
   The field said "set in Vercel, read-only here" and stopped, which is
   true and useless: the owner could see the SAM key was wrong and had
   nowhere to go. An environment value beats a stored one on purpose —
   that is a property worth keeping — so the answer is to say where the
   real switch is, not to move it. */
body.v3 .kf-locked{display:grid;gap:var(--v2-s2);padding:var(--v2-s3);
  border:1px dashed var(--v2-line);border-radius:var(--v2-r-control);
  background:var(--v2-bg)}
body.v3 .kf-locked p{margin:0;font-size:var(--v2-t-small);line-height:1.55;color:var(--v2-sub)}
body.v3 .kf-locked code{font-family:var(--v2-mono);font-size:var(--v2-t-label);
  background:var(--v2-line2);padding:var(--v2-s0) var(--v2-s1h);
  border-radius:4px;color:var(--v2-ink)}
body.v3 .kf-locked .pd-btn{justify-self:start}

/* ══ R39 · paper and rules, not boxes inside boxes ══════════════════
   Counted on the Dashboard: 64 bordered, rounded surfaces on one screen,
   46 of them list rows. That pattern — a 1px grey border, a 12-16px
   radius, a soft shadow, repeated down the page — is the most recognisable
   single tell of a generated interface, and no change of palette survives
   it. The research names it exactly: rounded-2xl, shadow-lg, muted greys.

   A printed document does not box every paragraph. It uses a rule, a
   change of weight, and space. That is the whole move here:

     · panels keep their paper background and lose the outline. Paper sits
       1.05 off the ground, which is enough to read as a sheet.
     · a radius of 3px, not 14. Enough to look cut rather than torn; not
       enough to look like a bubble.
     · list rows lose their individual boxes entirely and are separated by
       a hairline rule, the way a table or a statement separates rows.
     · the shadow goes. A document does not float.

   Nothing is hidden and no spacing is lost — this is the same information
   with the furniture taken away. */
body.v3 .st-card,
body.v3 .ob-new,
body.v3 .bz-card,
body.v3 .chartcard,
body.v3 .bx,
body.v3 .stat,
body.v3 .pd-panel,
body.v3 .v2-block,
body.v3 .ibx-list,
body.v3 .ibx-thread{
  border:0;
  border-radius:3px;
  box-shadow:none;
}
/* Rows in a list are rows, not cards. */
body.v3 .ob-wnl{gap:0}
body.v3 .ob-wnl li{
  border:0;border-radius:0;background:none;
  border-bottom:1px solid var(--v2-line)}
body.v3 .ob-wnl li:last-child{border-bottom:0}
body.v3 .ob-wnl li.fresh{
  border-left:2px solid var(--v2-accent);padding-left:var(--v2-s0)}
body.v3 .ob-wnl li.open{background:var(--v2-line2)}
/* A section heading earns a rule under it instead of a box around it. */
body.v3 .st-card > h3,
body.v3 .ob-wnh{
  padding-bottom:var(--v2-s2);
  border-bottom:1px solid var(--v2-line);
  margin-bottom:var(--v2-s3)}

/* ══ R41 · the Profile Builder language ════════════════════════════
   Borrowed from the owner's own other product, gmbtool.dnai.solutions,
   because she pointed at it rather than let me keep guessing — and her
   shipped taste beats my reasoning. What is taken is the SYSTEM, not any
   code or copy: a dark rail against a bone canvas, condensed uppercase
   headings, uppercase micro-labels, pill actions in burnt orange, and one
   bordered sheet per group with rules inside it rather than a box around
   every row. */

/* The rail goes dark against the light canvas. That split is the most
   recognisable thing about Profile Builder and it does real work here:
   navigation stops competing with the page for attention. */
/* V9 · `.app > aside`, not `aside`. These rules were written as
   `body.v3 aside`, which is EVERY <aside> in the app — and Comps has one:
   the evidence rail beside the three comparison cards. It was painted
   black along with the navigation, the only dark surface on a page of
   white cards, for no reason anyone could have guessed by looking at it.
   The sticky full-height rules above had the same reach. The navigation
   aside is the direct child of .app, and nothing else is.

   This rule carried !important for one afternoon, because index.html's
   inline <style> held `aside{background:var(--shell)!important}` and
   painted the rail white over it. That is gone — the inline block has
   no !important left in it at all — so the theme layers win on load
   order, which is how the cascade was always meant to settle this. */
body.v3 .app > aside{background:hsl(0 0% 9%);border-right:0}
body.v3 .app > aside .navitem,
body.v3 .app > aside .navlbl,
body.v3 .app > aside .brand-tag,
/* `body.v3 aside .ct` loses to `body.v3 .navitem .ct` higher up this file —
   three classes beat two — so the nine arena counts kept the --v2-faint
   grey that was measured for the PAPER canvas and sat at 3.31:1 on the
   near-black rail. Matching that selector's shape is what makes the
   override real; 62% lightness measures 6.7:1, and stays dimmer than the
   72% the labels beside it use, which is the job a count has. */
body.v3 .app > aside .navitem .ct{color:hsl(60 5% 62%)}
body.v3 .app > aside .navitem:hover{background:hsl(0 0% 15%);color:#fff}
/* On the dark rail the accent is the brand CYAN, not the deep blue —
   the blue measures 1.57:1 there and would vanish. 12.34:1, and it is the
   same cyan as the helix in the mark above it. */
body.v3 .app > aside .navitem.on{background:hsl(176 90% 49%);color:hsl(0 0% 9%);
  border-radius:var(--v2-r-full);font-weight:600}
body.v3 .app > aside .navitem.on .ct{color:hsl(0 0% 9%)}
/* The real mark, from the Brand folder. It survives the dark rail because
   its gradient runs periwinkle to cyan — the bright half carries it. */
body.v3 .app > aside .brand::before{content:"";display:block;width:104px;height:46px;
  margin-bottom:var(--v2-s1h);
  background:url("/brand/dnai-mark.png") left center/contain no-repeat}
/* The mark already SAYS "DNAi Solutions". Leaving the text wordmark beside
   it put the name on the rail twice — "DNAi · DNAi Solutions · Command
   Center", three things at the top of the rail, which is the exact fault
   R4 removed when it took out the old badge. The mark is the name now;
   "Command Center" stays, because that is what the product is. */
body.v3 .app > aside .brand .brand-n{display:none}
body.v3 .app > aside .brand .brand-tag{margin-top:0}
body.v3 .app > aside .brand,body.v3 .app > aside .brand b{color:#fff}

/* Headings: condensed, uppercase, lightly tracked — Oswald's register. */
body.v3 h1,body.v3 .ttl,body.v3 .st-card h2{
  font-family:var(--v2-display);text-transform:uppercase;
  letter-spacing:.01em;font-weight:600}

/* Actions are pills, as they are on Profile Builder. */
body.v3 .pd-btn,body.v3 .ob-cta,body.v3 .fm-btn{border-radius:var(--v2-r-full)}

/* R39 said panels lose their outline. Profile Builder keeps ONE border per
   group and rules the rows inside it, which is better: the sheet has an
   edge, and nothing inside it does. Corrected here rather than left as my
   more austere version. */
body.v3 .st-card,
body.v3 .ob-new,
body.v3 .bz-card,
body.v3 .chartcard,
body.v3 .pd-panel,
body.v3 .v2-block{
  border:1px solid var(--v2-line);border-radius:12px;background:var(--v2-panel)}

/* Column and section labels: the uppercase micro-label, 11.5px, tracked. */
body.v3 .find-table th,
body.v3 .v2-table th,
body.v3 .sope-score th,
body.v3 .wks-days th,
body.v3 .ppl-sec,
body.v3 .st-lbl{
  font-size:var(--v2-t-label);font-weight:600;letter-spacing:.04em;
  text-transform:uppercase;color:var(--v2-sub)}

/* ── Ready to hire: the ten boxes ──────────────────────────────────── */
/* No progress bar and no score, deliberately: nine of ten is not ninety
   per cent ready, and a bar that fills invites the last box to be waved
   through. The verdict is a sentence that names what is missing. */
body.v3 .sv-modal { max-width: 720px; }
body.v3 .sv-verdict { margin: 0 0 var(--v2-s3); padding: var(--v2-s3) var(--v2-s4);
  border-radius: 10px; background: var(--v2-panel);
  border-left: 3px solid var(--v2-line); line-height: 1.5; }
body.v3 .sv-verdict.good { border-left-color: var(--v2-ok); }
body.v3 .sv-verdict.bad { border-left-color: var(--v2-bad); }
body.v3 .sv-list { margin-top: var(--v2-s3); }
body.v3 .sv-row { display: grid; grid-template-columns: 28px 1fr; gap: var(--v2-s3);
  padding: var(--v2-s3) 0; border-top: 1px solid var(--v2-line); align-items: start; }
body.v3 .sv-row:first-child { border-top: 0; }
body.v3 .sv-box { width: 24px; height: 24px; border-radius: 6px; padding: 0;
  border: 1.5px solid var(--v2-line); background: transparent; cursor: pointer;
  font-size: var(--v2-t-entity); line-height: 1; color: var(--v2-ink); }
body.v3 .sv-row.on .sv-box { background: var(--v2-ok); border-color: var(--v2-ok); color: var(--on-bright); }
body.v3 .sv-row.bad .sv-box { background: var(--v2-bad); border-color: var(--v2-bad); color: var(--on-bright); }
body.v3 .sv-box.auto { display: grid; place-items: center; cursor: default; opacity: .9; }
body.v3 .sv-main { display: flex; flex-direction: column; gap: var(--v2-s1h); min-width: 0; }
body.v3 .sv-main > b { font-weight: 600; }
body.v3 .sv-ev { font-size: var(--v2-t-small); line-height: 1.5; color: var(--v2-sub); }
body.v3 .sv-ev.bad { color: var(--v2-bad); }
body.v3 .sv-who { font-size: var(--v2-t-label); color: var(--v2-sub); }
body.v3 .sv-exp { display: flex; align-items: center; gap: var(--v2-s2);
  font-size: var(--v2-t-small); color: var(--v2-sub); }
body.v3 .sv-row.stale { background: color-mix(in srgb, var(--v2-bad) 6%, transparent); }

/* The script list's group headings — nineteen scripts need the guide's
   own grouping, or the right one cannot be found. */
body.v3 .em-tplgrp { margin: var(--v2-s4) 0 var(--v2-s1h); padding: 0 var(--v2-s2);
  font-size: var(--v2-t-label); font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--v2-sub); }
body.v3 .em-tplgrp:first-child { margin-top: 0; }
