/* ============================================================
   Profit Plus  —  ProfitPlus Media team workspace (liquid-glass, brand red)
   Single-file team workspace. Replaces ClickUp Master Task List
   + Partner Status Tracker. Google-Sheets backed (Apps Script).
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* v637 RESET — the `hidden` attribute must always win.
   `hidden` is only a UA-stylesheet `[hidden]{display:none}` (specificity 0,1,0), so ANY author
   rule that sets `display` on the same element defeats it — `.dops-noresults{display:flex}`
   made "No clients match your search" render UNDER 5 visible clients on the phone. 42 classes
   across 8 files render with `hidden` while an author rule sets their display; 10 had already
   been patched one-at-a-time (`.home-fold-body[hidden]`, `.weeklog-detail[hidden]`, …).
   `!important` is required, not stylistic: most of those display rules live in <style> layers
   injected at runtime, so they land AFTER this file and equal specificity resolves on source
   order. Safe by construction — every show path removes the attribute (`.hidden = false` /
   `removeAttribute('hidden')`), so nothing that should be visible can be caught by this. */
[hidden] { display: none !important; }

:root {
  /* ============================================================
     LIGHT theme — DESIGN_LANGUAGE.md v1.0 · PHASE 1 (values only).
     Apple/Linear/Stripe bar: flat neutrals (no warm cast), borders
     instead of shadows, radii capped at 12px, one type family, red
     restricted to a real accent. Every token NAME preserved; new
     tokens are DEFINITIONS ONLY (call-sites land in Phase 2).
     Spec: .agents/DESIGN_LANGUAGE.md §2
     ============================================================ */
  /* Atmospheric background — flatter, cool-neutral (§2.7) */
  --bg-grad-1: #f2f4f7;
  --bg-grad-2: #eef1f6;
  --bg-grad-3: #f6f7f9;
  --bg-solid: #f4f6f9;
  --bg: #ffffff;        /* solid panel/inset base (alias used w/ fallbacks app-wide) */
  --bg-2: #f4f5f8;      /* recessed field base */
  --card: #ffffff;      /* opaque card base — cards are NEVER glass (§3.4) */
  /* Glass — only chrome, floating popovers and the modal scrim may use it (§2.9) */
  --glass: rgba(255,255,255,0.78);
  --glass-strong: rgba(255,255,255,0.90);
  --glass-border: var(--hairline);   /* was white-on-white = an invisible box */
  --surface-60: rgba(255,255,255,0.72);
  /* Hairlines — alpha-based so borders recede instead of drawing boxes (§2.5) */
  --hairline: rgba(15,23,42,0.07);
  --hairline-strong: rgba(15,23,42,0.12);
  --hairline-w: 1px;   /* dividers / row borders only; control borders stay 1px */
  /* Shadows — FLOATING layers only (§2.6). Cards/tiles/rows get a hairline, not these. */
  --shadow-sm: 0 1px 2px rgba(15,23,42,0.05);
  --shadow: 0 1px 2px rgba(15,23,42,0.04), 0 4px 12px rgba(15,23,42,0.07);
  --shadow-lg: 0 2px 4px rgba(15,23,42,0.05), 0 12px 32px rgba(15,23,42,0.12);
  /* Brand RED — the single accent (E5322B family). ONE accent per view (§2.7). */
  --accent: #E5322B;
  --accent-strong: #C81E18;
  --accent-fill: #D6261F;   /* solid fill behind WHITE text only — 5.05:1 AA (plain --accent is 4.35:1, fails) */
  --accent-soft: rgba(229,50,43,0.12);
  --accent-softer: rgba(229,50,43,0.06);
  /* Ink ramp — 4 steps, no hex text colors anywhere else (§2.7) */
  --text: #16181d;
  --text-2: #51555f;
  --text-3: #6b7079;
  --text-4: #9aa0aa;       /* disabled / quaternary */
  --text-on-accent: #ffffff;
  --surface: #f7f8fa;      /* OPAQUE (was rgba .65) — the muddiness fix */
  --surface-2: #fbfbfc;    /* OPAQUE (was rgba .40) */
  --row-hover: rgba(15,23,42,0.035);   /* NEUTRAL — red is not a hover state */
  --row-selected: rgba(15,23,42,0.055);
  /* Five semantic status slots (§2.7). --purple/--yellow/--orange/--gray stay
     defined for legacy call-sites but are BANNED in new UI. *-bg alpha = 0.12. */
  --slate:#4b5a74; --slate-bg:rgba(75,90,116,0.12);
  --green:#138a4e; --green-bg:rgba(19,138,78,0.12);
  --amber:#b06a00; --amber-bg:rgba(176,106,0,0.12);
  --blue:#2f6fed;  --blue-bg:rgba(47,111,237,0.12);
  --orange:#c2410c;--orange-bg:rgba(194,65,12,0.12);
  --red:#E5322B;   --red-bg:rgba(229,50,43,0.12);
  --purple:#7c3aed;--purple-bg:rgba(124,58,237,0.12);
  --gray:#6b7282;  --gray-bg:rgba(107,114,130,0.12);
  --yellow:#a16207;--yellow-bg:rgba(161,98,7,0.12);
  /* toast / scrollbar / overlays — flip in dark for contrast (B6) */
  --toast-bg: #16181d;
  --toast-text: #ffffff;
  --toast-error-bg: #C81E18;   /* deeper red so 13px white error text clears AA 4.5:1 (was #E5322B ≈ 4.0:1) */
  --scroll-thumb: rgba(17,24,39,0.16);
  --scroll-thumb-hover: rgba(17,24,39,0.30);
  --scrim: rgba(17,24,39,0.32);
  --scrim-strong: rgba(17,24,39,0.40);
  --placeholder: #8b909a;
  /* ONE type family. --font-display is an alias now — the second display face is dead app-wide (§2.1) */
  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Segoe UI', Roboto, sans-serif;
  --font-display: var(--font);
  --font-mono: ui-monospace, 'SF Mono', 'Menlo', monospace;   /* IDs, code, raw JSON only */
  /* Weights — exactly four, Inter optical compensation (§2.1). 550/600/650/700/750/800/900 banned. */
  --fw-normal: 400;
  --fw-medium: 510;
  --fw-semi: 590;
  --fw-bold: 680;
  /* Type scale — exactly eight steps, zero half-pixels (§2.1) */
  --fs-micro: 11px;
  --fs-small: 12px;
  --fs-body: 13px;
  --fs-md: 15px;
  --fs-lg: 17px;
  --fs-xl: 20px;
  --fs-metric: 26px;
  --fs-hero: 32px;
  /* Radii — 12px is THE CEILING (§2.4) */
  --radius-lg: 12px;   /* modal shell, full-height side panel */
  --radius: 10px;      /* large cards, sheets */
  --radius-md: 8px;    /* cards, panels, table wrappers, popovers */
  --radius-sm: 6px;    /* buttons, inputs, menu items, row selection */
  --radius-xs: 4px;    /* badges, chips, kbd, progress fills, tiny glyph squares */
  --radius-pill: 999px;/* avatars, status dots, count pills ONLY */
  --blur: blur(20px) saturate(120%);
  --blur-modal: blur(8px) saturate(110%);   /* backdrop scrim only */
  --topbar-h: 48px;
  --subbar-h: 40px;
  /* Control + row heights (§2.3) */
  --ctl-xs: 22px;      /* badge, chip, kbd chip, count pill, status pill */
  --ctl-sm: 26px;      /* dense inline control */
  --ctl-md: 32px;      /* DEFAULT: button, input, select trigger, menu item, tab */
  --ctl-lg: 38px;      /* primary CTA, search field, modal footer button */
  --ctl-touch: 44px;   /* mobile minimum only (≤720px) */
  --row-h: 36px;
  --row-h-head: 28px;
  --row-h-compact: 30px;
  --row-h-tall: 44px;
  --icon-sm: 14px; --icon-md: 16px; --icon-lg: 18px;   /* three icon sizes, no others */
  --sidebar-w: 240px;
  --sidebar-w-collapsed: 56px;
  --modal-w-sm: 400px; --modal-w: 520px; --modal-w-lg: 720px;
  /* 4px atomic spacing grid (§2.2) — 6/10/14/18 were off-grid */
  --space-0: 2px;
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --content-pad: 20px;      /* page gutter */
  --card-pad: 16px;         /* inside cards/panels */
  --card-pad-tight: 12px;   /* dense tiles, KPI cards */
  --row-pad-x: 12px;        /* list-row horizontal padding */
  --gap-grid: 12px;         /* gap between cards in a grid */
  /* z-index ladder (§2.11) — replaces ad-hoc 90/100/120/200/900/1000/2200 */
  --z-base: 1; --z-sticky: 50; --z-header: 100; --z-sidebar: 120;
  --z-overlay: 500; --z-popover: 600; --z-cmdk: 650;
  --z-panel: 690; --z-modal-backdrop: 699; --z-modal: 700;
  --z-toast: 800; --z-tooltip: 1100; --z-menu-float: 1200;
  /* iOS safe-area insets (0 on non-notched devices) */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --tabbar-h: 56px;
  /* SIM-14 · the vertical strip at the bottom of the viewport that the fixed tab bar owns.
     ONE definition, so a scroller that needs to end above the nav says --tabbar-safe instead of
     re-deriving the sum and drifting when --tabbar-h changes. Above 720px the bar is
     display:none and every consumer of this var lives inside a max-width:720px block.
     run5 §1.2: the bar now floats var(--g-s-2) above the safe area, so that gap is part of
     the strip too — otherwise the last row of every scroller hides under the pill. */
  /* run6 W5c (R6-5): +4px breathing room — 56+8 put the last row's edge EXACTLY on the bar's
     top edge (64px vs the ~67px needed), so the final row could sit ≤3px under the pill */
  --tabbar-safe: calc(var(--tabbar-h) + var(--safe-bottom) + var(--g-s-2, 8px) + 4px);
}

[data-theme="dark"] {
  /* ============================================================
     DARK theme — DESIGN_LANGUAGE.md v1.0 · PHASE 1 (values only).
     Warm cast removed (neutral near-blacks), opaque surfaces,
     neutral row hover, hairlines + shadows per §2.5/§2.6.
     Mirrors the light token set 1:1 (names identical).
     ============================================================ */
  --bg-grad-1: #0c0d10;
  --bg-grad-2: #0e0f13;
  --bg-grad-3: #101116;
  --bg-solid: #0a0b0e;
  --bg: #121317;          /* solid panel/inset base */
  --bg-2: #191a1f;        /* recessed field base */
  --card: #14151a;        /* opaque card base */
  /* Glass — chrome / floating popovers / modal scrim only (§2.9) */
  --glass: rgba(18,19,23,0.72);
  --glass-strong: rgba(20,21,26,0.88);
  --glass-border: var(--hairline);
  --surface-60: rgba(32,34,40,0.72);
  --hairline: rgba(255,255,255,0.08);
  --hairline-strong: rgba(255,255,255,0.14);
  /* Shadows — floating layers only (§2.6) */
  --shadow-sm: 0 1px 2px rgba(0,0,0,0.35);
  --shadow: 0 2px 6px rgba(0,0,0,0.40), 0 8px 20px rgba(0,0,0,0.35);
  --shadow-lg: 0 4px 12px rgba(0,0,0,0.45), 0 20px 48px rgba(0,0,0,0.50);
  /* Brand RED — single accent, brightened slightly for dark contrast */
  --accent: #FF4A42;
  --accent-strong: #FF6B63;
  --accent-fill: #E02D26;   /* solid fill behind WHITE text only — 4.6:1 AA (plain --accent #FF4A42 is 3.3:1, fails) */
  --accent-soft: rgba(255,74,66,0.20);
  --accent-softer: rgba(255,74,66,0.10);
  /* Ink ramp (dark) — 4 steps, soft off-white → cool gray */
  --text: #f2f3f5;
  --text-2: #c0c3ca;
  --text-3: #92959d;
  --text-4: #6c6f77;
  --text-on-accent: #ffffff;
  --surface: #1a1c21;      /* OPAQUE (was rgba(255,255,255,.045)) */
  --surface-2: #16171c;    /* OPAQUE (was rgba(255,255,255,.03)) */
  --row-hover: rgba(255,255,255,0.045);   /* neutral */
  --row-selected: rgba(255,255,255,0.07);
  /* Five semantic status slots (§2.7). *-bg alpha = 0.16 in dark. */
  --slate:#8a99b8; --slate-bg:rgba(138,153,184,0.16);
  --green:#3ad17f; --green-bg:rgba(58,209,127,0.16);
  --amber:#f0a23c; --amber-bg:rgba(240,162,60,0.16);
  --blue:#5b96ff;  --blue-bg:rgba(91,150,255,0.16);
  --orange:#fb923c;--orange-bg:rgba(251,146,60,0.16);
  --red:#FF4A42;   --red-bg:rgba(255,74,66,0.16);
  --purple:#a78bfa;--purple-bg:rgba(167,139,250,0.16);
  --gray:#9a9ca6;  --gray-bg:rgba(154,156,166,0.16);
  --yellow:#eab308;--yellow-bg:rgba(234,179,8,0.16);
  /* toast flips to light pill; scrollbar/overlays go lighter for dark bg (B6) */
  --toast-bg: #e9e9ee;
  --toast-text: #16181d;
  --toast-error-bg: #B11710;   /* deep red; white error text ≈ 6:1 in dark theme */
  --scroll-thumb: rgba(255,255,255,0.14);
  --scroll-thumb-hover: rgba(255,255,255,0.28);
  --scrim: rgba(0,0,0,0.56);
  --scrim-strong: rgba(0,0,0,0.66);
  --placeholder: #7c7f88;
}

html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body {
  font-family: var(--font);
  /* refined Inter rendering: real kerning, contextual ligatures, optical sizing */
  font-feature-settings: 'cv11', 'ss01', 'calt' 1, 'kern' 1;
  font-optical-sizing: auto;
  color: var(--text);
  line-height: 1.5;
  letter-spacing: -0.011em;   /* subtle negative tracking = crisper UI text */
  font-size: 14px;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  /* THE GROUND (run5, v695): paint from the theme system, not the legacy
     --bg-grad-* set. Before this, per-theme canvases (Cobalt's blue, Vellum's
     cream, every mesh) and auto-dark NEVER reached the body — glass.css §4
     built .g-app for exactly this and nothing ever applied it. Fallback keeps
     the old light gradient if glass/themes.css ever fail to load. */
  background-color: var(--g-canvas, var(--bg-grad-1));
  background-image: var(--g-mesh, none);
  background-size: cover;
  background-attachment: fixed;
  overflow-x: hidden;
}
/* iOS: fixed-attachment repaints every frame (glass.css §4's documented trap) */
@media (pointer: coarse) {
  body, .login-screen { background-attachment: scroll; }
}
/* ---- Typography base (v235): display face on headings, tighter optical tracking,
   tabular numerals where digits live. Pure value/feature layer — no markup change. ---- */
/* run7 W4: `.home-hero-title` dropped from this selector list — DEAD. Zero hits app-wide; Home's
   hero renders its heading as `.home-greet` (still listed) inside `.home-hero`. The other six
   selectors here are live and keep the display face. */
h1, h2, h3, .brand-name, .modal-head h3, .home-greet {
  font-family: var(--font-display);
  letter-spacing: -0.02em;
  font-feature-settings: 'ss01', 'kern' 1;
}
h1 { line-height: 1.12; } h2 { line-height: 1.18; } h3 { line-height: 1.25; }
/* money / time / counts read aligned across rows */
table, .ptable, .ptable td, .ptable th { font-variant-numeric: tabular-nums; }

/* --- App shell --- */
/* ⚠️ DEAD RULE — READ THIS BEFORE YOU TRUST THE 1640px CAP.
   Nothing in this app ever carries `class="app"`. Verified two ways on 2026-08-06:
   (1) grep — the only `app` class tokens in the tree are `cal-det-badge-app` (js/calendar.js)
   and `g-app` in glass-spec.html, which is a spec page, not the product;
   (2) live page — `document.querySelectorAll('.app').length === 0`, and `.layout` / `main.main`
   / `.content` all compute `max-width: none`.
   The REAL shell is `<div class="layout" id="layout">` (index.html body), and it is UNCAPPED.
   Consequence, and it is the headline wide-end finding: at 2560px and 3840px the content column
   is ~2250px / ~3530px wide and every fixed-column grid (.home-stats 4-col, .pay-cards 3-col,
   .apl-cards2 4-col, .ar-aging-grid 4-col, .adsv-metrics 6-col) stretches with it. `.home` is
   the ONLY capped surface — and its cap is NOT one number: `max-width:760px` at index.html:528,
   raised to **1000px** by `@media (min-width:1100px)` at index.html:2067-2068. So on every screen
   the owner actually uses (1512 / 1728 / 2560 / 3840) the effective cap is 1000px, not 760px.
   [Corrected 2026-08-06 — the first draft of this tombstone asserted a flat 760px. A verifier
   measured 1000px in a real browser and was right. A comment written to stop the next reader
   trusting a stale declaration must not itself contain one.]
   Left in place rather than deleted because whether the app should be capped at wide widths is
   the OWNER's call, not a lane's — but do not read this line as evidence that it already is. */
.app { display: flex; flex-direction: column; min-height: 100vh; max-width: 1640px; margin: 0 auto; }

/* run6 W5a: `.topbar` deleted — DEAD. Zero markup hits for class="topbar" in index.html or any
   js/*.js (the app chrome was rebuilt on .mainhead/.sidebar/.g-chrome; client-portal.js builds its
   own .g-topbar recipe). The --topbar-h token is still live elsewhere and stays in the themes. */
.brand { display: flex; align-items: center; gap: 11px; flex-shrink: 0; }
.brand-logo {
  width: 34px; height: 34px; border-radius: var(--radius-md); position: relative; overflow: hidden;
  background: #0b0b0e;
  display: grid; place-items: center; color: #fff;
  box-shadow: 0 4px 14px rgba(0,0,0,0.28), inset 0 0 0 1px rgba(255,255,255,0.06);
}
/* the fallback lion SVG fills the badge; the real PNG sits on top, padded so the
   transparent lion is faithfully framed (no edge-clipping) and crisp */
.brand-logo svg { width: 72%; height: 72%; display: block; }
.brand-logo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; object-position: center; padding: 4px; background: transparent; image-rendering: -webkit-optimize-contrast; }
.brand-name { font-weight: 700; font-size: 15px; letter-spacing: -0.2px; white-space: nowrap; }
.brand-name span { color: var(--text-3); font-weight: 500; }

.mod-tabs { display: flex; gap: 4px; margin-left: 6px; background: var(--surface-2); padding: 4px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); }
.mod-tab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 14px; border-radius: var(--radius-sm); font-size: 13.5px; font-weight: 600;
  color: var(--text-2); cursor: pointer; border: none; background: transparent;
  transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; white-space: nowrap;
}
.mod-tab:hover { color: var(--text); }
.mod-tab.active { background: var(--glass); color: var(--accent); box-shadow: var(--shadow-sm); }
.mod-tab svg { width: 16px; height: 16px; }

.icon-btn {
  width: 36px; height: 36px; border-radius: var(--radius-md); border: 1px solid var(--hairline);
  background: var(--surface); color: var(--text-2); cursor: pointer;
  display: grid; place-items: center; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; flex-shrink: 0;
}
.icon-btn:hover { color: var(--text); background: var(--glass-strong); }
.icon-btn svg { width: 17px; height: 17px; }

/* Viewing-as switcher */
.viewas { position: relative; }
.viewas-btn {
  display: flex; align-items: center; gap: 9px; padding: 5px 10px 5px 6px;
  border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface);
  cursor: pointer; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease;
}
.viewas-btn:hover { background: var(--glass-strong); box-shadow: var(--shadow-sm); }
.avatar {
  width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center;
  font-size: 11px; font-weight: 700; color: #fff; flex-shrink: 0; letter-spacing: -0.3px;
  overflow: hidden;
}
/* a photo avatar: constrain the image to the circle so an upload never blows up the layout */
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: inherit; }
/* v666 — PRESENCE DOT, BASE STATE. paintPresence() (js/app.js) injects a #pres-css <style> the first
   time it runs, and until then these two classes had no rule anywhere: the wrapper was a plain inline
   box with no positioning context and the dot was a 0×0 unsized <i>. Every avatar in the app wears
   them, so the very first paint of Team, Tasks, Payroll or a partner card shipped an element with no
   geometry, and the dot popped into existence on the first presence poll. The declarations below are
   the SAME ones paintPresence injects, so nothing changes once it runs — its <style> lands later in
   <head> at equal specificity and simply re-states these values. The scoped V2 overrides
   (.v2prl/.v2mpy .pres-wrap .pres-dot in v2/payments.css, specificity 0,3,0) still win over both. */
.pres-wrap { position: relative; display: inline-flex; flex: none; }
.pres-dot {
  position: absolute; right: -1px; bottom: -1px; width: 10px; height: 10px; border-radius: 50%;
  background: #86868b; border: 2px solid var(--bg-solid, var(--bg, #fff));
  box-shadow: 0 0 0 .5px rgba(0,0,0,.08); transition: background .2s;
}
.pres-wrap.is-online .pres-dot { background: var(--green, #27c06a); }
.viewas-meta { text-align: left; line-height: 1.1; }
.viewas-meta b { font-size: 12.5px; font-weight: 600; display: block; }
.viewas-meta small { font-size: 11px; color: var(--text-3); font-weight: 500; }
/* view-as: highlight the toggle while impersonating + the exit row + the "you" badge */
.sb-viewas-btn.is-viewing { color: var(--accent); background: var(--accent-softer); }
.menu .viewas-exit { color: var(--accent); border-bottom: 1px solid var(--hairline); border-radius: 0; }
.menu .viewas-exit b { color: var(--accent); }
.menu .viewas-exit svg { width: 16px; height: 16px; }
.viewas-you { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--text-3); background: var(--surface-2); border-radius: var(--radius-xs); padding: 1px 5px; margin-left: 6px; }
.viewas-btn .chev { width: 14px; height: 14px; color: var(--text-3); }

/* Dropdown menu (shared). run6 W5c: surface → .glass-3 at every shell site in js/app.js
   (24 className builders + 1 template — app.js owns ALL shells, grep-proven). NOT .g-menu:
   this system animates via its own `.open` class below, and .g-menu ships visibility:hidden
   keyed to .is-open, which would permanently hide every menu. Only the four surface props
   moved; the open machinery stays. */
.menu {
  position: absolute; top: calc(100% + 8px); right: 0; min-width: 240px; z-index: 200;
  padding: 7px; opacity: 0; visibility: hidden; transform: translateY(-6px) scale(.98);
  transition: opacity var(--dur-2) cubic-bezier(.2,.8,.2,1), transform var(--dur-2) cubic-bezier(.2,.8,.2,1), visibility var(--dur-2) cubic-bezier(.2,.8,.2,1); transform-origin: top right;
}
.menu.open { opacity: 1; visibility: visible; transform: translateY(0) scale(1); }
.menu-label { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-3); font-weight: 700; padding: 8px 10px 5px; }
.menu-item {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--radius-md);
  cursor: pointer; font-size: 13px; color: var(--text); transition: background var(--dur-1) ease; border: none; background: transparent; width: 100%; text-align: left; font-family: var(--font);
}
.menu-item:hover { background: var(--row-hover); }
.menu-item.active { background: var(--accent-soft); color: var(--accent); }
.menu-item .ck { margin-left: auto; width: 15px; height: 15px; color: var(--accent); opacity: 0; }
.menu-item.active .ck { opacity: 1; }
.menu-item small { display: block; color: var(--text-3); font-size: 11px; font-weight: 500; }
/* uiSelect floating menu sits above modals/panels */
.uis-menu { z-index: 2200; max-height: 320px; overflow-y: auto; }

/* ---- uiSelect (custom dropdown that replaces native <select>) ---- */
.uiselect { position: relative; width: 100%; }
.uis-trigger {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%;
  padding: 10px 12px; border-radius: var(--radius-md); border: 1px solid var(--hairline);
  background: var(--surface); color: var(--text); font-size: 13.5px; font-weight: 500;
  font-family: var(--font); cursor: pointer; text-align: left; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease;
}
.uis-trigger:hover { background: var(--glass-strong); border-color: var(--hairline-strong); }
.uis-trigger.uis-open { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-softer); background: var(--glass-strong); }
.uis-val { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.uis-txt { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.uis-txt.is-ph { color: var(--text-3); }
.uis-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.uis-chev { width: 14px; height: 14px; color: var(--text-3); flex-shrink: 0; transition: transform var(--dur-2) ease; }
.uis-trigger.uis-open .uis-chev { transform: rotate(180deg); }
/* compact inline variant (group-by control in the header) */
.uiselect.uis-inline { width: auto; display: inline-block; }
.uis-inline .uis-trigger { padding: 7px 10px; border-radius: var(--radius-sm); font-size: 12.5px; font-weight: 600; }

/* ---- side-panel field trigger (opens our picker, not the Apple menu) ---- */
.fv-trigger {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%;
  padding: 7px 10px; border-radius: var(--radius-sm); border: 1px solid transparent; background: transparent;
  color: var(--text); font-size: 13px; font-family: var(--font); cursor: pointer; text-align: left;
  transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease;
}
.fv-trigger:hover { background: var(--surface); border-color: var(--hairline); }
.fv-trigger.uis-open { background: var(--glass-strong); border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-softer); }
.fv-trigger-val { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.fv-trigger-val span:last-child { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fv-trigger.is-ph .fv-trigger-val span:last-child { color: var(--text-3); }
.fv-multi { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px; cursor: pointer; padding: 4px 6px; border-radius: var(--radius-sm); border: 1px solid transparent; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; min-height: 30px; }
.fv-multi:hover { background: var(--surface); border-color: var(--hairline); }

/* ---- danger button + confirm message (uiConfirm) ---- */
/* V734-P1 · the plate rule, literal-ink family. `#fff` on the OPAQUE --red plate failed 13/24
   theme/mode blocks (worst 1.150, cobalt/light — "Delete" barely legible; ink/dark 3.034). Opaque
   plate ⇒ ground-independent: it fails on every rung, in every module, with no ceiling-note escape.
   --g-text-on-red is the per-theme ink built for exactly this and measures 0/24 (worst 5.503).
   Same shape as the .clock-btn.work.is-stop precedent at :651; #fff stays as the no-stylesheet fallback. */
.btn-danger { background: var(--red); color: var(--g-text-on-red,#fff); box-shadow: 0 6px 18px var(--red-bg); }
.btn-danger:hover { filter: brightness(1.05); }
.ui-confirm-msg { font-size: 13.5px; line-height: 1.55; color: var(--text-2); margin: 0; white-space: pre-line; }

/* ══ ORCH-1 · THE ONE TAP-TARGET PREDICATE ══════════════════════════════════
   `@media (max-width: 720px), (hover: none) and (pointer: coarse)` — the UNION.
   Before this, the app enforced its 44px minimum through TWO predicates that were
   not supersets of one another, so two real, common situations lost half their
   targets: a touch laptop / iPad (>720px + coarse pointer) missed everything on
   the width-only query (.btn, .menu-item, .sb-list, the pickers), and a narrow
   desktop window (<=720px + mouse) missed everything on the capability-only query
   (every close X, every modal-footer button, the Ads-Manager controls).
   The union is what "give me a real tap target" actually means.
   RULE FOR ANYONE EDITING THIS FILE: a tap target is a POINTER concern and goes
   on the union; stacking / column-collapse / sheet geometry is a WIDTH concern and
   stays on `(max-width: 720px)` alone. Mixing the two is what created the split.
   Every rule on the union is a floor (min-height / a fixed 44px box), so widening
   the predicate can only ever raise a target, never shrink a correct one. */
@media (max-width: 720px), (hover: none) and (pointer: coarse){
  .uis-trigger, .fv-trigger { min-height: 44px; }
  .menu-item { min-height: 44px; }
  .fv-multi { min-height: 44px; }
}
@media (max-width: 720px){
  /* phone-only compaction — an INLINE status trigger sits inside a row, not on its own.
     (0,2,0), so it beats the 44px floor above on specificity regardless of source order.
     Deliberately NOT on the union: a tablet / touch laptop gets the full 44px here. */
  .uis-inline .uis-trigger { min-height: 38px; }
  /* never let a floating picker/menu overflow a phone's right edge; long labels truncate */
  .menu { max-width: calc(100vw - 16px); }
  .menu .menu-item .mi-label, .menu .menu-item small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* run6 W5a: `.subbar` deleted — DEAD. Zero markup hits for class="subbar" anywhere (view tabs and
   module actions render inside .mainhead/.view-tabs now). Its sibling `.subbar-spacer` below is
   left untouched — different class, out of this wave's dead-code ruling. */
.view-tabs { display: flex; gap: 3px; }
.view-tab {
  padding: 6px 13px; border-radius: var(--radius-sm); font-size: 13px; font-weight: 600; cursor: pointer;
  color: var(--text-2); border: 1px solid transparent; background: transparent; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease;
  display: inline-flex; align-items: center; gap: 6px; font-family: var(--font);
}
.view-tab svg { width: 15px; height: 15px; }
.view-tab:hover { color: var(--text); background: var(--surface); }
.view-tab.active { color: var(--text); background: var(--glass-strong); border-color: var(--hairline); box-shadow: var(--shadow-sm); }
.subbar-spacer { flex: 1; }

.chip-filter { display: inline-flex; align-items: center; gap: 7px; }
.chip {
  padding: 6px 12px; border-radius: var(--radius-sm); font-size: 12.5px; font-weight: 600; cursor: pointer;
  border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2);
  transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; font-family: var(--font);
}
.chip:hover { color: var(--text); border-color: var(--hairline-strong); }
.chip.active { background: var(--accent); color: var(--text-on-accent); border-color: var(--accent); box-shadow: 0 2px 8px var(--accent-soft); }

.btn {
  display: inline-flex; align-items: center; gap: 7px; padding: 8px 15px; border-radius: var(--radius-md);
  font-size: 13px; font-weight: 600; cursor: pointer; border: 1px solid transparent;
  font-family: var(--font); transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease, filter var(--dur-2) ease; white-space: nowrap;
}
.btn svg { width: 16px; height: 16px; }
/* Primary — refined red with a soft branded glow + subtle top sheen (depth, not flat fill) */
.btn-primary {
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent-fill) 92%, #fff 8%), var(--accent-fill));
  color: var(--text-on-accent);
  box-shadow: 0 1px 1px rgba(0,0,0,.06), 0 6px 16px var(--accent-soft), inset 0 1px 0 rgba(255,255,255,.18);
}
.btn-primary:hover { background: var(--accent-strong); box-shadow: 0 2px 3px rgba(0,0,0,.08), 0 10px 24px var(--accent-soft), inset 0 1px 0 rgba(255,255,255,.16); }
.btn-ghost { background: var(--surface); color: var(--text); border-color: var(--hairline); box-shadow: var(--shadow-sm); }
.btn-ghost:hover { background: var(--glass-strong); border-color: var(--hairline-strong); }
.btn-sm { padding: 6px 11px; font-size: 12.5px; border-radius: var(--radius-sm); }

/* Main content */
.content { flex: 1; padding: var(--content-pad); }

/* ===================== HOME — brief, glanceable command center ===================== */
.home { max-width: 760px; margin: 0 auto; width: 100%; display: flex; flex-direction: column; gap: var(--space-4); padding-bottom: var(--space-2); }
.home-hero { padding: 2px 2px 0; }
.home-greet { font-size: var(--fs-small); line-height: 16px; color: var(--text-3); font-weight: var(--fw-medium); }
.home-name { font-size: var(--fs-xl); font-weight: var(--fw-bold); letter-spacing: -0.020em; line-height: 26px; margin: var(--space-0) 0 var(--space-1); color: var(--text); }
.home-date { font-size: var(--fs-small); line-height: 16px; color: var(--text-3); font-weight: var(--fw-normal); }

.home-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--gap-grid); }
/* run6 W5b: surface props deleted — markup now ships `home-stat glass-2` (js/app.js). Hover
   re-pin retargeted to the glass fill ramp (--g-fill-3 = one tier up, keeps sheen+blur);
   the old border-color half is dead with the border. */
.home-stat { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1); padding: var(--card-pad-tight); cursor: pointer; font-family: var(--font); transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); text-align: left; }
.home-stat:hover { background-color: var(--g-fill-3); }
.home-stat-n { font-size: var(--fs-xl); font-weight: var(--fw-bold); letter-spacing: -0.020em; font-variant-numeric: tabular-nums; line-height: 26px; color: var(--text); }
.home-stat-l { font-size: var(--fs-micro); line-height: 14px; font-weight: var(--fw-semi); color: var(--text-3); }
.home-stat.is-red .home-stat-n { color: var(--red); }
/* Admin agency snapshot on Home — the money that matters, each card deep-links to its full page */
.home-ov { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap-grid); margin-bottom: var(--space-1); }
/* run6 W5b: surface props deleted — markup now ships `home-ov-card glass-2` (js/app.js);
   hover retargeted to the glass fill ramp. */
.home-ov-card { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1); padding: var(--card-pad-tight); cursor: pointer; font-family: var(--font); text-align: left; transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.home-ov-card:hover { background-color: var(--g-fill-3); }
.home-ov-k { font-size: var(--fs-micro); line-height: 14px; font-weight: var(--fw-semi); color: var(--text-3); text-transform: uppercase; letter-spacing: .05em; }
.home-ov-v { font-size: var(--fs-metric); font-weight: var(--fw-bold); letter-spacing: -0.024em; font-variant-numeric: tabular-nums; line-height: 28px; color: var(--text); }
.home-ov-sub { font-size: var(--fs-micro); line-height: 14px; font-weight: var(--fw-normal); color: var(--text-3); }
@media (max-width: 700px) { .home-ov { grid-template-columns: repeat(2, 1fr); } }
/* Overdue-AR callout under the Home agency snapshot — the owner's #1 cash-survival signal */
.home-ov-alert { display: flex; align-items: center; gap: var(--space-2); width: 100%; margin-top: var(--space-2); padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); border: 1px solid color-mix(in srgb, var(--red) 28%, transparent); background: var(--red-bg); color: var(--red); font-family: var(--font); font-size: var(--fs-body); font-weight: var(--fw-medium); cursor: pointer; text-align: left; transition: background-color var(--dur-1) var(--ease); }
.home-ov-alert:hover { background: color-mix(in srgb, var(--red) 18%, transparent); }
.home-ov-alert svg { width: var(--icon-md); height: var(--icon-md); flex: none; }
.home-ov-alert b { font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; }
.home-ov-alert-cta { margin-left: auto; font-weight: var(--fw-semi); white-space: nowrap; }
/* New-leads pill (Home) — fresh-lead urgency, deep-links to the pipeline */
.home-newleads { display: flex; align-items: center; gap: var(--space-2); width: 100%; margin-top: var(--space-2); padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); border: 1px solid color-mix(in srgb, var(--green) 28%, transparent); background: var(--green-bg); color: var(--green); font-family: var(--font); font-size: var(--fs-body); font-weight: var(--fw-medium); cursor: pointer; text-align: left; transition: background-color var(--dur-1) var(--ease); }
.home-newleads:hover { background: color-mix(in srgb, var(--green) 18%, transparent); }
.home-newleads b { font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; }
.home-nl-dot { width: 8px; height: 8px; border-radius: var(--radius-pill); background: var(--green); flex: none; }
.home-nl-cta { margin-left: auto; font-weight: var(--fw-semi); white-space: nowrap; }

/* Agency pulse (admin) */
.home-pulse-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--gap-grid); padding: var(--space-1) var(--space-2) var(--space-3); }
@media (max-width: 640px){ .home-pulse-grid { grid-template-columns: repeat(2, 1fr); } }
/* run6 W5b: surface props deleted — markup now ships `home-pulse-tile g-solid-2` (js/app.js;
   repeated per-client grid, so the opaque twin). Hover border-color re-pin is dead with the
   border — retargeted to the solid ramp (--g-solid-3 = one tier up in every theme-mode). */
.home-pulse-tile { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-1); padding: var(--card-pad-tight); cursor: pointer; font-family: var(--font); text-align: left; transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.home-pulse-tile:hover { background-color: var(--g-solid-3); }
.home-pulse-n { font-size: var(--fs-xl); font-weight: var(--fw-bold); letter-spacing: -0.020em; font-variant-numeric: tabular-nums; line-height: 26px; color: var(--text); }
.home-pulse-l { font-size: var(--fs-micro); line-height: 14px; font-weight: var(--fw-semi); color: var(--text-3); }
.home-pulse-tile.is-red .home-pulse-n { color: var(--red); }

/* run6 W5b: surface props deleted — every render site now ships `home-card glass-2` (js/app.js,
   20 template sites incl. cr-card/rg-card/home-clock variants) and the post-paint
   _glassifyHomeRegion decorator is retired. The leftover 1px border was double-edging every
   themed card (glass edges are box-shadow, not border). Tight padding kept — children rows
   (.home-task/.home-risk-row/…) rely on it; no .g-pad. */
.home-card { padding: var(--space-1); }
.home-card-h { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-3) var(--row-pad-x) var(--space-2); font-size: var(--fs-micro); line-height: 14px; font-weight: var(--fw-semi); letter-spacing: .05em; text-transform: uppercase; color: var(--text-3); }
.home-card-h svg { width: var(--icon-sm); height: var(--icon-sm); color: var(--text-3); }
.home-card-meta { margin-left: auto; text-transform: none; letter-spacing: 0; font-size: var(--fs-micro); font-weight: var(--fw-semi); color: var(--text-3); background: var(--surface-2); border-radius: var(--radius-pill); padding: var(--space-0) var(--space-2); }
/* foldable Home sections (at-risk / agency pulse) — Task #11 */
.home-fold-h { cursor: pointer; -webkit-user-select: none; user-select: none; }
.home-fold-h .home-card-meta { margin-left: auto; }
.home-risk-title { display: inline-flex; align-items: center; gap: var(--space-2); }
.home-fold-chev { margin-left: var(--space-2); display: inline-flex; align-items: center; color: var(--text-3); transition: transform var(--dur-2) var(--ease), color var(--dur-1) var(--ease); }
.home-fold-chev svg { width: var(--icon-sm); height: var(--icon-sm); }
.home-fold-h:not(.is-folded) .home-fold-chev { transform: rotate(90deg); }
.home-fold-h:hover .home-fold-chev { color: var(--text); }
.home-fold-body[hidden] { display: none; }

.home-tasks { display: flex; flex-direction: column; }
.home-task { display: flex; align-items: center; gap: var(--space-3); width: 100%; min-height: var(--row-h-tall); padding: var(--space-2) var(--row-pad-x); border: none; background: transparent; border-radius: var(--radius-sm); cursor: pointer; font-family: var(--font); text-align: left; transition: background-color var(--dur-1) var(--ease); }
.home-task:hover { background: var(--row-hover); }
.home-task-dot { width: 8px; height: 8px; border-radius: var(--radius-pill); flex-shrink: 0; }
.home-task-tx { display: flex; flex-direction: column; gap: var(--space-0); min-width: 0; flex: 1; }
.home-task-tx b { font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.home-task-tx small { font-size: var(--fs-small); color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.home-task-tx small.di-overdue { color: var(--red); font-weight: var(--fw-semi); }
.home-task-go { color: var(--text-3); display: inline-flex; flex-shrink: 0; }
.home-task-go svg { width: var(--icon-md); height: var(--icon-md); }

.home-clear { display: flex; flex-direction: column; align-items: center; gap: var(--space-0); text-align: center; padding: var(--space-5) var(--card-pad); color: var(--text-3); }
.home-clear svg { width: var(--icon-lg); height: var(--icon-lg); color: var(--green); margin-bottom: var(--space-3); }
.home-clear b { font-size: var(--fs-body); color: var(--text); font-weight: var(--fw-semi); }
.home-clear small { font-size: var(--fs-small); color: var(--text-3); }

.home-more { width: 100%; min-height: var(--ctl-md); padding: var(--space-2) var(--row-pad-x); border: none; background: transparent; color: var(--text-2); font-size: var(--fs-body); font-weight: var(--fw-medium); font-family: var(--font); cursor: pointer; border-radius: var(--radius-sm); }
.home-more:hover { background: var(--row-hover); color: var(--text); }

.home-next { display: flex; align-items: center; gap: var(--space-3); width: 100%; padding: var(--space-2) var(--row-pad-x) var(--space-3); border: none; background: transparent; cursor: pointer; font-family: var(--font); text-align: left; }
.home-next:hover { background: var(--row-hover); border-radius: var(--radius-sm); }
/* Home "Today" agenda timeline */
.home-ag { display: flex; flex-direction: column; gap: var(--space-0); padding: var(--space-0) var(--row-pad-x) var(--space-3); cursor: pointer; }
.home-ag-row { display: flex; gap: var(--space-3); align-items: baseline; padding: var(--space-1) var(--space-2); border-radius: var(--radius-sm); }
.home-ag:hover .home-ag-row { background: transparent; }
.home-ag-row:hover { background: var(--row-hover); }
.home-ag-time { flex: 0 0 62px; font-size: var(--fs-small); font-weight: var(--fw-semi); color: var(--text-2); font-variant-numeric: tabular-nums; }
.home-ag-body { min-width: 0; display: flex; flex-direction: column; gap: var(--space-0); }
.home-ag-body b { font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.home-ag-body small { font-size: var(--fs-micro); color: var(--text-3); }
.home-ag-row.is-past { color: var(--text-3); }   /* AUDIT_dark F2: dim by colour, not opacity - opacity stacked on text-3 fell to 2.3:1 */
.home-ag-row.is-past .home-ag-time { color: var(--text-3); }
.home-ag-now { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-2); font-size: var(--fs-micro); font-weight: var(--fw-semi); color: var(--amber); }
.home-ag-now-dot { width: 6px; height: 6px; border-radius: var(--radius-pill); background: var(--amber); flex: none; }
.home-ag-more { font-size: var(--fs-micro); color: var(--text-3); padding: var(--space-1) var(--space-2) 0; }
.home-next-time { display: flex; flex-direction: column; align-items: center; justify-content: center; flex-shrink: 0; min-width: 66px; padding: var(--space-2); border-radius: var(--radius-sm); background: var(--surface); border: 1px solid var(--hairline); }
.home-next-time b { font-size: var(--fs-body); font-weight: var(--fw-semi); color: var(--text); letter-spacing: -0.011em; }
.home-next-time small { font-size: var(--fs-micro); font-weight: var(--fw-medium); color: var(--text-3); }
.home-next-body { display: flex; flex-direction: column; gap: var(--space-0); min-width: 0; flex: 1; }
.home-next-body b { font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.home-next-body small { font-size: var(--fs-small); color: var(--text-3); }

/* End-of-day submit card on Home */
/* run6 W5b: surface props deleted — the element is `home-card glass-2 home-eod` in markup
   (surface comes from the home-card conversion); hover retargeted to the glass fill ramp. */
.home-eod { display: flex; align-items: center; gap: var(--space-3); width: 100%; padding: var(--card-pad); cursor: pointer; font-family: var(--font); text-align: left; transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.home-eod:hover { background-color: var(--g-fill-3); }
.home-eod:active { transform: scale(.99); }
.home-eod:focus-visible { outline: none; box-shadow: var(--ring); }
.home-eod-ic { display: inline-grid; place-items: center; width: var(--ctl-lg); height: var(--ctl-lg); border-radius: var(--radius-md); background: var(--amber-bg); color: var(--amber); flex-shrink: 0; }
.home-eod-ic svg { width: var(--icon-lg); height: var(--icon-lg); }
.home-eod-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-0); }
.home-eod-tx b { font-size: var(--fs-body); font-weight: var(--fw-semi); color: var(--text); }
.home-eod-tx small { font-size: var(--fs-small); color: var(--text-2); }
.home-eod-go { color: var(--text-3); display: inline-grid; place-items: center; } .home-eod-go svg { width: var(--icon-md); height: var(--icon-md); }
.home-eod.is-done .home-eod-ic { background: var(--green-bg); color: var(--green); }

/* ── TIME (F1) — Home card: CLOCK IN/OUT (day marker) + START/STOP WORK (timer) ── */
/* run6 W5b: state rings became FULL border declarations — the home-card base border is gone,
   so a bare border-color no longer paints (same treatment as .sla-tile's tone rings in W5a). */
.home-clock.is-clocked { border: 1px solid var(--hairline-strong); }
.home-clock.is-timing { border: 1px solid var(--green-bg); }
.home-clock .clock-live { margin-left: auto; display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--fs-small); font-weight: var(--fw-medium); text-transform: none; letter-spacing: 0; color: var(--green); }
.home-clock .clock-live i { width: 8px; height: 8px; border-radius: var(--radius-pill); background: var(--green); animation: clockPulse 1.8s ease-in-out infinite; }
.home-clock .clock-live b { font-variant-numeric: tabular-nums; }
.home-clock .clock-onmark { color: var(--amber); }
@keyframes clockPulse { 0%,100% { opacity: 1; } 50% { opacity: .45; } }
.clock-body { display: flex; align-items: center; gap: 14px; padding: 4px 12px 10px; flex-wrap: wrap; }
.clock-actions { display: flex; align-items: center; gap: 8px; }
.clock-btn { flex: none; display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-width: 112px; padding: 11px 16px; border-radius: var(--radius-sm); border: none; font-family: var(--font); font-size: 14px; font-weight: 650; cursor: pointer; transition: transform var(--dur-1) ease, box-shadow var(--dur-1) ease, filter var(--dur-1) ease, background var(--dur-1) ease, color var(--dur-1) ease; }
.clock-btn:active { transform: scale(.97); }
.clock-btn .clock-btn-ic { display: inline-grid; place-items: center; }
.clock-btn .clock-btn-ic svg { display: block; width: 14px; height: 14px; }
/* CLOCK IN/OUT — secondary, calm (it's just a day marker, not the hour-driver) */
.clock-btn.day.is-in { background: var(--glass-strong, var(--glass)); color: var(--text); border: 1px solid var(--hairline-strong, var(--hairline)); }
.clock-btn.day.is-in:hover { border-color: var(--accent); color: var(--accent); }
.clock-btn.day.is-out { background: var(--accent-softer, var(--glass)); color: var(--accent); border: 1px solid var(--accent-soft, var(--hairline-strong)); }
.clock-btn.day.is-out:hover { filter: brightness(1.03); }
/* START/STOP WORK — primary, the hours tracker */
.clock-btn.work.is-start { background: var(--accent); color:var(--text-on-accent,#fff); box-shadow: var(--shadow-sm); }
/* run6 R6-16/F7 · hover: brightness(1.05) on a token background is a ~5% luminance nudge the contrast
   sweep couldn't even measure — use the codebase's standard fill+shadow ramp instead (.btn-primary /
   .send-btn / .login-btn all hover to --accent-strong + a deeper shadow). The green Stop has no
   *-strong token, so mix its fill 12% toward the page ink (--text): that darkens in light themes and
   lightens in dark ones — the same "away from the canvas" direction every theme's accent-strong takes —
   and it RAISES the button-ink contrast (mixing toward --g-text-on-green instead would CUT it below
   4.5:1 in 8 light themes — computed, not guessed). Ink light is the one theme where green == --text
   (both #16150F, zero fill delta) — there the --shadow-sm→--shadow ramp (3px→4px offset block) carries
   the hover on its own. */
.clock-btn.work.is-start:hover { background: var(--accent-strong, var(--accent)); box-shadow: var(--shadow); }
.clock-btn.work.is-stop { background: var(--green, #1f9d57); color: var(--g-text-on-green,#fff); box-shadow: var(--shadow-sm); }   /* run6 W5c (R6-4 straggler): 28 distinct --g-green values, no single ink clears them — per-theme --g-text-on-green lands in css/themes.css (parallel lane), #fff is the pre-token fallback */
.clock-btn.work.is-stop:hover { background: color-mix(in srgb, var(--green, #1f9d57) 88%, var(--text) 12%); box-shadow: var(--shadow); }
/* run6 R6-16 · focus: the variant's own resting box-shadow at specificity (0,3,0) beat the global
   button:focus-visible ring at (0,1,1), so keyboard focus was INVISIBLE on the most-used button —
   siblings .clock-btn.day / .clock-sc-toggle carry no resting shadow, which is why the global ring
   reaches them untouched. Compose the same 2-layer halo (--ring: surface 2px + accent 4px) WITH the
   resting depth in one list — the §1 polish-pass rule: never clobber an element's own shadow.
   Declared AFTER :hover so a focused+hovered button keeps its halo. */
.clock-btn.work.is-start:focus-visible,
.clock-btn.work.is-stop:focus-visible { outline: none; box-shadow: var(--ring), var(--shadow-sm); }
.clock-hours { display: flex; gap: 16px; margin-left: auto; }
.clock-hcell { display: flex; flex-direction: column; align-items: flex-end; }
.clock-hn { font-size: 20px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; line-height: 1.1; }
.clock-hl { font-size: 11px; color: var(--text-3); font-weight: 600; }
/* TEAM CLOCK BOARD (owner 2026-07-14 #2) — who's in/out now + what they're on + weekly hours */
.clock-team { width: 100%; margin-top: 4px; padding-top: 8px; border-top: 1px solid var(--hairline); }
.clock-team-h { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--text-3); padding: 2px 2px 6px; }
.clock-team-h svg { width: 13px; height: 13px; }
.clock-team-row { display: flex; align-items: center; gap: 10px; padding: 6px 2px; border-radius: var(--radius-md); }
.clock-team-row + .clock-team-row { border-top: 1px solid var(--hairline); }
.clock-team-row .ct-name { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.clock-team-row .ct-name b { font-size: 13px; font-weight: 650; color: var(--text); }
.clock-team-row .ct-name b small { color: var(--text-3); font-weight: 500; }
.clock-team-row .ct-note { font-size: 11.5px; color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clock-team-row .ct-state { flex: none; font-size: 11.5px; font-weight: 650; color: var(--text-3); background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-pill); padding: 2px 9px; font-variant-numeric: tabular-nums; }
.clock-team-row .ct-state.on { color: var(--green, #1f9d57); background: rgba(31,157,87,.09); border-color: rgba(31,157,87,.25); }
.clock-team-row .ct-hrs { flex: none; min-width: 44px; text-align: right; font-size: 13px; font-weight: 700; color: var(--text-2); font-variant-numeric: tabular-nums; }
.clock-team-row .ct-hrs small { font-size: 11px; color: var(--text-3); font-weight: 600; margin-left: 2px; }
.clock-note { font-weight: 500; opacity: .85; }
.clock-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 12px 6px; border-top: 1px solid var(--hairline); }
.clock-hint { font-size: 11.5px; color: var(--text-3); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.clock-hint b { color: var(--text-2); font-weight: 700; }
.clock-sc-toggle { flex: none; padding: 5px 10px; border-radius: var(--radius-pill); border: 1px solid var(--hairline-strong, var(--hairline)); background: transparent; color: var(--text-3); font-family: var(--font); font-size: 11px; font-weight: 650; cursor: pointer; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; }
.clock-sc-toggle.on { border-color: var(--green-bg); background: var(--green-bg); color: var(--green, #1f9d57); }
@media (max-width: 540px) {
  .clock-actions { flex: 1 1 100%; }
  .clock-actions .clock-btn { flex: 1 1 0; min-width: 0; }
  .clock-hours { margin-left: 0; flex: 1 1 100%; justify-content: space-between; gap: 10px; }
}

/* ── HOME WEEKLY LOG — each day this week you clocked in: date · intervals · hours ── */
.home-weeklog .weeklog-body { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-1) var(--row-pad-x) var(--space-3); }
.weeklog-loading, .weeklog-empty { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-3); padding: 10px 2px; }
.weeklog-empty svg { width: 15px; height: 15px; flex: none; opacity: .7; }
/* run6 W5b: surface props deleted — markup now ships `weeklog-row g-solid-2` (js/app.js;
   repeated day rows, so the opaque twin). Hover border-color re-pin retargeted to the solid
   ramp; .is-open keeps its accent tint (0,2,0 still wins over the primitive). */
/* R5 (v824): .weeklog-item is the surface (g-solid-2) and a wrapping flex row: [row button][edit][del] then the
   full-width detail. The row button is transparent inside it. */
.weeklog-item { display: flex; flex-wrap: wrap; align-items: center; gap: 0 8px; padding-right: 9px; }
.weeklog-item .weeklog-edit, .weeklog-item .weeklog-del { flex: none; }
.weeklog-row { display: grid; grid-template-columns: 1fr auto auto 16px; align-items: center; gap: 10px; flex: 1 1 0; min-width: 0; background: transparent; border: 0; text-align: left;
  padding: 9px 11px; color: var(--text);
  font-family: var(--font); cursor: pointer; transition: border-color var(--dur-1) ease, background var(--dur-1) ease; }
.weeklog-del { display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: transparent; color: var(--text-3); cursor: pointer; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; }
.weeklog-del:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-softer, transparent); }
.weeklog-del svg { width: 13px; height: 13px; }
/* day-editor pencil (owner #1: edit exact interval times) — same chip style as the delete */
.weeklog-edit { display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: transparent; color: var(--text-3); cursor: pointer; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; }
.weeklog-edit:hover { border-color: var(--text-2); color: var(--text); background: var(--surface); }
.weeklog-edit svg { width: 13px; height: 13px; }
/* TIMESHEET DAY-EDITOR sheet */
.tde-hint { font-size: 12.5px; color: var(--text-3); margin: 0 0 12px; line-height: 1.5; }
.tde-row { display: flex; align-items: center; gap: 8px; padding: 8px 2px; border-bottom: 1px solid var(--hairline); }
.tde-row.tde-invalid { background: var(--accent-softer); box-shadow: inset 3px 0 0 var(--accent); border-radius: var(--radius-sm); }
.tde-row.tde-invalid .tde-t, .tde-row.tde-invalid .tde-note { border-color: var(--accent); }
.tde-row.is-removed { opacity: .38; text-decoration: line-through; }
.tde-row.is-removed input { pointer-events: none; }
.tde-n { flex: none; width: 20px; text-align: center; font-size: 11px; font-weight: 700; color: var(--text-3); font-variant-numeric: tabular-nums; }
.tde-t { flex: none; width: 92px; padding: 6px 8px; border: 1px solid var(--hairline-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--text); font: inherit; font-size: 16px; font-variant-numeric: tabular-nums; }
.tde-arrow { flex: none; color: var(--text-3); font-size: 12px; }
.tde-running { flex: none; font-size: 11.5px; font-weight: 650; color: var(--green, #1f9d57); background: rgba(31,157,87,.09); border: 1px solid rgba(31,157,87,.25); border-radius: var(--radius-pill); padding: 3px 10px; }
.tde-note { flex: 1; min-width: 80px; padding: 6px 9px; border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: transparent; color: var(--text-2); font: inherit; font-size: 16px; }
.tde-x { flex: none; display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: transparent; color: var(--text-3); cursor: pointer; }
.tde-x:hover { border-color: var(--accent); color: var(--accent); }
.tde-x svg { width: 13px; height: 13px; }
.tde-empty { padding: 14px 4px; color: var(--text-3); font-size: 13.5px; }
#tdeAdd { margin-top: 12px; }
@media (max-width: 520px){ .tde-note { flex-basis: 100%; order: 9; } .tde-row { flex-wrap: wrap; } }
.weeklog-item:hover { background-color: var(--g-solid-3); }   /* run6 W5b: border-color re-pin was dead with the border — solid ramp instead */
.weeklog-item.is-open { background: var(--accent-softer, var(--glass)); }   /* run6 W5b: border-color half dropped (dead); accent tint kept */
.weeklog-date { font-size: 13px; font-weight: 650; color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.weeklog-cell { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.1; }
.weeklog-cell b { font-size: 15px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.weeklog-cell small { font-size: 11px; color: var(--text-3); font-weight: 600; }
.weeklog-chev { display: inline-grid; place-items: center; color: var(--text-3); transition: transform var(--dur-2) ease; }
.weeklog-chev svg { width: 15px; height: 15px; }
.weeklog-item.is-open .weeklog-chev { transform: rotate(90deg); }
.weeklog-detail { flex-basis: 100%; font-size: 11.5px; color: var(--text-2); padding-top: 6px; margin: 0 11px 9px; border-top: 1px dashed var(--hairline); }
.weeklog-detail[hidden] { display: none; }
.weeklog-detail-sum { display: block; }
.weeklog-ivs { list-style: none; margin: 7px 0 1px; padding: 0; display: flex; flex-direction: column; gap: 3px; }
/* run6 W5b: background deleted — markup now ships `weeklog-iv g-solid-2` (js/app.js). The small
   radius is LAYOUT-CRITICAL on a ~24px-tall micro row (the theme's 22px card radius would clamp
   it into a pill), so it moved to the (0,2,0) bump below, same pattern as .ptr-indicator in W5a. */
.weeklog-iv { display: grid; grid-template-columns: 18px 1fr auto; align-items: center; gap: 8px; padding: 3px 8px; font-variant-numeric: tabular-nums; }
.weeklog-iv.g-solid-2 { border-radius: var(--radius-sm); }
.weeklog-iv-n { width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 700; color: var(--text-3); background: var(--hairline); border-radius: 50%; }
.weeklog-iv-when { color: var(--text-2); font-size: 11.5px; }
.weeklog-iv-dur { color: var(--text); font-weight: 600; font-size: 11.5px; white-space: nowrap; }
.weeklog-iv.is-running { background: var(--accent-softer, rgba(229,50,43,.08)); }
.weeklog-iv.is-running .weeklog-iv-dur { color: var(--accent, #e5322b); }
.weeklog-iv.is-running .weeklog-iv-n { background: var(--accent, #e5322b); color:var(--text-on-accent,#fff); }
.weeklog-total { display: flex; align-items: center; justify-content: space-between; padding: 8px 11px 2px; margin-top: 2px; border-top: 1px solid var(--hairline); font-size: 12px; color: var(--text-3); }
.weeklog-total b { color: var(--text); font-weight: 700; font-variant-numeric: tabular-nums; }

/* ── ROLES & PERMISSIONS (admin) ── */
.roles-admin { display: flex; flex-direction: column; gap: 10px; margin-bottom: 8px; }
.roles-list { display: flex; flex-direction: column; gap: 8px; }
/* run6 W5b: surface props deleted — markup now ships `role-row g-solid-2` (js/app.js). */
.role-row { display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 12px; padding: 10px 12px; }
.role-mark { display: inline-grid; place-items: center; min-width: 34px; height: 34px; padding: 0 8px; border-radius: var(--radius-sm); font-size: 12.5px; font-weight: 800; letter-spacing: .3px; }
.role-id { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.role-id b { font-size: 13.5px; font-weight: 700; color: var(--text); }
.role-id small { font-size: 11px; color: var(--text-3); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.roles-add { align-self: flex-start; }
.roles-note { display: flex; align-items: flex-start; gap: 7px; font-size: 11.5px; color: var(--text-3); line-height: 1.5; padding: 2px 2px 0; }
.roles-note svg { width: 14px; height: 14px; flex: none; margin-top: 1px; opacity: .7; }
.role-perms { display: flex; flex-direction: column; gap: 8px; }
.role-perm { display: flex; align-items: flex-start; gap: 9px; font-size: 12.5px; color: var(--text-2); cursor: pointer; line-height: 1.35; }
.role-perm input { margin-top: 2px; accent-color: var(--accent); flex: none; }
.role-perm.is-locked { opacity: .6; cursor: default; }
.mhint { display: block; font-size: 11px; color: var(--text-3); margin-top: 4px; line-height: 1.4; }

/* ── PER-CLIENT DELIVERY SERVICES ── */
.fv-cliservice { width: 100%; border: 0; background: transparent; color: var(--text); font-family: var(--font); font-size: 13px; padding: 2px 0; }
.csvc-intro { font-size: 12.5px; color: var(--text-2); line-height: 1.5; margin: 0 0 14px; }
.csvc-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--hairline); }
.csvc-row:last-child { border-bottom: 0; }
.csvc-l { display: flex; flex-direction: column; line-height: 1.3; font-size: 13.5px; font-weight: 650; color: var(--text); }
.csvc-l small { font-size: 11px; font-weight: 500; color: var(--text-3); margin-top: 2px; }
.csvc-toggle { position: relative; width: 44px; height: 26px; border-radius: var(--radius-pill); border: 1px solid var(--hairline); background: var(--glass); cursor: pointer; flex: none; transition: background var(--dur-2) ease, border-color var(--dur-2) ease; }
.csvc-toggle .csvc-knob { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%; background: var(--text-3); transition: transform var(--dur-2) ease, background var(--dur-2) ease; }
.csvc-toggle.on { background: var(--accent); border-color: var(--accent); }
.csvc-toggle.on .csvc-knob { transform: translateX(18px); background: #fff; }

/* ── ADMIN TIMES / HOURS SHEET (profile) — per employee, per day: date · in · out · int · hrs ── */
.pf-times { display: flex; flex-direction: column; gap: 12px; }
.pf-times-loading, .pf-times-empty { display: flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--text-3); padding: 8px 2px; }
.pf-times-empty svg { width: 15px; height: 15px; flex: none; opacity: .7; }
/* run6 W5c: surface → .g-solid-2 at the render site (js/profile.js) — same recipe as .pf-audit;
   overflow:hidden keeps day-rows clipped to the themed radius */
.pf-times-user { overflow: hidden; }
.pf-times-uname { font-size: 12.5px; font-weight: 700; color: var(--text); padding: 9px 12px; border-bottom: 1px solid var(--hairline); background: var(--accent-softer, transparent); }
.pf-times-row { display: grid; grid-template-columns: 1.3fr .9fr .9fr auto auto auto auto; align-items: center; gap: 8px; padding: 9px 12px; border-bottom: 1px solid var(--hairline); }
.pf-times-row:last-child { border-bottom: 0; }
.pf-times-date { font-size: 12.5px; font-weight: 600; color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pf-times-io { display: flex; flex-direction: column; line-height: 1.15; font-size: 12px; color: var(--text-2); font-variant-numeric: tabular-nums; }
.pf-times-io i { font-style: italic; color: var(--text-3); }
.pf-times-io small { font-size: 11px; color: var(--text-3); font-weight: 600; }
.pf-times-n { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.1; }
.pf-times-n b { font-size: 14px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.pf-times-n small { font-size: 11px; color: var(--text-3); font-weight: 600; }
.pf-times-del { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: transparent; color: var(--text-3); cursor: pointer; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; }
.pf-times-del:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-softer, transparent); }
.pf-times-edit { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: transparent; color: var(--text-3); cursor: pointer; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; }
.pf-times-edit:hover { border-color: var(--text-2); color: var(--text); background: var(--surface); }
.pf-times-edit svg { width: 14px; height: 14px; }
.pf-times-del svg { width: 14px; height: 14px; }
.pf-times-note { display: flex; align-items: center; gap: 7px; font-size: 11.5px; color: var(--text-3); padding: 2px 2px 0; }
.pf-times-note svg { width: 14px; height: 14px; flex: none; opacity: .7; }
@media (max-width: 540px) {
  .pf-times-row { grid-template-columns: 1fr auto auto; row-gap: 6px; }
  .pf-times-date { grid-column: 1 / -1; }
}

/* ── PER-TASK TIMER (F1) — ▶/⏸ button on task rows + panel ── */
.ttimer-btn { display: inline-flex; align-items: center; gap: 5px; padding: 3px 7px; border-radius: var(--radius-sm); border: 1px solid transparent; background: transparent; color: var(--text-3); cursor: pointer; font-family: var(--font); transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; vertical-align: middle; }
.ttimer-btn .ttimer-ic { display: inline-grid; place-items: center; }
.ttimer-btn .ttimer-ic svg { display: block; }
.ttimer-row { opacity: 0; }                         /* hidden until row hover (desktop) */
.trow:hover .ttimer-row, .ttimer-row.is-running { opacity: 1; }
.ttimer-btn:hover { background: var(--accent-softer); color: var(--accent); border-color: var(--accent-soft); }
.ttimer-btn.is-running { opacity: 1; background: var(--accent-soft); color: var(--accent); border-color: var(--accent-soft); }
.ttimer-el { font-size: 11.5px; font-weight: 650; font-variant-numeric: tabular-nums; }
.tpanel-timer { display: flex; align-items: center; gap: 10px; padding: 8px 0; }
.tpanel-timer .ttimer-panel { opacity: 1; padding: 7px 12px; border: 1px solid var(--hairline-strong, var(--hairline)); border-radius: var(--radius-md); }
.tpanel-timer .ttimer-panel.is-running { border-color: var(--accent-soft); }
.tpanel-timer-tx { font-size: 13px; color: var(--text-2); flex: 1; min-width: 0; }
.tpanel-timer-hint { font-size: 11px; color: var(--text-3); padding: 3px 7px; border-radius: var(--radius-xs); background: var(--glass-strong, var(--glass)); border: 1px solid var(--hairline); white-space: nowrap; }
@media (hover: none) { .ttimer-row { opacity: 1; } }   /* touch devices: always show the timer button */
/* G5: on touch devices :hover fires on TAP and "sticks" until you tap elsewhere — most visible as
   cards/buttons staying LIFTED after you tap them. Neutralize every hover-lift transform on touch-only
   devices so nothing stays stuck. Desktop (hover-capable) keeps the full lift feedback, untouched. */
@media (hover: none) and (pointer: coarse) {
  .icon-btn:hover, .btn-danger:hover, .btn-primary:hover, .home-stat:hover, .home-pulse-tile:hover,
  .home-eod:hover, .home-act:hover, .home-card:hover, .home-pending:hover, .home-cd:hover, .home-next:hover,
  .pipe-card:hover, .bcard:hover, .w3-card:hover, .w3-rolerow:hover, .ig-card:hover, .ig-cta:hover,
  /* run7 W3: `.u-lift:hover` dropped from this list — that rule was deleted as DEAD */
  .login-btn:hover, .client-mini:hover, .member-card:hover, .dops-card:hover,
  .adsm-card:hover, .ws-card:hover {
    transform: none;
  }
}

/* ── AUDIT LOG (F2) — admin-only activity feed in profile/settings ── */
/* run6 W5c: surface → .g-solid-2 at the render site (js/profile.js) — scroll container inside
   the profile modal, blur-capped context; scroll behavior stays here */
.pf-audit { max-height: 300px; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.pf-audit-loading, .pf-audit-empty { padding: 16px; font-size: 13px; color: var(--text-3); display: flex; align-items: center; gap: 8px; }
.pf-audit-empty svg { width: 16px; height: 16px; flex: none; color: var(--text-3); }
.pf-au-row { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px; border-bottom: 1px solid var(--hairline); }
.pf-au-row:last-child { border-bottom: none; }
.pf-au-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); margin-top: 6px; }
.pf-au-body { flex: 1; min-width: 0; }
.pf-au-line { font-size: 13px; color: var(--text); line-height: 1.4; }
.pf-au-line b { font-weight: 650; }
.pf-au-detail { display: block; font-size: 12px; color: var(--text-2); margin-top: 2px; overflow-wrap: anywhere; }
.pf-au-behalf { display: inline-block; margin-left: 6px; font-size: 11px; font-weight: 600; color: var(--accent); background: var(--accent-softer); padding: 1px 6px; border-radius: var(--radius-xs); }
.pf-au-time { flex: none; font-size: 11px; color: var(--text-3); white-space: nowrap; padding-top: 1px; }
/* Archive (TS2) — deleted clients/tasks, restorable */
/* run6 W5c: surface → .g-solid-2 at the render site (js/profile.js) — same lane as .pf-audit */
.pf-archive { max-height: 320px; overflow-y: auto; -webkit-overflow-scrolling: touch; }
.pf-archive-loading, .pf-archive-empty { padding: 16px; font-size: 13px; color: var(--text-3); display: flex; align-items: center; gap: 8px; }
.pf-archive-empty svg { width: 16px; height: 16px; flex: none; color: var(--text-3); }
.pf-arc-row { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-bottom: 1px solid var(--hairline); }
.pf-arc-row:last-child { border-bottom: none; }
.pf-arc-ic { flex: none; display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: var(--radius-sm); background: var(--bg-2); color: var(--text-3); }
.pf-arc-ic svg { width: 14px; height: 14px; }
.pf-arc-body { flex: 1; min-width: 0; }
.pf-arc-name { font-size: 13px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pf-arc-meta { font-size: 11.5px; color: var(--text-3); margin-top: 1px; }
.pf-arc-restore { flex: none; display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; color: var(--accent); background: var(--accent-softer); border: 1px solid transparent; border-radius: var(--radius-sm); padding: 5px 10px; cursor: pointer; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; }
.pf-arc-restore svg { width: 13px; height: 13px; }
.pf-arc-restore:hover { background: var(--accent-soft); }
.pf-arc-restore:disabled { opacity: .6; cursor: default; }
.pf-arc-purge { flex: none; display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: transparent; color: var(--text-3); cursor: pointer; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; }
.pf-arc-purge:hover { border-color: var(--accent); color: var(--accent); }
.pf-arc-purge svg { width: 14px; height: 14px; }

/* per-role intro line + "your clients today" */
.home-roleline { font-size: var(--fs-small); color: var(--text-2); font-weight: var(--fw-normal); margin-top: var(--space-1); }
.home-clients { padding: var(--space-1) var(--space-1) var(--space-2); }
/* at-risk clients card — the #1 cash-survival signal, styled to draw the eye (red accent) */
.home-risk { padding: var(--space-1) var(--space-1) var(--space-2); }   /* run6 W5b: border-color re-pin dropped — dead once .home-card's border was deleted */
/* run5 wave4: `.home-clients-h` / `.home-risk-h` deleted — DEAD. Both cards render their header
   through _foldHead() (js/app.js:3320), which emits `.home-card-h .home-fold-h`; the -h classes
   were never in the markup. Their live siblings (.home-clients, .home-clients-meta, .home-risk,
   .home-risk-title, .home-risk-list/-row/-id/-badges) are untouched. */
.home-risk-list { display: flex; flex-direction: column; }
.home-risk-row { display: flex; align-items: center; gap: var(--space-3); width: 100%; padding: var(--space-1) var(--row-pad-x); border: none; background: transparent; border-radius: var(--radius-sm); cursor: pointer; font-family: var(--font); text-align: left; }
.home-risk-row:hover { background: var(--row-hover); }
.home-risk-id { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-0); }
.home-risk-id b { font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.home-risk-badges { display: flex; flex-wrap: wrap; gap: var(--space-1); }
.home-risk-badge { font-size: var(--fs-micro); font-weight: var(--fw-semi); color: var(--red); background: var(--red-bg); border: none; border-radius: var(--radius-xs); padding: var(--space-0) var(--space-2); white-space: nowrap; }
.home-na-title { display: inline-flex; align-items: center; gap: var(--space-2); font-weight: var(--fw-semi); font-size: var(--fs-micro); color: var(--text); }
.home-na-title svg { width: var(--icon-sm); height: var(--icon-sm); color: var(--text-3); }
.home-na-list { display: flex; flex-direction: column; gap: var(--space-0); }
.home-na-row { display: flex; align-items: center; gap: var(--space-3); width: 100%; padding: var(--space-1) var(--row-pad-x); border: none; background: transparent; border-radius: var(--radius-sm); cursor: pointer; font-family: var(--font); text-align: left; transition: background-color var(--dur-1) var(--ease); }
.home-na-row:hover { background: var(--row-hover); }
.home-na-ic { flex: none; width: var(--ctl-md); height: var(--ctl-md); display: inline-flex; align-items: center; justify-content: center; border-radius: var(--radius-md); }
.home-na-ic svg { width: var(--icon-md); height: var(--icon-md); }
.home-na-row.na-money .home-na-ic { color: var(--red); background: var(--red-bg); }
.home-na-row.na-risk .home-na-ic { color: var(--amber); background: var(--amber-bg); }
.home-na-row.na-msg .home-na-ic { color: var(--amber); background: var(--amber-bg); }
.home-na-row.na-approve .home-na-ic { color: var(--green); background: var(--green-bg); }
.home-na-row.na-creative .home-na-ic { color: var(--slate); background: var(--slate-bg); }
.home-na-row.na-task .home-na-ic { color: var(--text-2); background: var(--surface-2); }
.home-na-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-0); }
.home-na-tx b { font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.home-na-tx small { font-size: var(--fs-small); color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.home-na-more { font-size: var(--fs-small); color: var(--text-3); padding: var(--space-1) var(--space-2) var(--space-0); font-weight: var(--fw-normal); }
.home-clients-meta { font-size: var(--fs-small); color: var(--text-3); font-weight: var(--fw-normal); } .home-clients-meta b { color: var(--text); font-variant-numeric: tabular-nums; }
.home-hstrip { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: var(--space-0) var(--space-2) var(--space-3); }
.home-hs-item { position: relative; display: inline-flex; cursor: pointer; border-radius: var(--radius-pill); }
.home-hs-item:hover, .home-hs-item:focus-visible { outline: none; }
.home-hs-item img, .home-hs-item .avatar, .home-hs-item > span { border-radius: var(--radius-pill); }
.home-hs-dot { position: absolute; right: -1px; bottom: -1px; width: 8px; height: 8px; border-radius: var(--radius-pill); border: 2px solid var(--bg); box-sizing: content-box; }
.home-hs-item.hs-good .home-hs-dot { background: var(--green); }
.home-hs-item.hs-watch .home-hs-dot { background: var(--amber); }
.home-hs-item.hs-risk .home-hs-dot { background: var(--red); }
.home-hs-item.hs-off .home-hs-dot { background: var(--text-3); }
.home-cfilters { display: flex; gap: var(--space-2); flex-wrap: wrap; padding: 0 var(--space-2) var(--space-3); }
.home-cfilter { display: inline-flex; align-items: center; gap: var(--space-2); height: var(--ctl-sm); font-family: var(--font); font-size: var(--fs-small); font-weight: var(--fw-medium); color: var(--text-2); background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: 0 var(--space-2); cursor: pointer; white-space: nowrap; transition: border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease), background-color var(--dur-1) var(--ease); }
.home-cfilter:hover { border-color: var(--hairline-strong); color: var(--text); }
.home-cfilter.on { background: var(--row-selected); border-color: var(--hairline-strong); color: var(--text); }
.home-cfilter i { font-style: normal; font-size: var(--fs-micro); font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; padding: 0 var(--space-1); border-radius: var(--radius-pill); background: var(--row-selected); color: inherit; }
.home-cfilter.is-new:not(.on) i { background: var(--amber-bg); color: var(--amber); }
.home-cfilter.is-risk:not(.on) i { background: var(--red-bg); color: var(--red); }
.home-cempty { padding: var(--space-4) var(--row-pad-x); text-align: center; color: var(--text-3); font-size: var(--fs-body); }
.home-client-list { display: flex; flex-direction: column; gap: var(--space-1); padding: 0 var(--space-1); }
.home-client { display: flex; align-items: center; gap: var(--space-3); width: 100%; min-height: var(--row-h-tall); padding: var(--space-1) var(--row-pad-x); border: 1px solid transparent; border-radius: var(--radius-sm); background: transparent; cursor: pointer; font-family: var(--font); text-align: left; transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.home-client:hover { background: var(--row-hover); border-color: var(--hairline); }
.home-client:active { transform: scale(.99); }
.home-client:focus-visible { outline: none; box-shadow: var(--ring); }
.home-client .p-logo, .home-client .p-logo-img { width: var(--ctl-md); height: var(--ctl-md); border-radius: var(--radius-md); flex: 0 0 auto; }
.home-client-id { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-0); }
.home-client-id b { font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.home-client-id small { font-size: var(--fs-micro); color: var(--text-3); }
.home-client.is-done .home-client-id small { color: var(--green); }
.home-client-id small { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.home-client.has-new { background: color-mix(in srgb, var(--amber) 7%, transparent); border-color: color-mix(in srgb, var(--amber) 26%, transparent); }
.hc-new { display: inline-block; font-size: var(--fs-micro); font-weight: var(--fw-semi); letter-spacing: .05em; text-transform: uppercase; color: var(--amber); background: var(--amber-bg); border-radius: var(--radius-xs); padding: 1px 5px; margin-right: var(--space-0); vertical-align: 1px; }
.home-client-st { flex: 0 0 auto; display: inline-grid; place-items: center; width: var(--ctl-xs); height: var(--ctl-xs); }
.home-client-st svg { width: var(--icon-md); height: var(--icon-md); color: var(--green); }
.home-client-st .hc-dot { width: 8px; height: 8px; border-radius: var(--radius-pill); background: var(--amber); display: block; }
/* ===== chat markdown (Client Delivery thread + client portal messages) — Discord-style ===== */
.md-hr { border: none; border-top: 1px solid currentColor; opacity: .25; margin: 8px 0; }
.md-h { font-weight: 700; margin: 5px 0 2px; line-height: 1.25; }
.md-h1 { font-size: 1.18em; } .md-h2 { font-size: 1.1em; } .md-h3 { font-size: 1.02em; }
.md-list { margin: 3px 0; padding-left: 20px; }
.md-list li { margin: 2px 0; }
.md-list.md-ol { list-style: decimal; }
.md-list.md-checks { list-style: none; padding-left: 1px; }
.md-check { display: flex; align-items: flex-start; gap: 7px; }
.md-check .md-box { flex: 0 0 auto; width: 16px; height: 16px; border: 1.5px solid currentColor; border-radius: var(--radius-xs); display: inline-grid; place-items: center; font-size: 11px; font-weight: 800; opacity: .75; margin-top: 1px; }
/* V734-P1 · `#fff` on the OPAQUE --green plate = 13/24 fail (worst 1.042, cobalt/light). This `color`
   drives the "✓" glyph (js/app.js:31), so the tick itself vanished. --g-text-on-green = 0/24. See :651. */
.md-check.done .md-box { background: var(--green); border-color: var(--green); color: var(--g-text-on-green,#fff); opacity: 1; }
.md-check.done > span:last-child { opacity: .65; }
.md-quote { border-left: 3px solid currentColor; margin: 4px 0; padding: 1px 0 1px 10px; opacity: .85; }
.md-code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .88em; background: rgba(127,127,127,.18); padding: 1px 5px; border-radius: var(--radius-xs); }
.md-pre { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; background: rgba(127,127,127,.16); padding: 10px 12px; border-radius: var(--radius-sm); overflow-x: auto; margin: 6px 0; white-space: pre-wrap; }
.md-pre code { background: none; padding: 0; font-size: inherit; }
/* EOD review (owner) */
.eodr-wrap { max-height: 70vh; display: flex; flex-direction: column; }
.eodr-search { margin-bottom: 12px; }
.eodr-list { overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
/* run6 W5b: surface props deleted — markup now ships `eodr-card g-solid-2` (js/app.js;
   repeated per report, inside a modal — solid twice over). */
.eodr-card { padding: 14px; }
.eodr-date { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 650; color: var(--text); margin-bottom: 10px; }
.eodr-date svg { width: 14px; height: 14px; color: var(--accent); }
.eodr-time { margin-left: auto; font-weight: 500; color: var(--text-3); font-variant-numeric: tabular-nums; }
.eodr-qa { margin-bottom: 9px; } .eodr-qa:last-child { margin-bottom: 0; }
.eodr-q { display: block; font-size: 11.5px; font-weight: 600; color: var(--text-3); margin-bottom: 2px; }
.eodr-a { display: block; font-size: 13.5px; color: var(--text); line-height: 1.5; }
/* EOD form editor */
.eodf-roles { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 10px; }
/* run6 W5b: surface props deleted — markup now ships `eodf-rolepill g-solid-2` (js/app.js).
   The PILL radius + muted ink are layout/tone-critical, so both live in the (0,2,0) bump
   (glass.css's later .g-solid-2 sets --g-r-card + color:var(--g-text) at (0,1,0)). Hover was a
   text-token-as-border pin (the .pf-ro trap) — retargeted to the solid ramp. .active became a
   FULL border (its base border is gone). */
.eodf-rolepill { display: inline-flex; align-items: center; gap: 6px; padding: 7px 13px; font-family: var(--font); font-size: 13px; font-weight: 600; cursor: pointer; transition: border-color var(--dur-1), color var(--dur-1), background var(--dur-1); }
.eodf-rolepill.g-solid-2 { border-radius: var(--radius-pill); color: var(--text-2); border: 1px solid transparent; }   /* transparent baseline: .active toggles a real border on tap — keeps the pill's inner metrics stable (border-box) */
.eodf-rolepill:hover { background-color: var(--g-solid-3); }
.eodf-rolepill.active { border: 1px solid var(--accent); color: var(--accent); background: var(--accent-softer, var(--surface)); }
.eodf-roledot { width: 6px; height: 6px; border-radius: 50%; background: var(--green); flex: 0 0 auto; }
.eodf-note { font-size: 12.5px; color: var(--text-3); margin: 0 0 14px; }
.eodf-list { display: flex; flex-direction: column; gap: 12px; }
.eodf-row { display: flex; flex-direction: column; gap: 6px; }
.eodf-row-top { display: flex; align-items: center; gap: 8px; }
.eodf-row-top .eodf-q { flex: 1; min-width: 0; }
.eodf-type { flex: 0 0 auto; width: auto; max-width: 150px; }
.eodf-opts { width: 100%; }
.eodf-del { flex: 0 0 auto; color: var(--text-3); } .eodf-del:hover { color: var(--red, #ff3b30); }
/* EOD submit — choice inputs */
.eod-opts { display: flex; flex-direction: column; gap: 7px; padding: 3px 0; }
.eod-opt { display: flex; align-items: center; gap: 9px; font-size: 13.5px; cursor: pointer; color: var(--text); }
.eod-opt input { width: 16px; height: 16px; accent-color: var(--accent); flex: 0 0 auto; margin: 0; }
.eod-noopts { color: var(--text-3); font-size: 12.5px; }
/* Client Delivery — visible-statuses settings (CEO) */
.dscfg-list { display: flex; flex-direction: column; gap: 6px; }
/* run6 W5b: surface props deleted — markup now ships `dscfg-row g-solid-2` (js/app.js; repeated
   rows in a modal). The hover pinned border-color to a TEXT token (the .pf-ro trap) and is dead
   with the border anyway — retargeted to the solid ramp. .on accent tint kept (0,2,0 wins). */
.dscfg-row { display: flex; align-items: center; gap: 11px; width: 100%; padding: 11px 13px; font-family: var(--font); cursor: pointer; text-align: left; transition: border-color var(--dur-1), background var(--dur-1); }
.dscfg-row:hover { background-color: var(--g-solid-3); }
.dscfg-row.on { background: var(--accent-softer, var(--surface)); }
/* Team-side client chat (cmsg channel) */
.ccht-thread { display: flex; flex-direction: column; gap: 8px; max-height: 46vh; overflow-y: auto; padding: 4px 2px; }
.ccht-empty { color: var(--text-3); font-size: 13px; line-height: 1.5; text-align: center; padding: 24px 12px; }
.ccht-msg { display: flex; }
.ccht-msg.me { justify-content: flex-end; }
.ccht-bub { max-width: 78%; padding: 9px 12px; border-radius: var(--radius-lg); background: var(--surface-2, rgba(127,127,127,.1)); font-size: 13.5px; line-height: 1.45; }
/* run5 wave4: `.ccht-atts` / `.ccht-img img` / `.ccht-file` deleted — DEAD. The client-chat thread
   renders attachments through PPMChat.attachments() (js/chat.js:340), which emits `.ppm-atts` +
   `.ppm-att-img` / `.ppm-att-vid` / `.ppm-att-file` and styles them itself (js/chat.js:631-660).
   `.ccht-voice` below is NOT dead — app.js:12959 still passes it as the voiceHtml override. */
.ccht-voice { width: 210px; max-width: 100%; height: 36px; }
.ccht-foot [data-cchtvoice].recording { background: var(--accent); color:var(--text-on-accent,#fff); animation: cchtpulse 1s ease-in-out infinite; }
@keyframes cchtpulse { 0%,100%{ opacity:1 } 50%{ opacity:.55 } }
.ccht-msg.me .ccht-bub { background: var(--accent); color:var(--text-on-accent,#fff); }
.ccht-who { display: block; font-size: 11px; font-weight: 700; color: var(--text-3); margin-bottom: 2px; }
.ccht-time { display: block; font-size: 11px; opacity: .7; margin-top: 3px; text-align: right; }
.dscfg-dot { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto; }
.dscfg-name { flex: 1; font-size: 14px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dscfg-state { font-size: 11.5px; color: var(--text-3); min-width: 46px; text-align: right; }
.dscfg-sw { width: 38px; height: 22px; border-radius: var(--radius-pill); background: var(--surface-2, rgba(0,0,0,.14)); position: relative; flex: 0 0 auto; transition: background var(--dur-2); }
.dscfg-sw.on { background: var(--green); }
.dscfg-knob { position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.25); transition: transform var(--dur-2); }
.dscfg-sw.on .dscfg-knob { transform: translateX(16px); }
/* ===== Partner panel — Manage client view ===== */
/* run6 W5b: surface props deleted — markup now ships `panel-manage g-solid-2` (js/app.js;
   lives inside the glass .panel drawer, so solid). */
.panel-manage { margin: 0 0 16px; padding: 12px 14px; }
.panel-manage > summary.panel-manage-h { display: flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 800; letter-spacing: .01em; cursor: pointer; user-select: none; list-style: none; }
.panel-manage-h::-webkit-details-marker { display: none; }
.panel-manage-h svg { width: 16px; height: 16px; color: var(--accent); }
.panel-manage-toggle { margin-left: auto; display: inline-flex; transition: transform var(--dur-2) ease; }
.panel-manage-toggle svg { width: 16px; height: 16px; color: var(--text-3); }
.panel-manage[open] .panel-manage-toggle { transform: rotate(180deg); }
.panel-manage-sub { font-size: 12px; color: var(--text-3); margin: 8px 0 12px; }
.panel-cedit { display: flex; align-items: center; gap: 10px; padding: 10px 12px; margin: 0 0 12px; border: 1px solid var(--accent-soft, rgba(229,50,43,.3)); background: var(--accent-softer, rgba(229,50,43,.08)); border-radius: var(--radius-sm); }
.panel-cedit > svg { width: 16px; height: 16px; color: var(--accent, #e5322b); flex: 0 0 auto; }
.panel-cedit-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.panel-cedit-tx b { font-size: 12.5px; color: var(--text); }
.panel-cedit-tx small { font-size: 11px; color: var(--text-3); }
.panel-cedit-acts { display: flex; gap: 6px; flex: 0 0 auto; }
.panel-manage-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
@media (max-width: 520px){ .panel-manage-grid { grid-template-columns: repeat(2, 1fr); } }
.pmg-btn { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px; padding: 10px 8px; border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--bg, transparent); color: var(--text-2); font-family: var(--font); font-size: 11.5px; font-weight: 600; cursor: pointer; transition: border-color var(--dur-1), color var(--dur-1), transform .08s, background var(--dur-1); }
.pmg-btn:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-softer, transparent); }
.pmg-btn:active { transform: scale(.97); }
.pmg-btn svg { width: 18px; height: 18px; }
.pmg-ct { position: absolute; top: 7px; right: 9px; font-style: normal; font-size: 11px; font-weight: 800; min-width: 16px; height: 16px; padding: 0 4px; display: inline-grid; place-items: center; border-radius: var(--radius-pill); background: var(--accent); color:var(--text-on-accent,#fff); }
/* client Tasks manager modal */
.cltask-list { display: flex; flex-direction: column; gap: 6px; margin-bottom: 12px; max-height: 44vh; overflow-y: auto; }
.cltask-empty { font-size: 13px; color: var(--text-3); line-height: 1.5; padding: 18px 12px; text-align: center; }
.cltask-row { display: flex; align-items: center; gap: 10px; padding: 9px 10px; border: 1px solid var(--hairline); border-radius: var(--radius-md); }
.cltask-row.done { opacity: .6; }
.cltask-check { width: 22px; height: 22px; flex: 0 0 auto; border: 2px solid var(--hairline); border-radius: var(--radius-sm); background: transparent; color: #fff; cursor: pointer; display: grid; place-items: center; }
.cltask-row.done .cltask-check { background: var(--green); border-color: var(--green); }
.cltask-check svg { width: 13px; height: 13px; }
.cltask-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cltask-title { font-size: 13.5px; color: var(--text); }
.cltask-row.done .cltask-title { text-decoration: line-through; }
.cltask-meta { display: flex; gap: 5px; }
.cltask-tag { font-style: normal; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--text-3); border: 1px solid var(--hairline); border-radius: var(--radius-pill); padding: 1px 6px; }
.cltask-tag.notify { color: var(--accent); border-color: var(--accent-soft, var(--hairline)); }
.cltask-del { border: none; background: transparent; color: var(--text-3); cursor: pointer; padding: 2px; } .cltask-del:hover { color: var(--red, #e5322b); } .cltask-del svg { width: 15px; height: 15px; }
/* v643 ONE TASK SYSTEM: the client-task row now shows its Master-list assignees + a jump to the real task. */
.cltask-who { flex: 0 0 auto; display: inline-flex; }
.cltask-open { border: none; background: transparent; color: var(--text-3); cursor: pointer; padding: 2px; display: grid; place-items: center; }
.cltask-open:hover { color: var(--text-2); }
.cltask-open svg { width: 16px; height: 16px; }
.cltask-add { display: flex; gap: 8px; align-items: center; }
.cltask-add .minput { flex: 1; }
.cltask-notify { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--text-2); white-space: nowrap; }
/* client Creatives view */
.clcr-sec { margin-bottom: 16px; }
.clcr-sec-h { display: flex; align-items: center; justify-content: space-between; font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; color: var(--text-3); margin-bottom: 8px; }
.clcr-sec-h i { font-style: normal; font-size: 11px; padding: 1px 7px; border-radius: var(--radius-pill); background: var(--surface-2, rgba(127,127,127,.12)); }
.clcr-empty { font-size: 12.5px; color: var(--text-3); padding: 12px; border: 1px dashed var(--hairline); border-radius: var(--radius-md); text-align: center; }
/* run5 wave4: `.clcr-grid` / `.clcr-card` / `.clcr-ic` / `.clcr-cap` deleted — DEAD. The old
   square creatives GRID was replaced by the list below (`.clcr-list` > `.clcr-item`, emitted by
   openClientCreatives() at js/app.js:12742); none of the four appear in any renderer. */
/* creatives management — list items, media thumbs, status, deliver composer */
.clcr-list { display: flex; flex-direction: column; gap: 9px; }
/* run6 W5b: surface props deleted — markup now ships `clcr-item g-solid-2` (js/app.js). */
.clcr-item { overflow: hidden; }
.clcr-media { display: flex; gap: 0; overflow-x: auto; scrollbar-width: none; } .clcr-media::-webkit-scrollbar { display: none; }
.clcr-th { position: relative; flex: 0 0 auto; min-width: 42%; display: block; background: #000; }
.clcr-media .clcr-th:only-child { min-width: 100%; }
.clcr-media .clcr-th + .clcr-th { border-left: 2px solid var(--bg, #0b0b0e); }
.clcr-th img, .clcr-th video { display: block; width: 100%; height: 120px; object-fit: cover; }
.clcr-th-v span { position: absolute; inset: 0; margin: auto; width: 34px; height: 34px; display: grid; place-items: center; background: rgba(0,0,0,.5); border-radius: 50%; color: #fff; font-size: 13px; }
.clcr-th-f { display: flex; align-items: center; gap: 7px; padding: 14px; color: var(--text-2); font-size: 12px; min-width: 100%; } .clcr-th-f svg { width: 16px; height: 16px; }
.clcr-body { padding: 10px 12px; }
.clcr-top { display: flex; align-items: center; gap: 8px; }
.clcr-name { font-size: 13.5px; font-weight: 700; color: var(--text); flex: 1; word-break: break-word; }
.clcr-tag { font-style: normal; font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .03em; color: var(--accent, #e5322b); flex: 0 0 auto; }
.clcr-del { flex: 0 0 auto; border: none; background: transparent; color: var(--text-3); cursor: pointer; padding: 2px; border-radius: var(--radius-xs); } .clcr-del svg { width: 15px; height: 15px; } .clcr-del:hover { color: var(--red, #e5322b); }
/* v549 staff-side read-only client-approval chip on delivered ('made') creatives */
.clcr-appr { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: var(--radius-pill); font-size: 10.5px; font-weight: 700; letter-spacing: .02em; white-space: nowrap; }
.clcr-appr svg { width: 11px; height: 11px; }
.clcr-appr-ok { background: var(--green-bg, rgba(19,138,78,.13)); color: var(--green, #138a4e); }
.clcr-appr-chg { background: var(--amber-bg, rgba(176,106,0,.13)); color: var(--amber, #b06a00); cursor: help; }
.clcr-appr-pend { background: var(--surface-2, rgba(127,127,127,.08)); color: var(--text-3); }
.clcr-desc { margin: 6px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--text-2); word-break: break-word; }
.clcr-status { display: flex; gap: 6px; margin-top: 9px; flex-wrap: wrap; }
.clcr-st { font-size: 11px; font-weight: 700; padding: 4px 11px; border-radius: var(--radius-pill); border: 1px solid var(--hairline); background: transparent; color: var(--text-2); cursor: pointer; transition: background-color var(--dur-1), color var(--dur-1), border-color var(--dur-1), box-shadow var(--dur-1), opacity var(--dur-1), transform var(--dur-1); }
.clcr-st:hover { border-color: var(--text-2); }
.clcr-st.on { background: var(--accent, #e5322b); border-color: var(--accent, #e5322b); color:var(--text-on-accent,#fff); }
.clcr-deliver { margin-top: 16px; padding: 14px; border: 1px solid var(--accent-soft, rgba(229,50,43,.3)); border-radius: var(--radius-md); background: var(--surface, rgba(127,127,127,.03)); display: flex; flex-direction: column; gap: 10px; }
.clcr-deliver-h { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--text); } .clcr-deliver-h svg { width: 17px; height: 17px; color: var(--accent, #e5322b); }
.clcr-deliver-row { display: flex; align-items: center; gap: 12px; }
.clcr-notify { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-2); cursor: pointer; }
.clcr-staged { display: flex; flex-wrap: wrap; gap: 8px; } .clcr-staged:empty { display: none; }
.clcr-chip { display: inline-flex; align-items: center; gap: 6px; max-width: 180px; padding: 4px 7px 4px 4px; border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface-2, rgba(127,127,127,.06)); font-size: 11.5px; }
.clcr-chip img { width: 24px; height: 24px; border-radius: var(--radius-xs); object-fit: cover; } .clcr-chip svg { width: 14px; height: 14px; color: var(--text-3); }
.clcr-chip small { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: var(--text-2); }
.clcr-chipx { border: none; background: transparent; color: var(--text-3); cursor: pointer; font-size: 15px; line-height: 1; padding: 0 2px; } .clcr-chipx:hover { color: var(--text); }
.clcr-up { width: 11px; height: 11px; border: 2px solid var(--text-3); border-top-color: transparent; border-radius: 50%; animation: clcr-spin .7s linear infinite; } @keyframes clcr-spin { to { transform: rotate(360deg); } }
/* bookings management */
.clbk-list { display: flex; flex-direction: column; gap: 9px; }
/* run6 W5b: surface props deleted — markup now ships `clbk-row g-solid-2` (js/app.js);
   grid-template-areas layout kept intact. */
.clbk-row { padding: 12px 14px; display: grid; grid-template-columns: 1fr auto; grid-template-areas: 'when acts' 'title title' 'loc loc' 'checks checks'; gap: 6px 10px; align-items: center; }
.clbk-when { grid-area: when; display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--accent, #e5322b); font-weight: 600; } .clbk-when svg { width: 14px; height: 14px; }
.clbk-title { grid-area: title; font-size: 14px; font-weight: 700; color: var(--text); }
.clbk-loc { grid-area: loc; display: flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-3); } .clbk-loc svg { width: 13px; height: 13px; }
.clbk-checks { grid-area: checks; display: flex; gap: 8px; margin-top: 4px; }
.clbk-chk { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-2); padding: 5px 11px; border: 1px solid var(--hairline); border-radius: var(--radius-pill); cursor: pointer; transition: background-color var(--dur-1), color var(--dur-1), border-color var(--dur-1), box-shadow var(--dur-1), opacity var(--dur-1), transform var(--dur-1); }
.clbk-chk.on { background: var(--green-bg); border-color: var(--green); color: var(--green); }
.clbk-chk input { accent-color: var(--green); }
.clbk-acts { grid-area: acts; display: flex; align-items: center; gap: 6px; justify-self: end; }
.btn-xs { font-size: 11.5px; padding: 5px 9px; }
.btn-xs svg { width: 12px; height: 12px; }
.pmg-ct-warn { background: var(--accent, #e5322b) !important; color:var(--text-on-accent,#fff) !important; }
/* client Messages badge: plain total = muted/informational; an "awaiting your reply" count keeps the accent */
.pmg-ct-muted { background: var(--surface-2, #e9ebef) !important; color: var(--text-3) !important; }
.pmg-awaiting { border-color: var(--accent) !important; color: var(--accent) !important; }
/* payments management */
.clpay-sum { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 16px; }
.clpay-kpi { border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: 12px 14px; }
.clpay-kpi b { display: block; font-size: 19px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; }
.clpay-kpi i { font-style: normal; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-3); }
.clpay-kpi.due { border-color: var(--accent-soft, rgba(229,50,43,.3)); background: var(--accent-softer, rgba(229,50,43,.07)); } .clpay-kpi.due b { color: var(--accent, #e5322b); }
.clpay-list { display: flex; flex-direction: column; gap: 8px; }
/* run6 W5b: surface props deleted — markup now ships `clpay-row g-solid-2` (js/app.js). */
.clpay-row { display: flex; align-items: center; gap: 12px; padding: 12px 14px; }
.clpay-month { flex: 1; font-size: 14px; font-weight: 600; color: var(--text); }
.clpay-amt { font-size: 14px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.clpay-st { border: none; cursor: pointer; font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .03em; padding: 5px 12px; border-radius: var(--radius-pill); transition: filter var(--dur-1); } .clpay-st:hover { filter: brightness(1.12); }
.clpay-st.clpay-paid { background: var(--green-bg); color: var(--green); }
.clpay-st.clpay-due { background: var(--amber-bg); color: var(--amber); }
.clpay-st.clpay-overdue { background: rgba(229,50,43,.16); color: #ff6a62; }
.clpay-st.clpay-pending { background: var(--surface-2, rgba(127,127,127,.12)); color: var(--text-3); }
/* client stats modal */
.clst-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 16px; }
@media (max-width: 520px){ .clst-grid { grid-template-columns: repeat(2, 1fr); } }
.clst-kpi { border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: 13px 14px; }
.clst-ic { width: 28px; height: 28px; border-radius: var(--radius-sm); display: grid; place-items: center; background: var(--accent-softer, rgba(229,50,43,.1)); margin-bottom: 9px; } .clst-ic svg { width: 15px; height: 15px; color: var(--accent, #e5322b); }
.clst-kpi b { display: block; font-size: 22px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; line-height: 1.1; }
.clst-kpi i { font-style: normal; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-3); }
.clst-links { display: flex; flex-wrap: wrap; gap: 8px; }
/* Pipeline (kanban) */
.pipe-page { padding: 2px 2px 40px; }
.pipe-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin: 2px 2px 18px; flex-wrap: wrap; }
.pipe-title { font-size: 22px; font-weight: 800; margin: 0 0 4px; }
.pipe-sub { font-size: 13px; color: var(--text-3); margin: 0; max-width: 60ch; line-height: 1.5; }
.pipe-headmeta { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.pipe-total { text-align: right; } .pipe-total b { display: block; font-size: 20px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; } .pipe-total i { font-style: normal; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-3); }
.pipe-total.pipe-fc b { color: var(--accent); } .pipe-total.pipe-won b { color: var(--green); }
.pipe-touch { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; color: var(--text-3); }
.pipe-touch b { font-weight: 700; color: var(--text-2); }
@media (max-width: 560px){ .pipe-headmeta { gap: 12px; } .pipe-total b { font-size: 17px; } }
.pipe-board { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(220px, 1fr); gap: 12px; overflow-x: auto; padding-bottom: 8px; -webkit-overflow-scrolling: touch; }
@media (max-width: 760px){ .pipe-board { grid-auto-columns: 80%; } }
/* run6 W5c: .pipe-col surface → .g-solid-2 in the column template (js/app.js renderPipeline);
   bespoke background/border/border-radius deleted — primitives draw edges via box-shadow, a
   leftover border double-edges. Layout stays here. */
.pipe-col { padding: 12px; display: flex; flex-direction: column; min-height: 200px; }
.pipe-col-head { display: flex; align-items: center; gap: 8px; font-size: 13px; }
.pipe-col-head b { flex: 1; font-weight: 700; color: var(--text); }
.pipe-col-head i { font-style: normal; font-size: 12px; font-weight: 700; color: var(--text-2); background: var(--surface-2, rgba(127,127,127,.12)); padding: 1px 8px; border-radius: var(--radius-pill); }
/* V734-P1 · going-cold lead COUNT (js/app.js:9962). `#fff` on the opaque --red plate = 13/24 fail
   (worst 1.150, cobalt/light) — the number was a ghost. --g-text-on-red = 0/24. See :651. */
.pipe-col-cold { font-size: 11px; font-weight: 800; color: var(--g-text-on-red,#fff); background: var(--red, #e5322b); min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--radius-pill); display: inline-flex; align-items: center; justify-content: center; }
.pipe-col-cold::before { content: '❄'; font-size: 11px; margin-right: 2px; }
.pipe-col-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--text-3); flex: 0 0 auto; }
.pipe-new .pipe-col-dot { background: var(--text-3); } .pipe-work .pipe-col-dot { background: var(--amber); } .pipe-appt .pipe-col-dot { background: var(--slate); } .pipe-showed .pipe-col-dot { background: var(--slate); } .pipe-won .pipe-col-dot { background: var(--green); }
.pipe-col-val { font-size: 12px; font-weight: 700; color: var(--text-3); font-variant-numeric: tabular-nums; margin: 8px 0 10px; }
.pipe-col-body { display: flex; flex-direction: column; gap: 8px; }
/* run6 W5c: .pipe-card surface → .g-solid-2 in the lead-card template (js/app.js pipeLeadCard);
   the _glassifyPipelineRegion post-paint decorator is retired in the same edit. border-color
   dropped from the transition (no border on a primitive); hover retargeted to the system
   card-hover recipe (accent border was the drop affordance — the lifted shadow keeps the
   "interactive" read without spending the reserved accent on every hover). */
.pipe-card { padding: 11px 12px; cursor: default; transition: background-color var(--dur-1), transform var(--dur-1), box-shadow var(--dur-1); }
.pipe-card:hover { box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-3); }
.pipe-card-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.pipe-card-top b { font-size: 13.5px; font-weight: 700; color: var(--text); }
.pipe-val { font-size: 12px; font-weight: 700; color: var(--green); font-variant-numeric: tabular-nums; }
.pipe-card-svc { font-size: 12px; color: var(--text-2); margin-top: 3px; }
.pipe-card-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 8px; }
.pipe-client { font-size: 11px; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pipe-when { font-size: 11px; font-weight: 600; color: var(--text-3); flex: 0 0 auto; text-decoration: none; font-variant-numeric: tabular-nums; transition: color var(--dur-1); }
.pipe-when:hover { text-decoration: underline; color: var(--accent, #e5322b); }
.pipe-empty { font-size: 12px; color: var(--text-3); text-align: center; padding: 16px 8px; border: 1px dashed var(--hairline); border-radius: var(--radius-md); }
.pe-touch { display: none; }
@media (hover: none){ .pe-hover { display: none; } .pe-touch { display: inline; } }
/* keyboard focus rings for clickable cards/rows (a11y) */
.pipe-card-main:focus-visible, .trow:focus-visible, .tname:focus-visible, .p-nametext:focus-visible, .cr-title:focus-visible, .member-id:focus-visible, .bcard:focus-visible, .pt-namecell:focus-visible, .adsm-card:focus-visible { outline: var(--g-focus-w, 2px) solid var(--g-focus-color, var(--accent)); outline-offset: 2px; border-radius: var(--radius-sm); box-shadow: none; } /* v811: the a11y wave moved the tab stop from the row/card onto its name child; .tname sits under .tname-wrap{overflow:hidden}, which clips the global [tabindex] box-shadow ring, so these targets keep an OUTLINE (critic B1) */
.pipe-lost .pipe-col-dot { background: var(--text-3); }
/* interactive pipeline */
.pipe-actions { display: flex; gap: 8px; margin: 0 2px 14px; flex-wrap: wrap; }
.pipe-card { position: relative; padding-left: 38px; cursor: grab; }
.pipe-card:active { cursor: grabbing; }
.pipe-card.pipe-dragging { opacity: .5; }
.pipe-card-check { position: absolute; left: 10px; top: 12px; width: 22px; height: 22px; border-radius: var(--radius-sm); border: 2px solid var(--hairline-strong, rgba(127,127,127,.4)); background: transparent; color: transparent; cursor: pointer; display: grid; place-items: center; padding: 0; transition: background-color var(--dur-1), color var(--dur-1), border-color var(--dur-1), box-shadow var(--dur-1), opacity var(--dur-1), transform var(--dur-1); }
.pipe-card-check svg { width: 13px; height: 13px; }
.pipe-card-check:hover { border-color: var(--green); }
/* V734-P1 · `color` here is what the icon('check') SVG inherits (stroke="currentColor", js/icons.js:3/15),
   so at 13/24 (worst 1.042) the ICON disappeared, not just text. --g-text-on-green = 0/24. See :651. */
.pipe-card.is-contacted .pipe-card-check { background: var(--green); border-color: var(--green); color: var(--g-text-on-green,#fff); }
.pipe-card-main { cursor: pointer; }
.pipe-card-adv { position: absolute; right: 8px; bottom: 8px; width: 26px; height: 26px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface, rgba(127,127,127,.06)); color: var(--text-2); cursor: pointer; display: grid; place-items: center; opacity: 0; transition: opacity var(--dur-1), background var(--dur-1), color var(--dur-1), border-color var(--dur-1); }
.pipe-card-adv svg { width: 15px; height: 15px; }
.pipe-card:hover .pipe-card-adv, .pipe-card-adv:focus-visible { opacity: 1; }
.pipe-card-adv:hover { background: var(--accent, #e5322b); color:var(--text-on-accent,#fff); border-color: var(--accent, #e5322b); }
@media (hover: none){ .pipe-card-adv { opacity: 1; } }
.pipe-src { font-size: 11px; font-weight: 800; letter-spacing: .04em; color: var(--amber); background: var(--amber-bg); padding: 1px 6px; border-radius: var(--radius-xs); margin-left: auto; }
/* lead age "going cold" pill — fresh<2d / warm 3-6d / cold 7d+ */
.pipe-age { font-size: 11px; font-weight: 700; padding: 1px 7px; border-radius: var(--radius-pill); flex: 0 0 auto; margin-left: auto; font-variant-numeric: tabular-nums; }
.pipe-age-fresh { color: var(--green); background: var(--green-bg); }
.pipe-age-warm { color: var(--amber); background: var(--amber-bg); }
.pipe-age-cold { color: var(--red, #e5322b); background: rgba(229,50,43,.13); }
.pipe-col-body { min-height: 90px; }
.pipe-col.drop-on { outline: 2px dashed var(--accent, #e5322b); outline-offset: -3px; background: var(--accent-softer, rgba(229,50,43,.06)); }
.pipe-col.drop-on .pipe-empty { border-color: var(--accent, #e5322b); color: var(--accent, #e5322b); }
.pipe-hint-inline { font-size: 11.5px; color: var(--text-3); align-self: center; }
/* ── BUILD 3: Call Center / Sales "Today" day-view (renderDayView) — Pipeline nav replacement */
.dv-page { padding: 2px 2px 48px; max-width: 860px; }
.dv-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; margin: 2px 2px 20px; }
.dv-title { font-family: var(--font-display, inherit); font-size: 24px; font-weight: 800; letter-spacing: -.02em; margin: 0 0 4px; color: var(--text); }
.dv-date { font-size: 13px; color: var(--text-3); margin: 0; }
.dv-stats { display: flex; gap: 10px; flex-wrap: wrap; }
/* Call-next quick action + speed-to-lead urgency chip */
.dv-callnext { display: inline-flex; align-items: center; gap: 7px; padding: 9px 15px; border: none; border-radius: var(--radius-sm); background: var(--accent); color:var(--text-on-accent,#fff); font-family: var(--font); font-size: 14px; font-weight: 700; cursor: pointer; box-shadow: var(--shadow-sm); transition: transform var(--dur-1), box-shadow var(--dur-1); }
.dv-callnext:hover { box-shadow: var(--shadow); }
.dv-callnext svg { width: 15px; height: 15px; }
.dv-callnext b { font-weight: 800; opacity: .92; }
.dv-speed { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 2px; font-size: 11px; font-weight: 700; padding: 2px 7px; border-radius: var(--radius-sm); white-space: nowrap; }
.dv-speed svg { width: 11px; height: 11px; }
.dv-speed.is-hot { color: var(--green, #1f9d57); background: color-mix(in srgb, var(--green, #1f9d57) 12%, transparent); }
.dv-speed.is-late { color: var(--red, #e5322b); background: color-mix(in srgb, var(--red, #e5322b) 12%, transparent); }
.dv-ltime { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 3px; font-size: 11px; font-weight: 600; padding: 2px 7px; border-radius: var(--radius-sm); white-space: nowrap; color: var(--text-2); background: var(--surface-2, rgba(127,127,127,.08)); }
.dv-ltime svg { width: 11px; height: 11px; }
.dv-ltime.is-off { color: var(--amber, #e0900b); background: color-mix(in srgb, var(--amber, #e0900b) 13%, transparent); }
.pt-bill-free { color: var(--green, #1f9d55); } .pt-bill-free .pt-bill-dot { background: var(--green, #1f9d55); }
.bil-foldhead { display: flex; align-items: center; gap: 10px; cursor: pointer; padding: 6px 2px; }
.bil-foldhead .home-card-meta { margin-left: auto; font-size: 12px; color: var(--text-3); }
.home-hero { position: relative; }
.home-pp-btn { position: absolute; top: var(--space-3); right: var(--space-3); display: inline-flex; align-items: center; gap: var(--space-2); height: var(--ctl-md); padding: 0 var(--space-3); border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--glass); color: var(--text); font-weight: var(--fw-medium); font-size: var(--fs-body); cursor: pointer; transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.home-pp-btn:hover { background: var(--surface); border-color: var(--hairline-strong); }
.home-pp-btn b { font-size: var(--fs-body); font-weight: var(--fw-semi); color: var(--text); font-variant-numeric: tabular-nums; }
.home-pp-btn svg { width: var(--icon-sm); height: var(--icon-sm); }
.pp-kind { display: inline-flex; gap: 6px; }
.pp-kbtn { padding: 7px 16px; border-radius: var(--radius-sm); border: 1px solid var(--border, rgba(127,127,127,.16)); background: transparent; color: var(--text-2); font-weight: 700; font-size: 13px; cursor: pointer; }
.pp-kbtn.on { background: var(--accent, #7c5cff); border-color: var(--accent, #7c5cff); color:var(--text-on-accent,#fff); }
.pp-success { display: flex; gap: 10px; align-items: flex-start; padding: 12px; border-radius: var(--radius-md); background: color-mix(in srgb, var(--green, #1f9d55) 10%, transparent); font-size: 13.5px; }
.pp-success svg { width: 18px; height: 18px; color: var(--green, #1f9d55); flex: 0 0 auto; margin-top: 2px; }
.pp-link-row { display: flex; gap: 8px; margin-top: 8px; } .pp-link-row .minput { flex: 1; font-size: 12.5px; }
.pp-err { padding: 10px 12px; border-radius: var(--radius-md); background: color-mix(in srgb, var(--red, #e5322b) 9%, transparent); font-size: 13px; }
/* v525 Payment-Processor ledger (Recent links) + reconciliation (Unmatched payers) — orchestrator: review */
.pp-section { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--hairline, rgba(127,127,127,.12)); }
.pp-section:empty { display: none; border-top: none; margin: 0; padding: 0; }
.pp-h4 { margin: 0 0 8px; font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; color: var(--text-2); }
.pp-empty { margin: 0; font-size: 12.5px; color: var(--text-2); }
/* SIM-03: the payer filter above the unmatched-payer list (only rendered past 8 rows) */
.pp-payerfilter { margin: 8px 0; }
.pp-list { display: flex; flex-direction: column; gap: 6px; }
/* run6 W5b: surface props deleted — markup now ships `pp-lrow g-solid-2` (js/app.js, all 3
   sites; repeated payer rows inside the Payment Processor modal — solid). */
.pp-lrow { display: flex; align-items: center; gap: 10px; padding: 9px 11px; }
.pp-lmain { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; }
.pp-ltitle { font-size: 13.5px; font-weight: 700; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* SIM-16 · the payer's EMAIL is the only thing that identifies "New payers without an account",
   and `white-space: nowrap` meant a normal address (name@somelongdomain.com · last paid …) simply
   overflowed .pp-lmain and painted straight across — and under — the "Create client account"
   button sitting to its right. It was unreadable exactly where it had to be read before you press
   an account-creating button. It wraps now, and `anywhere` lets the break land inside a long local
   part or domain, because an email has no spaces to break at. min-width:0 is what actually lets a
   flex item shrink below its content width; without it the wrap never gets the chance to happen. */
.pp-lmeta { font-size: 12px; color: var(--text-2); min-width: 0; max-width: 100%; white-space: normal; overflow-wrap: anywhere; word-break: break-word; line-height: 1.45; }
/* On a phone the row has no width to share at all — stack it, so the address gets the full card
   and the button becomes a full-width target instead of a sliver competing with the text. */
@media (max-width: 560px) {
  .pp-lrow { flex-direction: column; align-items: stretch; gap: 8px; }
  .pp-lmain { align-items: flex-start; }
  .pp-lacts { width: 100%; }
  .pp-lacts .btn { flex: 1; justify-content: center; min-height: 40px; }
}
.pp-chip { font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: var(--radius-pill); color: var(--accent, #7c5cff); background: color-mix(in srgb, var(--accent, #7c5cff) 13%, transparent); }
.pp-lacts { display: inline-flex; gap: 6px; flex: 0 0 auto; }
.pp-lacts .btn-sm { display: inline-flex; align-items: center; gap: 4px; }
.pp-lacts svg { width: 13px; height: 13px; }
.lead-ltime { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; padding: 4px 10px; border-radius: var(--radius-sm); color: var(--text-2); background: var(--surface-2, rgba(127,127,127,.08)); }
.lead-ltime svg { width: 12px; height: 12px; }
.lead-ltime.is-off { color: var(--amber, #e0900b); background: color-mix(in srgb, var(--amber, #e0900b) 13%, transparent); }
.dv-ana-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 12px; }
/* run6 W5c: surface → .g-solid-2 in the analytics template (js/app.js); layout stays */
.dv-ana-card { padding: 8px 10px; overflow-x: auto; }
.dv-ana-tbl { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.dv-ana-tbl th { text-align: left; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--text-2); padding: 6px 8px; border-bottom: 1px solid var(--border, rgba(127,127,127,.14)); white-space: nowrap; }
.dv-ana-tbl td { padding: 6px 8px; border-bottom: 1px solid var(--border, rgba(127,127,127,.08)); white-space: nowrap; }
.dv-ana-tbl tbody tr:last-child td { border-bottom: none; }
.dv-ana-name { font-weight: 600; max-width: 160px; overflow: hidden; text-overflow: ellipsis; }
.dv-ana-hot { color: var(--green, #1f9d55); font-weight: 700; }
.dv-ana-empty { padding: 14px; text-align: center; color: var(--text-2); font-size: 12.5px; }
.dv-ana-win { display: inline-flex; gap: 4px; margin-left: 8px; }
.dv-ana-wbtn { font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: var(--radius-sm); border: 1px solid var(--border, rgba(127,127,127,.16)); background: transparent; color: var(--text-2); cursor: pointer; }
.dv-ana-wbtn.is-on { background: var(--accent, #7c5cff); border-color: var(--accent, #7c5cff); color:var(--text-on-accent,#fff); }
.pf-navorder { display: flex; flex-direction: column; gap: 2px; }
.pf-nav-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 4px; border-bottom: 1px solid var(--hairline, rgba(127,127,127,.1)); }
.pf-nav-row:last-of-type { border-bottom: none; }
.pf-nav-name { font-size: 13.5px; font-weight: 600; }
.pf-nav-btns { display: inline-flex; gap: 4px; }
.pf-nav-btn { width: 30px; height: 26px; border-radius: var(--radius-sm); border: 1px solid var(--border, rgba(127,127,127,.16)); background: transparent; color: var(--text-2); cursor: pointer; font-size: 11px; line-height: 1; }
.pf-nav-btn:disabled { opacity: .3; cursor: default; }
.pf-nav-btn:not(:disabled):hover { background: var(--surface-2, rgba(127,127,127,.08)); }
.pf-nav-reset { margin-top: 8px; align-self: flex-start; }
/* run6 W5c: surface → .g-solid-2 in the stat template (js/app.js); the non-standard
   var(--radius-2,14px) radius goes with it — the primitive's --g-r-card owns the shape */
.dv-stat { min-width: 82px; padding: 10px 14px; text-align: center; }
.dv-stat b { display: block; font-size: 22px; font-weight: 800; line-height: 1.05; color: var(--text); font-variant-numeric: tabular-nums; }
.dv-stat i { font-style: normal; font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-3); }
.dv-stat-call b { color: var(--accent, #e5322b); }
.dv-stat-booked b { color: var(--green); }
.dv-stat-follow b { color: var(--amber, #d98a00); }
.dv-stat-warn b { color: var(--red, #e5322b); }
.dv-sec { margin: 0 2px 22px; }
.dv-sec-head { display: flex; align-items: center; gap: 9px; margin: 0 0 11px; }
.dv-sec-head h2 { font-size: 15px; font-weight: 750; color: var(--text); margin: 0; }
.dv-sec-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.dv-dot-call { background: var(--accent, #e5322b); } .dv-dot-booked { background: var(--green); } .dv-dot-follow { background: var(--amber, #d98a00); } .dv-dot-warn { background: var(--red, #e5322b); } .dv-dot-done, .dv-dot-muted { background: var(--text-3); }
.dv-sec-ct { font-size: 12px; font-weight: 700; color: var(--text-2); background: var(--surface-2, rgba(127,127,127,.12)); padding: 1px 9px; border-radius: var(--radius-pill); font-variant-numeric: tabular-nums; }
.dv-sec-hint { font-size: 11.5px; color: var(--text-3); margin-left: auto; text-align: right; }
.dv-worked-tally { margin-left: auto; font-size: 11.5px; font-weight: 650; color: var(--green, #1f9d57); font-variant-numeric: tabular-nums; white-space: nowrap; }
@media (max-width: 560px){ .dv-sec-hint { display: none; } }
.dv-list { display: flex; flex-direction: column; gap: 8px; }
/* run6 W5c: surface → .g-solid-2 in the lead-row template (js/app.js); hover retargeted to the
   solid ramp (repeated rows step, not a lift) */
.dv-row { display: flex; align-items: center; gap: 11px; padding: 11px 12px; cursor: pointer; transition: background-color var(--dur-1), transform var(--dur-1), box-shadow var(--dur-1); }
.dv-row:hover { background-color: var(--g-solid-3); }
.dv-row:focus-visible, .dv-top b:focus-visible { outline: 2px solid var(--accent, #e5322b); outline-offset: 2px; box-shadow: none; }
.dv-time { flex: 0 0 auto; font-size: 12px; font-weight: 800; color: var(--green); background: var(--green-bg); padding: 3px 8px; border-radius: var(--radius-sm); font-variant-numeric: tabular-nums; min-width: 58px; text-align: center; }
.dv-time.dv-time-overdue { color: var(--red, #e5322b); background: color-mix(in srgb, var(--red, #e5322b) 12%, transparent); display: inline-flex; align-items: center; gap: 3px; min-width: 0; padding: 3px 9px; text-align: left; }
.dv-time.dv-time-overdue svg { width: 12px; height: 12px; }
/* Callback chips + row highlight */
.dv-cbtime { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 3px; font-size: 12px; font-weight: 700; color: var(--accent); background: var(--accent-soft, rgba(0,0,0,.05)); padding: 3px 8px; border-radius: var(--radius-sm); white-space: nowrap; }
.dv-cbtime.is-overdue { color: var(--red, #e5322b); background: color-mix(in srgb, var(--red, #e5322b) 12%, transparent); }
.dv-cbtime svg, .dv-cb-badge svg { width: 12px; height: 12px; }
.dv-cb-badge { flex: 0 0 auto; display: inline-flex; color: var(--accent); opacity: .7; margin-right: 2px; }
/* run6 W5c: the overdue signal was a border tint — the border is gone with the primitive, so the
   signal is restated as an inset ring appended to the g-solid-2 shadow stack. (0,2,0) on purpose:
   it must beat the primitive's (0,1,0) box-shadow, which wins plain ties (glass.css loads later). */
.dv-row.dv-row-overdue { box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-2), inset 0 0 0 1.5px color-mix(in srgb, var(--red, #e5322b) 38%, transparent); }
.lead-callback { display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.lead-callback.is-hi { animation: cbPulse 1.2s ease; }
@keyframes cbPulse { 0%,100% { background: transparent; } 30% { background: var(--accent-soft, rgba(0,0,0,.05)); } }
.lead-cb-lbl { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; font-weight: 600; color: var(--text-2); }
.lead-cb-lbl svg { width: 14px; height: 14px; }
.lead-callback .minput { flex: 1 1 170px; min-width: 150px; }
/* Your-day performance strip (per-rep, real numbers from the call log) */
/* run6 W5c: surface → .glass-2 in the perf-strip template (js/app.js); single panel, real glass */
.dv-perf { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 4px 0 18px; padding: 12px 14px; }
.dv-perf-cell { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.dv-perf-cell b { font-size: 21px; font-weight: 800; letter-spacing: -.5px; font-variant-numeric: tabular-nums; }
.dv-perf-cell span { font-size: 11px; font-weight: 600; color: var(--text-3); text-transform: uppercase; letter-spacing: .03em; }
.dv-av { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center; color: #fff; font-size: 12px; font-weight: 700; letter-spacing: .02em; }
.dv-main { flex: 1 1 auto; min-width: 0; }
.dv-top { display: flex; align-items: baseline; gap: 8px; }
.dv-top b { font-size: 14px; font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.dv-val { flex: 0 0 auto; font-size: 12px; font-weight: 700; color: var(--green); font-variant-numeric: tabular-nums; margin-left: auto; }
.dv-sub { display: flex; align-items: center; gap: 7px; margin-top: 4px; flex-wrap: wrap; }
.dv-client { font-size: 11.5px; font-weight: 600; color: var(--text-2); }
.dv-svc { font-size: 11.5px; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 40vw; }
.dv-stage { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 600; color: var(--text-3); }
.dv-stage .pipe-col-dot { width: 7px; height: 7px; }
.dv-last { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--text-3); }
.dv-last svg { width: 12px; height: 12px; }
.dv-last b { font-weight: 700; color: var(--text-2); }
.dv-call { flex: 0 0 auto; width: 40px; height: 40px; border-radius: var(--radius-md); border: 1px solid var(--hairline); background: var(--surface, rgba(127,127,127,.06)); color: var(--text-2); display: grid; place-items: center; text-decoration: none; transition: background var(--dur-1), color var(--dur-1), border-color var(--dur-1); }
.dv-call-off { opacity: .4; cursor: not-allowed; color: var(--red, #e5322b); }
.dv-call-off svg { width: 16px; height: 16px; }
.dv-dnc { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 2px; font-size: 11px; font-weight: 800; letter-spacing: .03em; color: var(--red, #e5322b); background: color-mix(in srgb, var(--red, #e5322b) 12%, transparent); padding: 2px 7px; border-radius: var(--radius-sm); }
.dv-dnc svg { width: 11px; height: 11px; }
.lead-dnc-toggle { display: inline-flex; align-items: center; gap: 6px; margin: 8px 0 2px; font-size: 12.5px; font-weight: 600; color: var(--text-2); cursor: pointer; }
.lead-dnc-toggle.is-on { color: var(--red, #e5322b); }
.lead-dnc-toggle svg { width: 13px; height: 13px; }
.lead-dnc-toggle small { font-weight: 500; color: var(--text-3); }
.dv-call svg { width: 17px; height: 17px; }
/* V734-P1 · HOVER state. Rest state (:1389) is `color:var(--text-2)` on `var(--surface)` — a different,
   non-literal pairing, left untouched. The hover flipped the plate to opaque --green and the ink to a
   literal #fff: 13/24 fail (worst 1.042), and the phone SVG (stroke="currentColor") went with it. */
.dv-call:hover { background: var(--green); border-color: var(--green); color: var(--g-text-on-green,#fff); }
.dv-sec-empty { display: flex; align-items: center; gap: 8px; padding: 14px; font-size: 12.5px; color: var(--text-3); border: 1px dashed var(--hairline); border-radius: var(--radius-2, 12px); }
.dv-sec-empty svg { width: 15px; height: 15px; color: var(--green); flex: 0 0 auto; }
.dv-sec-worked { opacity: .96; }   /* v825 (VERIFY_v824 REG-2): .9 blended the green age chip to 4.39:1; .96 keeps the dim and clears 4.5:1 */ .dv-list-done .dv-row { background: transparent; }
/* run6 W5c: keep hover feedback on the flattened worked-list rows — the (0,2,0) flatten above
   now outranks the base .dv-row:hover background step by source order */
.dv-list-done .dv-row:hover { background-color: var(--g-solid-3); }
/* Clients at a glance — per-client leads + bookings + a little 7-day calendar (Pipeline×Today hybrid) */
.cig-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 10px; }
/* run6 W5c: surface → .g-solid-2 in the client-grid template (js/app.js); hover retargeted to the
   system card-hover recipe */
.cig-card { display: flex; flex-direction: column; gap: 12px; width: 100%; text-align: left; font-family: var(--font); padding: 13px 14px; cursor: pointer; transition: background-color var(--dur-1), transform var(--dur-1), box-shadow var(--dur-1); }
.cig-card:hover { box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-3); }
.cig-card:focus-visible { outline: 2px solid var(--accent, #e5322b); outline-offset: 2px; }
.cig-card.cig-quiet { opacity: 1; border-color: var(--hairline); }   /* AUDIT_dark F6/F7/F9/F10: the .62 opacity took 9-11px text under 3:1 in both themes */
.cig-top { display: flex; align-items: center; gap: 10px; min-width: 0; }
.cig-av { flex: 0 0 auto; display: inline-flex; }
.cig-id { display: flex; flex-direction: column; min-width: 0; }
.cig-name { font-size: 13.5px; font-weight: 750; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cig-next { font-size: 11px; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
.cig-nums { display: flex; gap: 8px; }
.cig-num { flex: 1 1 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 3px 6px; padding: 8px 10px; border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--surface, rgba(127,127,127,.05)); }
.cig-num b { font-size: 19px; font-weight: 800; letter-spacing: -.5px; color: var(--text); font-variant-numeric: tabular-nums; }
.cig-num i { font-size: 11px; font-weight: 600; font-style: normal; color: var(--text-3); }
.cig-num em { font-size: 10.5px; font-weight: 700; font-style: normal; color: var(--green, #1f9d57); font-variant-numeric: tabular-nums; margin-left: auto; }
.cig-num-book b { color: var(--green, #1f9d57); }
.cig-cal { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.cig-day { display: flex; flex-direction: column; align-items: center; gap: 1px; padding: 5px 0 6px; border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface, rgba(127,127,127,.04)); min-width: 0; }
.cig-day i { font-size: 9px; font-weight: 700; font-style: normal; color: var(--text-3); text-transform: uppercase; letter-spacing: .02em; }
.cig-day u { font-size: 11px; font-weight: 700; text-decoration: none; color: var(--text-2); font-variant-numeric: tabular-nums; }
/* V734-P1 · the booking-COUNT number (js/app.js:9117) at 10px/800. `#fff` on the opaque --green plate
   = 13/24 fail (worst 1.042, cobalt/light). --g-text-on-green = 0/24 (worst 5.209). See :651. */
.cig-day b { display: grid; place-items: center; min-width: 15px; height: 15px; margin-top: 1px; font-size: 10px; font-weight: 800; color: var(--g-text-on-green,#fff); background: var(--green, #1f9d57); border-radius: var(--radius-pill); font-variant-numeric: tabular-nums; }
.cig-day b.cig-dot { min-width: 0; width: 4px; height: 4px; background: var(--text-3); opacity: .4; }
.cig-day.today { border-color: var(--accent, #e5322b); }
.cig-day.today u { color: var(--accent, #e5322b); }
.cig-day.has { background: var(--green-bg, color-mix(in srgb, var(--green, #1f9d57) 12%, transparent)); border-color: color-mix(in srgb, var(--green, #1f9d57) 34%, var(--hairline)); }
@media (max-width: 560px){ .cig-grid { grid-template-columns: 1fr; } }
/* run6 W5a: surface props deleted — markup now ships `dv-cc-empty glass-2` (js/app.js). Big
   empty-state padding kept bespoke (no .g-pad). */
.dv-cc-empty { text-align: center; padding: 48px 20px; }
.dv-cc-empty svg { width: 40px; height: 40px; color: var(--text-3); margin-bottom: 8px; }
.dv-cc-empty h2 { font-size: 18px; font-weight: 750; margin: 0 0 6px; color: var(--text); }
.dv-cc-empty p { font-size: 13px; color: var(--text-3); max-width: 44ch; margin: 0 auto 12px; line-height: 1.5; }
.dv-cc-hint { font-size: 12px; color: var(--text-3); }
@media (max-width: 560px){ .dv-title { font-size: 21px; } .dv-stat { min-width: fit-content; flex: 1 1 auto; padding: 9px 8px; } .dv-stat b { font-size: 19px; } .dv-stats { width: 100%; } .dv-svc { max-width: 32vw; } }   /* SD-10 (v817): a $6,000 tile wraps to the next row instead of clipping to $6,00( */
@media (max-width: 680px){ .pipe-hint-inline { display: none; } }
/* pipeline toolbar — live search + client filter */
.pipe-toolbar { display: flex; gap: 10px; align-items: center; margin: 0 2px 14px; flex-wrap: wrap; }
.pipe-search { position: relative; display: flex; align-items: center; flex: 1; min-width: 200px; max-width: 380px; }
.pipe-search svg { position: absolute; left: 11px; width: 15px; height: 15px; color: var(--text-3); pointer-events: none; }
.pipe-search-inp { width: 100%; font-family: var(--font); font-size: 13.5px; color: var(--text); background: var(--surface, rgba(127,127,127,.05)); border: 1px solid var(--hairline); border-radius: var(--radius-md); padding: 9px 12px 9px 34px; outline: none; transition: border-color var(--dur-2), background var(--dur-2); }
.pipe-search-inp:focus { border-color: var(--accent); background: var(--bg, #fff); }
.pipe-search-inp::placeholder { color: var(--text-3); }
/* run5 wave4: `.pipe-client-sel` deleted — DEAD. renderPipeline() (js/app.js:9641) builds that
   dropdown with uiSelect + className 'uis-inline' now, so the bespoke select skin was orphaned. */
.pipe-filter-count { font-size: 12px; font-weight: 650; color: var(--text-2); font-variant-numeric: tabular-nums; }
.pipe-states { display: flex; gap: 7px; align-items: center; flex-wrap: wrap; margin: -6px 2px 14px; }
.pipe-state-chip { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font); font-size: 12.5px; font-weight: 600; color: var(--text-2); background: var(--surface, rgba(127,127,127,.05)); border: 1px solid var(--hairline); border-radius: var(--radius-pill); padding: 7px 13px; cursor: pointer; white-space: nowrap; transition: border-color var(--dur-1), color var(--dur-1), background var(--dur-1); }
.pipe-state-chip:hover { border-color: var(--text-3); color: var(--text); }
.pipe-state-chip.on { background: var(--accent); border-color: var(--accent); color:var(--text-on-accent,#fff); }
.pipe-state-chip i { font-style: normal; font-variant-numeric: tabular-nums; font-size: 11px; font-weight: 700; padding: 1px 6px; border-radius: var(--radius-pill); background: rgba(127,127,127,.16); color: inherit; }
.pipe-state-chip.on i { background: rgba(255,255,255,.25); }
.pipe-state-chip.is-cold:not(.on) i { background: rgba(229,150,43,.18); color: #c2740f; }
/* run6 W5a: surface props deleted — markup now ships `pipe-cc-empty glass-2` (js/app.js). The big
   38/32px empty-state padding is deliberate — kept bespoke (no .g-pad). */
.pipe-cc-empty { max-width: 520px; margin: 40px auto; text-align: center; padding: 38px 32px; }
.pipe-cc-empty svg { width: 38px; height: 38px; color: var(--accent); margin-bottom: 8px; }
.pipe-cc-empty h2 { font-size: 19px; font-weight: 750; margin: 6px 0 8px; color: var(--text); }
.pipe-cc-empty p { font-size: 13.5px; color: var(--text-2); line-height: 1.6; margin: 0 0 16px; }
.pipe-cc-empty .pipe-cc-hint { font-size: 12px; color: var(--text-3); margin: 14px 0 0; }
.pipe-cc-empty .btn { margin: 0 auto; }
@media (max-width: 560px){ .pipe-search { max-width: none; } .pipe-states { gap: 6px; } .pipe-state-chip { flex: 1 1 auto; justify-content: center; } }
/* client account shell (clients use the same staff shell, scoped to their company) */
.cl-content { padding: 0 !important; }
/* Owner-preview affordance — a floating bottom-right pill (NOT a top banner) so the client account's
   header/nav is fully visible for a clean peek. Always reachable; also exits via Esc / browser back. */
.cl-prevbar { position: fixed; bottom: 18px; right: 18px; left: auto; top: auto; display: inline-flex; align-items: center; gap: 8px; padding: 9px 10px 9px 14px; background: var(--accent, #e5322b); color:var(--text-on-accent,#fff); border-radius: var(--radius-pill); box-shadow: 0 8px 28px rgba(0,0,0,.28); font-size: 12.5px; font-weight: 600; z-index: 60; max-width: calc(100vw - 36px); }
/* run5 wave4: v699 tokenised .cl-prevbar's own label but missed its two children, which still
   forced #fff on the SAME var(--accent) pill — so in the 7 light-accent themes (ink, cobalt,
   vellum, terra, ledger, verde, halo) the icon and the Exit button read white-on-bone while the
   label beside them went dark. Same fix, same fallback: no-op in studio (--text-on-accent #FFF). */
.cl-prevbar svg { width: 15px; height: 15px; color:var(--text-on-accent,#fff); }
.cl-prevbar > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cl-prevbar .btn { background: rgba(255,255,255,.22); color:var(--text-on-accent,#fff); border: none; padding: 5px 11px; font-weight: 700; }
.cl-prevbar .btn:hover { background: rgba(255,255,255,.34); }
@media (max-width: 640px) { .cl-prevbar { bottom: 78px; right: 12px; } }   /* sit above the client mobile tab-bar */
.cp-embed-wrap { max-width: 880px; margin: 0 auto; padding: 22px 18px 60px; display: flex; flex-direction: column; gap: 14px; }
@media (max-width: 600px){ .cp-embed-wrap { padding: 16px 14px 80px; } }
.cp-embed-wrap .cp-section { display: flex; flex-direction: column; gap: 14px; }
.cl-pending { max-width: 460px; margin: 60px auto; text-align: center; padding: 0 20px; }
.cl-pending svg { width: 44px; height: 44px; color: var(--accent, #e5322b); margin-bottom: 8px; }
.cl-pending h2 { font-size: 20px; margin: 0 0 8px; } .cl-pending p { color: var(--text-3); line-height: 1.6; margin: 0; }
/* ===== v545 DEDICATED CLIENT SHELL — branded, warm, zero staff chrome ===== */
/* body.cl-app re-skins the shared layout slots (#sidebar/#mainhead/#tabbar) into the client's own look. */
/* SOLID GROUND (2026-08-03, reworked run5 §1.1): .g-chrome (glass.css §5) now paints the
   sidebar's background-color + blur, so the client accent wash is a background-IMAGE layered
   on top of it — the gradient fades to TRANSPARENT (never to a second fill: two stacked fills
   made dark themes muddy, and if iOS WebKit ever drops the gradient the g-chrome fill is still
   the solid ground underneath). g-chrome's sheen layer is re-declared behind the wash because
   this 0-2-0 rule outranks glass.css's background-image and would otherwise erase it. */
body.cl-app .sidebar { background-image: linear-gradient(180deg, var(--g-accent-softer, rgba(229,50,43,.06)) 0, transparent 128px), var(--g-sheen-1, none); }
.cl-brand { display: flex; align-items: center; gap: 11px; padding: 18px 16px 15px; padding-top: calc(18px + var(--safe-top)); border-bottom: 1px solid var(--hairline); }
.cl-brand-logo { flex: 0 0 auto; display: inline-flex; }
.cl-brand-logo .avatar { border-radius: var(--radius-md); }
.cl-brand-ph { width: 42px; height: 42px; border-radius: var(--radius-md); display: grid; place-items: center; background: var(--surface); color: var(--text-3); flex: 0 0 auto; }
.cl-brand-ph svg { width: 20px; height: 20px; }
.cl-brand-meta { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.cl-brand-meta b { font-size: 15px; font-weight: 800; letter-spacing: -.2px; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cl-brand-meta small { font-size: 12px; font-weight: 600; color: var(--text-3); }
.cl-nav { flex: 1; overflow-y: auto; padding: 12px 12px 14px; display: flex; flex-direction: column; gap: 3px; }
/* run6 client-shell: the ACTIVE row ships `cl-navlink active g-solid-2 g-r-sm` (js/app.js
   renderClientSidebar) — the .sla-tile ruling: the primitive supplies the themeable structure
   (edge/spec/shadow + §19.1's border) while .cl-navlink.active (0,2,0) keeps its accent TONE on
   top. `g-r-sm` is mandatory, not decorative: .g-solid-2's --g-r-card (0,1,0, glass.css loads
   after this <style>) would otherwise beat .cl-navlink's --radius-sm and jump one nav row to the
   card radius. R6-41 CORRECTION (v723): the g-r-sm UTILITY CLASS (css/glass.css:800) resolves the
   RAW --g-r-sm token — the v720 cap lives only on the --radius-* aliases and does NOT reach this
   class. In tahoe/halo/aurora the row therefore reads 999px and renders as a full stadium — KEPT
   DELIBERATELY: a nav row is control-tier and pill controls are those themes' identity (same
   ruling as js/app.js's g-r-* comment corrections; see BUGS.md R6-41).
   `border: none` -> a --g-border-w-wide TRANSPARENT border so all 14 rows keep one box: on the
   active row §19.1 (glass.css:2096, later, same 0-1-0) repaints that border in --g-border-c, and
   in Ink/Pop that is 1.5-2px of real edge. Without the matching transparent border on the
   inactive rows, border-box would pull the active row's icon+label in by that much. */
.cl-navlink {
  display: flex; align-items: center; gap: 12px; width: 100%; padding: 11px 13px; border-radius: var(--radius-sm);
  border: var(--g-border-w, 0px) solid transparent; background: transparent; cursor: pointer; text-align: left; font-family: var(--font);
  font-size: 14px; font-weight: 650; color: var(--text-2); transition: background var(--dur-1) ease, color var(--dur-1) ease;
}
.cl-navlink:hover { background: var(--row-hover); color: var(--text); }
.cl-navlink.active { background: var(--accent-soft); color: var(--accent); }
/* run6 client-shell: was a bare `0 0 0 2px var(--accent-soft)`, which on the now-converted active
   row REPLACED the primitive's whole edge+spec+shadow stack (the v717 bug) — and accent-soft at
   2px was a weak ring to begin with. --g-focus-ring is what glass.css §6 puts on every one of its
   own focusable primitives, so the replacement is the system's own behaviour. */
.cl-navlink:focus-visible { outline: none; box-shadow: var(--g-focus-ring, 0 0 0 2px var(--accent-soft)); }
.cl-nav-ic { width: 19px; height: 19px; flex: 0 0 auto; }
.cl-nav-lbl { flex: 1; min-width: 0; }
.cl-nav-badge { flex: 0 0 auto; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 9px; background: var(--accent); color:var(--text-on-accent,#fff); font-size: 12px; font-weight: 800; display: grid; place-items: center; }
.cl-foot { border-top: 1px solid var(--hairline); padding: 12px; padding-bottom: calc(12px + var(--safe-bottom)); display: flex; flex-direction: column; gap: 10px; }
/* run6 client-shell: surface props deleted — the tray ships `cl-theme g-solid-2 g-r-md` and the
   selected mode ships `g-solid-4` (js/app.js renderClientSidebar). OPAQUE twins, not .glass-2/-4:
   the tray sits inside the .g-chrome sidebar, which already blurs, so a second blurred layer here
   spends the whole §5 budget on a 3-button strip and buys nothing.
   WHY THE PILL MOVED TOO (it was not on the straggler list): the tray's fill goes from
   --surface-2 (bridged to --g-solid-sunken, e.g. #e6eaf5 / #0c0e14) UP to --g-solid-2
   (#f4f6fb / #13161d), and the pill's --glass is bridged to the translucent --g-fill-2 — so on
   the new tray the old pill would have composited to within a hair of its own background and the
   selected mode would have read only from its label colour. --g-solid-4 (#fbfcfd / #26282f) is
   the same tray/pill token pair glass.css's own .g-segment uses, and it is a BIGGER step in dark
   than the pre-conversion pair was. Radius: --radius-sm on `.cl-theme button` is (0,1,1) and
   already beats .g-solid-4's --g-r-modal, so no g-r-* class is needed there (an inert one would
   just be noise); the tray needs `g-r-md` because .g-solid-2's --g-r-card WOULD beat its
   (0,1,0) --radius-md. R6-41 CORRECTION (v723): note the SPLIT here — `.cl-theme button` reads
   the capped ALIAS --radius-sm (min(--g-r-sm,12px), legacy-bridge.css:83-84) so it never pills;
   the TRAY's g-r-md class resolves the RAW --g-r-md (999px in tahoe/halo/aurora — the cap does
   not reach utility classes), so the tray is a capsule there. KEPT DELIBERATELY: the tray is a
   segmented-control track and .g-segment itself uses --g-r-pill in all 12 themes (control-tier
   pill identity; same ruling as the .cl-navlink comment above and BUGS.md R6-41). */
.cl-theme { display: flex; gap: 3px; padding: 3px; }
.cl-theme button { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 36px; padding: 8px; border-radius: var(--radius-sm); border: var(--g-border-w, 0px) solid transparent; color: var(--text-3); font-family: var(--font); font-size: 12.5px; font-weight: 650; cursor: pointer; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; }
/* `background: transparent` moved OFF the base rule: at (0,1,1) it outranked .g-solid-4 (0,1,0)
   and would have left the selected pill with an edge, a shadow and no fill. Scoped to the
   unselected two, it does the same job it always did (a <button>'s UA ButtonFace fill). */
.cl-theme button:not(.active) { background: transparent; }
/* Fill + edge + spec + shadow now come from .g-solid-4. The border-color re-pin is required, not
   belt-and-braces: the base rule's `border` SHORTHAND is (0,1,1), so it beats §19.1's (0,1,0)
   themed border and would have kept Ink's and Pop's outline transparent on the one button that
   is meant to show it. */
/* v719: the v718 pill relied on the fill step + a themed border, but glass themes set
   --g-border-w to 0px, so in Cobalt light the only cue was a 0.32-alpha inset ring and the
   fill step actually SHRANK (1.42 -> 1.07 — caught by the cold-client verifier). Selection is
   semantically ACCENT here (same language as .cl-navlink.active), and --g-accent exists in all
   36 theme blocks, so an accent outline reads in every theme regardless of border width.
   `outline` deliberately, NOT box-shadow: overriding box-shadow replaces the primitive's whole
   stack — the bug this project has now hit twice. outline-offset:-1.5px keeps layout identical. */
.cl-theme button.active { color: var(--text); border-color: transparent; outline: 1.5px solid var(--g-accent, var(--accent)); outline-offset: -1.5px; }
.cl-theme svg { width: 15px; height: 15px; }
/* run6 client-shell: surface props deleted — markup ships `cl-userchip g-solid-2 g-r-sm`
   (js/app.js renderClientSidebar). Same tier as the theme tray directly above it, so the two
   footer panes read as one pair. The deleted 1px hairline border is replaced by §19.1's themeable
   border plus --g-edge-2's inset hairline ring; keeping it would have double-drawn. */
.cl-userchip { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 48px; padding: 9px 11px; color: var(--text); font-family: var(--font); cursor: pointer; text-align: left; transition: background var(--dur-2) ease, box-shadow var(--dur-2) ease; }
/* Hover wrote a BARE `box-shadow: var(--shadow-sm)`, which replaced the primitive's whole
   edge+spec+shadow stack on hover — the exact v717 bug. Now the fill ramps one tier (the v706
   language) and the shadow keeps edge+spec while lifting to --g-shadow-3, which is what
   glass.css §6 does for a hovered .glass-2. */
.cl-userchip:hover { background-color: var(--g-solid-3, var(--glass-strong)); box-shadow: var(--g-edge-2, none), var(--g-spec-2, none), var(--g-shadow-3, var(--shadow-sm)); }
.cl-userchip-ic { width: 30px; height: 30px; flex: 0 0 auto; border-radius: var(--radius-sm); display: grid; place-items: center; background: var(--surface-2); color: var(--text-2); }
.cl-userchip-ic svg { width: 16px; height: 16px; }
.cl-userchip-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.cl-userchip-meta b { font-size: 13px; font-weight: 700; }
.cl-userchip-meta small { font-size: 12px; color: var(--text-3); }
.cl-userchip > svg:last-child { width: 15px; height: 15px; color: var(--text-3); flex: 0 0 auto; }
.cl-signout { display: inline-flex; align-items: center; justify-content: center; gap: 8px; width: 100%; min-height: 40px; padding: 10px; border-radius: var(--radius-md); border: 1px solid var(--hairline); background: transparent; color: var(--text-2); font-family: var(--font); font-size: 13px; font-weight: 650; cursor: pointer; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; }
.cl-signout:hover { color: var(--text); background: var(--surface); }
.cl-signout svg { width: 16px; height: 16px; }
/* client header (in #mainhead slot) — hamburger + section title only */
body.cl-app .mainhead { padding-bottom: 14px; }
.cl-head { display: flex; align-items: center; gap: 10px; }
.cl-head-ic { width: 26px; height: 26px; flex: 0 0 auto; border-radius: var(--radius-sm); display: grid; place-items: center; background: var(--accent-soft); color: var(--accent); }
.cl-head-ic svg { width: 15px; height: 15px; }
.cl-head-t { font-size: 19px; font-weight: 800; letter-spacing: -.4px; color: var(--text); }
.cl-menu { display: none; place-items: center; width: 34px; height: 34px; flex: 0 0 auto; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2); cursor: pointer; }
.cl-menu svg { width: 18px; height: 18px; }
@media (max-width: 900px) { .cl-menu { display: grid; } }
/* client mobile tab bar (in #tabbar slot) */
body.cl-app .tabbar { justify-content: space-around; }
.cl-tab {
  flex: 1; position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  min-height: var(--tabbar-h); padding: 7px 2px 6px; border: none; background: transparent; cursor: pointer;
  color: var(--text-3); font-family: var(--font); font-size: 11px; font-weight: 650; letter-spacing: -.1px;
  transition: color var(--dur-2) ease; -webkit-tap-highlight-color: transparent;
}
.cl-tab svg { width: 22px; height: 22px; }
.cl-tab span { line-height: 1; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cl-tab.active { color: var(--accent); }
.cl-tab-badge { position: absolute; top: 5px; right: calc(50% - 20px); min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px; background: var(--accent); color:var(--text-on-accent,#fff); font-size: 10px; font-weight: 800; display: grid; place-items: center; border: 2px solid var(--bg-solid); }
.bootfail { max-width: 440px; margin: 12vh auto; text-align: center; padding: 0 24px; }
/* run6 R6-21 · boot-fail owns the viewport: renderBootFail() empties the sidebar/crumb-bar/tab-bar
   but their floating chrome frames stayed painted — an outage message boxed in by empty outlined
   panels reads as "the app broke", not "the connection hiccuped". body.cc-bootfail is stamped by
   renderBootFail() and dropped by render() on recovery. (0,2,0) beats every media-query display
   override on these bars ((0,1,0)/(0,1,1)), so the frames stay gone on phones too. */
body.cc-bootfail .sidebar, body.cc-bootfail .sb-scrim,
body.cc-bootfail .mainhead, body.cc-bootfail .tabbar { display: none; }
.bootfail-ic { width: 56px; height: 56px; margin: 0 auto 14px; border-radius: var(--radius-md); display: grid; place-items: center; background: var(--accent-softer, rgba(229,50,43,.1)); }
.bootfail-ic svg { width: 28px; height: 28px; color: var(--accent, #e5322b); }
.bootfail h2 { font-size: 22px; margin: 0 0 10px; color: var(--text); }
.bootfail p { color: var(--text-3); line-height: 1.6; margin: 0 0 18px; }
/* run7 W4: `.sb-user-meta` (+ b, + small) deleted — DEAD. Zero hits app-wide. The sidebar's
   user block renders through the `.sb-user*` siblings that js/app.js actually emits; this
   name-and-role stack was orphaned when that footer was rebuilt. */
/* lead detail / add modal */
.lead-id { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.lead-av { width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; color: #fff; font-weight: 800; font-size: 16px; flex: 0 0 auto; }
.lead-id-meta { flex: 1; min-width: 0; } .lead-id-meta b { display: block; font-size: 15px; color: var(--text); } .lead-id-meta small { font-size: 12px; color: var(--text-3); }
.lead-contact-toggle { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--text-2); cursor: pointer; flex: 0 0 auto; }
.lead-contact-toggle input { accent-color: var(--green); }
.lead-quick { display: flex; gap: 8px; margin-bottom: 14px; }
.lead-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.lead-f { display: flex; flex-direction: column; gap: 5px; } .lead-f-wide { grid-column: 1 / -1; }
.lead-f span { font-size: 11.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .03em; color: var(--text-3); }
.lead-f select.minput, .lead-f input.minput, .lead-f textarea.minput { width: 100%; box-sizing: border-box; }
/* call console — one-tap outcomes + append-only call log */
.lead-console { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--hairline); }
.lead-console-h { display: inline-flex; align-items: center; gap: 7px; font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--text-3); margin-bottom: 9px; }
.lead-console-h svg { width: 13px; height: 13px; }
.lead-outcomes { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 9px; }
.lead-oc-btn { font-family: var(--font); font-size: 12.5px; font-weight: 650; color: var(--text); background: var(--surface, rgba(127,127,127,.05)); border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: 7px 12px; cursor: pointer; transition: border-color var(--dur-1), background var(--dur-1), transform .08s; }
.lead-oc-btn:hover { border-color: var(--accent); background: var(--accent-softer); }
.lead-oc-btn:active { transform: scale(.96); }
.lead-oc-btn.lead-oc-booked { color: var(--green); } .lead-oc-btn.lead-oc-showed { color: var(--slate); } .lead-oc-btn.lead-oc-not_interested { color: var(--red, #e5322b); }
.lead-log { margin-top: 14px; display: flex; flex-direction: column; gap: 9px; max-height: 220px; overflow-y: auto; }
.lead-log-empty { font-size: 12.5px; color: var(--text-3); padding: 8px 2px; }
.lead-log-item { display: flex; gap: 10px; align-items: flex-start; }
.lead-log-oc { flex: 0 0 auto; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: var(--radius-xs); background: var(--surface, rgba(127,127,127,.08)); color: var(--text-2); white-space: nowrap; }
.lead-log-oc.lead-oc-booked { color: var(--green); background: var(--green-bg); } .lead-log-oc.lead-oc-showed { color: var(--slate); background: var(--slate-bg); } .lead-log-oc.lead-oc-not_interested { color: var(--red, #e5322b); background: rgba(229,50,43,.1); }
.lead-log-body { flex: 1; min-width: 0; } .lead-log-note { font-size: 13px; color: var(--text); line-height: 1.4; }
.lead-log-meta { font-size: 11px; color: var(--text-3); margin-top: 2px; }
/* client leads (Manage hub) */
.cll-list { display: flex; flex-direction: column; gap: 8px; }
/* run6 W5b: surface props deleted — markup now ships `cll-row g-solid-2` (js/app.js);
   .is-contacted child check tint below is untouched. */
.cll-row { display: flex; align-items: center; gap: 11px; padding: 11px 13px; }
.cll-check { width: 22px; height: 22px; flex: 0 0 auto; border-radius: var(--radius-sm); border: 2px solid var(--hairline-strong, rgba(127,127,127,.4)); background: transparent; color: transparent; cursor: pointer; display: grid; place-items: center; padding: 0; } .cll-check svg { width: 13px; height: 13px; }
/* V734-P1 · `color` feeds the icon('check') SVG (stroke="currentColor") emitted at js/app.js:13291,
   so the tick vanished in 13/24 blocks (worst 1.042). --g-text-on-green = 0/24. See :651. */
.cll-row.is-contacted .cll-check { background: var(--green); border-color: var(--green); color: var(--g-text-on-green,#fff); }
.cll-main { flex: 1; min-width: 0; cursor: pointer; }
.cll-top { display: flex; align-items: center; gap: 8px; } .cll-top b { font-size: 14px; color: var(--text); }
.cll-val { font-size: 12px; font-weight: 700; color: var(--green); }
.cll-sub { font-size: 12px; color: var(--text-3); margin-top: 2px; }
.cll-stage { flex: 0 0 auto; font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .03em; padding: 3px 9px; border-radius: var(--radius-pill); background: var(--surface-2, rgba(127,127,127,.12)); color: var(--text-2); }
.cll-stage.pipe-new { color: var(--text-3); } .cll-stage.pipe-work { color: var(--amber); } .cll-stage.pipe-appt { color: var(--slate); } .cll-stage.pipe-showed { color: var(--slate); } .cll-stage.pipe-won { color: var(--green); } .cll-stage.pipe-lost { color: var(--text-3); }
/* Ads Manager */
.adsm-page { padding: 2px 2px 40px; }
.adsm-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; margin: 2px 2px 18px; }
.adsm-title { font-size: 22px; font-weight: 800; margin: 0 0 3px; }
.adsm-sub { font-size: 13px; color: var(--text-3); margin: 0; max-width: 60ch; }
/* v702 — surface properties (border/radius/fill/blur/shadow) now come from .glass-2 + g-pad in
   glass.css §4, so each theme's structural traits (Ink's hard border, Pop's ledge, Terra's uneven
   corners) finally reach Ads Manager. Only layout/typography stays here. */
.adsm-rollup { margin: 0 2px 18px; }
.adsm-rollup:empty { display: none; }
.adsm-rollup-loading { display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--text-3); }
.adsm-roll-head { display: flex; align-items: center; gap: 8px; font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--text-3); margin-bottom: 14px; }
.adsm-roll-head svg { width: 15px; height: 15px; color: var(--accent); }
.adsm-roll-meta { margin-left: auto; text-transform: none; letter-spacing: 0; font-weight: 500; color: var(--text-3); }
.adsm-roll-cells { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.adsm-roll-big { font-size: 24px; font-weight: 800; color: var(--text); font-variant-numeric: tabular-nums; line-height: 1.1; }
.adsm-roll-cell.is-accent .adsm-roll-big { color: var(--accent); }
.adsm-roll-small { font-size: 11.5px; color: var(--text-3); margin-top: 3px; }
@media (max-width: 560px){ .adsm-roll-cells { grid-template-columns: repeat(2, 1fr); gap: 12px; } .adsm-roll-big { font-size: 20px; } }
/* v544 — PORTFOLIO SPEND TREND: stacked daily spend by client, above the rollup. Display-only. */
.adsm-trend { margin: 0 2px 14px; }
.adsm-trend:empty { display: none; }
.adsm-trend-loading { display: flex; align-items: center; gap: 9px; padding: 18px; font-size: 13px; color: var(--text-3); border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--glass, var(--surface)); -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur); }
.adsm-trend-note { display: flex; align-items: flex-start; gap: 11px; }
.adsm-trend-note svg { width: 17px; height: 17px; color: var(--accent); flex: 0 0 auto; margin-top: 1px; }
.adsm-trend-note-t { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.adsm-trend-note-t b { font-size: 13.5px; font-weight: 700; color: var(--text); }
.adsm-trend-note-t span { font-size: 12px; color: var(--text-3); line-height: 1.5; }
.adsm-trend-card { padding-bottom: 14px; }


.adsm-trend-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px 24px; flex-wrap: wrap; margin-bottom: 16px; }
.adsm-trend-head { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.adsm-trend-k { display: inline-flex; align-items: center; gap: 7px; font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--text-3); }
.adsm-trend-k svg { width: 14px; height: 14px; color: var(--accent); }
.adsm-trend-total { font-size: 26px; font-weight: 800; letter-spacing: -.5px; font-variant-numeric: tabular-nums; line-height: 1.05; color: var(--text); margin-top: 3px; }
.adsm-trend-sub { font-size: 12px; color: var(--text-3); }
.adsm-trend-legend { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 14px; max-width: 100%; }
.adsm-trend-lg { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 600; color: var(--text-2); max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.adsm-trend-lg i { width: 10px; height: 10px; border-radius: var(--radius-xs); flex: 0 0 auto; }
.adsm-trend-lg--more { color: var(--text-3); font-weight: 500; }
.adsm-trend-chart { position: relative; display: flex; align-items: flex-end; gap: 5px; height: 148px; overflow: visible; }
.adsm-trend-col { position: relative; flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 5px; height: 100%; justify-content: flex-end; }
.adsm-trend-col:focus { outline: none; }
.adsm-trend-daytot { font-size: 10px; font-weight: 700; color: var(--text-3); font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap; }
.adsm-trend-stack { width: 100%; max-width: 46px; height: 100px; display: flex; flex-direction: column-reverse; justify-content: flex-start; }
.adsm-trend-seg { display: block; flex: 0 0 auto; width: 100%; min-height: 2px; }
.adsm-trend-seg:first-child { border-radius: 0 0 var(--radius-xs) var(--radius-xs); }
.adsm-trend-seg:last-child { border-radius: var(--radius-xs) var(--radius-xs) 0 0; }
.adsm-trend-seg + .adsm-trend-seg { box-shadow: inset 0 1px 0 rgba(0,0,0,.16); }
.adsm-trend-xlbl { font-size: 10px; color: var(--text-3); line-height: 1; white-space: nowrap; min-height: 10px; }
/* SIM-27 · the selected-bar outline follows the same explicit .is-open state as the popover, so
   the highlighted bar is always the one whose numbers are on screen (it used to hover-stick on
   touch and mark a bar whose tooltip had already been replaced by another). */
.adsm-trend-col.is-open .adsm-trend-stack, .adsm-trend-col:focus-visible .adsm-trend-stack { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-xs); }
@media (hover: hover) { .adsm-trend-col:hover .adsm-trend-stack { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: var(--radius-xs); } }
/* per-day breakdown popover — pure-CSS reveal on hover/focus (tap works via focus; no JS/data-* hook) */
.adsm-trend-pop { position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%) translateY(4px); width: max-content; max-width: 230px; padding: 9px 11px; border-radius: var(--radius-md); background: var(--surface, #fff); border: 1px solid var(--hairline-strong, var(--hairline)); box-shadow: var(--shadow); opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .14s var(--ease), transform .14s var(--ease); z-index: 20; }
/* SIM-27 · openness is EXPLICIT now (.is-open, set by _wireAdsTrendTaps in js/app.js).
   It used to be :focus-within, which is why a second tap on the same bar did nothing: the column
   was already focused, focus did not change, and there was no dismiss path at all. :hover is kept
   for real mice only — under `hover: none` a tapped bar would otherwise stay stuck open on top of
   the next one you tapped — and :focus-visible keeps the keyboard path (Tab through the bars). */
.adsm-trend-col.is-open .adsm-trend-pop,
.adsm-trend-col:focus-visible .adsm-trend-pop { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }
.adsm-trend-col:first-child .adsm-trend-pop { left: 0; transform: translateX(0) translateY(4px); }
.adsm-trend-col:first-child.is-open .adsm-trend-pop,
.adsm-trend-col:first-child:focus-visible .adsm-trend-pop { transform: translateX(0) translateY(0); }
.adsm-trend-col:last-child .adsm-trend-pop { left: auto; right: 0; transform: translateX(0) translateY(4px); }
.adsm-trend-col:last-child.is-open .adsm-trend-pop,
.adsm-trend-col:last-child:focus-visible .adsm-trend-pop { transform: translateX(0) translateY(0); }
@media (hover: hover) {
  .adsm-trend-col:hover .adsm-trend-pop { opacity: 1; visibility: visible; transform: translateX(-50%) translateY(0); }
  .adsm-trend-col:first-child:hover .adsm-trend-pop { transform: translateX(0) translateY(0); }
  .adsm-trend-col:last-child:hover .adsm-trend-pop { transform: translateX(0) translateY(0); }
}
/* PHONE (2026-08-03): this popover is a POINTER-hover affordance — the block above gates every
   way of showing it behind (hover: hover), so on a touch phone it can never appear. It was still
   in layout though (visibility:hidden keeps the box), and its 230px width on a mid-chart column
   pushed the document 15px past the 402pt viewport, so Ads Manager rubber-banded sideways on
   every drag. No hover = no popover = no reason to reserve the box. */
@media (hover: none) {
  .adsm-trend-pop { display: none; }
}
/* …and the popover no longer covers the card's own headline. Anchored above the bar it reached
   straight over "Spend trend / $X / last N days" on a 132px-tall mobile chart — the tooltip hid
   the number it was explaining. _adsTrendPlacePop measures and adds .is-below when that would
   happen, which re-anchors it under the bar instead. The transform pairs must be restated here or
   the reveal rules above would drag it back up by 4px. */
.adsm-trend-pop.is-below { bottom: auto; top: calc(100% + 6px); }
.adsm-trend-col .adsm-trend-pop.is-below { transform: translateX(-50%) translateY(-4px); }
.adsm-trend-col.is-open .adsm-trend-pop.is-below,
.adsm-trend-col:focus-visible .adsm-trend-pop.is-below { transform: translateX(-50%) translateY(0); }
.adsm-trend-col:first-child .adsm-trend-pop.is-below { transform: translateX(0) translateY(-4px); }
.adsm-trend-col:first-child.is-open .adsm-trend-pop.is-below,
.adsm-trend-col:first-child:focus-visible .adsm-trend-pop.is-below { transform: translateX(0) translateY(0); }
.adsm-trend-col:last-child .adsm-trend-pop.is-below { transform: translateX(0) translateY(-4px); }
.adsm-trend-col:last-child.is-open .adsm-trend-pop.is-below,
.adsm-trend-col:last-child:focus-visible .adsm-trend-pop.is-below { transform: translateX(0) translateY(0); }
@media (hover: hover) {
  .adsm-trend-col:hover .adsm-trend-pop.is-below { transform: translateX(-50%) translateY(0); }
  .adsm-trend-col:first-child:hover .adsm-trend-pop.is-below { transform: translateX(0) translateY(0); }
  .adsm-trend-col:last-child:hover .adsm-trend-pop.is-below { transform: translateX(0) translateY(0); }
}
.adsm-trend-pop-h { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 11px; font-weight: 700; color: var(--text-3); padding-bottom: 6px; margin-bottom: 6px; border-bottom: 1px solid var(--hairline); white-space: nowrap; }
.adsm-trend-pop-h b { color: var(--text); font-variant-numeric: tabular-nums; }
.adsm-trend-pl { display: flex; align-items: center; gap: 7px; font-size: 11.5px; color: var(--text-2); padding: 2px 0; }
.adsm-trend-pl i { width: 9px; height: 9px; border-radius: var(--radius-xs); flex: 0 0 auto; }
.adsm-trend-pn { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.adsm-trend-pl b { color: var(--text); font-variant-numeric: tabular-nums; font-weight: 700; }
.adsm-trend-foot { font-size: 11px; color: var(--text-3); line-height: 1.5; margin-top: 12px; }
.adsm-trend-chart.is-dense { gap: 3px; }
.adsm-trend-chart.is-dense .adsm-trend-daytot { display: none; }
@media (max-width: 560px){
  .adsm-trend-total { font-size: 22px; }
  .adsm-trend-chart { height: 132px; gap: 3px; }
  .adsm-trend-stack { height: 88px; }
  .adsm-trend-daytot { display: none; }
  .adsm-trend-legend { gap: 5px 10px; }
  .adsm-trend-lg { font-size: 11px; max-width: 120px; }
}
.adsm-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 14px; }
.adsm-card { padding: 14px 16px; display: flex; flex-direction: column; gap: 12px; }
.adsm-card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.adsm-card-id { display: flex; align-items: center; gap: 10px; min-width: 0; }
.adsm-logo { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: var(--radius-sm); overflow: hidden; flex: 0 0 auto; font-size: 13px; font-weight: 700; color: #fff; }
.adsm-logo img { width: 100%; height: 100%; object-fit: cover; }
.adsm-card-idt { min-width: 0; display: flex; flex-direction: column; }
.adsm-card-idt b { font-size: 14.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.adsm-card-idt small { font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.adsm-open { flex: 0 0 auto; white-space: nowrap; }
.adsm-metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 13px 14px; padding: 2px 0; }
.adsm-metric { display: flex; flex-direction: column; gap: 1px; }
.adsm-metric b { font-size: 17px; font-weight: 700; letter-spacing: -.01em; font-variant-numeric: tabular-nums; line-height: 1.15; }
.adsm-metric i { font-style: normal; font-size: 11px; color: var(--text-3); text-transform: uppercase; letter-spacing: .04em; }
/* Ads trend chip — current vs prior equal window (green = moved the good way, red = bad, grey = neutral) */
.adsm-delta { display: inline-flex; align-items: center; gap: 2px; font-size: 10.5px; font-weight: 700; font-variant-numeric: tabular-nums; margin-top: 2px; padding: 1px 5px; border-radius: var(--radius-xs); width: fit-content; }
.adsm-d-good { color: var(--green, #1f9d57); background: color-mix(in srgb, var(--green, #1f9d57) 12%, transparent); }
.adsm-d-bad { color: var(--red, #e5322b); background: color-mix(in srgb, var(--red, #e5322b) 12%, transparent); }
.adsm-d-neutral { color: var(--text-3); background: var(--glass, rgba(120,120,128,.1)); }
/* Ads Overview sparklines — one tiny per-day trend chart per key metric over the selected window */
.adsm-sparks { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin: 14px 0 4px; }
.adsm-spark-card { display: flex; flex-direction: column; gap: 4px; padding: 9px 11px; border: 1px solid var(--glass-border, var(--hairline)); border-radius: var(--radius-md); background: var(--glass); }
.adsm-spark-lbl { font-size: 10.5px; font-weight: 600; color: var(--text-3); text-transform: uppercase; letter-spacing: .04em; }
.adsm-spark-svg { width: 100%; height: 26px; display: block; }
@media (max-width: 720px) { .adsm-sparks { grid-template-columns: repeat(2, 1fr); } }
/* Ads Insights card — deterministic rule-based reads of the account's real numbers */
.adsm-insights { margin: 14px 0 4px; border: 1px solid var(--glass-border, var(--hairline)); border-radius: var(--radius-sm); background: var(--glass); overflow: hidden; }
.adsm-ai-h { display: flex; align-items: center; gap: 7px; padding: 11px 14px; border-bottom: 1px solid var(--hairline); font-weight: 700; font-size: 13.5px; }
.adsm-ai-h svg { width: 15px; height: 15px; color: var(--accent); }
.adsm-ai-h small { margin-left: auto; font-weight: 500; font-size: 11px; color: var(--text-3); }
.adsm-ai-list { display: flex; flex-direction: column; }
.adsm-ai-row { display: flex; gap: 9px; align-items: flex-start; padding: 10px 14px; font-size: 13px; line-height: 1.42; border-top: 1px solid var(--hairline); }
.adsm-ai-row:first-child { border-top: none; }
.adsm-ai-dot { flex: 0 0 auto; font-size: 12px; line-height: 1.5; }
.adsm-ai-bad .adsm-ai-dot { color: var(--red, #e5322b); }
.adsm-ai-warn .adsm-ai-dot { color: var(--amber, #e0900b); }
.adsm-ai-good .adsm-ai-dot { color: var(--green, #1f9d57); }
.adsm-ai-info .adsm-ai-dot { color: var(--text-3); }
@media (max-width: 720px) { .adsm-ai-h small { display: none; } }
.adsm-card-cta { margin-bottom: 10px; }
.adsm-card-cta .btn { width: 100%; justify-content: center; }
.adsm-ql-row { display: flex; flex-wrap: wrap; gap: 7px; }
.adsm-card[role="button"] { cursor: pointer; transition: border-color var(--dur-1), transform .08s; }
.adsm-card[role="button"]:hover { border-color: var(--text-3); }
.adsm-ql { font-size: 12px; font-weight: 600; color: var(--text-2, var(--text-3)); padding: 5px 11px; border-radius: var(--radius-pill); border: 1px solid var(--hairline); background: transparent; font-family: var(--font); cursor: pointer; text-decoration: none; white-space: nowrap; transition: border-color var(--dur-1), color var(--dur-1), background var(--dur-1); }
.adsm-ql:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-softer, transparent); }
.adsm-noacct { font-size: 12.5px; color: var(--text-3); margin: 16px 2px 0; }
@media (max-width: 560px){ .adsm-grid { grid-template-columns: 1fr; } }
/* internal client ad view (our own UI over the Meta API) */
.adsv-head { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 2px 2px 16px; }
.adsv-head-actions { margin-left: auto; }
.adsm-open-real { text-decoration: none; }
.adsm-card-foot { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--hairline); }
.adsm-card-foot .adsm-open-real { width: 100%; justify-content: center; }
.adsv-launch { text-align: center; padding: 36px 18px; border: 1px dashed var(--hairline); border-radius: var(--radius-md); }
.adsv-launch .adsv-soon-ic { display: inline-grid; place-items: center; width: 48px; height: 48px; border-radius: var(--radius-md); background: var(--accent-softer, rgba(127,127,127,.1)); color: var(--accent); margin: 0 auto 14px; }
.adsv-launch .adsv-soon-ic svg { width: 24px; height: 24px; }
.adsv-launch h3 { font-size: 17px; font-weight: 700; margin: 0 0 8px; }
.adsv-launch p { font-size: 13.5px; color: var(--text-2, var(--text-3)); line-height: 1.55; max-width: 48ch; margin: 0 auto 18px; }
.adsv-sechead { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.adsv-back { display: inline-flex; align-items: center; gap: 4px; padding: 8px 13px 8px 9px; border-radius: var(--radius-md); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2); font-family: var(--font); font-size: 13px; font-weight: 600; cursor: pointer; transition: border-color var(--dur-1), color var(--dur-1); }
.adsv-back:hover { border-color: var(--accent); color: var(--accent); }
.adsv-back svg { width: 16px; height: 16px; }
.adsv-id { display: flex; align-items: center; gap: 10px; min-width: 0; }
.adsv-idt { display: flex; flex-direction: column; min-width: 0; }
.adsv-idt b { font-size: 17px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.adsv-idt small { font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.adsv-tabs { display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none; border-bottom: 1px solid var(--hairline); margin: 0 0 18px; padding-bottom: 0; }
.adsv-tabs::-webkit-scrollbar { display: none; }
/* Ads date-range picker (7/14/30/90d) — sits on the tab bar, drives every live Meta pull */
.adsv-tabbar { display: flex; align-items: flex-end; justify-content: space-between; gap: 12px; border-bottom: 1px solid var(--hairline); margin: 0 0 18px; flex-wrap: wrap; }
.adsv-tabbar .adsv-tabs { border-bottom: none; margin: 0; }
.adsv-range { display: inline-flex; gap: 3px; background: var(--glass, rgba(120,120,128,.08)); border: 1px solid var(--hairline); border-radius: var(--radius-md); padding: 3px; margin-bottom: 7px; }
.adsv-range-btn { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; min-height: 32px; padding: 6px 13px; border: none; background: transparent; color: var(--text-3); font-family: var(--font); font-size: 12.5px; font-weight: 600; cursor: pointer; border-radius: var(--radius-sm); transition: background var(--dur-1), color var(--dur-1); }
.adsv-range-btn:hover { color: var(--text); }
.adsv-range-btn.on { background: var(--card, #fff); color: var(--text); box-shadow: var(--shadow-sm); }
/* Per-client range control on the Ads Manager glance cards — its own row, a full-width segmented
   control with equal-width, comfortable (>=34px) hit targets that never collide at any card width. */
.adsm-winrow { display: flex; align-items: center; gap: 10px; }
.adsm-winrow-lbl { flex: 0 0 auto; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--text-3); }
.adsv-range--mini { flex: 1 1 auto; min-width: 0; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 3px; padding: 3px; border-radius: var(--radius-md); margin: 0; }
.adsv-range--mini .adsv-range-btn { width: auto; min-height: 34px; padding: 6px 4px; font-size: 12px; border-radius: var(--radius-sm); }
.adsv-tab { flex: 0 0 auto; padding: 9px 14px; border: none; border-bottom: 2px solid transparent; background: transparent; color: var(--text-3); font-family: var(--font); font-size: 13.5px; font-weight: 600; cursor: pointer; white-space: nowrap; transition: color var(--dur-1), border-color var(--dur-1); }
.adsv-tab:hover { color: var(--text); }
.adsv-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.adsv-metrics { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 14px; }
@media (min-width: 700px){ .adsv-metrics { grid-template-columns: repeat(6, 1fr); } }
.adsv-hint { font-size: 12.5px; color: var(--text-3); margin: 0; }
.adsv-soon { text-align: center; padding: 42px 18px; border: 1px dashed var(--hairline); border-radius: var(--radius-md); }
.adsv-soon-ic { display: inline-grid; place-items: center; width: 48px; height: 48px; border-radius: var(--radius-md); background: var(--accent-softer, rgba(127,127,127,.1)); color: var(--accent); margin: 0 auto 14px; }
.adsv-soon-ic svg { width: 24px; height: 24px; }
.adsv-soon h3 { font-size: 17px; font-weight: 700; margin: 0 0 8px; }
.adsv-soon p { font-size: 13.5px; color: var(--text-2, var(--text-3)); line-height: 1.55; max-width: 46ch; margin: 0 auto 16px; }
/* Ads Manager tabs — internal data views */
.adsv-section { margin-top: 6px; }
.adsv-section + .adsv-section { margin-top: 22px; }
.adsv-sechead { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.adsv-h4 { font-size: 14px; font-weight: 700; margin: 0 0 12px; color: var(--text); }
.adsv-sechead .adsv-h4 { margin: 0; }
.adsv-sechead .btn { margin-left: auto; }
/* run7 W1: `.adsv-sample` deleted — DEAD. Zero hits app-wide. It was the "SAMPLE DATA" badge from
   the pre-Meta-sync era; the live Ads Manager says the honest thing instead (`.adsv-ov-live`
   below, plus the adsHonest empty/error cards at js/app.js:7277-7333). */
.adsv-ov-live { color: var(--green); font-weight: 600; } .adsv-ov-live svg { width: 11px; height: 11px; vertical-align: -1px; }
.adsv-camploading { display: flex; align-items: center; gap: 10px; padding: 22px; color: var(--text-3); font-size: 13px; justify-content: center; border: 1px dashed var(--hairline); border-radius: var(--radius-md); }
.adsv-spin { width: 14px; height: 14px; border: 2px solid var(--text-3); border-top-color: transparent; border-radius: 50%; animation: clcr-spin .7s linear infinite; flex: 0 0 auto; }
.adsv-table-wrap { overflow-x: auto; border: 1px solid var(--hairline); border-radius: var(--radius-md); }
.adsv-table { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 460px; }
.adsv-table thead th { text-align: left; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--text-3); padding: 11px 14px; border-bottom: 1px solid var(--hairline); white-space: nowrap; }
.adsv-table thead th.adsv-th-sort { cursor: pointer; user-select: none; }
.adsv-table thead th.adsv-th-sort:hover { color: var(--text); }
.adsv-table thead th.adsv-th-sort.on { color: var(--accent); }
.adsv-sarr { margin-left: 4px; font-size: 9px; }
.adsv-camptools { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; }
.adsv-camptoggle { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 600; padding: 5px 12px; border-radius: var(--radius-pill); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2); cursor: pointer; font-family: var(--font); transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; }
.adsv-camptoggle svg { width: 13px; height: 13px; }
.adsv-camptoggle:hover { color: var(--text); }
.adsv-camptoggle.on { background: var(--accent); border-color: var(--accent); color:var(--text-on-accent,#fff); }
/* SIM-08 — the OFF state's empty box. Same 13px footprint as the ✓ it replaces, so the
   chip never changes width when it flips and the row cannot jitter. */
.adsv-camptoggle-box { width: 13px; height: 13px; flex-shrink: 0; border: 1.5px solid currentColor; border-radius: var(--radius-xs); opacity: .55; }
.adsv-camptoggle:hover .adsv-camptoggle-box { opacity: .8; }
.adsv-camptools-n { font-size: 11.5px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.adsv-campsearch-wrap { display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px; border: 1px solid var(--hairline); border-radius: var(--radius-pill); background: var(--surface); }
.adsv-campsearch-wrap svg { width: 13px; height: 13px; color: var(--text-3); flex: none; }
.adsv-campsearch { border: 0; background: none; outline: 0; font-size: 12.5px; font-family: var(--font); color: var(--text); width: 150px; }
.adsv-campsearch::placeholder { color: var(--text-3); }
.adsv-table tbody td { padding: 12px 14px; border-bottom: 1px solid var(--hairline); color: var(--text-2); font-variant-numeric: tabular-nums; vertical-align: middle; white-space: nowrap; }
.adsv-table tbody tr:last-child td { border-bottom: none; }
.adsv-table tfoot .adsv-tot td { padding: 11px 14px; border-top: 2px solid var(--hairline-strong, var(--hairline)); font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; background: var(--surface-2, var(--surface, transparent)); }
.adsv-table td b { display: block; font-size: 13.5px; font-weight: 600; color: var(--text); white-space: normal; }
.adsv-table td small { display: block; font-size: 11px; color: var(--text-3); margin-top: 2px; }
.adsv-pill { display: inline-flex; align-items: center; font-size: 11px; font-weight: 700; padding: 3px 10px; border-radius: var(--radius-pill); }
.adsv-pill.on { background: var(--green-bg); color: var(--green); }
.adsv-pill.off { background: var(--amber-bg); color: var(--amber); }
/* Per-campaign health flags (Ads Manager live table) — dead/no-delivery + spent-but-0-leads */
.adsv-flag { display: inline-flex; align-items: center; margin-left: 6px; font-size: 10px; font-weight: 800; letter-spacing: .02em; padding: 2px 7px; border-radius: var(--radius-pill); white-space: nowrap; vertical-align: middle; }
.adsv-flag-dead { color: var(--red, #e5322b); background: color-mix(in srgb, var(--red, #e5322b) 12%, transparent); }
.adsv-flag-noleads { color: var(--amber, #e0900b); background: color-mix(in srgb, var(--amber, #e0900b) 14%, transparent); }
.adsv-cplbadge { display: inline-flex; align-items: center; margin-left: 7px; font-size: 10px; font-weight: 800; letter-spacing: .02em; padding: 2px 7px; border-radius: var(--radius-pill); white-space: nowrap; vertical-align: middle; font-variant-numeric: tabular-nums; }
.adsv-cplbadge.hi { color: var(--red, #e5322b); background: color-mix(in srgb, var(--red, #e5322b) 12%, transparent); }
.adsv-cplbadge.lo { color: var(--green, #17915a); background: color-mix(in srgb, var(--green, #17915a) 14%, transparent); }
/* editable campaign controls (admin / media-buyer) */
.adsv-mcell { text-align: right; }
.adsv-mbtn { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font); font-size: 12px; font-weight: 650; color: var(--text); background: var(--surface, rgba(127,127,127,.05)); border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: 6px 11px; cursor: pointer; transition: border-color var(--dur-2), background var(--dur-2), transform var(--dur-1); white-space: nowrap; }
.adsv-mbtn:hover { border-color: var(--accent); background: var(--accent-softer); }
.adsv-mbtn:active { transform: scale(.97); }
.adsv-mbtn svg { width: 14px; height: 14px; }
.adsv-dim { color: var(--text-3); }
/* v555 — ad-set / ad table name cell: creative thumb (ads), budget subtext (ad sets), per-row Meta deep link */
.adsv-entname { display: flex; align-items: center; gap: 10px; min-width: 0; }
.adsv-entname-txt { min-width: 0; }
.adsv-adthumb-sm { flex: 0 0 auto; display: inline-grid; place-items: center; width: 34px; height: 34px; border-radius: var(--radius-sm); overflow: hidden; background: var(--accent-softer, rgba(127,127,127,.1)); color: var(--accent); }
.adsv-adthumb-sm img { width: 100%; height: 100%; object-fit: cover; }
.adsv-adthumb-sm svg { width: 15px; height: 15px; }
.adsv-metalink { flex: 0 0 auto; display: inline-flex; align-items: center; font-size: 11px; font-weight: 650; color: var(--text-3); text-decoration: none; padding: 3px 8px; border-radius: var(--radius-pill); border: 1px solid transparent; white-space: nowrap; transition: color var(--dur-1), border-color var(--dur-1), background var(--dur-1); }
.adsv-metalink:hover { color: var(--accent); border-color: var(--hairline); background: var(--surface, rgba(127,127,127,.05)); }
.adsv-soon-cta { display: flex; justify-content: center; margin-top: 16px; }
.adsm-mgname { font-size: 15px; font-weight: 700; color: var(--text); margin: 0 0 16px; }
.adsm-mgrow { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 12px 0; border-top: 1px solid var(--hairline); }
.adsm-mgrow > span:first-child { font-size: 13px; font-weight: 600; color: var(--text-2); }
.adsm-seg { display: inline-flex; background: var(--surface, rgba(127,127,127,.06)); border: 1px solid var(--hairline); border-radius: var(--radius-md); padding: 3px; gap: 2px; }
.adsm-segb { display: inline-flex; align-items: center; gap: 5px; font-family: var(--font); font-size: 12.5px; font-weight: 650; color: var(--text-3); background: transparent; border: none; border-radius: var(--radius-sm); padding: 7px 13px; cursor: pointer; transition: background var(--dur-2), color var(--dur-2); }
.adsm-segb svg { width: 13px; height: 13px; }
.adsm-segb.on { background: var(--accent); color:var(--text-on-accent,#fff); box-shadow: var(--shadow-sm); }
.adsm-budget { display: inline-flex; align-items: center; gap: 4px; }
.adsm-budget i { font-style: normal; font-size: 14px; font-weight: 700; color: var(--text-3); }
.adsm-budget input { width: 110px; text-align: right; }
.adsm-mgnote { font-size: 12px; color: var(--text-3); line-height: 1.5; margin: 14px 0 0; padding-top: 14px; border-top: 1px solid var(--hairline); display: flex; gap: 7px; }
.adsm-mgnote svg { width: 15px; height: 15px; flex-shrink: 0; color: var(--amber); margin-top: 1px; }
.adsv-adgrid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
@media (max-width: 640px){ .adsv-adgrid { grid-template-columns: 1fr; } }
.adsv-adcard { border: 1px solid var(--hairline); border-radius: var(--radius-md); overflow: hidden; background: var(--surface, rgba(127,127,127,.03)); display: flex; flex-direction: column; }
.adsv-adthumb { height: 132px; display: grid; place-items: center; color: rgba(255,255,255,.9); }
.adsv-adthumb svg { width: 30px; height: 30px; }
.adsv-adbody { padding: 12px 14px; display: flex; flex-direction: column; gap: 4px; }
.adsv-adbody b { font-size: 13.5px; font-weight: 700; color: var(--text); }
.adsv-adbody small { font-size: 12px; color: var(--text-3); line-height: 1.45; }
/* run7 W1: the whole Ads-manager V1 report + bar-chart set deleted — DEAD. `.adsv-admetrics`
   (+ b, + .adsv-pill), `.adsv-report-kpis` (+ its 540px @media), `.adsv-kpi` (+ b, + i),
   `.adsv-chart`, `.adsv-chart-label`, `.adsv-bars`, `.adsv-bar-col` (+ span, + i), `.adsv-bar`.
   Zero hits for any of the 9 class names in index.html, js/*.js, v2/*, css/*, sw.js or the
   apps-script/scripts trees, and nothing builds an `adsv-` name dynamically — every live
   `adsv-*` in js/app.js (7259-7397, 8005-8419) is a complete literal in a template string.
   The Ads Manager renders its numbers through `.adsv-metrics`/`.adsm-*` (js/app.js:7368) and
   its creatives through `.adsv-adgrid/-adcard/-adthumb/-adbody` (7394-7395); those are UNTOUCHED
   and stay directly above. This block was the earlier hand-drawn <div> bar chart that never
   shipped a renderer. */
/* run6 W5b: surface props deleted — the element is `home-card glass-2 home-pending` in markup. */
.home-pending { display: flex; align-items: center; gap: var(--space-3); width: 100%; padding: var(--card-pad); cursor: pointer; font-family: var(--font); text-align: left; }
.home-pending-ic { display: inline-grid; place-items: center; width: var(--ctl-lg); height: var(--ctl-lg); border-radius: var(--radius-md); background: var(--amber-bg); color: var(--amber); flex-shrink: 0; }
.home-pending-ic svg { width: var(--icon-lg); height: var(--icon-lg); }
.home-pending-tx { display: flex; flex-direction: column; gap: var(--space-0); flex: 1; min-width: 0; }
.home-pending-tx b { font-size: var(--fs-body); color: var(--text); font-weight: var(--fw-semi); }
.home-pending-tx small { font-size: var(--fs-small); color: var(--text-3); }
/* run6 W5b: surface props deleted — the element is `home-card glass-2 home-cd` in markup. */
.home-cd { display: flex; align-items: center; gap: var(--space-3); width: 100%; padding: var(--card-pad); cursor: pointer; font-family: var(--font); text-align: left; }
.home-cd-ic { display: inline-grid; place-items: center; width: var(--ctl-lg); height: var(--ctl-lg); border-radius: var(--radius-md); background: var(--green-bg); color: var(--green); flex-shrink: 0; }
.home-cd-ic svg { width: var(--icon-lg); height: var(--icon-lg); }
.home-cd-tx { display: flex; flex-direction: column; gap: var(--space-0); flex: 1; min-width: 0; }
.home-cd-tx b { font-size: var(--fs-body); color: var(--text); font-weight: var(--fw-semi); }
.home-cd-tx small { font-size: var(--fs-small); color: var(--text-3); }

.home-acts { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap-grid); padding: var(--space-1) var(--space-1) var(--space-2); }
/* run6 W5b: surface props deleted — markup now ships `home-act glass-2` (js/app.js); hover
   (row-selected + border-color) retargeted to the glass fill ramp. */
.home-act { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-2); padding: var(--space-3) var(--space-2); cursor: pointer; font-family: var(--font); transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.home-act:hover { background-color: var(--g-fill-3); }
.home-act-ic { display: inline-grid; place-items: center; width: var(--ctl-md); height: var(--ctl-md); border-radius: var(--radius-md); background: var(--row-selected); color: var(--text-2); }
.home-act-ic svg { width: var(--icon-lg); height: var(--icon-lg); }
.home-act-l { font-size: var(--fs-small); font-weight: var(--fw-medium); color: var(--text-2); text-align: center; }

/* home header: notification bell pinned to the right of the crumb */
.crumb-home .crumb-bell { margin-left: auto; position: relative; display: none; place-items: center; width: 38px; height: 38px; border-radius: var(--radius-md); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2); cursor: pointer; }
@media (max-width: 720px){ .crumb-home .crumb-bell { display: grid; } }
.crumb-home .crumb-bell svg { width: 19px; height: 19px; }
.crumb-bell-badge { position: absolute; top: -5px; right: -5px; min-width: 17px; height: 17px; padding: 0 4px; border-radius: 9px; background: var(--accent); color:var(--text-on-accent,#fff); font-size: 11px; font-weight: 800; display: grid; place-items: center; border: 2px solid var(--bg-solid); }

@media (max-width: 520px) {
  .home-stats { grid-template-columns: repeat(2, 1fr); gap: var(--gap-grid); }
  .home-name { font-size: var(--fs-lg); line-height: 22px; }
}
/* desktop: HOME is a single clean column (owner preference). Every card is full-width and stacked
   top-to-bottom — never paired — so nothing ever looks weird when a card is opened. The column is
   capped at a comfortable width and centered; the 4 stat tiles and quick-actions keep their own
   internal multi-column grids. (<=520px mobile untouched.) */
@media (min-width: 1100px) {
  .home { max-width: 1000px; }
  .home-acts { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
}

/* ===== Tasks: list view =====
   v639 ZONE A1 — re-valued onto the design system (DESIGN_LANGUAGE §3.6/§4).
   The 52px row was the single biggest density lever in the app: 12 rows fit a
   900px viewport, against the >=14 the spec demands. --row-h (36px) is the
   Linear/Raycast body-row height. Group head, table-card shell and the header
   row move with it so the vertical rhythm stays one system, not three. */
.group { margin-bottom: var(--space-5); }
.group-head {
  display: flex; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-2); cursor: pointer;
  border-radius: var(--radius-sm); transition: background-color var(--dur-1) var(--ease);
}
/* mutually-exclusive pair: dense on desktop, a real 44px touch target on phones */
@media (min-width: 721px){ .group-head { min-height: var(--row-h); } }
@media (max-width: 720px){ .group-head { min-height: var(--ctl-touch); } }
.group-head:hover { background: var(--row-hover); }
.group-caret { width: var(--icon-md); height: var(--icon-md); color: var(--text-3); transition: transform var(--dur-2) var(--ease); flex-shrink: 0; }
.group.collapsed .group-caret { transform: rotate(-90deg); }
.group-dot { width: var(--space-2); height: var(--space-2); border-radius: var(--radius-xs); flex-shrink: 0; }
.group-title { font-weight: var(--fw-semi); font-size: var(--fs-body); }
.group-count { font-size: var(--fs-micro); font-weight: var(--fw-semi); color: var(--text-2); background: var(--surface); padding: 0 var(--space-1); border-radius: var(--radius-pill); }
.group-overdue { font-size: var(--fs-micro); font-weight: var(--fw-semi); color: var(--red); background: var(--red-bg); padding: 0 var(--space-1); border-radius: var(--radius-pill); white-space: nowrap; }
.group-add { margin-left: auto; font-size: var(--fs-small); color: var(--text-3); font-weight: var(--fw-medium); display: inline-flex; align-items: center; gap: var(--space-1); padding: var(--space-1) var(--space-2); border-radius: var(--radius-sm); opacity: 0; transition: opacity var(--dur-1) var(--ease), background-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease); }
.group-head:hover .group-add { opacity: 1; }
.group-add:hover { background: var(--row-hover); color: var(--text); }
.group-add svg { width: var(--icon-sm); height: var(--icon-sm); }

/* the table shell is a CARD, not a floating pane — opaque, never blurred. run6 W5c: the surface
   moved to .g-solid-2 in the tCardClass builder (js/app.js); bespoke background/border/radius/
   box-shadow:none deleted (the primitive's themed edge+shadow replaces the deliberate flatness —
   that is the point of the conversion). The ≤720/≤520 phone strips below still win (!important). */
.table-card {
  overflow: hidden; margin-top: var(--space-1);
}
.group.collapsed .table-card { display: none; }

/* Task-list scroll wrapper — on phones the WHOLE table scrolls left/right
   (like the partner table) so every column is reachable; see the phone block. */
.tlist-scroll { width: 100%; }
.tlist-inner { width: 100%; }

.trow {
  display: grid;
  /* --tcc holds extra tracks for user-added custom columns; EMPTY by default
     (so the list is unchanged until someone adds a field). Custom columns show
     on desktop only; the responsive breakpoints below exclude them. */
  grid-template-columns: 26px minmax(200px, 2.2fr) 122px 134px minmax(120px,1fr) 96px 104px 84px var(--tcc, );
  align-items: center; gap: var(--space-3); padding: 0 var(--row-pad-x); min-height: var(--row-h);
  border-bottom: var(--hairline-w) solid var(--hairline); cursor: pointer; transition: background-color var(--dur-1) var(--ease);
  position: relative;
}
.trow:last-child { border-bottom: none; }
.task-col-custom { font-size: var(--fs-body); color: var(--text-2); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: flex; align-items: center; gap: var(--space-1); }
.trow.thead .task-col-custom { color: var(--text-3); }
/* Sortable task List column headers (click to sort asc → desc → manual) */
.trow.thead .th-sortable { cursor: pointer; user-select: none; border-radius: var(--radius-xs); transition: color var(--dur-1) var(--ease); }
.trow.thead .th-sortable:hover { color: var(--text); }
.trow:hover { background: var(--row-hover); }
.trow.thead { min-height: var(--row-h-head); background: var(--surface-2); cursor: default; }
.trow.thead:hover { background: var(--surface-2); }
/* when admin hides built-in task columns, the grid template is recomputed inline (--trow-tpl) */
.table-card.has-hidden-cols .trow { grid-template-columns: var(--trow-tpl) !important; }
.trow-kebab-cell { display: flex; align-items: center; justify-content: flex-end; }
.th { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .05em; color: var(--text-3); font-weight: var(--fw-semi); }
/* inline "+ Field" header chip (Master Task List) — sits at the right end of the header, after all
   columns (absolute so it never wraps the fixed-track grid to a second row). */
.th-addfield-task { position: absolute; right: var(--space-3); top: 50%; transform: translateY(-50%); z-index: 3; display: inline-flex; align-items: center; gap: var(--space-1); white-space: nowrap; cursor: pointer; color: var(--text-3); font-weight: var(--fw-semi); font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .05em; padding: var(--space-0) var(--space-2); border-radius: var(--radius-xs); border: 1px dashed var(--hairline-strong); background: var(--surface-2); transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), background-color var(--dur-1) var(--ease); }
.th-addfield-task:hover { color: var(--text); border-color: var(--hairline-strong); background: var(--row-hover); }
.th-addfield-task svg { width: var(--icon-sm); height: var(--icon-sm); }
/* Reserve a right gutter on EVERY task row (header + data share the same value, so the
   columns stay aligned) — gives the absolutely-positioned "+ Field" header chip its own
   space instead of overlapping the 84px Priority column (was rendering "Prio…+Field").
   The chip is position:absolute right:12px, so padding doesn't move it — only the columns. */
.trow { padding-right: calc(var(--row-pad-x, 18px) + 78px); }
/* table SHADE variants applied to the Master Task List wrapper (owner ask) */
.tlist-inner.shade-zebra .trow:not(.thead):nth-of-type(even) { background: var(--surface-2); }
.tlist-inner.shade-lines .trow { border-bottom-color: var(--hairline-strong); }
.tlist-inner.shade-tint .table-card { background: var(--surface); border-radius: var(--radius-md); }
.tlist-inner.shade-tint .trow.thead { background: var(--surface); }
.tlist-inner.shade-contrast .trow.thead { background: var(--hairline-strong); }
.tlist-inner.shade-contrast .trow:not(.thead):nth-of-type(even) { background: var(--surface-2); }
.tlist-inner.shade-contrast .trow { border-bottom-color: var(--hairline-strong); }
/* shade-picker preview swatches */
.shade-sw { display: inline-block; width: 22px; height: 16px; border-radius: var(--radius-xs); border: 1px solid var(--hairline-strong); margin-right: 9px; vertical-align: middle; flex-shrink: 0; }
.shade-sw-none { background: var(--surface); }
.shade-sw-zebra { background: repeating-linear-gradient(var(--surface) 0 4px, var(--surface-2) 4px 8px); }
.shade-sw-lines { background: var(--surface); border-bottom: 3px solid var(--hairline-strong); }
.shade-sw-tint { background: var(--surface); }
.shade-sw-contrast { background: var(--hairline-strong); }
.btn-icon { padding-left: 11px !important; padding-right: 11px !important; }
.kebab-sw.on { box-shadow: 0 0 0 2px var(--accent) !important; }
/* Manage-options modal — reorder / recolor / rename / delete / add for any dropdown field */
.mo-hint { font-size: 12px; color: var(--text-3); margin: 0; line-height: 1.5; }
.mo-list { display: flex; flex-direction: column; gap: 6px; }
/* run6 W5b: surface props deleted — markup now ships `mo-row g-solid-2` (js/app.js). */
.mo-row { display: grid; grid-template-columns: auto auto 1fr auto auto; align-items: center; gap: 10px; padding: 8px 10px; }
.mo-ar { display: inline-flex; flex-direction: column; gap: 1px; }
.mo-mv { width: 22px; height: 15px; display: inline-flex; align-items: center; justify-content: center; border: none; background: transparent; color: var(--text-3); cursor: pointer; border-radius: var(--radius-xs); padding: 0; }
.mo-mv:hover:not(:disabled) { color: var(--text); background: var(--row-hover); }
.mo-mv:disabled { opacity: .3; cursor: default; }
.mo-mv svg { width: 13px; height: 13px; }
.mo-mv-up svg { transform: rotate(180deg); }
.mo-dot { width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--surface); box-shadow: 0 0 0 1px var(--hairline-strong); cursor: pointer; padding: 0; transition: transform var(--dur-1) ease; }
.mo-dot:hover { transform: scale(1.14); }
.mo-name { font-size: 14px; font-weight: 600; color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mo-icon { width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2); border-radius: var(--radius-sm); cursor: pointer; padding: 0; }
.mo-icon:hover { color: var(--text); border-color: var(--hairline-strong); }
.mo-icon.mo-del:hover { color: var(--accent); border-color: var(--accent); }
.mo-icon svg { width: 14px; height: 14px; }
.mo-add { align-self: flex-start; }
/* Manage account — per-client portal section toggles */
.ma-list { display: flex; flex-direction: column; gap: 4px; }
/* run6 W5b: surface props deleted — markup now ships `ma-row g-solid-2` (js/app.js); hover
   border-color re-pin was dead with the border — retargeted to the solid ramp. */
.ma-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 12px; cursor: pointer; }
.ma-row:hover { background-color: var(--g-solid-3); }
.ma-l { display: inline-flex; align-items: center; gap: 9px; font-size: 14px; font-weight: 600; color: var(--text); }
.ma-l svg { width: 16px; height: 16px; color: var(--text-3); }
.ma-always { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--text-3); background: var(--surface-2); border-radius: var(--radius-xs); padding: 1px 6px; }
.ma-ck { width: 18px; height: 18px; accent-color: var(--accent); cursor: pointer; flex-shrink: 0; }
.ma-ck:disabled { opacity: .55; cursor: default; }
/* run6 W5b: surface props deleted — markup now ships `ma-panel-row g-solid-2` (js/app.js;
   inside the .panel drawer, so solid). */
.ma-panel-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 12px; margin-top: 4px; }
.ma-panel-tx { font-size: 12.5px; color: var(--text-2); line-height: 1.4; }

/* ClickUp-style status control: a ring colored by the task's current status
   (clicking it opens the status picker). Complete = filled green + check. */
.tcheck { width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--sc, var(--hairline-strong)); cursor: pointer; display: grid; place-items: center; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; flex-shrink: 0; position: relative; }
/* invisible ~32px hit area at ALL widths so a near-miss toggles status instead of
   opening the task panel (was phone-only ≤520px; tablets 521–1024px missed it) */
.tcheck::before { content: ""; position: absolute; inset: -7px; border-radius: 50%; }
.tcheck:hover { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-softer); }
.tcheck.done { background: var(--green); border-color: var(--green); }
.tcheck svg { width: 11px; height: 11px; color: #fff; opacity: 0; }
.tcheck.done svg { opacity: 1; }

/* run6 W5c (R6-2): parent-task titles collapsed to ~42px ("La…") in a 214px wrap because the
   title had no grow/min floor while the subtask pill + progress bar refused to shrink. The title
   now takes GROW priority with a readable 110px floor; the progress cluster yields (shrinks/clips)
   once the title hits its floor; overflow:hidden stops any residue bleeding into the next column. */
.tname-wrap { display: flex; align-items: center; gap: var(--space-2); min-width: 0; overflow: hidden; }
.subcaret { width: var(--icon-md); height: var(--icon-md); color: var(--text-3); flex-shrink: 0; transition: transform var(--dur-2) var(--ease); cursor: pointer; border-radius: var(--radius-xs); }
.subcaret:hover { background: var(--surface); color: var(--text); }
.subcaret.collapsed { transform: rotate(-90deg); }
.tname { font-size: var(--fs-body); font-weight: var(--fw-medium); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1 1 auto; min-width: 110px; }   /* R6-2: grow priority + readable floor; ellipsis only when genuinely out of space */
.tname.done { color: var(--text-3); text-decoration: line-through; }
.tname-meta { display: inline-flex; gap: var(--space-1); margin-left: var(--space-2); vertical-align: middle; }
.mini-icon { display: inline-flex; align-items: center; gap: var(--space-0); font-size: var(--fs-micro); color: var(--text-3); font-weight: var(--fw-semi); }
.mini-icon svg { width: var(--icon-sm); height: var(--icon-sm); }
.sub-count { font-size: var(--fs-micro); color: var(--text-3); font-weight: var(--fw-semi); background: var(--surface); padding: 0 var(--space-1); border-radius: var(--radius-pill); }
/* Parent-task progress rollup (% of descendant subtasks complete). R6-2: the cluster now YIELDS
   (shrink + clip) instead of crushing the title — decoration loses to information */
.tprog { display: inline-flex; align-items: center; gap: var(--space-1); flex: 0 1 auto; min-width: 0; overflow: hidden; }
.tprog-bar { width: 40px; height: var(--space-1); border-radius: var(--radius-xs); background: var(--hairline); overflow: hidden; }
/* width is NEVER animated (§2.10) — the fill snaps to its new value */
.tprog-fill { display: block; height: 100%; border-radius: var(--radius-xs); background: var(--accent); }
.tprog.done .tprog-fill { background: var(--green); }
.tprog-txt { font-size: var(--fs-micro); font-weight: var(--fw-semi); color: var(--text-3); font-variant-numeric: tabular-nums; min-width: var(--ctl-sm); }
.tprog.done .tprog-txt { color: var(--green); }
@media (max-width: 640px){ .tprog-bar { width: 28px; } }

.badge {
  display: inline-flex; align-items: center; gap: var(--space-1); min-height: var(--ctl-xs);
  padding: 0 var(--space-2); border-radius: var(--radius-xs);
  font-size: var(--fs-micro); font-weight: var(--fw-semi); white-space: nowrap; max-width: 100%;
}
/* run6 W5c (R6-3) — SYSTEMIC chip-ink fix. The badge builders (js/app.js) used the raw palette
   hue as 11-12.5px ink on a 13-14% tint of itself: measured floor 1.90:1 (role-mark, Ink light)
   and a flat 1.0:1 on Cobalt's blue canvas. The builders now emit the hue as `--chip` instead of
   an inline color, and the ink is DERIVED here: the chip hue pulled toward the theme's own text
   ink. Light themes have near-black --text → darkened hue; dark themes near-white → lightened
   hue; Cobalt (white text on blue in BOTH modes) gets the right direction for free because the
   mix follows --text, not the mode attribute. 33% hue share is the MEASURED maximum at which
   every palette chip × every badge backdrop (canvas / solid-2 / solid-3 / sunken, both tints)
   clears 4.5:1 in all 24 theme-modes (static math; worst survivor 4.54:1 — #b0b0b6 on Terra
   light). Cobalt's saturated mid-blue canvas caps at 9% hue share — scoped below. The b-dot
   keeps the full-strength hue (non-text). Chip-less badges fall back to --text and the named
   variants (.badge-owner/-you/-incomplete, later in this sheet) still win by source order. */
.badge, .role-mark { color: color-mix(in srgb, var(--chip, var(--text)) var(--chip-ink-mix, 33%), var(--text)); }
[data-ui-theme="cobalt"] .badge, [data-ui-theme="cobalt"] .role-mark { --chip-ink-mix: 9%; }
.badge .b-dot { width: 6px; height: 6px; border-radius: var(--radius-pill); flex-shrink: 0; }
.badge.sel { cursor: pointer; }
.badge.sel:hover { filter: brightness(0.97); }

.cell-client { font-size: var(--fs-small); color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cell-client b { color: var(--text); font-weight: var(--fw-semi); display:block; font-size: var(--fs-small); }
.cell-client small { color: var(--text-3); font-size: var(--fs-micro); }

.assignees { display: flex; flex-wrap: wrap; row-gap: var(--space-1); }
.assignees .avatar { width: var(--ctl-sm); height: var(--ctl-sm); margin-left: calc(var(--space-2) * -1); border: 2px solid var(--bg-solid); font-size: var(--fs-micro); }
.assignees .avatar:first-child { margin-left: 0; }
.assignee-empty { width: var(--ctl-sm); height: var(--ctl-sm); border-radius: var(--radius-pill); border: 1px dashed var(--hairline-strong); display: grid; place-items: center; color: var(--text-3); }
.assignee-empty svg { width: var(--icon-sm); height: var(--icon-sm); }

.due { font-size: var(--fs-small); font-weight: var(--fw-semi); color: var(--text-2); white-space: nowrap; }
.due.overdue { color: var(--red); }
.due.soon { color: var(--amber); }
.due.none { color: var(--text-3); font-weight: var(--fw-medium); }

.prio { display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--fs-small); font-weight: var(--fw-semi); }
.prio svg { width: var(--icon-sm); height: var(--icon-sm); }

.subrow-indent { padding-left: var(--space-4); }
/* Task group footer — sums of number custom fields across the group's tasks */
.group-foot { display: flex; flex-wrap: wrap; gap: var(--space-4); padding: var(--space-2) var(--space-4); border-top: var(--hairline-w) solid var(--hairline); background: var(--surface-2); }
.group-foot-item { display: inline-flex; align-items: baseline; gap: var(--space-1); font-size: var(--fs-small); }
.group-foot-item i { font-style: normal; color: var(--text-3); }
.group-foot-item b { font-weight: var(--fw-semi); color: var(--text); font-variant-numeric: tabular-nums; }
.group-foot-item small { color: var(--text-3); font-size: var(--fs-micro); }
.add-row {
  display: flex; align-items: center; gap: var(--space-2); min-height: var(--row-h);
  padding: 0 var(--space-4); color: var(--text-3);
  font-size: var(--fs-body); font-weight: var(--fw-medium); cursor: pointer;
  transition: background-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.add-row:hover { color: var(--text); background: var(--row-hover); }
.add-row svg { width: var(--icon-md); height: var(--icon-md); }

/* ===== Board (Kanban) =====
   v639 ZONE A3 — the board card onto the §3.4 card contract: opaque surface,
   one hairline, token padding, NO shadow (it does not float), and a transition
   that names only the two properties that actually change on hover. `transition:
   all` was animating layout + box-shadow on every card in every column. */
.board { display: flex; gap: var(--space-4); overflow-x: auto; padding-bottom: var(--space-3); align-items: flex-start; }
.bcol { flex: 0 0 296px; max-width: 296px; }
.bcol-head { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-1) var(--space-2) var(--space-2); }
.bcol-dot { width: var(--space-2); height: var(--space-2); border-radius: var(--radius-pill); }
.bcol-title { font-weight: var(--fw-semi); font-size: var(--fs-body); }
.bcol-count { font-size: var(--fs-micro); font-weight: var(--fw-semi); color: var(--text-3); background: var(--surface); padding: 0 var(--space-1); border-radius: var(--radius-pill); }
/* run6 W5c: .bcol-body/.bcard surfaces → .g-solid-2 in the board templates (js/app.js).
   .dragover keeps its accent wash (0,2,0 — beats the primitive, that's the drop affordance);
   its border-color half died with the border. .bcard hover retargeted to the solid ramp. */
.bcol-body {
  padding: var(--space-2); min-height: 120px; display: flex; flex-direction: column; gap: var(--space-2);
  transition: background-color var(--dur-2) var(--ease);
}
.bcol-body.dragover { background: var(--accent-soft); }
.bcard {
  padding: var(--card-pad-tight); cursor: pointer;
  transition: background-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
}
.bcard:hover { background-color: var(--g-solid-3); }
/* v548 — pointer-drag "lift": the picked-up card pops with scale + shadow (existing tokens) */
.bcard.dragging { opacity: .92; transform: scale(1.03); box-shadow: var(--shadow-lg); position: relative; z-index: 6; cursor: grabbing; user-select: none; }
.bcard-top { display: flex; justify-content: space-between; align-items: center; gap: var(--space-2); margin-bottom: var(--space-1); }
.bcard-title { font-size: var(--fs-body); font-weight: var(--fw-semi); line-height: 1.35; margin-bottom: var(--space-2); }
.bcard-meta { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
.bcard-foot { display: flex; align-items: center; justify-content: space-between; margin-top: var(--space-2); }
.board-add { display:flex; align-items:center; gap:var(--space-1); padding:var(--space-2); color:var(--text-3); font-size:var(--fs-small); font-weight:var(--fw-medium); cursor:pointer; border-radius:var(--radius-sm); }
.board-add:hover { background: var(--row-hover); color: var(--text); }
.board-add svg { width:var(--icon-md); height:var(--icon-md); }
/* v550 — board card: reorder grip, tap-to-change status dot, inline subtask chip + list */
.bcard-top-sp { flex:1 1 auto; }
.bcard-grip { display:inline-flex; align-items:center; justify-content:center; min-width:var(--ctl-md); min-height:var(--ctl-md); margin:calc(var(--space-1) * -1) 0 calc(var(--space-1) * -1) calc(var(--space-1) * -1); color:var(--text-3); cursor:grab; opacity:.55; border-radius:var(--radius-sm); touch-action:none; flex:0 0 auto; }
.bcard-grip:hover { opacity:1; background:var(--row-hover); color:var(--text-2); }
.bcard-grip:active { cursor:grabbing; }
.bcard-grip svg { width:var(--icon-md); height:var(--icon-md); }
.bcard.dragging .bcard-grip { cursor:grabbing; }
/* drop indicator = one accent rail. No shadow: the card it sits on does not float. */
.bcard-dropbefore { box-shadow: 0 -3px 0 -1px var(--accent); }
.bcard-chips { display:flex; align-items:center; flex-wrap:wrap; gap:var(--space-2); margin-bottom:var(--space-0); }
.bcard-subchip { display:inline-flex; align-items:center; gap:var(--space-1); min-height:var(--ctl-md); padding:0 var(--space-2); border-radius:var(--radius-sm); background:var(--surface); border:1px solid var(--hairline); color:var(--text-2); font-size:var(--fs-small); font-weight:var(--fw-medium); cursor:pointer; }
.bcard-subchip:hover { border-color:var(--hairline-strong); color:var(--text); }
.bcard-subchip.done { color:var(--green); }
.bcard-subchip svg { width:var(--icon-sm); height:var(--icon-sm); }
.bcard-subchip b { font-weight:var(--fw-semi); }
.bcard-subcaret { display:inline-flex; transition: transform var(--dur-2) var(--ease); }
.bcard-subcaret svg { width:var(--icon-sm); height:var(--icon-sm); }
.bcard-subcaret.open { transform: rotate(180deg); }
.bcard-foot-l { display:flex; align-items:center; gap:var(--space-2); min-width:0; }
.bcard-foot-r { display:flex; align-items:center; gap:var(--space-2); }
.bcard-status { display:inline-flex; align-items:center; justify-content:center; min-width:var(--ctl-md); min-height:var(--ctl-md); margin:calc(var(--space-1) * -1); border-radius:var(--radius-sm); cursor:pointer; flex:0 0 auto; }
.bcard-status:hover { background:var(--row-hover); }
.bcard-status-dot { width:12px; height:12px; border-radius:var(--radius-pill); box-shadow: inset 0 0 0 1px var(--hairline-strong); }
.bcard-subs { margin-top:var(--space-2); padding-top:var(--space-2); border-top:var(--hairline-w) solid var(--hairline); display:flex; flex-direction:column; gap:var(--space-0); }
.bcard-sub { display:flex; align-items:center; gap:var(--space-2); min-height:var(--ctl-md); padding:var(--space-0) var(--space-1); border-radius:var(--radius-sm); cursor:pointer; }
.bcard-sub:hover { background:var(--row-hover); }
.bcard-sub-dot { width:var(--space-2); height:var(--space-2); border-radius:var(--radius-pill); flex:0 0 auto; }
.bcard-sub-name { font-size:var(--fs-small); color:var(--text-2); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.bcard-sub.done .bcard-sub-name { text-decoration:line-through; color:var(--text-3); }

/* ===== Partners table ===== */
/* run6 W5c: surface → .glass-2 at all three ptable-wrap template sites (js/app.js); only
   overflow:hidden (clips rows to the themed radius) stays bespoke */
.ptable-wrap {
  overflow: hidden;
}
.ptable-scroll { overflow-x: auto; }
.ptable { width: 100%; border-collapse: collapse; min-width: 1080px; }
/* partner health indicator — sortable risk signal (sort desc = at-risk first) */
.pt-link { color: var(--text-2); text-decoration: none; }
.pt-link:hover { color: var(--accent); text-decoration: underline; }
.pt-health { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 650; padding: 2px 9px 2px 7px; border-radius: var(--radius-pill); white-space: nowrap; }
.pt-health-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.pt-health-risk { color: var(--red, #e5322b); background: var(--accent-softer, rgba(229,50,43,.1)); box-shadow: 0 0 0 1px rgba(229,50,43,.22) inset; max-width: 160px; }
.pt-health-risk:hover { box-shadow: 0 0 0 1.5px rgba(229,50,43,.45) inset; }
.pt-health-risk .pt-health-dot { background: var(--red, #e5322b); }
.pt-health-risk svg { width: 13px; height: 13px; flex: none; }
.pt-health-reason { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-health-more { font-size: 11px; font-weight: 700; flex: none; }   /* AUDIT_dark: no opacity on small text */
.pt-health-ok { color: var(--green); background: var(--green-bg); }
.pt-health-ok .pt-health-dot { background: var(--green); }
.pt-totals td { position: sticky; bottom: 0; background: var(--surface-2, var(--surface, #f7f7f8)); border-top: 2px solid var(--hairline-strong, var(--hairline)); padding: 11px 16px; }
.pt-tot { display: inline-flex; align-items: baseline; gap: 5px; font-size: 12.5px; color: var(--text-3); font-weight: 500; }
.pt-tot i { font-style: normal; font-weight: 700; font-size: 13.5px; color: var(--text); font-variant-numeric: tabular-nums; }
.pt-tot-sep { margin-left: 20px; } .pt-tot:not(.pt-tot-sep) + .pt-tot { margin-left: 20px; }
.pt-tot-gross i { color: var(--green, #1f9d57); }
.pt-tot-risk i { color: var(--amber, #e0900b); }
.pt-tot-overdue i { color: var(--red, #e5322b); }
/* v639 ZONE A4 — the BASE .ptable cell rhythm onto the --row-h scale (§3.6).
   Vertical padding only: the horizontal 18px is deliberately left alone because
   the Partner roster's BODY cells are re-padded to `15px 18px` from js/app.js
   (_v567EnsureCss), which this lane must not edit — moving the header's 18px
   without it would offset every Partners column against its own header.
   A sticky table header is not one of the three surfaces allowed to blur
   (§2.9), so the frost comes off and the surface goes opaque. */
.ptable th {
  text-align: left; font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-3); font-weight: var(--fw-semi); padding: var(--space-2) 18px; background: var(--surface-2);
  border-bottom: 1px solid var(--hairline); white-space: nowrap; position: sticky; top: 0;
}
.ptable td { padding: var(--space-2) 18px; border-bottom: var(--hairline-w) solid var(--hairline); font-size: var(--fs-body); white-space: nowrap; }
.ptable tr { cursor: pointer; transition: background-color var(--dur-1) var(--ease); }
.ptable tbody tr:hover { background: var(--row-hover); }
.ptable tr:last-child td { border-bottom: none; }
.p-name { display: flex; align-items: center; gap: 10px; }
.p-logo { width: 32px; height: 32px; border-radius: var(--radius-sm); display: grid; place-items: center; font-weight: 700; font-size: 13px; color: #fff; flex-shrink: 0; }
.p-logo.p-logo-img { background: var(--surface); overflow: hidden; }
.p-logo.p-logo-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.panel-title-row { display: flex; align-items: center; gap: 11px; }
.p-logo-edit { position: relative; border: 0; background: none; padding: 0; cursor: pointer; flex-shrink: 0; border-radius: var(--radius-sm); line-height: 0; }
.p-logo-edit .p-logo-av, .p-logo-edit .avatar { border-radius: var(--radius-sm); }
.p-logo-edit .p-logo-av img, .p-logo-edit .avatar img { border-radius: var(--radius-sm); object-fit: cover; }
.p-logo-cam { position: absolute; right: -4px; bottom: -4px; width: 19px; height: 19px; border-radius: 50%; background: var(--accent); color:var(--text-on-accent,#fff); display: grid; place-items: center; box-shadow: 0 1px 4px rgba(0,0,0,.3); }
.p-logo-cam svg { width: 11px; height: 11px; }
.p-name b { font-weight: 600; font-size: 13.5px; display: block; }
.p-name small { color: var(--text-3); font-size: 11.5px; }
.p-nametext { min-width: 0; }
/* Health-column composite bands — 'watch' (amber) + 'off' (offboarded), matching the existing risk/ok pills */
.pt-health-watch { color: var(--amber, #e0900b); background: color-mix(in srgb, var(--amber, #e0900b) 13%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--amber, #e0900b) 22%, transparent) inset; max-width: 160px; }
.pt-health-watch:hover { box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--amber, #e0900b) 42%, transparent) inset; }
.pt-health-watch .pt-health-dot { background: var(--amber, #e0900b); }
.pt-health-watch svg { width: 13px; height: 13px; flex: none; }
.pt-health-off { color: var(--text-3, #9a9aa0); background: var(--surface-2, #f2f2f5); }
.pt-health-off .pt-health-dot { background: var(--text-3, #9a9aa0); }
/* Lead-momentum column (Partner Tracker → "Leads (mo)") — this-month count + MoM delta + days-since-last */
.pt-lm { display: inline-flex; align-items: baseline; gap: 6px; font-variant-numeric: tabular-nums; }
.pt-lm-n { font-weight: 700; font-size: 13.5px; color: var(--text, #1d1d1f); }
.pt-lm-delta { font-size: 11px; font-weight: 700; }
.pt-lm-up { color: var(--green, #1f9d57); }
.pt-lm-down { color: var(--red, #e5322b); }
.pt-lm-flat { color: var(--text-3, #9a9aa0); }
.pt-lm-since { font-size: 11px; color: var(--text-3, #9a9aa0); }
.pt-lm-stale { color: var(--red, #e5322b); font-weight: 700; }
/* Billing-status column (Partner Tracker → "Billing") — paid / due / overdue at a glance, click to collect */
.pt-bill { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 650; padding: 2px 9px 2px 7px; border-radius: var(--radius-pill); white-space: nowrap; }
.pt-bill-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: currentColor; }
.pt-bill-paid { color: var(--green, #1f9d57); background: var(--green-bg, rgba(31,157,87,.1)); }
.pt-bill-due { color: var(--amber, #e0900b); background: color-mix(in srgb, var(--amber, #e0900b) 13%, transparent); }
.pt-bill-overdue { color: var(--red, #e5322b); background: var(--accent-softer, rgba(229,50,43,.1)); box-shadow: 0 0 0 1px rgba(229,50,43,.22) inset; }
.pt-bill-next { margin-left: 6px; font-size: 11px; color: var(--text-3, #9a9aa0); }
/* Per-client activity timeline (Partner panel → Activity tab) */
.pt-timeline { display: flex; flex-direction: column; gap: 2px; padding: 4px 0; }
.pt-tl-row { display: flex; gap: 11px; padding: 9px 2px 9px 0; position: relative; }
.pt-tl-row::before { content: ''; position: absolute; left: 13px; top: 30px; bottom: -9px; width: 1.5px; background: var(--line, #e6e6ea); }
.pt-tl-row:last-child::before { display: none; }
.pt-tl-ic { flex: 0 0 27px; width: 27px; height: 27px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; background: var(--surface-2, #f2f2f5); color: var(--text-2, #6b6b70); z-index: 1; }
.pt-tl-ic svg { width: 14px; height: 14px; }
.pt-tl-body { min-width: 0; flex: 1; padding-top: 1px; }
.pt-tl-top { display: flex; align-items: baseline; gap: 8px; justify-content: space-between; }
.pt-tl-text { font-size: 13px; font-weight: 600; color: var(--text, #1d1d1f); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-tl-time { flex: 0 0 auto; font-size: 11px; color: var(--text-3, #9a9aa0); white-space: nowrap; }
.pt-tl-sub { font-size: 12px; color: var(--text-2, #6b6b70); margin-top: 1px; line-height: 1.35; overflow-wrap: anywhere; }
.pt-tl-note { margin-top: 12px; font-size: 11px; color: var(--text-3, #9a9aa0); text-align: center; }
.pt-timeline-empty { display: flex; gap: 12px; align-items: center; padding: 26px 16px; color: var(--text-2, #6b6b70); }
.pt-timeline-empty svg { width: 26px; height: 26px; flex: 0 0 26px; color: var(--text-3, #9a9aa0); }
.pt-timeline-empty b { display: block; font-size: 14px; color: var(--text, #1d1d1f); }
.pt-timeline-empty small { display: block; font-size: 12px; margin-top: 2px; }
/* per-row quick actions: delivery chat + client-view. Reveal on row hover (always on touch). */
.pt-rowacts { display: inline-flex; align-items: center; gap: 4px; margin-left: auto; padding-left: 8px; opacity: 0; transition: opacity var(--dur-1) ease; }
.ptable tbody tr:hover .pt-rowacts, .pt-rowacts:focus-within { opacity: 1; }
.pt-rowact { width: 30px; height: 30px; flex: 0 0 auto; display: grid; place-items: center; border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface); color: var(--text-2); cursor: pointer; transition: background var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, transform var(--dur-1) ease; }
.pt-rowact:hover { background: var(--accent-softer); color: var(--accent); border-color: var(--accent-soft); }
.pt-rowact:active { transform: scale(.92); }
.pt-rowact:focus-visible { outline: none; box-shadow: var(--ring); }
.pt-rowact svg { width: 15px; height: 15px; }
@media (max-width: 720px) { .pt-rowacts { opacity: 1; } }
.money { font-weight: 700; font-variant-numeric: tabular-nums; }
.cs-labels { display: flex; gap: 4px; flex-wrap: wrap; }

/* ============================================================
   PREMIUM TABLES REVAMP (v237) — Partner Tracker + Master Task List
   ADDITIVE refinement only. Same markup, classes, handlers, columns.
   Both surfaces (real <table class="ptable"> + the CSS-grid .tlist-inner)
   are unified onto one premium look: one clean toolbar header, frosted
   sticky column header, refined hairlines + cell rhythm, tabular numerals,
   a subtle hover highlight, consistent status chips, and tasteful reveal
   motion. Everything reads off the shared v235 tokens so light + dark and
   prefers-reduced-motion are correct for free. Scoped to .pt-partners /
   .tlist-inner so the payroll table and other .ptable users are untouched.
   ============================================================ */

/* ---- 1. Header / toolbar: one calm row, identical on both pages ---- */
.mainhead .head-controls { gap: var(--space-2) var(--space-3); padding-bottom: var(--space-3); align-items: center; }
.mainhead .head-controls .vtab-row { flex: 1 1 auto; min-width: 0; }
/* Task quick-filters — one-click My Work / Overdue chips */
.tq-chips { display: inline-flex; gap: var(--space-1); background: var(--surface-2); border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: var(--space-0); flex: 0 0 auto; }
.tq-chip { display: inline-flex; align-items: center; gap: var(--space-1); min-height: var(--ctl-sm); border: none; background: none; color: var(--text-2); font-size: var(--fs-small); font-weight: var(--fw-medium); padding: 0 var(--space-2); border-radius: var(--radius-xs); cursor: pointer; font-family: inherit; white-space: nowrap; transition: background-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease); }
.tq-chip svg { width: var(--icon-sm); height: var(--icon-sm); }
.tq-chip:hover { background: var(--row-hover); color: var(--text); }
/* run6 R6-17 · the count badge sits on translucent --hairline, so the chip's hover fill bleeds
   through and DROPS the badge's contrast mid-hover (Ink dark: text-2 on the composited badge is
   3.81:1 during hover — sub-AA). Ramp the badge ink WITH the chip (text-2 → text, same direction
   as the chip's own hover ink): --text on the hovered composite is 6.72:1 in Ink dark. :where()
   keeps specificity at (0,3,0) so the LATER `.tq-chip.on .tq-n` inverse still wins on selected
   chips, and .warn is excluded so the red overdue badge keeps its status ink under hover. */
.tq-chip:hover .tq-n:where(:not(.warn)) { color: var(--text); }
/* ACTIVE filter chip = an INVERSE PILL, not a tint.
   Red is reserved: --accent/--red is the overdue signal and the one primary action
   per view (§2.7), so a filter toggle must not use it. But a 5.5% --row-selected
   tint is indistinguishable from :hover on a control that changes WHICH TASKS YOU
   CAN SEE — too weak for a state you must be able to spot without looking for it.
   So: the ink ramp's darkest step becomes the fill and the panel base becomes the
   label. That is a LUMINANCE inversion, not a hue change, so it reads as ON for
   colour-blind users too, and it flips for free in dark (near-black pill on light,
   near-white pill on dark). MEASURED in a real browser, both themes: label
   17.76:1 light / 16.72:1 dark; nested count pill 7.03:1 / 8.95:1 — all four well
   past AA 4.5:1. The count's 28% backing is HEAD's own rgba(255,255,255,.28)
   strength expressed through tokens, so it is the same weight, not a new value. */
.tq-chip.on { background: var(--text); color: var(--bg); }
.tq-chip.on:hover { background: var(--text); }
.tq-n { display: inline-flex; align-items: center; justify-content: center; min-width: var(--space-4); height: var(--space-4); padding: 0 var(--space-1); border-radius: var(--radius-pill); background: var(--hairline); color: var(--text-2); font-size: var(--fs-micro); font-weight: var(--fw-semi); }
.tq-chip.on .tq-n { background: color-mix(in srgb, var(--bg) 28%, transparent); color: var(--bg); }
.tq-n.warn { background: var(--red-bg); color: var(--red); }
/* DESKTOP: keep the view-tabs and the primary actions on ONE line. The tab strip
   scrolls horizontally instead of shoving "New Partner"/Refresh onto an orphaned
   second row (the old layout wrapped the primary CTA below the tabs — the #1 thing
   that read as "terrible"). Mobile (≤720) keeps its own intentional stacked layout.

   ── v738 · `nowrap` → `wrap`. TOMBSTONE, read before "tidying" this back. ──
   THE BUG IT FIXES (live on prod at 1280×900, measured): the Tasks header pushed the
   WHOLE DOCUMENT 202px wide — a horizontal scrollbar across every page of the app.
   THE LAW: `nowrap` here + `.vtab-row`'s `min-width:0` (:2445) make the saved-views strip
   the row's ONLY shrinkable item, so it absorbs 100% of any deficit. Once it hits 0 the
   remaining toolbar has no shrink left, its overflow escapes `.head-controls` (nothing
   between here and the viewport establishes containment) and the document grows.
   That law was already known — twice — and both prior fixes were SCOPED PATCHES over it:
   v677 (js/app.js `_vtabBandEnsureCss`, `:has(.groupby)` + a 721-1679 band) and F-A1-9
   (js/app.js `_vtabPartnersEnsureCss`, `.hc-partners` + the `.hc-tools` wrapper). Between
   them they cover Partners and the Tasks LIST tab. They do not cover the Tasks header with
   NO group-by select — Board and Calendar (renderHeader gates `.groupby` on
   `State.taskTab!=='board'&&!=='calendar'`) — which is the header that was overflowing.
   So the cause is fixed HERE, at the shared rule, instead of adding a third patch.
   WHY `wrap` IS SAFE: a flex row only wraps when its items DON'T fit, so wherever the
   one-line layout works today it is untouched; where it doesn't, the row breaks into the
   strip-then-toolbar shape the ≤720 block, v677 and F-A1-9 all already ship. Only two
   elements in the app carry `.head-controls` (js/app.js:1897 tasks, :1986 partners), and
   partners is a byte-for-byte no-op — `_vtabPartnersEnsureCss` already sets `wrap` on it.
   MEASURED, real browser, index.html's own sheet, tasks × {board,list} × {3,8,14 views} ×
   {800,1024,1280,1440,1680}px: document overflow 291/347/91/0/0px → 0px everywhere, and
   the strip itself 0/0/0/31/271px → 724/668/924/1084/1324px. Nothing regressed to overflow. */
@media (min-width: 721px){
  .mainhead .head-controls { flex-wrap: wrap; }
  /* the spacer no longer needs to fight the tab-strip for growth — let the tabs own
     the left, the actions sit flush right, with one clean gap between them */
  .mainhead .head-controls .head-spacer { flex: 1 1 0; min-width: 8px; }
}
/* ════════════════════════════════════════════════════════════════════════════════════
   OB-3 (v752) · THE TASKS TOP STRIP STOPS HIDING CONTROLS.
   Owner, verbatim: "the top UI is a little bit weird and I'm scrolling over and stuff."

   WHAT IS ACTUALLY IN THAT STRIP — read from js/app.js:1631-1663 (renderViewRow), not assumed:
   N saved-view tabs (`data-act="apply-view"`, :1642) · then Board (:1658) · Calendar (:1660) ·
   Timeline (:1661) · then "Save view" (`.tab.pfilter-edit`, :1662). All of them are SIBLING
   children of the one `<div class="tabset vtab-row">` at js/app.js:2064, inside
   `<div class="head-controls hc-tasks">` at :2063. `.tabset` is `overflow-x:auto` (:5348) and
   `.tab` is `white-space:nowrap` (:5350), so the row scrolls sideways instead of wrapping.
   That is ELEVEN controls of THREE different kinds — department FILTERS, VIEW MODES, one
   ACTION — in one scrolling row.

   MEASURED LIVE, signed in on prod v750 (.agents/mission/wave-ob/OB14-viewport-ladder-live.md §1):
     1512 (his MacBook Pro 14")  strip client 1156 / scroll 1630 → 474px HIDDEN:
                                 Jarvis, Board, Calendar, Timeline, Save view
     1728 (his MacBook Pro 16")  strip client 1372 / scroll 1630 → 258px HIDDEN: Timeline, Save view
     3840 (TV)                   1924 / 1924 → 0 hidden.
   Threshold ≈ 1986px. BOTH of his laptops sit below it, which is why he hits this daily.
   Switching to Board or Calendar — primary navigation, not filtering — means scrolling past
   seven filters, and the view modes are the first things hidden because they sit last.

   WHY `flex-wrap:wrap` AND NOT A WIDTH/PADDING TWEAK: the strip's content width is USER DATA
   (one tab per saved view; he adds departments regularly — "Jarvis - (AI)" is recent), so any
   hard-coded crossover is wrong the day he adds one. This is the same argument F-A1-9 already
   made at js/app.js:1274-1278 and the v738 tombstone at :2517-2521 above: a flex row only wraps
   when its items DON'T fit, so at ≥ the threshold this is a byte-identical no-op, and below it
   nothing can be hidden — the strip cannot scroll because there is nothing to scroll to.

   WHY IT IS GATED ≥721px AND NOT GLOBAL: on a phone the sideways-scrolling strip is DELIBERATE.
   js/app.js:1945-1971 (PHONE-02) exists purely to preserve its scrollLeft across re-renders, and
   :4831 below gives it its own full-width row there. MEASURED in a real browser against this
   file's own sheet (fixture: index.html's <style> extracted verbatim + the two sheets app.js
   injects at :1247 and :1425 + renderHeader's own markup — calibrated below): letting it wrap on
   a 390px phone gives SEVEN tab lines, a 362px strip and a 647px header, vs 333px shipped. 721px
   is the gate every other rule in this band already uses (:2538 above, js/app.js:1247, :1425).

   MEASURED BEFORE → AFTER, same fixture, real Inter, tabs = the 7 real saved views + the 4
   built-ins. CALIBRATION FIRST, because a fixture that doesn't reproduce the live defect proves
   nothing: it lands strip client 1156 @1512 and 1372 @1728 — OB-14's live numbers EXACTLY — and
   scroll width 1637 vs 1630 live (0.4%), with the identical hidden set at 1512.

     viewport   hidden BEFORE      tab lines AFTER   header height  Δ
     390/430    (gate off — unchanged, still one scrolling line)     0
     1024       969px / 7 tabs     3                 199 → 290      +91
     1200       793px / 7 tabs     3                 199 → 290      +91
     1280       713px / 6 tabs     2                 199 → 253      +54
     1512  ←his 481px / 5 tabs     2                 199 → 253      +54
     1728  ←his 265px / 3 tabs     2                 157 → 194      +37
     1920        73px / 1 tab      2                 157 → 194      +37
     2000        (see note)                                              ← DISPUTED, do not cite
     2560/3840    0px / 0 tabs     1                 unchanged        0   ← no-op, confirmed twice

   [The 2000px row originally read "0px hidden / 1 line / byte-identical no-op". REMOVED as an
    unverifiable specific: an independent second fixture measured BEFORE client 1644 / scroll 1644
    at 2000 and AFTER wrapping to 2 lines (+38px), putting the crossover between 2000 and 2560.
    The three fixtures disagree on the strip's own content width (1630 live · 1637 · 1644), which
    is exactly the width the crossover depends on, so no single 2000px claim is defensible. The
    no-op is confirmed by BOTH fixtures at 2560 and 3840 — that is the claim that carries weight,
    and it is the only one this rule needs, since the whole point is that wrapping is
    self-scaling rather than pinned to a crossover anyone has to be right about.]

   READ THE COST HONESTLY: this BUYS zero unreachable controls at every width ≥721 and COSTS up to
   +108px of sticky header at the bottom of the 721–1279 band (three tab lines). [Was written as
   "+91px": that is the measurement at 1024. 721 itself was never measured by the lane; an
   independent fixture measures 3 lines and 244 → 352 = +108px there. The two agree at 1024
   (+92 vs +91). Quote the worst case, not the convenient one.] That trade is taken because the
   strip HIDES ITS OWN SCROLLBAR (`scrollbar-width:none` at :5348 + the ::-webkit-scrollbar rule at :5349),
   so there is no visual affordance that anything is off-screen at all — which is precisely why it
   reads as "weird" rather than as "scrollable". If the tablet band is ever judged too expensive,
   raise this ONE media query to `min-width:1280px`: 1280 is the widest tested width that still
   needs three lines, so above it the cost is capped at +54px. Nothing else changes.

   WHY `.hc-tasks` AND NOT EVERY `.vtab-row`: Partners renders the same strip (js/app.js:2155)
   and plausibly has the same defect, but it was NOT measured and its strip carries 11+ saved
   views, so untested wrapping there could cost three header rows. Scoped to the one surface the
   complaint and the measurements are about. Partners is filed as a follow-up, not fixed blind.

   WHY NOT "pin the view modes outside the scroll area" (OB-14's own recommendation): the four
   trailing controls are siblings inside the scroll container, so CSS alone cannot lift them out
   of it. The only CSS-only approximation is `position:sticky; right:<n>px` on each pinned tab,
   which needs four hard-coded pixel offsets derived from the rendered widths of
   Board/Calendar/Timeline/Save view — font-metric-dependent, transparent-background overlap, and
   wrong the first time a label changes. The real cure is a second container in renderViewRow,
   which is js/app.js and NOT this lane's file. Handed off instead of half-done.
   → THAT HANDOFF WAS TAKEN. renderViewRow now emits `.vtab-actions`; see the v754 block below,
     which is what actually pays the +54px back. The rule under this comment is UNCHANGED and is
     still what runs whenever `.vtab-actions` is absent.
   ════════════════════════════════════════════════════════════════════════════════════ */
@media (min-width: 721px){
  .mainhead .head-controls.hc-tasks .tabset.vtab-row { flex-wrap: wrap; row-gap: 6px; }
}
/* ════════════════════════════════════════════════════════════════════════════════════
   OB-3 ROUND 2 (v754) · THE WRAP KEEPS ITS FIX AND GIVES THE +54px BACK.

   WHAT v752 BOUGHT AND WHAT IT COST (live, signed in, his own machines — OB-14 §1 + v752's
   own before/after): 1512 → 474px hidden / 5 unreachable became 0 / 0, but the sticky header
   went 236 → 290px. 1728 → 258px / 2 became 0 / 0, header 194 → 232px. On a 944px-tall 14"
   laptop that is 31% of the screen permanently spent on chrome. The fix was right; the price
   was a second (and at 1024, a third) line of tabs.

   THE PRICE WAS ONLY EVER NECESSARY BECAUSE ELEVEN CONTROLS OF THREE KINDS SHARED ONE ROW.
   renderViewRow now emits two containers instead of one: `.tabset.vtab-row` keeps ONLY the
   saved-view FILTERS (`data-act="apply-view"`), and a new sibling `.vtab-actions` carries the
   VIEW MODES (Board / Calendar / Timeline) and the one ACTION (Save view). `.vtab-actions` is
   NOT a scroll container and never wraps, so nothing inside it can ever be hidden. The header
   had spare HORIZONTAL room; this spends that instead of a second row.

   THE THREE DECLARATIONS AND WHY EACH ONE EXISTS:
   · `.vtab-actions{flex:0 0 auto;flex-wrap:nowrap}` — it must not shrink and must not wrap, or
     a view mode could be clipped, which is the whole defect. gap:2px matches `.tabset`'s own
     gap (search `.tabset { display: flex; gap: 2px;` — :5465 at the time of writing) so the two
     groups still read as one strip.
   · `flex:1 1 40%` on the filter strip — this is a FLOOR EXPRESSED AS A PROPORTION, not a
     crossover. Flex breaks a line on hypothetical sizes, so with the default `flex-basis:auto`
     the strip asks for its full content width (1246px in the fixture) and shoves `.vtab-actions`
     onto a line of its own — measured 240px @1512 instead of 201. A basis of 40% of the header
     asks for a share, not the content, so the two groups stay on one line and the strip then
     GROWS past 40% to eat whatever is left. It is deliberately not a pixel: it scales with his
     window. Measured at 34% / 40% / 46% across sixteen widths — 34% is too small (at 3000px
     everything fits on one line and the strip is squeezed to 902px, hiding 2 filters that are
     visible today), 46% is identical to 40% everywhere except one tablet rung. 40% is the only
     tested value with no regression at any rung.
   · This whole ≥721 rule is gated on `:has(.vtab-actions)` for ONE reason beyond scoping: if the
     markup ever reverts, every declaration here evaporates and v752's wrap above runs again
     unchanged. PROVEN, not asserted — the ladder below was re-run with this CSS against the
     OLD single-strip markup and came back byte-identical at all nine widths.

   PHONE (≤720) IS A SEPARATE RULE AND IT IS NOT OPTIONAL. `.vtab-actions` is ~417px of
   non-shrinking content; on a 390px phone the head-controls row is 338px, so without the
   `flex:1 0 100%` below it overflows and pushes the WHOLE DOCUMENT sideways — measured 53px
   @390 and 13px @430. That is exactly the v738 catastrophe (see the tombstone at :2516).
   So on phones it takes its own full-width row and scrolls sideways, mirroring what `.tabset`
   already deliberately does there (search `.head-controls .tabset { order: -1;` — :4948 at the
   time of writing — and PHONE-02 in js/app.js, search `var HSTRIP_SEL`).
   ⚠ HANDOFF, cross-file so it is not fixed here: HSTRIP_SEL is `.v2p-segs, .v2t-segs, .vtab-row`,
   so `.vtab-actions` scrollLeft is NOT stashed across a re-render. At ≤720 this rule DOES make it
   scroll (79px @390), so the js-side note that "it does not scroll" holds only from 721 up. The
   consequence is benign — it resets to 0, which is where Board/Calendar already are — but the
   claim, not just the code, is what needs to match.

   MEASURED, ladder in full. Fixture (mine, described below), tasks LIST tab, 7 real saved views:
     width   header BEFORE → AFTER    hidden px   controls unreachable
     390     348 → 394  (+46)         1328 → 908  9 → 6   (6 = 5 filters + Save view)
     430     308 → 354  (+46)         1288 → 868  9 → 6
     720     216 → 262  (+46)          998 → 578  7 → 3   (all 4 actions reachable from here up)
     1024    332 → 240  (-92)            0 → 578  0 → 3   (filters only)
     1280    255 → 201  (-54)            0 → 771  0 → 5
     1512←his 255 → 201  (-54)           0 → 519  0 → 3
     1728←his 196 → 159  (-37)           0 → 303  0 → 2
     2560    159 → 159   (0)             0 → 0    0 → 0   ← no-op
     3840    115 → 115   (0)             0 → 0    0 → 0   ← no-op
   Document horizontal overflow is 0 at every rung, before and after. Board tab measured too:
   1512 213 → 159, 1728 196 → 159, TVs unchanged.

   READ THE TRADE HONESTLY, BOTH WAYS.
   · ≥721 it BUYS the whole +54/+37px back at both his laptops and −92px at 1024, and no view
     mode or Save view can be hidden at any width from 721 up. It COSTS department FILTERS being
     behind a sideways scroll again (3 of 7 at 1512, 2 of 7 at 1728) — the same scroll that
     existed before v752, minus the four controls that actually mattered. That is the trade
     OB-14 §1 recommended in as many words: filters are homogeneous and scanning them is
     expected; a hidden "Calendar" is a dead-feeling app.
   · ON PHONES IT COSTS +46px AND BUYS BACK 3 OF THE 4 ACTIONS. That cost is the markup split
     itself, not this rule — there is no arrangement in which 417px of actions and 1246px of
     filters share a 338px line and stay usable. "Save view" is still one short scroll away on a
     phone (the actions row overflows by 79px @390, 39px @430, 0 from 720 up).
   · If the tablet band is ever judged wrong, this rule is one media query, same as v752's.

   `:has()` IS A HARD DEPENDENCY of both rules above. It already is: js/app.js's v677 band
   (_vtabBandEnsureCss, `:has(.groupby)`) has shipped on this exact header since v677. A browser
   without `:has()` drops the ≥721 rule and falls back to v752's wrap — taller, never broken.

   PROVENANCE — say it plainly. These numbers are from MY OWN fixture, not from prod and not
   from the other lane's output: index.html's <style> extracted verbatim + the real sops/glass/
   themes/legacy-bridge sheets + the two sheets js/app.js injects (v677, v739) appended last +
   renderHeader's tasks markup rebuilt to the agreed contract. CALIBRATION, because a fixture
   that cannot reproduce the live defect proves nothing: it lands the strip's client width at
   1156 @1512 and 1372 @1728 — OB-14's live numbers EXACTLY — reproduces OB-14's unreachable set
   at 1512 (Jarvis, Board, Calendar, Timeline, Save view) exactly, and reproduces v752's header
   delta to within 1px (+54 @1512 measured vs +54 live; +37 @1728 vs +38 live). Its absolute
   header heights sit a CONSTANT 35-36px below live at all four calibration cells (the fixture's
   .viewfilter-row carries no filter chips), so read the deltas as exact and add ~35 to the
   absolutes: 201 @1512 is the live 236 — the pre-v752 baseline, to the pixel. Its strip content
   measures 1666 vs 1630 live (+2.2%), i.e. the fixture hides 36px MORE than reality, so every
   "hidden" figure above is pessimistic. VERIFY ON THE REAL PAGE BEFORE BELIEVING ANY OF IT.
   ════════════════════════════════════════════════════════════════════════════════════ */
.mainhead .head-controls .vtab-actions { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; flex-wrap: nowrap; }
@media (min-width: 721px){
  .mainhead .head-controls.hc-tasks:has(.vtab-actions) .tabset.vtab-row { flex-wrap: nowrap; flex: 1 1 40%; min-width: 0; }
}
@media (max-width: 720px){
  .mainhead .head-controls .vtab-actions { flex: 1 0 100%; max-width: 100%; overflow-x: auto; scrollbar-width: none; }
  .mainhead .head-controls .vtab-actions::-webkit-scrollbar { display: none; }
}
/* ════════════════════════════════════════════════════════════════════════════════════
   A+ (v757) · THE SCROLL AFFORDANCE — the missing half of the split above.

   THE DEFECT THE SPLIT LEAVES BEHIND. `.tabset` hides its scrollbar on purpose
   (`scrollbar-width: none` + `::-webkit-scrollbar{display:none}` — :5465-5466), so a strip that
   overflows looks IDENTICAL to a strip that fits. After the ≥721 rule above, 3 of 7 department
   filters sit past the right edge at his 1512 laptop (2 of 7 at 1728) with NOTHING on screen
   saying so — a chip row that ends flush at the edge reads as "that is all of them". The split
   traded a hidden view mode for a hidden filter and was right to; it is only right if the hidden
   filter announces itself. These three rules are that announcement.

   WHY A MASK AND NOT AN OVERLAY. The obvious build is a gradient pseudo-element fading to the
   header's background colour. That needs to KNOW the header's background — and this app ships
   ~12 themes, several of which repaint the header band (glass/frost surfaces, terra's multi-value
   chrome, the light/dark pairs), so an overlay is a hardcoded colour that is wrong somewhere and
   has to be re-tuned every time a theme lands. `mask-image` fades the strip's OWN PIXELS to
   transparent instead, letting whatever is actually behind it show through. It is therefore
   theme-proof with ZERO knowledge of the header background, and it costs NO box: no
   pseudo-element, no padding, no positioned child, no change to any measured dimension. That
   last part is load-bearing — every header height in the OB-3 ladder above was measured without
   this rule, and a mask cannot invalidate a single one of those numbers.

   WHY THREE RULES AND NOT TWO. Mask images do not stack: a second `mask-image` on the same
   element REPLACES the first, it does not compose with it. So the both-edges state (mid-scroll,
   content continuing left AND right) cannot be `.vt-more-l` plus `.vt-more-r` — it needs its own
   combined four-stop gradient, which is the third rule. It is last and doubly-specific, so it
   wins the cascade over the two single-edge rules whenever both classes are present.

   WHO TOGGLES THE CLASSES — CROSS-FILE, so it is not fixed here. `_stripEdgeFadeUpdate` in
   js/app.js (search `vt-more-r` there) measures each strip and sets `vt-more-r` only when
   `scrollLeft + clientWidth < scrollWidth` and `vt-more-l` only when `scrollLeft > 0`. That
   scroll-awareness is the whole safety story: a strip whose content FITS gets neither class,
   therefore no `mask-image`, therefore not one pixel of difference. The TV rungs (2560, 3840)
   hide 0px and are byte-identical to today, and so is any narrower window whose filters happen
   to fit. If the js lane is ever reverted, these rules simply never match and the header returns
   to exactly its v754 state. NOTHING here is self-activating.

   WHY BOTH SELECTORS. `.vtab-row` is the filter strip and it is NOT tasks-only — the partners
   header renders the same `.tabset.vtab-row` (js/app.js:2155), where the hidden-scroll defect is
   identical. It gets the same cure for free, with zero layout change, because this rule adds no
   box. `.vtab-actions` is included because it DOES scroll at ≤720 (the rule directly above makes
   it a scroll container; it overflows 79px @390, 39px @430, 0 from 720 up), so "Save view" hides
   there silently too. The v2 strips (`.v2p-segs`, `.v2t-segs`) are deliberately OUT of scope.

   WHY 34px. ≈ one-third of a filter chip: wide enough that the fade reads as "this continues"
   rather than as a rendering glitch, narrow enough that it never swallows a whole chip label —
   the chip under the fade stays identifiable, which is what makes it worth scrolling to.

   ⚠ NOT MEASURED, stated so nobody reads it as verified: `mask-repeat` defaults to `repeat`, so
   anything a child paints OUTSIDE the strip's border box (a focus ring on the first chip bleeding
   left of x=0) lands in the neighbouring tile and can be faded. Both strips are `overflow-x:auto`
   scroll containers, which already clip child overflow, so there should be nothing out there to
   fade — but keyboard-focus the first filter chip mid-scroll before calling it proven.
   ════════════════════════════════════════════════════════════════════════════════════ */
.mainhead .vtab-row.vt-more-r,
.mainhead .vtab-actions.vt-more-r {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent);
          mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent);
}
.mainhead .vtab-row.vt-more-l,
.mainhead .vtab-actions.vt-more-l {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 34px);
          mask-image: linear-gradient(to right, transparent, #000 34px);
}
.mainhead .vtab-row.vt-more-l.vt-more-r,
.mainhead .vtab-actions.vt-more-l.vt-more-r {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 34px, #000 calc(100% - 34px), transparent);
          mask-image: linear-gradient(to right, transparent, #000 34px, #000 calc(100% - 34px), transparent);
}
/* crumb title gets the display face + crisp tracking (matches the brand) */
.crumb .crumb-list { font-family: var(--font-display); letter-spacing: -0.022em; }
.crumb-meta { font-variant-numeric: tabular-nums; }
/* the saved-views tab row + the filter chip-row breathe consistently */
.mainhead .viewfilter-row { margin-top: 2px; padding-bottom: 2px; }
/* gentle reveal of the whole header band on route change (reduced-motion safe via .u-* rules) */
.mainhead { animation: uFadeIn var(--dur-2) var(--ease-out) both; }

/* ---- 2a. Shared table SHELL refinement ----
   run6 W5c TOMBSTONE: the (0,2,0) radius re-pin on .ptable-wrap.pt-partners/.tlist-scroll is
   DELETED — the wrap's .glass-2 owns --g-r-card now (the re-pin would beat it), and the desktop
   .tlist-scroll has no surface for a radius to shape. */
/* sticky COLUMN HEADER — one look for both technologies. §2.1 allows exactly one
   uppercase tracking value (.05em); .055em was an eyeballed off-grid variant. */
.ptable.thead, .ptable thead th,
.tlist-inner .trow.thead {
  letter-spacing: .05em;
}
/* run6 W5c: the frosted re-pin (surface-60 + blur) is DELETED — a sticky header that scrolling
   text passes under is not allowed to blur (§2.9), and inside the now-.glass-2 wrap it was also
   a stacked blur. The header falls back to the base .ptable th opaque var(--surface-2) fill. */
.ptable thead th {
  font-size: 11px; padding-top: 13px; padding-bottom: 12px;
  border-bottom: 1px solid var(--hairline-strong);
  box-shadow: 0 1px 0 0 var(--hairline);
}
/* opaque, unblurred sticky header: frosting a header that scrolling text passes
   UNDER is what made the column labels read mushy (§2.9 — blur is for chrome,
   floating popovers and the modal scrim only). */
.tlist-inner .trow.thead {
  background: var(--surface-2);
  border-bottom: 1px solid var(--hairline-strong);
  position: sticky; top: 0; z-index: var(--z-sticky);
}
.tlist-inner .trow.thead .th { font-size: var(--fs-micro); }

/* ---- 2b. Cell rhythm + hairlines + numerals (both surfaces) ---- */
.ptable tbody td { border-bottom-color: var(--hairline); }
.ptable tbody tr td { transition: background var(--dur-1) var(--ease); }
.pt-partners .ptable tbody td,
.tlist-inner .trow > * { font-variant-numeric: tabular-nums; }
.pt-partners .ptable tbody tr { transition: background var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease); }

/* ---- 2c. Subtle hover HIGHLIGHT (lift feel without moving layout) ---- */
.pt-partners .ptable tbody tr:hover {
  background: var(--row-hover);
  box-shadow: inset 3px 0 0 0 var(--accent-soft);
}
/* row hover is a BACKGROUND STEP and nothing else (§3.6): no lift, no shadow, and
   no inset accent rail — a red bar on every hovered row is why nothing in the app
   read as urgent. */
.tlist-inner .trow:not(.thead):hover {
  background: var(--row-hover);
}

/* ---- 2d. Refined totals / footer bar ----
   run6 W5c: the frosted re-pin is DELETED (same §2.9 sticky-surface rule as the thead above);
   the base .pt-totals td opaque var(--surface-2) fill takes over. */

/* ---- 3. STATUS CHIP / badge consistency across both tables ---- */
/* run7 W4: `.ptable .status-pill, .tlist-inner .status-pill` dropped from this list — `.status-pill`
   is DEAD (zero hits app-wide; every live status chip is a namespaced name — `cp-status-*`,
   `cpd-status-*`, `bil-status`, `dops-dv-status`, `clpay-st` — and none of them is built by
   appending `-pill` to a variable). `.badge` and `.pill` are live and keep the tabular numerals. */
.ptable .badge, .tlist-inner .badge,
.ptable .pill, .tlist-inner .pill {
  font-variant-numeric: tabular-nums; letter-spacing: .005em;
}

/* ---- 4. Row reveal on first paint ----
   v639: the Master Task List's staggered fade-up is DELETED (§2.10 reveal budget:
   no per-row entrance animation, no animation-delay chains). Task rows now paint
   instantly, which is what fast software feels like — and it removes 5 delay rules
   plus one animation from the app's densest list. The Partner roster keeps its own
   reveal untouched: that table belongs to another lane this round. */
.pt-partners .ptable tbody tr {
  animation: uFadeUp var(--dur-2) var(--ease-out) both;
}
.pt-partners .ptable tbody tr:nth-child(1){animation-delay:.01s}
.pt-partners .ptable tbody tr:nth-child(2){animation-delay:.03s}
.pt-partners .ptable tbody tr:nth-child(3){animation-delay:.05s}
.pt-partners .ptable tbody tr:nth-child(4){animation-delay:.07s}
.pt-partners .ptable tbody tr:nth-child(5){animation-delay:.09s}
.pt-partners .ptable tbody tr:nth-child(n+6){animation-delay:.10s}

/* ---- 5. In-UI components: consistent premium spacing on both pages ----
   The pickers (.uis-menu), view builder (.nv-*), add-field + option managers
   already share tokens + open motion; just normalize the chip-row rhythm so the
   two tables' filter/view areas look identical. */
.views-bar, .filter-bar { gap: 7px 8px; }
.view-chip { transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.view-chip:active { transform: scale(.97); }

/* ---- 6. Reduced-motion: freeze the table reveals (belt + suspenders) ---- */
@media (prefers-reduced-motion: reduce){
  .mainhead,
  .pt-partners .ptable tbody tr,
  .tlist-inner .table-card .trow:not(.thead) { animation: none !important; opacity: 1 !important; transform: none !important; }
}
/* ============================================================
   END PREMIUM TABLES REVAMP (v237)
   ============================================================ */

/* ============================================================
   WAVE 3 — Pipeline · Ads Manager · Team · Payments · Admin + modals
   (v238). Refinement-only layer on the shared v235 tokens, matching the
   wave 1/2 treatment: display-face headings, tasteful reveal/stagger
   motion, hover-lift cards, palette-aligned status colors, fold-down
   panels, consistent in-UI popups, and tightened responsiveness. Every
   rule is SCOPED to w3-* hooks (added in app.js render output) or to the
   existing page classes — no markup/handler/structure change, no existing
   class renamed. All motion is opacity+transform only and frozen under
   prefers-reduced-motion (belt + suspenders at the bottom).
   ============================================================ */

/* ---- shared w3 motion primitives (reuse the v235 keyframes/eases) ---- */
.w3-disp { font-family: var(--font-display); letter-spacing: -0.022em; font-feature-settings: 'ss01','kern' 1; }
.w3-reveal { animation: uFadeUp var(--dur-3) var(--ease-out) both; }
.w3-scale  { animation: uScaleIn var(--dur-2) var(--ease-out) both; }
.w3-sectitle { font-family: var(--font-display); letter-spacing: -0.012em; }
/* Home premium wave (v295, additive): card-header TITLES adopt the display face (excludes meta + chevron spans) so Home's hierarchy matches the other pages. */
.home .home-card-h > span:not(.home-card-meta):not(.home-clients-meta):not(.home-fold-chev) { letter-spacing: .05em; }
/* staggered card reveals — parent gets .w3-stagger, children fade-up in a capped cascade */
.w3-stagger > * { animation: uFadeUp var(--dur-3) var(--ease-out) both; }
.w3-stagger > *:nth-child(1){animation-delay:.02s} .w3-stagger > *:nth-child(2){animation-delay:.05s}
.w3-stagger > *:nth-child(3){animation-delay:.08s} .w3-stagger > *:nth-child(4){animation-delay:.11s}
.w3-stagger > *:nth-child(5){animation-delay:.14s} .w3-stagger > *:nth-child(6){animation-delay:.17s}
.w3-stagger > *:nth-child(7){animation-delay:.20s} .w3-stagger > *:nth-child(8){animation-delay:.23s}
.w3-stagger > *:nth-child(n+9){animation-delay:.25s}
/* premium hover-lift for cards (pay/ads/member) — transform+shadow only, springs back on press */
.w3-card { transition: transform var(--dur-1) var(--ease), box-shadow var(--dur-2) var(--ease), border-color var(--dur-1) var(--ease); }
.w3-card:hover { box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-3); }   /* run6 W5b: restated in g-terms — every w3-card user (pay/pod/member/adsm) is on a primitive now, and the legacy var(--shadow) re-pin was erasing the themed edge on hover; border-color half dead with the borders */
.w3-card:active { transform: translateY(0) scale(.995); }

/* ============================================================
   1. PIPELINE — premium kanban
   ============================================================ */
.w3-board { scroll-snap-type: none; }
/* board reveal once, then columns cascade in */
.w3-pipe .w3-board { animation: uFadeIn var(--dur-2) var(--ease-out) both; }
.w3-pipe .w3-pipe-col { animation: uFadeUp var(--dur-3) var(--ease-out) both; }
.w3-pipe .w3-pipe-col:nth-child(1){animation-delay:.01s} .w3-pipe .w3-pipe-col:nth-child(2){animation-delay:.04s}
.w3-pipe .w3-pipe-col:nth-child(3){animation-delay:.07s} .w3-pipe .w3-pipe-col:nth-child(4){animation-delay:.10s}
.w3-pipe .w3-pipe-col:nth-child(5){animation-delay:.13s} .w3-pipe .w3-pipe-col:nth-child(n+6){animation-delay:.15s}
/* run6 W5c: the w3 width-tier re-pin (frosted bg + blur + radius at 0,2,0) DELETED — it beat the
   .g-solid-2 primitive at desktop widths and per-column blur over a scrolling board is the
   stacked-blur trap. Hover retargeted to the solid ramp (one tier up in every theme-mode). */
.w3-pipe .pipe-col {
  transition: box-shadow var(--dur-2) var(--ease), background-color var(--dur-2) var(--ease);
}
.w3-pipe .pipe-col:hover { background-color: var(--g-solid-3); }
/* status DOTS + tones onto the restrained palette (slate/amber/green/red) */
.w3-pipe .pipe-new .pipe-col-dot { background: var(--text-3); }
.w3-pipe .pipe-work .pipe-col-dot { background: var(--amber); }
.w3-pipe .pipe-appt .pipe-col-dot { background: var(--slate); }
.w3-pipe .pipe-showed .pipe-col-dot { background: var(--slate); }
.w3-pipe .pipe-won .pipe-col-dot { background: var(--green); }
.w3-pipe .pipe-lost .pipe-col-dot { background: var(--text-3); }
/* run6 W5c: w3 radius re-pin + (0,3,0) hover re-pin DELETED — they beat both the .g-solid-2
   primitive and the base .pipe-card:hover recipe at desktop widths. Drag lift kept. */
.w3-pipe .pipe-card {
  transition: background-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
}
.w3-pipe .pipe-card.pipe-dragging { box-shadow: var(--shadow-lg); }
/* lead value + won totals onto the palette green */
.w3-pipe .pipe-val { color: var(--green); }
.w3-pipe .pipe-total.pipe-won b { color: var(--green); }
.w3-pipe .pipe-card-check:hover { border-color: var(--green); }
.w3-pipe .pipe-card.is-contacted .pipe-card-check { background: var(--green); border-color: var(--green); }
/* age pills onto palette tones */
.w3-pipe .pipe-age-fresh { color: var(--green); background: var(--green-bg); }
.w3-pipe .pipe-age-warm { color: var(--amber); background: var(--amber-bg); }
.w3-pipe .pipe-age-cold { color: var(--red); background: var(--red-bg); }
/* drop target uses the brand accent wash already; tighten the outline rhythm */
.w3-pipe .pipe-col.drop-on { box-shadow: 0 0 0 1px var(--accent-soft) inset; }
/* MOBILE — keep the existing horizontal-scroll board, add scroll-snap so columns
   land cleanly under a thumb; columns already size to 80% on <=760px. */
@media (max-width: 760px){
  .w3-pipe .w3-board { scroll-snap-type: x proximity; scroll-padding-left: 2px; }
  .w3-pipe .w3-pipe-col { scroll-snap-align: start; }
}
@media (max-width: 560px){
  /* state chips + toolbar already wrap; guarantee 44px tap targets on phones */
  .w3-pipe .pipe-state-chip { min-height: 40px; }
  .w3-pipe .pipe-card-check { width: 24px; height: 24px; }
  .w3-pipe .pipe-card-adv { width: 30px; height: 30px; }
}

/* ============================================================
   2. ADS MANAGER — account snapshot cards + metric tiles
   ============================================================ */
.w3-ads .adsm-card {
  background: var(--glass, var(--surface));
  -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}
.w3-ads .adsm-card.w3-card:hover { border-color: var(--accent-soft); }
/* rollup: frosted, a touch more lift on hover (it's a live snapshot panel) */
.w3-ads .adsm-rollup { transition: border-color var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease); }
.w3-ads .adsm-rollup:hover { box-shadow: var(--shadow); }
.w3-ads .adsm-roll-cell.is-accent .adsm-roll-big { color: var(--accent); }
/* metric tiles inside the card — tabular nums already on; tighten label tracking */
.w3-ads .adsm-metric i, .w3-ads .adsm-roll-small { letter-spacing: .04em; }
/* the deep-link "Open Ads Manager" + quick-links: clearer press feedback */
.w3-ads .adsm-ql, .w3-ads .adsm-open-real { transition: border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease), background var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.w3-ads .adsm-ql:active { transform: scale(.96); }
/* internal client view tabs — active underline uses accent already; add a soft hover wash */
.w3-ads .adsv-tab:hover { color: var(--text); }
.w3-ads .adsv-tab.active { color: var(--accent); }
@media (max-width: 560px){
  .w3-ads .adsm-ql { min-height: 36px; display: inline-flex; align-items: center; }
  .w3-ads .adsv-tab { min-height: 44px; }
  .w3-ads .adsv-range-btn { min-height: 36px; }
  .w3-ads .adsm-card .adsm-metrics { grid-template-columns: repeat(2, 1fr); }
}

/* ============================================================
   3. TEAM — payroll cards, roster, roles/permissions, presence dots
   ============================================================ */
/* section titles get the display face for a calmer hierarchy */
.w3-pay .w3-sectitle, .w3-admin .w3-sectitle { font-weight: 700; }
/* cash bar onto palette tones (was flat hexes) */
.w3-pay .cash-bar-net, .w3-pay .cash-bar-legend .cb-net { background: var(--green); }
.w3-pay .cash-bar-pay, .w3-pay .cash-bar-legend .cb-pay { background: var(--amber); }
/* payroll table rows — subtle inset accent on hover (matches wave-2 tables) */
.w3-pay .ptable tbody tr { transition: background var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease); }
.w3-pay .ptable tbody tr[data-act="payment-user"]:hover { box-shadow: inset 3px 0 0 0 var(--accent-soft); }
/* roles list — hover-lift + clearer affordance; presence dots untouched */
.w3-rolerow { transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.w3-rolerow:hover { border-color: var(--accent-soft); box-shadow: var(--shadow-sm); }
.w3-admin .roles-list { gap: 8px; }

/* ============================================================
   4. PAYMENTS / BILLING — cards, table, status pills
   ============================================================ */
/* billing table — align the hover + status pills to the table system + palette */
.w3-pay .bil-table tbody tr { transition: background var(--dur-1) var(--ease); }
.w3-pay .bil-table tbody tr:hover { background: var(--row-hover); }
.w3-pay .bil-table tbody td, .w3-pay .bil-table thead th { font-variant-numeric: tabular-nums; }
.w3-pay .bil-status { transition: filter var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.w3-pay .bil-status:active { transform: scale(.97); }
.w3-pay .bil-preset { transition: border-color var(--dur-1) var(--ease), background var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.w3-pay .bil-preset:active { transform: scale(.98); }
/* pay progress + bars onto palette */
.w3-pay .pay-progress-bar { background: linear-gradient(90deg, var(--green), color-mix(in srgb, var(--green) 70%, #fff 30%)); }
@media (max-width: 560px){
  .w3-pay .bil-status { min-height: 36px; }
}

/* ============================================================
   5. ADMIN roster + members
   ============================================================ */
/* run6 W5b: `.w3-admin .member-card` box-shadow re-pin deleted — at (0,2,0) it was overwriting
   .g-solid-2's edge/specular/shadow stack and un-theming the card. */
.w3-admin .admin-sec-head { font-family: var(--font-display); }
/* client mini cards get the same press feel */
.w3-admin .client-mini:active { transform: scale(.98); }

/* ============================================================
   6. SHARED IN-UI POPUPS — consistent premium menus/pickers across the app.
   Modals (.modal) already share scrim+blur+scale-in+mobile-sheet from the base
   system; here we make the FLOATING menus/pickers (.menu, kebab/option/picker
   menus, stage picker) feel identical: same frosted glass, same open spring,
   same item rhythm, and a frosted scrim feel via consistent shadow/blur. No
   handler/positioning JS touched — purely the look + open transition.
   ============================================================ */
/* run6 W5c TOMBSTONE: the shared radius re-pin for .menu/.opt-kebab-menu/.uis-menu/.dp-menu is
   DELETED — every one of those variants rides a `.menu` shell that now carries .glass-3, whose
   --g-r-sheet radius wins the (0,1,0) tie (glass.css loads after this <style>), so the rule was
   100% dead. */
/* a slightly springier, consistent open for every floating popup */
.menu { transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-spring), visibility var(--dur-2) var(--ease-out); }
/* modal foot buttons: consistent spring press across every modal */
.modal-foot .btn:active, .modal-foot .btn-primary:active { transform: scale(.98); }
/* every modal title uses the display face (already set globally for .modal-head h3) — ensure
   sub-modals built with bare h3 inside modal-body also align */
.modal-body h3 { font-family: var(--font-display); letter-spacing: -0.015em; }

/* ============================================================
   7. REDUCED MOTION — freeze every wave-3 reveal/lift (belt + suspenders)
   ============================================================ */
@media (prefers-reduced-motion: reduce){
  .w3-reveal, .w3-scale, .w3-stagger > *,
  .w3-pipe .w3-board, .w3-pipe .w3-pipe-col,
  .w3-pipe .pipe-card, .w3-card {
    animation: none !important; opacity: 1 !important; transform: none !important;
  }
  .w3-card:hover, .w3-pipe .pipe-card:hover, .w3-rolerow:hover { transform: none !important; }
}
/* ============================================================
   END WAVE 3 REVAMP (v238)
   ============================================================ */

/* ============================================================
   WAVE 6 — Profile/Settings · Integrations · Funnel (DISPLAY-ONLY)
   · Websites (v241). Final page wave. Refinement-only layer on the
   shared v235 tokens, matching wave 1/2/3 treatment: display
   face on titles + big numerals, tabular-nums on remaining digit
   surfaces, tasteful reveal/stagger + hover-lift/press motion (the
   shared keyframes/eases), palette-aligned status colors, and
   tightened responsiveness at tablet(768)/iPhone(390). Every rule is
   SCOPED to the pages' existing class hooks (.pf-* / .ig-* /
   #ppFunnelRO .ppf-* / .ws-* / .wsite-root) — NO markup/handler/
   structure change, NO existing class renamed, NO data/fetch/calc
   touched. FUNNEL is styling-only: only fonts/tabular-nums/reveal
   added; its proxy + every calculation are byte-identical. All motion
   is opacity+transform only and frozen under prefers-reduced-motion
   (belt + suspenders at the bottom).
   ============================================================ */

/* run7 W3: the shared wave-6 reveal primitives `.w6-reveal` / `.w6-stagger > *` (+ its six
   nth-child delays and the n+7 tail) deleted — DEAD. Zero hits for either name in index.html,
   js/*.js, v2/*, css/*, sw.js or the apps-script/scripts trees, and nothing builds a `w6-` name
   dynamically. The wave-6 pages ended up on the wave-3 twins instead, which ARE live and are
   untouched: `.w3-reveal` (js/app.js:7261 + 44 more), `.w3-stagger`, `.w3-scale`, `.w3-card`.
   The `uFadeUp` keyframe is KEPT — `.u-stagger > *` still uses it here, and js/calendar.js
   6743-6763 injects CSS that animates on `uFadeUp`/`uFadeIn` by name. */

/* ============================================================
   1. PROFILE / SETTINGS / ADMIN (profile.js: .pf-*)
   ============================================================ */
/* display face + tighter optics on the hero + card names and section labels */
.pf-hero-name, .pf-card-name { font-family: var(--font-display); letter-spacing: -0.022em; }
.pf-sec, .pf-card-title { font-feature-settings: 'ss01','kern' 1; }
/* hero reveals top-down; the meta/section blocks cascade in slightly */
.pf-modal .pf-hero { animation: uFadeIn var(--dur-2) var(--ease-out) both; }
/* read-only meta + notif rows get a gentle hairline-hover affordance (no layout shift).
   v704 (Fable-5 blocking fix): .pf-ro is now a .g-solid-2 primitive — hover must NOT re-tint
   a structural themed border (Ink's 1.5px black flipping to a grey hairline on hover reads as
   a glitch). var(--g-border-c) keeps the theme's own border colour (hover no-op where borders
   are structural); the hairline-strong fallback preserves the old affordance pre-theme. */
.pf-ro { transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease); }
.pf-ro:hover { border-color: var(--g-border-c, var(--hairline-strong)); }
.pf-nrow { transition: background var(--dur-1) var(--ease); }
/* danger zone: clearer press feedback */
.pf-danger-btn { transition: background var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.pf-danger-btn:active { transform: scale(.97); }
.pf-camera:active { transform: scale(.92); }

/* ---- AUDIT LOG: refined feed rows, tabular timestamps, subtle reveal ---- */
.pf-au-row { transition: background var(--dur-1) var(--ease); }
.pf-au-row:hover { background: var(--row-hover); }
.pf-au-time { font-variant-numeric: tabular-nums; }
.pf-au-line b { font-family: var(--font-display); letter-spacing: -0.012em; }
/* the scroll feed reveals as one unit when it (re)renders */
.pf-audit { animation: uFadeUp var(--dur-3) var(--ease-out) both; }

/* ---- TEAM TIMES SHEET: tabular numerals on every digit, refined rows ---- */
.pf-times-date, .pf-times-io, .pf-times-io small, .pf-times-n b, .pf-times-n small,
.pf-times-uname { font-variant-numeric: tabular-nums; }
.pf-times-uname { font-family: var(--font-display); letter-spacing: -0.012em; }
.pf-times-row { transition: background var(--dur-1) var(--ease); }
.pf-times-row:hover { background: var(--row-hover); }
.pf-times-del { transition: border-color var(--dur-1) var(--ease), color var(--dur-1) var(--ease), background var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.pf-times-del:active { transform: scale(.9); }
.pf-times-user { animation: uFadeUp var(--dur-3) var(--ease-out) both; }
/* tablet/phone: keep the times + audit panels comfortable + tap-safe */
@media (max-width: 768px){
  .pf-times-del { min-width: 34px; min-height: 34px; }
}
@media (max-width: 430px){
  .pf-au-row { padding: 11px 12px; }
  .pf-audit { max-height: 340px; }
}

/* ============================================================
   2. INTEGRATIONS (integrations.js: .ig-*)
   ============================================================ */
/* page title + card names get the display face; tighter, premium hierarchy */
.ig-page-title { font-family: var(--font-display); letter-spacing: -0.026em; }
.ig-card-name, .ig-section-label { font-family: var(--font-display); }
.ig-section-label { letter-spacing: .08em; }
.ig-summary strong { font-variant-numeric: tabular-nums; }
/* connect cards reveal in a tasteful cascade + lift on hover (already have a
   box-shadow hover; add the translate for a premium, consistent feel) */
.ig-grid { animation: uFadeIn var(--dur-2) var(--ease-out) both; }
.ig-card { animation: uFadeUp var(--dur-3) var(--ease-out) both; }
.ig-card:hover { will-change: transform; }   /* promote to its own layer only while interacting, not permanently */
.ig-grid .ig-card:nth-child(1){animation-delay:.02s} .ig-grid .ig-card:nth-child(2){animation-delay:.06s}
.ig-grid .ig-card:nth-child(3){animation-delay:.10s} .ig-grid .ig-card:nth-child(4){animation-delay:.14s}
.ig-card { transition: box-shadow var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease), transform var(--dur-1) var(--ease); }
/* logo tile lifts a hair with its card for depth */
.ig-card-logo { transition: box-shadow var(--dur-2) var(--ease), border-color var(--dur-2) var(--ease); }
.ig-card:hover .ig-card-logo { border-color: var(--hairline-strong); box-shadow: var(--shadow-sm); }
/* connect/disconnect buttons: consistent spring press + live-chip pulse-in */
.ig-btn:active { transform: scale(.96); }
.ig-chip, .ig-gcal-chip { animation: uScaleIn var(--dur-2) var(--ease-out) both; }
/* the green "live" chip dot gets a soft presence ring so connected reads instantly */
.ig-chip.live .ig-chip-dot, .ig-gcal-chip-dot { box-shadow: 0 0 0 3px var(--green-bg); }
/* tablet/phone: ≥44px tap targets on the card buttons, no overflow */
@media (max-width: 768px){
  .ig-card-btns { display: flex; flex-wrap: wrap; gap: 8px; justify-content: flex-end; }
  .ig-btn { min-height: 40px; }
}
@media (max-width: 430px){
  .ig-card-foot { flex-direction: column; align-items: stretch; gap: 10px; }
  .ig-card-btns { justify-content: stretch; }
  .ig-card-btns .ig-btn { flex: 1; justify-content: center; min-height: 44px; }
  .ig-summary { font-size: 12.5px; }
}

/* ============================================================
   3. FUNNEL STATS — DISPLAY/STYLING ONLY (funnel.js: #ppFunnelRO .ppf-*)
   ⚠ ZERO data/fetch/calc touched here. Only fonts (the display face on
   the big numerals + titles), tabular-nums reinforcement, and a single
   shared ease normalization. The numbers themselves are produced by JS
   that this block never reaches.
   ============================================================ */
/* page + modal + section titles → display face for a calmer analytics hierarchy */
#ppFunnelRO .ppf-header h1,
#ppFunnelRO .ppf-modal-header h2,
#ppFunnelRO .ppf-chart-modal-title,
#ppFunnelRO .ppf-empty-title,
#ppFunnelRO .ppf-error-title,
#ppFunnelRO .ppf-fv-title,
#ppFunnelRO .ppf-trend-title { font-family: var(--font-display); letter-spacing: -0.02em; font-feature-settings: 'ss01','kern' 1; }
/* the hero numerals (KPIs, goal, funnel overall %, ratios, trend, gs cards) →
   display face + tabular so they read as crisp, aligned, premium metrics */
#ppFunnelRO .ppf-scorecard-value,
#ppFunnelRO .ppf-goal-sold,
#ppFunnelRO .ppf-fv-overall-num,
#ppFunnelRO .ppf-fv-bar-val,
#ppFunnelRO .ppf-fv-count,
#ppFunnelRO .ppf-ratio-value,
#ppFunnelRO .ppf-trend-val,
#ppFunnelRO .ppf-gs-card .word,
#ppFunnelRO .ppf-goal-amount-display { font-family: var(--font-display); font-variant-numeric: tabular-nums; letter-spacing: -0.025em; }
/* any remaining digit surfaces stay aligned (belt + suspenders) */
#ppFunnelRO .ppf-goal-target, #ppFunnelRO .ppf-goal-remaining,
#ppFunnelRO .ppf-trend-month, #ppFunnelRO .ppf-fv-conv-chip,
#ppFunnelRO .ppf-trend-delta { font-variant-numeric: tabular-nums; }

/* ============================================================
   4. WEBSITES (Forge) — LIGHT TOUCH ONLY (websites.js: .wsite-root .ws-*)
   Layout + generate/preview/publish logic untouched. Only token-align
   the type (the display face), tabular-nums on the count, and a slightly
   more refined card lift that matches the rest of the app.
   ============================================================ */
.wsite-root .ws-hero h1, .wsite-root .ws-projhead h2 { font-family: var(--font-display); letter-spacing: -0.03em; }
.wsite-root .ws-projhead h2 .ws-count { font-variant-numeric: tabular-nums; font-family: var(--font); }
.wsite-root .ws-card-edited, .wsite-root .ws-pill { font-variant-numeric: tabular-nums; }
/* cards already lift; add a calm press + reveal-in so the grid settles, not snaps */
.wsite-root .ws-card:active { transform: translateY(-1px) scale(.995); }
.wsite-root .ws-grid { animation: uFadeIn var(--dur-2) var(--ease-out) both; }

/* ============================================================
   5. REDUCED MOTION — freeze every wave-6 reveal/lift (belt + suspenders)
   ============================================================ */
@media (prefers-reduced-motion: reduce){
  /* run7 W3: `.w6-reveal, .w6-stagger > *` dropped from this list — both rules deleted as DEAD */
  .pf-modal .pf-hero, .pf-audit, .pf-times-user,
  .ig-grid, .ig-card, .ig-chip, .ig-gcal-chip,
  .wsite-root .ws-grid {
    animation: none !important; opacity: 1 !important; transform: none !important;
  }
  .ig-card:hover, .pf-ro:hover, .wsite-root .ws-card:active { transform: none !important; }
}
/* ============================================================
   END WAVE 6 REVAMP (v241)
   ============================================================ */

/* ===== Side panel ===== */
.panel-backdrop { position: fixed; inset: 0; background: var(--scrim); z-index: 900; opacity: 0; visibility: hidden; transition: opacity var(--dur-3) ease; -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px); }
.panel-backdrop.open { opacity: 1; visibility: visible; }
/* run6 W5c: surface → .glass-3 on the static <aside class="panel"> shell (index.html markup).
   Hand-animated portal (translateX keyed to .open) — surface class only, never .g-drawer.
   Layout + slide machinery stay here. */
.panel {
  position: fixed; top: 0; right: 0; bottom: 0; width: 560px; max-width: 96vw; z-index: 901;
  transform: translateX(100%); transition: transform var(--dur-3) cubic-bezier(.32,.72,0,1);
  display: flex; flex-direction: column;
}
.panel.open { transform: translateX(0); }
/* .glass-3 brings var(--g-r-sheet) — a full-height screen-edge drawer must keep square corners
   or the theme radius leaks canvas at top/bottom-right. aside.panel (0,1,1) on purpose: a plain
   .panel (0,1,0) tie is won by glass.css (loads after this <style>). Desktop-scoped so the ≤720px
   bottom-sheet below keeps its own top radius. */
@media (min-width: 721px){ aside.panel { border-radius: 0; } }
.panel-head { padding: 20px 24px 14px; border-bottom: 1px solid var(--hairline); display: flex; flex-direction: column; gap: 12px; }
.panel-head-row { display: flex; align-items: center; gap: 10px; }
.panel-head-row .icon-btn { width: 32px; height: 32px; }
.panel-crumb { font-size: 11.5px; color: var(--text-3); font-weight: 600; flex: 1; display:flex; align-items:center; gap:6px; }
.panel-title { font-size: 19px; font-weight: 700; letter-spacing: -0.3px; line-height: 1.25; outline: none; border-radius: var(--radius-xs); padding: 2px 4px; margin: -2px -4px; }
.panel-title:focus { background: var(--surface); box-shadow: 0 0 0 2px var(--accent-soft); }
.panel-tabs { display: flex; gap: 3px; padding: 0 18px; border-bottom: 1px solid var(--hairline); overflow-x: auto; scrollbar-width: none; }
.panel-tabs::-webkit-scrollbar { display: none; }
.panel-tab { flex-shrink: 0; white-space: nowrap; }
.panel-tab { padding: 10px 12px; font-size: 13px; font-weight: 600; color: var(--text-3); cursor: pointer; border-bottom: 2px solid transparent; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; display:inline-flex; align-items:center; gap:6px; }
.panel-tab svg { width:15px; height:15px; }
.panel-tab:hover { color: var(--text); }
.panel-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.panel-tab .cnt { font-size: 12px; color: var(--text); background: var(--surface); padding: 0 6px; border-radius: var(--radius-md); font-weight: 700; }   /* R-A (v826): explicit text colour so the count reads at 390 */
.panel-body { flex: 1; overflow-y: auto; padding: 22px 24px 44px; }

.field-grid { display: grid; grid-template-columns: 130px 1fr; gap: 6px 16px; align-items: center; }
.field-grid.compact { gap: 12px 16px; }
.fl { font-size: 12.5px; color: var(--text-3); font-weight: 600; padding: 8px 0; display:flex; align-items:center; gap:7px; }
.fl svg { width: 14px; height: 14px; }
.fv { min-height: 34px; display: flex; align-items: center; }
.fv-edit[type="number"] { font-variant-numeric: tabular-nums; }
.fv-edit {
  width: 100%; padding: 7px 10px; border-radius: var(--radius-sm); border: 1px solid transparent; background: transparent;
  color: var(--text); font-size: 13px; font-family: var(--font); outline: none; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease;
}
.fv-edit:hover { background: var(--surface); }
.fv-edit:focus { background: var(--glass-strong); border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-softer); }
/* money fields in the partner panel: formatted $-display (tabular-nums) with click-to-edit,
   matching the table cells. .money/.cell-edit supply weight + hover; this is the tap target. */
.fv-money { display: inline-flex; align-items: center; min-height: 32px; padding: 6px 10px; border-radius: var(--radius-sm); }
select.fv-edit { cursor: pointer; -webkit-appearance: none; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2386868b' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 10px center; padding-right: 28px; }
textarea.fv-edit { resize: vertical; min-height: 70px; line-height: 1.5; }
.fv-link { color: var(--accent); font-size: 12.5px; font-weight: 600; text-decoration: none; display:inline-flex; align-items:center; gap:5px; }
.fv-link:hover { text-decoration: underline; }
.fv-link svg { width:13px; height:13px; }
/* editable link field: paste-able input + an open-icon when a value is set */
.fv-linkwrap { display: flex; align-items: center; gap: 4px; width: 100%; }
.fv-linkwrap .fv-edit { flex: 1; min-width: 0; }
.fv-linkopen { display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: var(--radius-sm); color: var(--accent); flex-shrink: 0; }
.fv-linkopen:hover { background: var(--accent-softer); }
.fv-linkopen svg { width: 14px; height: 14px; }

.section-title { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-3); font-weight: 700; margin: 22px 0 10px; display:flex; align-items:center; gap:8px; }
.section-title svg { width: 14px; height: 14px; flex-shrink: 0; }
.section-title::after { content:''; flex:1; height:1px; background: var(--hairline); }

/* Subtasks in panel */
.psub { display: flex; align-items: center; gap: 9px; padding: 8px 10px; border-radius: var(--radius-md); transition: background var(--dur-1) ease; }
.psub:hover { background: var(--surface); }
.psub-name { font-size: 13px; flex: 1; }
.psub-name.done { color: var(--text-3); text-decoration: line-through; }

/* Chat */
.chat-list { display: flex; flex-direction: column; gap: 0; margin-bottom: 16px; }
.chat-msg { display: flex; gap: 9px; align-items: flex-end; padding: 8px 0 0; }
.chat-bubble { min-width: 0; max-width: 78%; display: flex; flex-direction: column; }
.chat-meta { display: flex; align-items: baseline; gap: 8px; margin-bottom: 3px; }
.chat-author { font-size: 13px; font-weight: 600; }
.chat-time { font-size: 11px; color: var(--text-3); }
.chat-text { font-size: 13.5px; color: var(--text); line-height: 1.48; background: var(--surface); border: 1px solid var(--hairline); padding: 9px 13px; border-radius: var(--radius-lg); word-wrap: break-word; overflow-wrap: anywhere; max-width: 100%; }
.chat-empty { text-align: center; color: var(--text-3); font-size: 13px; padding: 24px 0; }
.chat-composer { display: flex; gap: 9px; align-items: flex-end; position: sticky; bottom: 0; padding-top: 10px; }
.chat-composer textarea {
  flex: 1; padding: 10px 12px; border-radius: var(--radius-sm); border: 1px solid var(--hairline);
  background: var(--glass-strong); color: var(--text); font-size: 16px; font-family: var(--font);
  resize: none; outline: none; max-height: 120px; line-height: 1.4;
}
.chat-composer textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-softer); }
.send-btn { width: 38px; height: 38px; border-radius: var(--radius-md); background: var(--accent); color:var(--text-on-accent,#fff); border: none; cursor: pointer; display: grid; place-items: center; flex-shrink: 0; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; }
.send-btn:hover { background: var(--accent-strong); }
.send-btn svg { width: 17px; height: 17px; }

/* ============================================================
   SHARED COMPOSER (v554) — task/partner chat skin for window.PPMComposer.
   The Client Delivery thread renders the same markup with the `dops-*`
   prefix (styled in js/daily-ops.js); this `ppmc-*` skin brings the full
   composer — @mentions, attachments with live progress, voice notes — to
   the internal task/partner chat. Touch targets are 42px (44px on phones),
   well above the 32px minimum. Kept structurally identical to dops so the
   two surfaces read as one system.
   ============================================================ */
.ppmc-composer-wrap { position: sticky; bottom: 0; padding-top: 10px; display: flex; flex-direction: column; gap: 8px; background: var(--bg, transparent); }
.ppmc-pending { display: flex; flex-wrap: wrap; gap: 8px; }
.ppmc-chip { display: inline-flex; align-items: center; gap: 8px; max-width: 240px; padding: 6px 8px 6px 6px; border-radius: var(--radius-md); border: 1px solid var(--hairline); background: var(--surface); }
.ppmc-chip-thumb { flex: 0 0 auto; width: 30px; height: 30px; border-radius: var(--radius-sm); display: grid; place-items: center; overflow: hidden; background: var(--glass-strong); color: var(--text-2); }
.ppmc-chip-thumb img { width: 100%; height: 100%; object-fit: cover; }
.ppmc-chip-thumb svg { width: 16px; height: 16px; }
.ppmc-chip-meta { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ppmc-chip-name { font-size: 12.5px; font-weight: 600; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ppmc-chip-sub { font-size: 11px; color: var(--text-3); font-variant-numeric: tabular-nums; }
.ppmc-chip-err { font-size: 11px; color: var(--danger, #e5484d); }
.ppmc-chip-bar { display: block; height: 3px; margin-top: 3px; border-radius: 2px; background: var(--hairline); overflow: hidden; }
.ppmc-chip-bar-fill { display: block; height: 100%; background: var(--accent); transition: width .18s ease; }
.ppmc-chip-x { flex: 0 0 auto; width: 22px; height: 22px; border: none; background: transparent; color: var(--text-3); cursor: pointer; display: grid; place-items: center; border-radius: var(--radius-sm); }
.ppmc-chip-x:hover { color: var(--text); background: var(--glass-strong); }
.ppmc-chip-x svg { width: 13px; height: 13px; }
.ppmc-composer { display: flex; gap: 8px; align-items: flex-end; }
.ppmc-attach, .ppmc-mic { flex: 0 0 auto; width: 42px; height: 42px; border-radius: var(--radius-sm); background: var(--surface); border: 1px solid var(--hairline); color: var(--text-2); cursor: pointer; display: grid; place-items: center; transition: color .12s, border-color .12s, background .12s, transform .1s; }
.ppmc-attach svg, .ppmc-mic svg { width: 19px; height: 19px; }
.ppmc-attach:hover, .ppmc-mic:hover { color: var(--accent); border-color: var(--accent); }
.ppmc-attach:active, .ppmc-mic:active { transform: translateY(.5px); }
.ppmc-attach:focus-visible, .ppmc-mic:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--accent-soft); }
.ppmc-mic[hidden], .ppmc-send[hidden] { display: none; }
.ppmc-composer textarea { flex: 1; min-width: 0; padding: 11px 13px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--glass-strong); color: var(--text); font-size: 16px; font-family: var(--font); resize: none; outline: none; max-height: 40vh; line-height: 1.45; transition: border-color .12s, box-shadow .12s; }
.ppmc-composer textarea::placeholder { color: var(--placeholder); }
.ppmc-composer textarea:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-softer); }
.ppmc-send { width: 42px; height: 42px; border-radius: var(--radius-sm); background: var(--accent); color: var(--text-on-accent, #fff); border: none; cursor: pointer; display: grid; place-items: center; flex-shrink: 0; transition: background .14s, transform .1s; }
.ppmc-send:hover { background: var(--accent-strong); }
.ppmc-send:active { transform: translateY(.5px) scale(.97); }
.ppmc-send:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--accent-soft); }
.ppmc-send svg { width: 18px; height: 18px; }
/* recording UI (replaces the input row while capturing) */
.ppmc-composer.ppmc-recording { align-items: center; gap: 10px; padding: 6px; border: 1px solid var(--accent); border-radius: var(--radius-sm); background: var(--accent-softer); }
.ppmc-rec-cancel { flex: 0 0 auto; width: 40px; height: 40px; border-radius: var(--radius-md); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2); cursor: pointer; display: grid; place-items: center; }
.ppmc-rec-cancel svg { width: 17px; height: 17px; }
.ppmc-rec-cancel:hover { color: var(--accent); border-color: var(--accent); }
.ppmc-rec-mid { flex: 1 1 auto; min-width: 0; display: flex; align-items: center; gap: 9px; }
.ppmc-rec-dot { flex: 0 0 auto; width: 10px; height: 10px; border-radius: 50%; background: var(--accent); animation: ppmc-rec-pulse 1.1s ease-in-out infinite; }
@keyframes ppmc-rec-pulse { 0%,100% { opacity: 1; transform: scale(1); } 50% { opacity: .4; transform: scale(.82); } }
.ppmc-rec-time { flex: 0 0 auto; font-size: 14px; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; min-width: 42px; }
.ppmc-rec-lbl { flex: 0 0 auto; font-size: 12.5px; color: var(--text-3); }
.ppmc-rec-wave { flex: 1 1 auto; display: flex; align-items: center; gap: 3px; height: 22px; overflow: hidden; justify-content: flex-end; }
.ppmc-rec-wave i { flex: 0 0 auto; width: 3px; border-radius: 2px; background: var(--accent); opacity: .55; animation: ppmc-rec-wave 1s ease-in-out infinite; }
.ppmc-rec-wave i:nth-child(1) { height: 8px; animation-delay: 0s } .ppmc-rec-wave i:nth-child(2) { height: 16px; animation-delay: .12s } .ppmc-rec-wave i:nth-child(3) { height: 11px; animation-delay: .24s } .ppmc-rec-wave i:nth-child(4) { height: 20px; animation-delay: .36s } .ppmc-rec-wave i:nth-child(5) { height: 9px; animation-delay: .48s } .ppmc-rec-wave i:nth-child(6) { height: 15px; animation-delay: .6s } .ppmc-rec-wave i:nth-child(7) { height: 7px; animation-delay: .72s }
@keyframes ppmc-rec-wave { 0%,100% { transform: scaleY(.5); } 50% { transform: scaleY(1); } }
.ppmc-rec-send { flex: 0 0 auto; width: 40px; height: 40px; border-radius: var(--radius-md); background: var(--accent); color: var(--text-on-accent, #fff); border: none; cursor: pointer; display: grid; place-items: center; }
.ppmc-rec-send svg { width: 18px; height: 18px; }
.ppmc-rec-send:hover { background: var(--accent-strong); }
/* @mention autocomplete popup */
.ppmc-mention-pop { position: relative; display: flex; flex-direction: column; gap: 2px; max-height: 232px; overflow-y: auto; padding: 5px; border-radius: var(--radius-md); border: 1px solid var(--hairline); background: var(--surface); box-shadow: var(--shadow-2, 0 8px 24px rgba(0,0,0,.18)); }
.ppmc-mention-pop[hidden] { display: none; }
.ppmc-mention-item { display: flex; align-items: center; gap: 9px; padding: 7px 9px; border: none; background: transparent; border-radius: var(--radius-sm); cursor: pointer; text-align: left; color: var(--text); }
.ppmc-mention-item:hover, .ppmc-mention-item.is-active { background: var(--glass-strong); }
.ppmc-mention-info { display: flex; flex-direction: column; min-width: 0; }
.ppmc-mention-info b { font-size: 13.5px; font-weight: 600; }
.ppmc-mention-info small { font-size: 11px; color: var(--text-3); }
@media (max-width: 560px) {
  .ppmc-attach, .ppmc-mic, .ppmc-send { width: 44px; height: 44px; }
  .ppmc-composer textarea { font-size: 16px; }
}
@media (prefers-reduced-motion: reduce) { .ppmc-rec-dot, .ppmc-rec-wave i { animation: none; } }

/* Relations & links */
/* run6 W5b: surface props deleted — markup now ships `rel-item g-solid-2` (js/app.js; rows
   inside the .panel drawer). Hover retargeted to the solid ramp. */
.rel-item { display: flex; align-items: center; gap: 10px; padding: 9px 11px; margin-bottom: 7px; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; cursor: pointer; }
.rel-item:hover { background-color: var(--g-solid-3); }
.rel-type { font-size: 11px; text-transform: uppercase; letter-spacing: .04em; font-weight: 700; color: var(--text-3); background: var(--bg-solid); padding: 2px 7px; border-radius: var(--radius-xs); flex-shrink: 0; }
.rel-name { font-size: 13px; flex: 1; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rel-x { width: 24px; height: 24px; border-radius: var(--radius-sm); display: grid; place-items: center; color: var(--text-3); flex-shrink: 0; }
.rel-x:hover { background: var(--red-bg); color: var(--red); }
.rel-x svg { width: 14px; height: 14px; }
/* run6 W5b: surface props deleted — markup now ships `link-item g-solid-2` (js/app.js, both sites). */
.link-item { display:flex; align-items:center; gap:10px; padding:9px 11px; margin-bottom:7px; }
.link-item svg.lk { width:15px; height:15px; color: var(--accent); flex-shrink:0; }
.link-item a { font-size:13px; color: var(--accent); text-decoration:none; flex:1; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.link-item a:hover { text-decoration: underline; }

.add-inline { display:flex; align-items:center; gap:7px; color: var(--text-3); font-size:12.5px; font-weight:600; cursor:pointer; padding:8px 4px; border-radius:var(--radius-sm); }
.add-inline:hover { color: var(--accent); }
.add-inline svg { width:15px; height:15px; }
/* collapsed empty resource-link slots (partner panel): summary styled like .add-inline, native marker hidden */
.pf-morelinks > summary { display:flex; align-items:center; gap:7px; color:var(--text-3); font-size:12.5px; font-weight:600; cursor:pointer; padding:8px 4px; border-radius:var(--radius-sm); list-style:none; -webkit-tap-highlight-color:transparent; }
.pf-morelinks > summary::-webkit-details-marker { display:none; }
.pf-morelinks > summary::marker { content:''; }
.pf-morelinks > summary:hover { color:var(--accent); }
.pf-morelinks > summary svg { width:15px; height:15px; }
.pf-morelinks[open] > summary { color:var(--text-2); margin-bottom:2px; }
.pf-more-n { margin-left:2px; font-size:11px; font-weight:700; color:var(--text-3); background:var(--surface-2); border-radius:var(--radius-pill); padding:1px 7px; }

/* ===== ⌘K Command Palette ===== */
.cmdk-ov { position: fixed; inset: 0; z-index: 1400; background: var(--scrim-strong); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); display: flex; justify-content: center; align-items: flex-start; padding: 12vh 16px 16px; }
/* run6 W5a: .cmdk surface props deleted — markup ships `cmdk glass-3` (js/app.js), which now owns
   background/blur/edge/radius/shadow; the js-side inline border:none band-aid is retired with it. */
.cmdk { width: 560px; max-width: 100%; max-height: 70vh; display: flex; flex-direction: column; overflow: hidden; animation: cmdkIn var(--dur-2) cubic-bezier(.2,.8,.2,1); }
@keyframes cmdkIn { from { opacity: 0; transform: scale(.97) translateY(-6px); } to { opacity: 1; transform: none; } }
.cmdk-inp-wrap { display: flex; align-items: center; gap: 10px; padding: 15px 18px; border-bottom: 1px solid var(--hairline); }
.cmdk-inp-wrap svg { width: 18px; height: 18px; color: var(--text-3); flex-shrink: 0; }
.cmdk-input { flex: 1; border: none; background: transparent; outline: none; font-size: 16px; color: var(--text); font-family: var(--font); }
.cmdk-input::placeholder { color: var(--text-3); }
.cmdk-results { overflow-y: auto; padding: 7px; flex: 1; }
.cmdk-item { display: flex; align-items: center; gap: 12px; width: 100%; padding: 10px 12px; border: none; background: transparent; border-radius: var(--radius-md); cursor: pointer; text-align: left; font-family: var(--font); }
.cmdk-item.sel { background: var(--accent-softer); }
.cmdk-ic { display: grid; place-items: center; width: 30px; height: 30px; border-radius: var(--radius-sm); background: var(--surface-2); flex-shrink: 0; }
.cmdk-ic svg { width: 16px; height: 16px; color: var(--text-2); }
.cmdk-item.sel .cmdk-ic svg { color: var(--accent); }
.cmdk-lab { flex: 1 1 auto; min-width: 0; font-size: 14px; font-weight: 550; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmdk-sub { font-size: 11.5px; font-weight: 600; color: var(--text-3); flex: 0 1 auto; min-width: 0; max-width: 50%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-transform: uppercase; letter-spacing: .03em; }
.cmdk-empty { padding: 26px; text-align: center; color: var(--text-3); font-size: 13.5px; }
/* v549 global search — type-section headers between grouped result blocks */
.cmdk-sec { padding: 11px 12px 4px; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--text-3); }
.cmdk-sec:first-child { padding-top: 5px; }
.cmdk-foot { display: flex; gap: 16px; padding: 9px 16px; border-top: 1px solid var(--hairline); font-size: 11px; color: var(--text-3); }
.cmdk-foot kbd { display: inline-block; min-width: 16px; padding: 1px 5px; border-radius: var(--radius-xs); background: var(--surface-2); border: 1px solid var(--hairline); font-family: var(--font); font-size: 11px; margin-right: 2px; }
@media (max-width: 720px) { .cmdk-ov { padding: 8vh 10px 10px; } .cmdk { max-height: 78vh; } .cmdk-foot { display: none; } }

/* ===== First-run onboarding welcome (renders inside the standard .modal) ===== */
.onb { padding: 26px 24px 22px; text-align: center; }
.onb-hero { padding: 2px 2px 4px; }
.onb-logo { width: 52px; height: 52px; margin: 0 auto 14px; border-radius: var(--radius-md); background: #0b0b0e; display: grid; place-items: center; box-shadow: var(--shadow-sm), inset 0 0 0 1px rgba(255,255,255,.06); }
.onb-logo svg { width: 26px; height: 26px; color: #fff; }
.onb-title { font-family: var(--font-display); font-size: 22px; font-weight: 800; letter-spacing: -0.02em; line-height: 1.15; color: var(--text); }
.onb-sub { margin: 8px 0 0; color: var(--text-2); font-size: 14px; line-height: 1.5; }
.onb-rows { display: flex; flex-direction: column; gap: 8px; margin: 18px 0 4px; text-align: left; }
/* run6 W5b: surface props deleted — markup now ships `onb-row g-solid-2` (js/app.js). */
.onb-row { display: flex; align-items: flex-start; gap: 12px; padding: 11px 13px; }
.onb-ic { width: 34px; height: 34px; flex: 0 0 auto; border-radius: var(--radius-md); display: grid; place-items: center; background: var(--accent-soft); color: var(--accent); }
.onb-ic svg { width: 18px; height: 18px; }
.onb-tx { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.onb-tx b { font-size: 14px; font-weight: 700; color: var(--text); letter-spacing: -0.1px; }
.onb-tx small { font-size: 12.5px; color: var(--text-2); line-height: 1.45; }
.onb-go { width: 100%; margin-top: 15px; min-height: 46px; font-size: 15px; justify-content: center; }
@media (max-width: 520px){ .onb { padding: 22px 18px 18px; } .onb-title { font-size: 20px; } .onb-rows { gap: 7px; } .onb-row { padding: 10px 12px; } }

/* ===== Modal ===== */
.modal-backdrop { position: fixed; inset: 0; background: var(--scrim-strong); z-index: 1000; display: grid; place-items: center; opacity: 0; visibility: hidden; transition: opacity var(--dur-2, var(--dur-2)) var(--ease, ease); -webkit-backdrop-filter: blur(6px) saturate(120%); backdrop-filter: blur(6px) saturate(120%); padding: 20px; }
.modal-backdrop.open { opacity: 1; visibility: visible; }
.modal {
  width: 520px; max-width: 100%; max-height: 88vh; overflow-y: auto;
  /* run6 W5a: surface props (background/blur/border/radius/shadow) deleted — the markup already
     ships `modal glass-4` (js/app.js openModal), and glass primitives draw their edge with
     box-shadow, so the leftover bespoke border was double-framing every modal. Only layout +
     the scale-in open animation remain; .modal-head's `background: inherit` now inherits the
     glass-4 fill+sheen. */
  transform: scale(.96) translateY(8px); transition: transform var(--dur-2, var(--dur-2)) var(--ease, cubic-bezier(.2,.8,.2,1));
}
.modal-backdrop.open .modal { transform: scale(1) translateY(0); }
/* SIM-03: `.modal` IS the scroll container (max-height + overflow-y above), so the header and its X
   used to scroll away — the Payment Processor's 30+ payer list left Close unreachable without
   scrolling all the way back up. Sticking the header to the top of that same container keeps the X on
   screen in EVERY modal. `background: inherit` takes the modal's own glass so nothing new is themed. */
.modal-head { padding: 22px 24px 2px; display: flex; align-items: center; justify-content: space-between; gap: 12px; position: sticky; top: 0; z-index: 2; background: inherit; -webkit-backdrop-filter: var(--blur); backdrop-filter: var(--blur); }
.modal-head h3 { font-size: 17px; font-weight: 700; letter-spacing: -0.3px; }
.modal-body { padding: 20px 24px; display: flex; flex-direction: column; gap: 16px; }
.mfield { display: flex; flex-direction: column; gap: 7px; }
.mfield.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.mlabel { font-size: 12px; font-weight: 600; color: var(--text-3); }
.minput, .mselect, .mtext {
  padding: 10px 12px; border-radius: var(--radius-md); border: 1px solid var(--hairline);
  background: var(--surface); color: var(--text); font-size: 13.5px; font-family: var(--font); outline: none; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; width: 100%;
}
.minput:focus, .mselect:focus, .mtext:focus { border-color: var(--accent); box-shadow: var(--ring-strong); background: var(--glass-strong); }
/* SIM-23 · <input type="date"> ships an INTRINSIC width (the widest the browser thinks
   "mm/dd/yyyy" plus its calendar glyph can get). On iOS that intrinsic width beats the `width:100%`
   above, so date fields pushed past the edge of their modal and the field — sometimes the picker
   button itself — sat outside the dialog. -webkit-appearance:none drops the platform sizing so the
   declared width is honoured, and min-width:0 lets the field shrink inside a flex/grid parent
   (a flex item's default min-width:auto is the other half of why it would not fit).
   16px is not cosmetic: below it iOS zooms the whole page on focus, which is its own overflow. */
input[type="date"].minput, input[type="datetime-local"].minput, input[type="time"].minput,
input[type="date"].cell-inline-input, input[type="datetime-local"].cell-inline-input {
  -webkit-appearance: none; appearance: none;
  width: 100%; max-width: 100%; min-width: 0; box-sizing: border-box;
}
@media (max-width: 560px) {
  input[type="date"].minput, input[type="datetime-local"].minput, input[type="time"].minput,
  input[type="date"].cell-inline-input, input[type="datetime-local"].cell-inline-input { font-size: 16px; }
  /* the one hard-coded date width in the billing modal cannot survive a 402pt screen either */
  .modal input[type="date"].minput { max-width: 100% !important; }
}
.mtext { resize: vertical; min-height: 70px; line-height: 1.5; }
.mselect { cursor: pointer; -webkit-appearance: none; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2386868b' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; padding-right: 30px; }
.modal-foot { padding: 6px 24px 24px; display: flex; gap: 11px; justify-content: flex-end; }
/* per-service field-visibility editor */
.svf-list { display: flex; flex-direction: column; gap: 2px; max-height: 46vh; overflow: auto; margin: 0 -6px; }
.svf-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 6px; border-radius: var(--radius-md); }
.svf-row:hover { background: var(--surface-2, rgba(127,127,127,.05)); }
.svf-name { font-size: 13.5px; font-weight: 600; color: var(--text); }
.svf-toggle { position: relative; width: 38px; height: 22px; border-radius: var(--radius-pill); border: 1px solid var(--hairline); background: var(--surface-2, rgba(127,127,127,.12)); cursor: pointer; padding: 0; flex: none; transition: background var(--dur-2), border-color var(--dur-2); }
.svf-toggle.on { background: var(--accent, #e5322b); border-color: var(--accent, #e5322b); }
.svf-knob { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 50%; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.25); transition: transform var(--dur-2); }
.svf-toggle.on .svf-knob { transform: translateX(16px); }
/* ClickUp-style date picker (our menu) */
.dp-menu { padding: 8px; border-radius: var(--radius-md); }
.dp-presets { display: grid; grid-template-columns: 1fr 1fr; gap: 5px; margin-bottom: 8px; }
.dp-preset { font-family: var(--font); font-size: 12.5px; font-weight: 600; color: var(--text-2); background: var(--surface-2, rgba(127,127,127,.06)); border: 1px solid var(--glass-border); border-radius: var(--radius-sm); padding: 7px 9px; cursor: pointer; text-align: left; transition: border-color var(--dur-1), color var(--dur-1), background var(--dur-1); }
.dp-preset:hover { border-color: var(--accent); color: var(--accent); }
.dp-calhead { display: flex; align-items: center; justify-content: space-between; padding: 4px 2px 6px; }
.dp-month { font-size: 13px; font-weight: 700; color: var(--text); }
.dp-nav { width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center; border-radius: var(--radius-sm); border: 1px solid var(--glass-border); background: var(--surface); color: var(--text-2); cursor: pointer; }
.dp-nav:hover { color: var(--text); border-color: var(--text-3); }
.dp-nav svg { width: 15px; height: 15px; }
.dp-dow { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; margin-bottom: 2px; }
.dp-dow span { text-align: center; font-size: 11px; font-weight: 700; color: var(--text-3); padding: 3px 0; }
.dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.dp-cell { aspect-ratio: 1; display: inline-flex; align-items: center; justify-content: center; font-family: var(--font); font-size: 12.5px; font-weight: 550; color: var(--text); background: transparent; border: 0; border-radius: var(--radius-sm); cursor: pointer; transition: background var(--dur-1), color var(--dur-1); }
.dp-cell:hover { background: var(--surface-2, rgba(127,127,127,.1)); }
.dp-cell.dp-empty { pointer-events: none; }
.dp-cell.dp-today { color: var(--accent); font-weight: 800; }
.dp-cell.dp-sel { background: var(--accent, #e5322b); color:var(--text-on-accent,#fff); }
.dp-clear { width: 100%; display: inline-flex; align-items: center; justify-content: center; gap: 5px; margin-top: 8px; font-family: var(--font); font-size: 12.5px; font-weight: 600; color: var(--text-3); background: transparent; border: 1px solid var(--glass-border); border-radius: var(--radius-sm); padding: 7px; cursor: pointer; }
.dp-clear:hover { color: var(--accent); border-color: var(--accent); }
.dp-clear svg { width: 13px; height: 13px; }

/* iPhone — modals fit the screen: safe-area-aware backdrop padding, internal
   scroll capped to the visible viewport, and a comfortable bottom inset so the
   footer buttons clear the home indicator. */
@media (max-width: 720px) {
  .modal-backdrop {
    padding: 16px;
    padding-top: calc(16px + var(--safe-top));
    padding-bottom: calc(16px + var(--safe-bottom));
    align-items: flex-end;   /* sheet-like: anchor to the bottom for thumb reach */
  }
  .modal {
    width: 100%; max-width: 100%;
    max-height: calc(100dvh - 32px - var(--safe-top) - var(--safe-bottom));
    border-radius: var(--radius-lg);
  }
  .modal-head { padding: 20px 20px 2px; }
  .modal-body { padding: 18px 20px; }
  .modal-foot { padding: 6px 20px 20px; }
  .modal-foot .btn { flex: 1; justify-content: center; }
  /* paired fields (date + date, name selects) stack on phones instead of cramming side-by-side */
  .mfield.row2 { grid-template-columns: 1fr; }
}

/* ===== Install guide (PWA "Add to Home Screen") ===== */
.ig-intro { font-size: 13px; color: var(--text-2); line-height: 1.55; margin: -2px 0 2px; }
.ig-cta {
  display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%;
  padding: 12px 16px; min-height: 46px; border-radius: var(--radius-sm); border: 1px solid transparent;
  background: var(--accent); color:var(--text-on-accent,#fff); font-size: 14px; font-weight: 700; font-family: var(--font);
  cursor: pointer; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; box-shadow: 0 6px 18px rgba(229,50,43,0.30);
}
.ig-cta:hover { background: var(--accent-strong); box-shadow: 0 8px 22px rgba(229,50,43,0.38); }
.ig-cta svg { width: 18px; height: 18px; }
.ig-cta-or { text-align: center; font-size: 11px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--text-3); margin: 4px 0 2px; }
.ig-tabs { display: flex; gap: 4px; background: var(--surface-2); border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: 4px; }
.ig-tab {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 9px 8px; min-height: 44px; border-radius: var(--radius-md); border: none; background: transparent;
  color: var(--text-2); font-size: 12.5px; font-weight: 600; font-family: var(--font);
  cursor: pointer; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; white-space: nowrap;
}
.ig-tab svg { width: 15px; height: 15px; flex-shrink: 0; }
.ig-tab:hover { color: var(--text); }
.ig-tab.active { background: var(--glass-strong); color: var(--accent); box-shadow: var(--shadow-sm); }
.ig-steps { display: flex; flex-direction: column; gap: 10px; }
.ig-panel-head { font-size: 13px; font-weight: 700; color: var(--text); display: flex; align-items: center; gap: 8px; }
.ig-panel-head svg { width: 16px; height: 16px; color: var(--accent); flex-shrink: 0; }
.ig-step { display: flex; align-items: flex-start; gap: 11px; }
.ig-step-n {
  flex-shrink: 0; width: 24px; height: 24px; border-radius: 50%; display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent); font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums;
}
.ig-step-t { font-size: 13px; color: var(--text-2); line-height: 1.5; padding-top: 2px; }
.ig-step-t b { color: var(--text); font-weight: 600; }
.ig-share-ic, .ig-inline-ic { display: inline-flex; align-items: center; vertical-align: -3px; color: var(--accent); }
.ig-share-ic svg, .ig-inline-ic svg { width: 15px; height: 15px; }
/* run6 W5a: surface props deleted — markup now ships `ig-note g-solid-2` (js/app.js); it renders
   inside the glass-4 install modal, so solid. */
.ig-note { font-size: 12px; line-height: 1.5; padding: 9px 11px; }
.ig-note.g-solid-2 { color: var(--text-3); }   /* muted note tone re-pinned at (0,2,0): .g-solid-2 sets color:var(--g-text) later at (0,1,0) */
.ig-installed { display: flex; align-items: center; gap: 9px; padding: 11px 13px; border-radius: var(--radius-sm); background: var(--green-bg); border: 1px solid var(--hairline); color: var(--green); font-size: 13px; font-weight: 600; }
.ig-installed svg { width: 17px; height: 17px; flex-shrink: 0; }
@media (max-width: 480px){
  .ig-tab { font-size: 12px; padding: 9px 6px; }
  .ig-tab svg { width: 14px; height: 14px; }
}

/* Empty / banner */
.empty { text-align: center; padding: 60px 20px; color: var(--text-3); }
.empty svg { width: 40px; height: 40px; margin-bottom: 12px; opacity: .5; }
.empty h4 { font-size: 15px; color: var(--text-2); font-weight: 600; margin-bottom: 4px; }
.empty p { font-size: 13px; }

.demo-banner {
  display: flex; align-items: center; gap: 10px; margin: 0 18px 0; padding: 9px 14px;
  background: var(--accent-softer); border: 1px solid var(--accent-soft); border-radius: var(--radius-sm);
  font-size: 12.5px; color: var(--accent-strong); font-weight: 500; margin-top: 12px;
}
.demo-banner svg { width: 16px; height: 16px; flex-shrink: 0; }
.viewas-bar {
  display: flex; align-items: center; gap: 10px; margin: 12px 18px 0; padding: 9px 14px;
  background: var(--accent); border-radius: var(--radius-sm); box-shadow: var(--shadow-sm);
  font-size: 13px; color:var(--text-on-accent,#fff); font-weight: 600;
}
.viewas-bar svg { width: 16px; height: 16px; flex-shrink: 0; }
.viewas-bar span { flex: 1; min-width: 0; }
.viewas-bar b { font-weight: 800; }
/* V733-N1 — the plate rule applies to LITERAL plates too, not just `--X-bg` tokens.
   This button shipped `background:#fff; color:var(--accent)`. A hard-coded plate has no
   theme dimension, but its INK does, so the pair silently inverts wherever a theme's
   accent goes light: cobalt is `--g-accent:#ffffff` (themes.css:2043) → white on white,
   1.00:1, pixel-arbitrated at 1.099 over the whole 145x27 button. 13 of 24 blocks failed
   — EVERY dark theme (halo 1.089, ink 1.204, ledger 1.241 … aurora 3.366). That is not
   cosmetic: this is the only exit from View-as, it renders on every module for the whole
   impersonation session (js/app.js:2122), so an admin in a dark theme could not see the
   way out. Lowering alpha could never have fixed it — see the plate rule in
   css/legacy-bridge.css:63-84.
   THE FIX is the sibling's own invariant, inverted. `.viewas-bar` above is
   `--accent` plate / `--text-on-accent` ink and measures 0/24, min 5.61. This button sits
   ON that bar, so it swaps the two: plate `--text-on-accent`, ink `--accent`. Both numbers
   the button needs then collapse onto that SAME guaranteed pair — label-vs-plate AND
   plate-vs-bar are both cr(--accent, --text-on-accent) = 0/24 fail, min 5.608
   (aurora/dark), max 18.04. It is the designed invariant, not an accident of where some
   neutral happens to land: `--g-text-on-accent` exists precisely to read against
   `--g-accent`, and it is defined in all 12 themes x light/dark plus the glass.css base.
   Do NOT "simplify" this to a neutral surface token. `--surface` (=`--g-fill-sunken`) is
   TRANSLUCENT and composites over the accent bar, not the page: measured 7/24 fail, min
   1.976. And a bare `--accent` plate (ghost button) reads 1.00 against the bar in 24/24 —
   the label passes but the affordance disappears.
   `#fff` stays as the var() fallback only, matching `.viewas-bar` above; the legacy
   no-stylesheet definitions at :84 / :224 already set --text-on-accent to #ffffff. */
.viewas-bar-exit {
  display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0; padding: 6px 13px;
  border: 0; border-radius: var(--radius-pill); background: var(--text-on-accent, #fff); color: var(--accent);
  font-family: var(--font); font-size: 12.5px; font-weight: 700; cursor: pointer;
}
.viewas-bar-exit svg { width: 14px; height: 14px; }
.demo-banner b { font-weight: 700; }
.demo-banner button { margin-left: auto; font-size: 12px; font-weight: 700; color: var(--accent); background: none; border: none; cursor: pointer; font-family: var(--font); padding: 4px 8px; border-radius: var(--radius-sm); }
.demo-banner button:hover { background: var(--accent-soft); }

/* Toast */
.toasts { position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%); z-index: 2000; display: flex; flex-direction: column; gap: 8px; align-items: center; }
@media (max-width: 860px){ .toasts { bottom: calc(var(--tabbar-h, 60px) + var(--safe-bottom, 0px) + 16px); } }
/* D2 (v812) CONNECTION STATUS BAR - #netBar (painted by renderNetBar in js/app.js from
   Store.netStatus()). Bottom-LEFT and non-blocking: the header actions live at the top of the shell,
   and the toast lane + the session-expired banner own the bottom CENTRE, so this can never cover any
   of them. It sits ABOVE the toast lane in both lanes (>860px: toasts end ~62px up, this starts at
   74px; <=860px: toasts end ~112px up, this starts at 128px), so a toast can never land on top of it.
   --netbar-left-clear is written by renderNetBar from the MEASURED sidebar: this is a body-level fixed
   element, so CSS cannot see a sidebar whose width changes when it collapses, and at 1440 the bar was
   measured sitting on top of .sb-user and .sb-viewas-btn. Zero whenever the sidebar is position:fixed
   (the phone drawer), so the full-width phone lane is untouched.
   Tokens only, so it flips with the theme like every other surface. --border has no :root definition
   in this file - the fallback is the house idiom (see .pp-kbtn, .dv-ana-tbl). */
.netbar { position: fixed; z-index: 1250; display: flex; align-items: center; gap: 9px;
  left: calc(var(--netbar-left-clear, 0px) + var(--safe-left) + 12px); bottom: calc(var(--safe-bottom) + 74px);
  max-width: min(460px, calc(100vw - 24px));
  padding: 9px 11px; border-radius: var(--radius-md);
  background: var(--card); border: 1px solid var(--border, rgba(127,127,127,.22));
  box-shadow: var(--shadow-lg); color: var(--text);
  font-family: var(--font); font-size: var(--fs-small); font-weight: var(--fw-medium); line-height: 1.45; }
.netbar[hidden] { display: none; }
.netbar-dot { flex: 0 0 auto; width: 8px; height: 8px; border-radius: var(--radius-pill); background: var(--text-3); }
.netbar-msg { flex: 1 1 auto; min-width: 0; }
.netbar-btn { flex: 0 0 auto; min-height: var(--ctl-sm); padding: 4px 10px; cursor: pointer;
  border: 1px solid var(--border, rgba(127,127,127,.22)); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text); white-space: nowrap;
  font-family: var(--font); font-size: var(--fs-small); font-weight: var(--fw-semi); }
.netbar-btn:hover { background: var(--row-hover); }
.netbar[data-state="offline"] .netbar-dot,
.netbar[data-state="pending"] .netbar-dot { background: var(--amber); }
.netbar[data-state="syncing"] .netbar-dot { background: var(--blue); }
.netbar[data-state="synced"]  .netbar-dot { background: var(--green); }
.netbar[data-state="refused"] .netbar-dot { background: var(--red); }
/* Phones: full-width strip, held above BOTH the floating tab bar and the toast lane. */
@media (max-width: 860px){
  .netbar { left: calc(var(--netbar-left-clear, 0px) + var(--safe-left) + 12px); right: calc(var(--safe-right) + 12px); max-width: none;
    bottom: calc(var(--tabbar-h, 60px) + var(--safe-bottom, 0px) + 72px); }
}
.toast { background: var(--toast-bg); color: var(--toast-text); padding: 10px 18px; border-radius: var(--radius-sm); font-size: 13px; font-weight: 500; box-shadow: var(--shadow-lg); display: flex; align-items: center; gap: 9px; animation: toastIn var(--dur-3) cubic-bezier(.2,.8,.2,1); }
/* in-app notification banner — guaranteed-visible layer (works without OS permission) */
.ian-wrap { position: fixed; top: calc(12px + var(--safe-top)); right: 12px; left: 12px; z-index: 3000; display: flex; flex-direction: column; gap: 8px; pointer-events: none; }
@media (min-width: 560px) { .ian-wrap { left: auto; width: 400px; } }
/* run6 W5c: surface → .glass-3 in the banner builder (js/app.js); the hand-animated `.in`
   enter (translateY/opacity) stays — only surface props moved */
.ian { pointer-events: auto; display: flex; align-items: center; gap: 11px; padding: 12px 13px; cursor: pointer; transform: translateY(-18px); opacity: 0; transition: transform var(--dur-3) cubic-bezier(.2,.8,.2,1), opacity var(--dur-3) ease; }
.ian.in { transform: translateY(0); opacity: 1; }
.ian-ic { display: grid; place-items: center; width: 34px; height: 34px; border-radius: var(--radius-md); background: var(--accent); color:var(--text-on-accent,#fff); flex-shrink: 0; }
.ian-ic svg { width: 18px; height: 18px; }
.ian-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.ian-tx b { font-size: 14px; font-weight: 700; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ian-tx small { font-size: 12.5px; color: var(--text-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ian-x { flex-shrink: 0; width: 26px; height: 26px; display: grid; place-items: center; border: none; background: transparent; color: var(--text-3); cursor: pointer; border-radius: var(--radius-sm); }
.ian-x:hover { background: var(--surface); color: var(--text); }
.ian-x svg { width: 14px; height: 14px; }
/* Integrations embedded in the Profile modal — single column to fit the narrower modal */
#pfIntegrations .ig-grid { grid-template-columns: 1fr !important; }
#pfIntegrations .ig-card { min-width: 0; }
.pf-integrations { margin-top: 4px; }
.toast svg { width: 16px; height: 16px; color: var(--green); flex: none; }
/* typed toasts — failures must NOT read as success (green check). */
.toast-error { background: var(--toast-error-bg, #C81E18); color: #fff; }
.toast-error svg { color: #fff; }
.toast-info svg { color: var(--slate); }
@keyframes toastIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }

/* ===== Magic-link login overlay (Supabase mode only) ===== */
/* Payment-portal re-auth gate (owner msg#31) */
.paygate-wrap { display: grid; place-items: center; min-height: 60vh; padding: 24px; }
/* run6 W5a: surface props deleted — markup now ships `paygate-card glass-4` (js/app.js). Bespoke
   28/26px padding kept instead of .g-pad (deliberately roomier than the 20px token). */
.paygate-card { width: 100%; max-width: 380px; padding: 28px 26px; text-align: center; }
.paygate-ic { width: 52px; height: 52px; margin: 0 auto 14px; border-radius: var(--radius-md); display: grid; place-items: center; background: var(--accent-soft); color: var(--accent); }
.paygate-ic svg { width: 26px; height: 26px; }
.paygate-h { font-size: 20px; font-weight: 800; margin: 0 0 6px; color: var(--text); }
.paygate-sub { font-size: 13.5px; color: var(--text-2); margin: 0 0 18px; line-height: 1.5; }
.paygate-pw { width: 100%; padding: 12px 14px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--bg-solid); color: var(--text); font: inherit; font-size: 15px; outline: none; }
.paygate-pw:focus { border-color: var(--accent); }
.paygate-err { color: var(--accent); font-size: 12.5px; min-height: 16px; margin: 8px 0 2px; font-weight: 600; }
.paygate-form { display: contents; }
/* hidden username field — present for password-manager credential association + a11y, but
   off-screen (NOT display:none, so managers still detect it). */
.paygate-user-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.paygate-btn { width: 100%; justify-content: center; margin-top: 6px; }
.paygate-cancel { display: block; width: 100%; margin-top: 10px; background: none; border: none; color: var(--text-3); font: inherit; font-size: 13px; cursor: pointer; padding: 6px; }
.paygate-cancel:hover { color: var(--text-2); }
.login-screen {
  position: fixed; inset: 0; z-index: 3000; display: grid; place-items: center;
  padding: 24px; padding-top: calc(24px + var(--safe-top)); padding-bottom: calc(24px + var(--safe-bottom));
  /* Themed ground (run5, v695) — was the legacy --bg-grad-* gradient, which left
     a light-gray canvas under dark glass cards (auto-dark) and under chromatic
     themes like Cobalt. Must mirror body's ground exactly. */
  background-color: var(--g-canvas, var(--bg-grad-1));
  background-image: var(--g-mesh, none);
  background-size: cover;
  animation: loginFade var(--dur-3) ease;
}
.login-screen[hidden] { display: none; }
@keyframes loginFade { from { opacity: 0; } to { opacity: 1; } }
.login-card {
  width: min(380px, 100vw - 48px); max-width: 100%; padding: 28px 26px 22px;
  /* run6 W5a: surface props deleted — glass-4 now lives in the STATIC markup (no pre-boot flash),
     and the runtime classList.add('glass-4') patch in js/app.js is retired. The leftover bespoke
     border was double-framing the card (glass edges are box-shadow, not border). */
}
.login-brand { display: flex; align-items: center; gap: 13px; margin-bottom: 22px; }
.login-logo {
  width: 52px; height: 52px; flex-shrink: 0; border-radius: var(--radius-md); overflow: hidden;
  background: #0b0b0e; box-shadow: var(--shadow-sm), inset 0 0 0 1px rgba(255,255,255,0.06); position: relative;
  display: flex; align-items: center; justify-content: center;
}
.login-logo svg { width: 72%; height: 72%; display: block; }
.login-logo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; object-position: center; padding: 7px; background: transparent; image-rendering: -webkit-optimize-contrast; }
.login-titles h1 { font-family: var(--font-display, var(--font)); font-size: 19px; font-weight: 800; letter-spacing: -0.5px; line-height: 1.1; }
.login-titles p { font-size: 13px; color: var(--text-3); font-weight: 500; margin-top: 2px; }
.login-revoked { background: color-mix(in srgb, var(--red) 12%, transparent); border: 1px solid color-mix(in srgb, var(--red) 35%, transparent); color: var(--red); border-radius: var(--radius-sm); padding: 11px 13px; font-size: 12.5px; line-height: 1.45; margin: 0 0 14px; }
/* Branded boot loader — covers the empty shell during the first Supabase hydrate so a fresh load never flashes blank. */
.boot-load { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; background: var(--bg-solid); animation: bootFade var(--dur-2) ease; }
.boot-load-inner { display: flex; flex-direction: column; align-items: center; gap: 20px; }
.boot-load-logo { width: 46px; height: 46px; display: grid; place-items: center; overflow: hidden; }
.boot-load-logo > *, .boot-load-logo svg, .boot-load-logo img { width: 46px !important; height: 46px !important; max-width: 46px; max-height: 46px; }
.boot-load-bar { width: 116px; height: 3px; border-radius: 3px; background: var(--hairline); overflow: hidden; }
.boot-load-bar span { display: block; width: 38%; height: 100%; border-radius: var(--radius-xs); background: var(--accent); animation: bootSlide 1.05s cubic-bezier(.4,0,.2,1) infinite; }
@keyframes bootSlide { 0% { transform: translateX(-110%); } 100% { transform: translateX(330%); } }
@keyframes bootFade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce){ .boot-load-bar span { animation: none; width: 100%; opacity: .6; } .boot-load { animation: none; } }
.login-revoked b { font-weight: 700; }
.login-form { display: flex; flex-direction: column; gap: 9px; }
.login-label { font-size: 12px; font-weight: 600; color: var(--text-3); }
.login-input {
  padding: 12px 13px; border-radius: var(--radius-sm); border: 1px solid var(--hairline);
  background: var(--surface); color: var(--text); font-size: 14.5px; font-family: var(--font);
  outline: none; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; width: 100%; min-height: 44px;
}
.login-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-softer); background: var(--glass-strong); }
.login-btn {
  margin-top: 4px; padding: 12px 16px; min-height: 44px; border-radius: var(--radius-sm); border: 1px solid transparent;
  background: var(--accent); color:var(--text-on-accent,#fff); font-size: 14px; font-weight: 700; font-family: var(--font);
  cursor: pointer; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; box-shadow: 0 6px 18px rgba(229,50,43,0.30);
}
.login-btn:hover:not(:disabled) { background: var(--accent-strong); box-shadow: 0 8px 22px rgba(229,50,43,0.38); }
.login-btn:disabled { opacity: .6; cursor: default; transform: none; box-shadow: none; }
.login-status { font-size: 13px; line-height: 1.45; color: var(--text-2); min-height: 1px; margin-top: 2px; }
.login-status.ok { color: var(--green, #34c759); font-weight: 600; }
.login-status.err { color: var(--red, #ff3b30); font-weight: 600; }
.login-forgot { align-self: center; margin-top: -2px; background: none; border: none; color: var(--text-3); font-size: 12.5px; font-weight: 600; cursor: pointer; padding: 5px 8px; border-radius: var(--radius-sm); min-height: 32px; }
.login-forgot:hover { color: var(--accent); text-decoration: underline; }
.login-forgot:disabled { opacity: .5; cursor: default; text-decoration: none; }
/* run7 W4: `.login-resend` (+ :hover) deleted — DEAD. Zero hits app-wide. The login card's only
   secondary action in the markup is `.login-forgot` (directly above, live); the resend-code button
   this skinned was never built. Public signup was removed by owner decision 2026-07-14 #4
   (invite-only), which is the same corner of the flow. */
.login-foot { margin-top: 18px; font-size: 11.5px; line-height: 1.5; color: var(--text-3); text-align: center; }
@media (max-width: 480px) { .login-card { padding: 24px 20px 20px; border-radius: var(--radius-lg); } .login-input { font-size: 16px; } }
/* password setup polish */
.setup-email { display: flex; align-items: center; gap: 7px; font-size: 13px; color: var(--text-2); background: var(--surface, rgba(127,127,127,.06)); border: 1px solid var(--hairline); border-radius: var(--radius-md); padding: 9px 12px; margin: 0 0 16px; }
.setup-email svg { width: 14px; height: 14px; color: var(--green); flex: 0 0 auto; } .setup-email b { color: var(--text); word-break: break-all; }
.setup-pwwrap { position: relative; }
.setup-pwwrap .login-input { padding-right: 44px; width: 100%; box-sizing: border-box; }
.setup-pweye { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); width: 30px; height: 30px; border: none; background: transparent; color: var(--text-3); cursor: pointer; display: grid; place-items: center; border-radius: var(--radius-sm); }
.setup-pweye svg { width: 17px; height: 17px; } .setup-pweye.on { color: var(--accent, #e5322b); }
.setup-strength { display: flex; align-items: center; gap: 4px; margin: 8px 0 4px; }
.setup-strength i { height: 4px; flex: 1; border-radius: 2px; background: var(--hairline-strong, rgba(127,127,127,.25)); transition: background var(--dur-2); }
.setup-strength span { font-size: 11px; font-weight: 600; margin-left: 6px; min-width: 42px; color: var(--text-3); }

/* Sidebar sign-out row (Supabase mode only) */
.sb-signout {
  display: flex; align-items: center; gap: 9px; width: 100%; margin-top: 8px;
  padding: 9px 11px; min-height: 40px; border-radius: var(--radius-md); border: 1px solid var(--hairline);
  background: var(--surface); color: var(--text-2); font-family: var(--font);
  font-size: 13px; font-weight: 600; cursor: pointer; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease;
}
.sb-signout:hover { background: var(--glass-strong); color: var(--text); }
/* dismissible Install-app row: the button + a small × to make it go away */
.sb-install-row { display: flex; align-items: center; gap: 6px; margin-top: 8px; }
.sb-install-row .sb-install { margin-top: 0; flex: 1; }
.sb-install-x { flex-shrink: 0; display: grid; place-items: center; width: 40px; min-height: 40px; border-radius: var(--radius-md); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-3); cursor: pointer; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; }
.sb-install-x svg { width: 15px; height: 15px; }
.sb-install-x:hover { background: var(--red-bg); color: var(--red); border-color: var(--red-bg); }
.sb-signout svg { width: 16px; height: 16px; flex-shrink: 0; }

/* Account-setup retry state (brand-new signup race) */
.acct-setup { display: grid; place-items: center; min-height: 60vh; padding: 24px; text-align: center; }
.acct-setup-card {
  max-width: 360px; padding: 26px 24px;
  /* run6 W5a: surface props deleted — markup now ships `acct-setup-card glass-4` (js/app.js),
     matching the login card's tier. */
}
.acct-setup h3 { font-size: 16px; font-weight: 700; margin-bottom: 6px; }
.acct-setup p { font-size: 13px; color: var(--text-3); line-height: 1.5; margin-bottom: 16px; }

/* scrollbars */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--scroll-thumb); border-radius: var(--radius-md); border: 2px solid transparent; background-clip: padding-box; }
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); background-clip: padding-box; }
::-webkit-scrollbar-track { background: transparent; }
* { scrollbar-color: var(--scroll-thumb) transparent; }
/* global placeholder + focus-ring consistency in both themes */
::placeholder { color: var(--placeholder); opacity: 1; }
input:focus-visible, select:focus-visible, textarea:focus-visible, button:focus-visible, [contenteditable]:focus-visible { outline: 2px solid transparent; }

/* Inline cell editing */
.cell-edit { cursor: pointer; border-radius: var(--radius-sm); transition: background var(--dur-1) ease; }
.cell-edit:hover { background: var(--row-hover); box-shadow: inset 0 0 0 1px var(--hairline); }
.cell-add { color: var(--text-3); font-size: 12px; font-weight: 500; opacity: 0; transition: opacity var(--dur-1) ease; }
.trow:hover .cell-add { opacity: 1; }
.cell-inline-input {
  width: 100%; padding: 5px 8px; border-radius: var(--radius-sm); border: 1px solid var(--accent);
  background: var(--glass-strong); color: var(--text); font-size: 13px; font-family: var(--font);
  outline: none; box-shadow: 0 0 0 3px var(--accent-softer);
}
.cell-inline-input.addnew { border-color: var(--accent); }
.cell-inline-input.inline-rename { padding: 3px 7px; font-weight: 500; max-width: 100%; }
.add-row.editing { padding: 6px 14px; }

/* row quick-action kebab (hover on desktop, always-tappable on touch) */
.col-prio { display: inline-flex; align-items: center; gap: 6px; }
.row-kebab { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: var(--radius-xs); color: var(--text-3); cursor: pointer; opacity: 0; transition: opacity var(--dur-1) ease, color var(--dur-1) ease, background var(--dur-1) ease; flex-shrink: 0; }
.row-kebab .kb-ic { width: 14px; height: 14px; }
.trow:hover .row-kebab, .ptable tbody tr:hover .row-kebab { opacity: .55; }
.row-kebab:hover { opacity: 1 !important; color: var(--accent); background: var(--surface); }
.p-kebab-cell { width: 34px; text-align: center; padding-left: 0 !important; padding-right: 6px !important; }
/* Always-visible kebab is a TOUCH AFFORDANCE (there is no hover to reveal it), not a tap
   target — so it stays on the capability-only query and does NOT join the ORCH-1 union.
   A narrow desktop window still has hover, so it still reveals the kebab the normal way. */
@media (hover: none) and (pointer: coarse) { .row-kebab { opacity: .55; } }
/* ORCH-1 union — the Ads-Manager controls govern LIVE ad spend, so they get a real target on a
   narrow desktop window as well as on a phone/tablet. Floors only; strictly widening. */
@media (max-width: 720px), (hover: none) and (pointer: coarse) {
  .adsv-mbtn { min-height: 44px; }
  .adsv-metalink { min-height: 32px; }
  .adsm-segb { min-height: 40px; padding-top: 10px; padding-bottom: 10px; }
}
.row-menu .menu-item svg { width: 15px; height: 15px; }
/* touch stage-picker sheet (mobile pipeline move) */
.stage-pick { display: flex; flex-direction: column; gap: 8px; }
.stage-pick-btn { display: flex; align-items: center; gap: 10px; width: 100%; text-align: left; font-family: var(--font); font-size: 15px; font-weight: 600; color: var(--text); background: var(--surface, rgba(127,127,127,.04)); border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: 14px 16px; min-height: 52px; cursor: pointer; transition: border-color var(--dur-1), background var(--dur-1); }
.stage-pick-btn:hover { border-color: var(--accent); }
.stage-pick-btn.on { border-color: var(--accent); background: var(--accent-softer); }
.stage-pick-btn .pipe-col-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.stage-pick-btn b { flex: 1; font-weight: 600; }
.stage-pick-cur { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--accent); }

/* drag handle + list drag-and-drop */
.row-grip { position: absolute; left: 0; top: 0; bottom: 0; width: 18px; display: grid; place-items: center; color: var(--text-3); opacity: 0; cursor: grab; }
.trow:hover .row-grip { opacity: .5; }
.row-grip:hover { opacity: 1; }
.row-grip:active { cursor: grabbing; }
.row-grip svg { width: 13px; height: 13px; }
.trow.thead .row-grip { display: none; }
/* v548 — pointer-drag "lift": the picked-up row pops with scale + shadow (existing tokens) */
.trow.row-dragging { opacity: .92; transform: scale(1.012); box-shadow: var(--shadow-lg); z-index: 6; cursor: grabbing; user-select: none; }
/* dropping onto a whole group (its header or empty body) re-buckets the task there */
.group.is-droptarget > .table-card { box-shadow: inset 0 0 0 2px var(--accent); border-radius: var(--radius-md); }
.group.is-droptarget > .group-head { background: var(--accent-softer); border-radius: var(--radius-sm); }
/* bulk-select checkbox — replaces the grip hint on hover / when selected */
.trow-grip-ic { display: inline-grid; place-items: center; }
.trow-sel { display: none; width: 16px; height: 16px; align-items: center; justify-content: center; border: 1.5px solid var(--hairline-strong, var(--text-3)); border-radius: var(--radius-xs); background: transparent; cursor: pointer; padding: 0; color: transparent; }
.trow-sel svg { width: 11px; height: 11px; }
.trow:hover .trow-grip-ic, .trow.is-sel .trow-grip-ic { display: none; }
.trow:hover .row-grip, .trow.is-sel .row-grip { opacity: 1; }
.trow:hover .trow-sel, .trow.is-sel .trow-sel { display: inline-flex; }
.trow-sel.on { background: var(--accent); border-color: var(--accent); color:var(--text-on-accent,#fff); }
.trow.is-sel { background: var(--accent-softer); }
/* floating bulk-action bar */
/* z 1150, not 1200: SIM-06's popover scrim parks itself one below the LOWEST open menu (1200), so at
   1200 the bulk bar was the one control an outside tap could still hit through it. Nothing else lives
   between 1000 (modal backdrop) and 1200, so this changes no other stacking relationship. */
.bulk-bar { position: fixed; left: 50%; transform: translateX(-50%); bottom: 22px; z-index: 1150; display: flex; align-items: center; gap: 8px; background: var(--toast-bg, #1c1c1e); color: var(--toast-text, #fff); padding: 8px 10px 8px 16px; border-radius: var(--radius-md); box-shadow: var(--shadow-lg); animation: toastIn var(--dur-3) cubic-bezier(.2,.8,.2,1); }
.bulk-n { font-size: 13px; font-weight: 700; margin-right: 4px; white-space: nowrap; }
.bulk-btn { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font); font-size: 12.5px; font-weight: 600; color: inherit; background: rgba(255,255,255,.1); border: none; border-radius: var(--radius-sm); padding: 7px 11px; cursor: pointer; white-space: nowrap; }
.bulk-btn:hover { background: rgba(255,255,255,.2); }
.bulk-btn svg { width: 14px; height: 14px; }
.bulk-del:hover { background: var(--red, #e5322b); }
@media (max-width: 520px){ .bulk-bar { left: 12px; right: 12px; transform: none; flex-wrap: wrap; justify-content: center; } }
.trow.row-dropbefore { box-shadow: inset 0 2px 0 0 var(--accent); }
.trow.row-dropchild { background: var(--accent-soft); box-shadow: inset 3px 0 0 0 var(--accent); }

/* flat sidebar nav */
.sb-nav-flat { padding-top: 8px; }
.sb-nav-flat .sb-list { font-size: 14px; padding: 10px 11px; margin: 1px 0; }
/* clean breadcrumb — drop the space label, keep the list name */
.crumb-space, .crumb-sep { display: none; }

/* partner table: clickable cells, sortable headers, drag-reorder */
.ptable td.cell-edit { cursor: pointer; }
.ptable tbody tr:hover td.cell-edit:hover { box-shadow: inset 0 0 0 1px var(--accent); border-radius: var(--radius-xs); }
.ptable .menu-add, .menu .menu-add { color: var(--accent); font-weight: 600; border-top: 1px solid var(--hairline); margin-top: 3px; }
.ptable .menu-add svg, .menu .menu-add svg { width: 14px; height: 14px; }
.th-sort { cursor: pointer; user-select: none; }
.th-sort:hover { color: var(--text); }
.th-draggable[draggable="true"] { cursor: grab; }
.th-draggable.col-dragging { opacity: .45; }
.th-draggable.col-drop { box-shadow: inset 2px 0 0 0 var(--accent); background: var(--accent-soft); }
.sort-arr { margin-left: 4px; color: var(--accent); font-size: 11px; }
.p-name .pgrip { position: static; opacity: 0; width: 16px; margin-right: -4px; }
.ptable tbody tr:hover .pgrip { opacity: .45; }
/* partner bulk-select checkbox — reuse the .trow-sel/.trow-grip-ic toggle for the partner table */
.ptable tbody tr:hover .trow-grip-ic, .ptable tbody tr.is-sel .trow-grip-ic { display: none; }
.ptable tbody tr:hover .trow-sel, .ptable tbody tr.is-sel .trow-sel { display: inline-flex; }
.ptable tbody tr:hover .pgrip, .ptable tbody tr.is-sel .pgrip { opacity: 1; }
.ptable tbody tr.is-sel { background: var(--accent-softer); }
.ptable tbody tr.row-dragging { opacity: .4; }
.ptable tbody tr.row-dropbefore td { box-shadow: inset 0 2px 0 0 var(--accent); }
.ptable td.cell-edit .cell-add { opacity: 0; transition: opacity var(--dur-1) ease; }
.ptable tbody tr:hover td.cell-edit .cell-add { opacity: 1; }
/* custom columns + add-field control */
.th-custom { position: relative; }
.th-custom .cf-del, .fl .cf-del { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; margin-left: 5px; border-radius: var(--radius-xs); color: var(--text-3); cursor: pointer; opacity: 0; vertical-align: middle; transition: opacity var(--dur-1) ease, color var(--dur-1) ease, background var(--dur-1) ease; }
.th-custom .cf-del svg, .fl .cf-del svg { width: 11px; height: 11px; }
.th-custom:hover .cf-del, .fl:hover .cf-del { opacity: .55; }
.th-custom .cf-del:hover, .fl .cf-del:hover { opacity: 1; color: var(--red); background: var(--surface); }
.th-addfield { width: 1%; }
.addfield-btn { display: inline-flex; align-items: center; gap: 5px; padding: 5px 10px; border-radius: var(--radius-sm); border: 1px dashed var(--hairline); background: transparent; color: var(--text-2); font-size: 11px; font-weight: 700; text-transform: none; letter-spacing: 0; cursor: pointer; font-family: var(--font); white-space: nowrap; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; }
.addfield-btn:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-softer); }
.addfield-btn svg { width: 13px; height: 13px; }
/* custom-FIELD kebab (rename/delete a whole column/field) */
.th-custom .cf-kebab, .fl .cf-kebab, .th-sort .cf-kebab { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; margin-left: 4px; border-radius: var(--radius-xs); color: var(--text-3); cursor: pointer; opacity: 0; vertical-align: middle; transition: opacity var(--dur-1) ease, color var(--dur-1) ease, background var(--dur-1) ease; }
.th-custom .cf-kebab .kb-ic, .fl .cf-kebab .kb-ic, .th-sort .cf-kebab .kb-ic { width: 13px; height: 13px; }
.th-custom:hover .cf-kebab, .fl:hover .cf-kebab, .th-sort:hover .cf-kebab { opacity: .5; }
.th-custom .cf-kebab:hover, .fl .cf-kebab:hover, .th-sort .cf-kebab:hover { opacity: 1; color: var(--accent); background: var(--surface); }
/* hide-column kebab on built-in MASTER TASK LIST headers (parity w/ partner table) */
.trow.thead .th .cf-kebab { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; margin-left: 4px; border-radius: var(--radius-xs); color: var(--text-3); cursor: pointer; opacity: 0; vertical-align: middle; transition: opacity var(--dur-1) ease, color var(--dur-1) ease, background var(--dur-1) ease; }
.trow.thead .th .cf-kebab .kb-ic { width: 13px; height: 13px; }
.trow.thead .th:hover .cf-kebab { opacity: .5; }
.trow.thead .th .cf-kebab:hover { opacity: 1; color: var(--accent); background: var(--surface); }
.fl { position: relative; }
/* per-OPTION kebab inside a picker menu + the kebab submenu */
.menu-item.has-kebab { padding-right: 30px; position: relative; }
.menu-item .mi-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.menu-item .opt-kebab { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: var(--radius-xs); color: var(--text-3); opacity: 0; transition: opacity var(--dur-1) ease, color var(--dur-1) ease, background var(--dur-1) ease; }
.menu-item:hover .opt-kebab { opacity: .6; }
.menu-item .opt-kebab:hover { opacity: 1; color: var(--text); background: var(--surface-2); }
.menu-item .opt-kebab .kb-ic { width: 14px; height: 14px; }
.opt-kebab-menu .menu-item { gap: 8px; }
.opt-kebab-menu .menu-item svg { width: 14px; height: 14px; }
/* editable option/status colors: swatch row inside the kebab menu */
.kebab-colors { display: grid; grid-template-columns: repeat(8, 20px); gap: 6px; padding: 8px 10px; justify-content: center; border-top: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline); }
.opt-kebab-menu { max-width: 230px; }
.kebab-sw { width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--surface); box-shadow: 0 0 0 1px var(--hairline); cursor: pointer; padding: 0; transition: transform var(--dur-1) ease; }
.kebab-sw:hover { transform: scale(1.18); box-shadow: 0 0 0 2px var(--accent); }
.menu-item.menu-danger { color: var(--red); }
.menu-item.menu-danger:hover { background: var(--accent-softer); }
/* stacked option inputs in the add-field modal */
.cf-optlist { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.cf-optrow { display: flex; align-items: center; gap: 6px; }
.cf-optrow .cf-opt-input { flex: 1; }
.cf-opt-x { flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: transparent; color: var(--text-3); cursor: pointer; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; }
.cf-opt-x:hover { color: var(--red); border-color: var(--red); }
.cf-opt-x svg { width: 13px; height: 13px; }
.cf-opt-add { margin-top: 2px; }
/* partner service-type sub-views */
.pviews { display: flex; gap: 2px; padding: 0 0 9px; overflow-x: auto; scrollbar-width: none; }
.pviews::-webkit-scrollbar { display: none; }
.pview { display: inline-flex; align-items: center; gap: 7px; padding: 6px 12px; border-radius: var(--radius-sm); font-size: 12.5px; font-weight: 600; color: var(--text-2); cursor: pointer; border: 1px solid transparent; background: transparent; white-space: nowrap; font-family: var(--font); transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; }
.pview:hover { background: var(--surface); color: var(--text); }
.pview.active { background: var(--glass-strong); color: var(--text); border-color: var(--hairline); box-shadow: var(--shadow-sm); }
.pview-ct { font-size: 11px; font-weight: 700; color: var(--text-3); background: var(--surface-2); border-radius: var(--radius-pill); padding: 1px 7px; min-width: 18px; text-align: center; }
.pview.active .pview-ct { color: var(--accent); }
/* unified view-chip parts (shared by partner status, partner service, task department rows) */
.tab-ct { font-size: 11px; font-weight: 700; color: var(--text-3); background: var(--surface-2); border-radius: var(--radius-pill); padding: 1px 7px; min-width: 18px; text-align: center; margin-left: 1px; }
.tab.active .tab-ct { color: var(--accent); }
.chip-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; display: inline-block; }
/* permanent-delete trash on a restore-menu row (user-created options only) */
.menu-restore-row { display: flex; align-items: center; gap: 1px; }
.menu-restore-row .mi-restore { flex: 1; }
.restore-purge { display: inline-grid; place-items: center; width: 28px; height: 28px; flex-shrink: 0; border: none; background: transparent; color: var(--text-3); border-radius: var(--radius-sm); cursor: pointer; margin-right: 4px; }
.restore-purge:hover { background: var(--accent-softer); color: var(--accent); }
.restore-purge svg { width: 14px; height: 14px; }
/* editable filters: the "+" manage button on the service/status filter rows + its menu */
.pfilter-edit { color: var(--text-3); flex-shrink: 0; padding: 7px 9px; }
.pfilter-edit:hover { color: var(--accent); }
.pfilter-edit svg { width: 15px; height: 15px; }
/* run7 W4: `.pfedit-check` (+ svg) and `.pfedit-row.is-off .mi-label` deleted — DEAD. Zero hits
   for either `pfedit-` name app-wide, and nothing builds a `pfedit-` class dynamically. The live
   half of this feature is `.pfilter-edit` directly above (the "+" manage button); its menu is
   rendered with the shared `.menu-item` / `.mi-label` primitives, never these bespoke rows. */
/* saved view pills (in the partner view row) */
.pview-saved { color: var(--accent); }
.pview-saved.active { background: var(--accent-soft); border-color: var(--accent-soft); color: var(--accent); }
/* run7 W4: `.pview-x` (+ :hover, + svg, + the coarse-pointer @media, + `.pview-saved:hover .pview-x`)
   deleted — DEAD. Zero hits for `pview-x` app-wide. The saved-view delete control that actually
   ships is `.view-chip-x` (js/app.js:1104 `data-act="delete-view"`, and 1664 `remove-filter`);
   `.pview-x` was its never-wired twin. `.pview-saved` / `.pview-edit` ARE live — js/app.js:6661
   injects `.pview-saved .pview-edit{opacity:.5}` at runtime — so both stay above. */
/* New View builder modal */
.nv-build { display: flex; flex-direction: column; gap: 6px; }
.nv-lbl { font-size: 11.5px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--text-3); margin-top: 8px; }
.nv-input { width: 100%; padding: 11px 13px; border-radius: var(--radius-md); border: 1px solid var(--hairline); background: var(--surface); color: var(--text); font-size: 14px; font-family: var(--font); }
.nv-input:focus { outline: none; border-color: var(--accent); }
.nv-fields { display: flex; flex-wrap: wrap; gap: 6px; }
.nv-fbtn { padding: 7px 13px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2); font-size: 13px; font-weight: 600; cursor: pointer; font-family: var(--font); }
.nv-fbtn.active { background: var(--accent); border-color: var(--accent); color:var(--text-on-accent,#fff); }
.nv-opts { display: flex; flex-direction: column; gap: 5px; max-height: 46vh; overflow-y: auto; }
.nv-opt { display: flex; align-items: center; gap: 9px; padding: 10px 12px; border-radius: var(--radius-md); border: 1px solid var(--hairline); background: var(--surface); color: var(--text); font-size: 14px; font-weight: 500; cursor: pointer; font-family: var(--font); text-align: left; }
.nv-opt.on { border-color: var(--accent); background: var(--accent-softer); }
.nv-opt .nv-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.nv-opt .nv-opt-l { flex: 1; }
.nv-opt svg { width: 16px; height: 16px; color: var(--accent); }
.nv-empty { padding: 14px; text-align: center; color: var(--text-3); font-size: 13px; }
.nv-sub { font-weight: 500; text-transform: none; letter-spacing: 0; color: var(--text-3); }
.nv-row { border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: 10px 11px; display: flex; flex-direction: column; gap: 7px; background: var(--surface-2); }
.nv-row-head { display: flex; align-items: center; justify-content: space-between; min-height: 18px; }
.nv-row-when { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text-3); }
.nv-row-x { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: none; background: transparent; color: var(--text-3); border-radius: var(--radius-xs); cursor: pointer; }
.nv-row-x:hover { background: var(--accent-softer); color: var(--accent); }
.nv-row-x svg { width: 14px; height: 14px; }
.nv-row .nv-opts { max-height: 28vh; }
.nv-addrow { display: inline-flex; align-items: center; gap: 6px; align-self: flex-start; margin-top: 2px; padding: 8px 12px; border-radius: var(--radius-sm); border: 1px dashed var(--hairline-strong); background: transparent; color: var(--text-2); font-size: 13px; font-weight: 600; cursor: pointer; font-family: var(--font); }
.nv-addrow:hover { border-color: var(--accent); color: var(--accent); }
.nv-addrow svg { width: 14px; height: 14px; }
/* ── PARTNERS VIEWS UNIFICATION P1 (.agents/v2/PARTNERS_VIEWS_SPEC.md) ──────────────────────
   The builder's per-row OPERATOR strip (is / is not / is empty). Reuses .nv-fields/.nv-fbtn so
   it inherits the existing sizing, focus ring, :active press and dark-mode treatment — the only
   new declarations are the ones that make it read as a second, quieter row than the field list. */
.nv-opsel { margin-top: -1px; }
.nv-opsel .nv-fbtn { padding: 6px 11px; font-size: 12.5px; -webkit-user-select: none; user-select: none; }
/* The panel's "+ Add field" (owner: "press + at the bottom of the panel, like under Funnel Link").
   .add-inline already carries the look; this only stops the label being text-selected mid-tap. */
.pf-addfield { -webkit-user-select: none; user-select: none; }
/* New-Partner modal: the custom-fields divider + its multi-select chips (reused .nv-opt). */
.mfield-sep { display: flex; align-items: center; gap: 7px; margin-top: 4px; padding-top: 12px; border-top: 1px solid var(--hairline); font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text-3); }
.mfield-sep svg { width: 14px; height: 14px; }
.npcf-ms { max-height: 30vh; }
.npcf-ms .nv-opt { -webkit-user-select: none; user-select: none; }
/* Touch targets — ORCH-1 union predicate (was coarse-pointer-only, which missed a narrow
   desktop window; see the ONE TAP-TARGET PREDICATE note at the top of this stylesheet).
   Scoped to THIS ship's new controls; the pre-existing .nv-fbtn/.nv-opt sizing is
   deliberately left alone rather than re-tuned from inside a views ship. */
@media (max-width: 720px), (hover: none) and (pointer: coarse) {
  .nv-opsel .nv-fbtn { min-height: 44px; }
  .pf-addfield { min-height: 44px; }
  .npcf-ms .nv-opt { min-height: 44px; }
}
.pview-edit { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; margin-left: 5px; border-radius: var(--radius-xs); color: var(--text-3); opacity: 0; cursor: pointer; vertical-align: middle; transition: opacity var(--dur-1) ease, color var(--dur-1) ease; }
.pview-saved:hover .pview-edit, .pview-saved.active .pview-edit { opacity: .5; }
.pview-edit:hover { opacity: 1 !important; color: var(--accent); }
.pview-edit svg { width: 12px; height: 12px; }
.picker-search { position: relative; padding: 8px 8px 6px; border-bottom: 1px solid var(--hairline); margin-bottom: 4px; }
.picker-search svg { position: absolute; left: 17px; top: 15px; width: 14px; height: 14px; color: var(--text-3); }
.picker-search input { width: 100%; padding: 7px 10px 7px 30px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface); color: var(--text); font-size: 13px; font-family: var(--font); outline: none; }
.picker-search input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-softer); }
.group.is-empty .group-head { opacity: .72; }
.group.is-empty .group-title { font-weight: 600; }

/* Payment Tracker */
/* Full-width on desktop — the payroll summary + team table span the content area;
   only the invoice card is constrained for readability (see .invoice-card). */
.pay-wrap { width: 100%; }
/* OB11-4 — Team Payroll's "no payments yet" state was the only empty state in the app that
   emitted its CTA OUTSIDE the centred wrapper. renderPersonalPay() (js/app.js) builds
   `<div class="pay-wrap">{back}{emptyState(...)}<button …>Add payment</button></div>`, i.e. the
   button is a SIBLING of .empty rather than emptyState()'s own `cta` argument. .empty centres
   its contents with `text-align:center`, which cannot reach a sibling, so the button landed
   hard-left under centred copy — on a phone it reads as an unrelated stray control.
   Auto margins alone do nothing here: .btn is `display:inline-flex`, and auto margins only
   centre a block-level box with a definite width. So: give it a block-level box (`display:flex`,
   which keeps the icon+label row intact) plus `width:fit-content`, and the auto margins bite.
   The element's inline `style="margin-top:14px"` is untouched — we set the inline axis only.
   Scope check (why this cannot leak): `.empty` is a direct child of `.pay-wrap` in exactly one
   render path — this one. The app's two other `data-act="add-payment"` buttons live inside
   `.pay-tabrow`, never as a sibling of `.empty`. Specificity (0,3,0). */
.pay-wrap > .empty + .btn { display: flex; width: fit-content; margin-left: auto; margin-right: auto; }
.pay-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-bottom: 22px; }
.cash-bar { margin: -6px 0 24px; }
.cash-bar-track { position: relative; height: 14px; border-radius: var(--radius-pill); overflow: hidden; background: var(--surface, rgba(127,127,127,.08)); }
.cash-bar-net { position: absolute; inset: 0; background: var(--green); border-radius: var(--radius-pill); }
.cash-bar-pay { position: absolute; left: 0; top: 0; bottom: 0; background: var(--amber); border-radius: var(--radius-pill) 0 0 999px; transition: width .4s cubic-bezier(.32,.72,0,1); }
.cash-bar-legend { display: flex; align-items: center; gap: 16px; margin-top: 9px; font-size: 12.5px; color: var(--text-2); flex-wrap: wrap; }
.cash-bar-legend .cb-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 5px; vertical-align: middle; }
.cash-bar-legend .cb-pay { background: var(--amber); } .cash-bar-legend .cb-net { background: var(--green); }
.cash-bar-legend .cb-mrr { margin-left: auto; color: var(--text-3); }
/* views + filter share one wrapping row so "+ Filter" sits beside "Save view" */
.viewfilter-row { display: flex; flex-wrap: wrap; align-items: center; gap: 7px 9px; margin-top: 4px; }
/* BUILD 2 · Partner segment grouping bar — its own row so it survives on mobile
   (the .viewfilter-row / filter chips are display:none on phones). Reuses .tabset/.tab. */
.psec-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.mainhead .psec-row { margin-top: 2px; padding-bottom: 2px; }
.psec-seg { display: flex; gap: 2px; overflow-x: auto; max-width: 100%; scrollbar-width: none; }
.psec-seg::-webkit-scrollbar { display: none; }
.viewfilter-row .views-bar, .viewfilter-row .filter-bar { margin: 0; }
/* iPhone — sit the Save-view / Filter chip row cleanly under the header controls:
   a hairline separator + comfortable spacing, no awkward drop, graceful wrap. */
@media (max-width: 720px) {
  .viewfilter-row {
    width: 100%; margin-top: 0; gap: 8px;
    padding: 11px 0 12px; row-gap: 8px;
    border-top: 1px solid var(--hairline);
  }
  .viewfilter-row .views-bar,
  .viewfilter-row .filter-bar { padding: 0; flex-wrap: wrap; }
}
/* run6 W5b: `.pay-card` base rule deleted — markup now ships `pay-card glass-2 g-pad`
   (js/app.js, all 34 sites); surface AND padding come from the primitives. The 14px phone
   padding below is bumped to .pay-card.g-pad so it still beats glass.css's later tie. */
/* AR aging report (Client Billing) — outstanding money bucketed by days overdue */
.ar-aging { margin: 0 0 22px; }
.ar-aging-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; color: var(--text-2); font-size: 13.5px; font-weight: 600; }
.ar-aging-head svg { width: 15px; height: 15px; opacity: .7; }
.ar-aging-head small { color: var(--text-3); font-weight: 400; font-size: 12px; }
.ar-aging-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
.ar-agecell { border: 1px solid var(--hairline); border-radius: var(--radius-md, 12px); padding: 13px 15px; background: var(--surface); }
.ar-age-lbl { font-size: 11.5px; font-weight: 600; color: var(--text-3); text-transform: uppercase; letter-spacing: .03em; }
.ar-age-amt { font-size: 20px; font-weight: 700; margin: 4px 0 2px; font-variant-numeric: tabular-nums; }
.ar-age-n { font-size: 11.5px; color: var(--text-3); }
.ar-agecell.ar-b0 .ar-age-amt { color: var(--text); }
.ar-agecell.ar-b30 .ar-age-amt { color: var(--amber, #e0900b); }
.ar-agecell.ar-b60 .ar-age-amt { color: var(--amber, #e0900b); }
.ar-agecell.ar-b90 { border-color: color-mix(in srgb, var(--red, #e5322b) 30%, var(--hairline)); }
.ar-agecell.ar-b90 .ar-age-amt { color: var(--red, #e5322b); }
.ar-agecell.ar-empty { opacity: .5; }
.ar-agecell.ar-empty .ar-age-amt { color: var(--text-3); }
@media (max-width: 640px){ .ar-aging-grid { grid-template-columns: repeat(2, 1fr); } .ar-aging-head small { display: none; } }
/* Collected-vs-expected MRR progress (Client Billing) */
.cvi { border: 1px solid var(--hairline); border-radius: var(--radius-md, 12px); padding: 15px 18px; margin: 0 0 22px; background: var(--surface); }
.cvi-top { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 9px; }
.cvi-lbl { font-size: 13px; font-weight: 600; color: var(--text-2); }
.cvi-pct { font-size: 19px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.cvi-pct small { font-size: 11.5px; font-weight: 500; color: var(--text-3); }
.cvi-bar { height: 8px; border-radius: var(--radius-xs); background: var(--hairline); overflow: hidden; }
.cvi-fill { height: 100%; border-radius: var(--radius-xs); background: var(--accent); transition: width .4s ease; }
.cvi.cvi-full .cvi-fill { background: var(--green, #1f9d57); }
.cvi.cvi-full .cvi-pct { color: var(--green, #1f9d57); }
.cvi-sub { font-size: 12px; color: var(--text-3); margin-top: 8px; }
.cvi-sub b { color: var(--amber, #e0900b); font-weight: 700; }
/* Agency Overview — admin P&L (BUILD 1) */
.apl-wrap { display: flex; flex-direction: column; gap: 26px; }
.apl-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.apl-head .apl-dl-row { margin-left: auto; display: flex; gap: 8px; flex-wrap: wrap; }
.apl-block { display: flex; flex-direction: column; gap: 14px; }
.apl-label { display: inline-flex; align-items: center; gap: 7px; font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--text-3); }
.apl-label svg { width: 14px; height: 14px; }
.apl-label.in { color: var(--green); }
.apl-label.out { color: var(--amber); }
.apl-cards2 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
/* run6 W5b: surface props deleted — markup now ships `apl-exp glass-2` (js/app.js, both sites).
   overflow:hidden kept (row/footer band clip). */
.apl-exp { overflow: hidden; }
.apl-exp-row { display: grid; grid-template-columns: 1fr auto auto; align-items: center; gap: 12px; padding: 12px 16px; border-bottom: 1px solid var(--hairline); }
.apl-exp-row:last-child { border-bottom: 0; }
.apl-exp-name { font-weight: 600; color: var(--text); }
.apl-exp-amt { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--text); white-space: nowrap; }
.apl-exp-acts { display: inline-flex; gap: 4px; }
.apl-exp-empty { padding: 16px; color: var(--text-3); font-size: 13px; line-height: 1.5; }
.apl-exp-foot { padding: 12px 16px; display: flex; align-items: center; gap: 12px; border-top: 1px solid var(--hairline); background: var(--surface-2, rgba(127,127,127,.03)); }
.apl-exp-foot .apl-subs-total { margin-left: auto; font-variant-numeric: tabular-nums; font-weight: 700; color: var(--amber); font-size: 13px; }
.apl-icon-btn { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2); cursor: pointer; transition: border-color var(--dur-1), color var(--dur-1); }
.apl-icon-btn:hover { border-color: var(--hairline-strong); color: var(--text); }
.apl-icon-btn svg { width: 15px; height: 15px; }
/* run6 W5b: surface + padding deleted — markup now ships `apl-net glass-2 g-pad` (js/app.js). */
.apl-net { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 28px; }
.apl-net-main { display: flex; flex-direction: column; gap: 5px; }
.apl-net-k { font-size: 12px; font-weight: 600; color: var(--text-3); }
.apl-net-v { font-size: 34px; font-weight: 800; letter-spacing: -.8px; font-variant-numeric: tabular-nums; line-height: 1; }
.apl-net-proj { margin-left: auto; text-align: right; display: flex; flex-direction: column; gap: 4px; }
.apl-net-proj-v { font-size: 19px; font-weight: 750; font-variant-numeric: tabular-nums; line-height: 1.1; }
@media (max-width: 720px) {
  .apl-cards2 { grid-template-columns: repeat(2, 1fr); }
  .apl-head .apl-dl-row { margin-left: 0; width: 100%; }
  .apl-head .apl-dl-row .btn { flex: 1; justify-content: center; }
  .apl-net-proj { margin-left: 0; text-align: left; width: 100%; border-top: 1px solid var(--hairline); padding-top: 12px; }
}
/* ===== v532 — Agency Overview: next-30-days incoming + month-over-month + one-time→link affinity ===== */
/* run6 W5b: surface + padding deleted — markup now ships `apl-next30 glass-2 g-pad` (js/app.js). */
.apl-next30 { display: flex; flex-direction: column; gap: 14px; }
.apl-n30-top { display: flex; align-items: flex-start; gap: 16px 24px; flex-wrap: wrap; }
.apl-n30-head { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.apl-n30-k { display: inline-flex; align-items: center; gap: 7px; font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--text-3); }
.apl-n30-k svg { width: 14px; height: 14px; }
.apl-n30-total { font-size: 30px; font-weight: 800; letter-spacing: -.6px; font-variant-numeric: tabular-nums; line-height: 1.05; color: var(--green); }
.apl-n30-sub { font-size: 12px; color: var(--text-3); }
.apl-n30-possible { margin-left: auto; text-align: right; display: flex; flex-direction: column; gap: 2px; padding: 8px 12px; border: 1px dashed var(--hairline-strong); border-radius: var(--radius-sm); }
.apl-n30-poss-k { font-size: 10px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--text-3); }
.apl-n30-poss-v { font-size: 18px; font-weight: 750; font-variant-numeric: tabular-nums; color: var(--text-2); }
.apl-n30-poss-sub { font-size: 11px; color: var(--text-3); }
.apl-n30-weeks { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; align-items: end; }
.apl-n30-wk { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.apl-n30-wk-bar { width: 100%; height: 70px; display: flex; align-items: flex-end; border-radius: var(--radius-xs); background: var(--glass-border); overflow: hidden; }
.apl-n30-wk-bar > span { display: block; width: 100%; background: var(--green); border-radius: var(--radius-sm) var(--radius-sm) 0 0; min-height: 2px; }
.apl-n30-wk-amt { font-size: 12.5px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text); }
.apl-n30-wk-lbl { font-size: 11px; color: var(--text-3); }
.apl-n30-empty { padding: 10px 2px; color: var(--text-3); font-size: 13px; line-height: 1.5; }
.apl-n30-foot { font-size: 11px; color: var(--text-3); line-height: 1.5; }
/* run6 W5b: surface props deleted — markup now ships `apl-mom glass-2` (js/app.js).
   overflow:hidden kept (header/footer band clip). */
.apl-mom { margin-top: 4px; overflow: hidden; }
.apl-mom-h { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: 12px; padding: 12px 16px; border-bottom: 1px solid var(--hairline); background: var(--surface-2); }
.apl-mom-title { font-size: 12px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: var(--text-3); }
.apl-mom-cols { display: grid; grid-template-columns: 92px 92px 92px; text-align: right; font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-3); }
.apl-mom-row { display: grid; grid-template-columns: 1fr 92px 92px 92px; align-items: center; padding: 10px 16px; border-bottom: 1px solid var(--hairline); }
.apl-mom-row:last-of-type { border-bottom: 0; }
.apl-mom-lbl { font-weight: 600; color: var(--text); font-size: 13px; }
.apl-mom-now, .apl-mom-prev, .apl-mom-delta { text-align: right; font-variant-numeric: tabular-nums; font-size: 13px; }
.apl-mom-now { font-weight: 700; color: var(--text); }
.apl-mom-prev { color: var(--text-3); }
.apl-mom-na { color: var(--text-3); opacity: .6; }
.apl-mom-d { font-weight: 700; font-size: 12px; }
.apl-mom-d.up { color: var(--green); }
.apl-mom-d.down { color: var(--red); }
.apl-mom-d.flat { color: var(--text-3); }
.apl-mom-foot { padding: 10px 16px; font-size: 11px; color: var(--text-3); line-height: 1.5; background: var(--surface-2); }
.apl-link-chip { display: inline-flex; align-items: center; gap: 4px; flex: 0 0 auto; max-width: 170px; overflow: hidden; padding: 2px 8px; border: 1px solid var(--hairline); border-radius: var(--radius-pill); background: var(--glass); color: var(--text-2); font-size: 11px; font-weight: 600; line-height: 1.4; white-space: nowrap; }
@media (max-width: 720px) {
  .apl-n30-weeks { gap: 7px; }
  .apl-n30-wk-bar { height: 56px; }
  .apl-n30-possible { margin-left: 0; text-align: left; }
  .apl-mom-cols { grid-template-columns: 64px 64px 54px; }
  .apl-mom-row { grid-template-columns: 1fr 64px 64px 54px; }
}
/* ===== v543 — Agency Overview: MRR movement (money item #377) — diverging new/churn stacked bars ===== */
/* run6 W5b: surface + padding deleted — markup now ships `apl-mrrm glass-2 g-pad` (js/app.js). */
.apl-mrrm { display: flex; flex-direction: column; gap: 16px; }
.apl-mrrm-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px 24px; flex-wrap: wrap; }
.apl-mrrm-head { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.apl-mrrm-k { display: inline-flex; align-items: center; gap: 7px; font-size: 11px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--text-3); }
.apl-mrrm-k svg { width: 14px; height: 14px; }
.apl-mrrm-net { font-size: 26px; font-weight: 800; letter-spacing: -.5px; font-variant-numeric: tabular-nums; line-height: 1.05; }
.apl-mrrm-sub { font-size: 12px; color: var(--text-3); }
.apl-mrrm-legend { display: inline-flex; align-items: center; gap: 14px; padding-top: 2px; }
.apl-mrrm-lg { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600; color: var(--text-3); }
.apl-mrrm-lg i { width: 10px; height: 10px; border-radius: var(--radius-xs); }
.apl-mrrm-lg.new i { background: var(--green); }
.apl-mrrm-lg.churn i { background: var(--red, #e5322b); }
.apl-mrrm-chart { display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px; align-items: stretch; }
.apl-mrrm-col { display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 0; }
.apl-mrrm-net-lbl { font-size: 11.5px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap; }
.apl-mrrm-net-lbl.up { color: var(--green); }
.apl-mrrm-net-lbl.down { color: var(--red, #e5322b); }
.apl-mrrm-net-lbl.flat { color: var(--text-3); }
.apl-mrrm-bars { width: 100%; display: flex; flex-direction: column; align-items: stretch; }
.apl-mrrm-up { height: 58px; display: flex; align-items: flex-end; }
.apl-mrrm-up > span { display: block; width: 100%; background: var(--green); border-radius: var(--radius-xs) var(--radius-xs) 0 0; min-height: 2px; }
.apl-mrrm-dn { height: 58px; display: flex; align-items: flex-start; }
.apl-mrrm-dn > span { display: block; width: 100%; background: var(--red, #e5322b); border-radius: 0 0 var(--radius-xs) var(--radius-xs); min-height: 2px; }
.apl-mrrm-zero { display: block; height: 2px; background: var(--hairline-strong); border-radius: 2px; }
.apl-mrrm-col.is-partial .apl-mrrm-up > span, .apl-mrrm-col.is-partial .apl-mrrm-dn > span { opacity: .55; background-image: repeating-linear-gradient(45deg, transparent, transparent 4px, rgba(255,255,255,.28) 4px, rgba(255,255,255,.28) 8px); }
.apl-mrrm-mlbl { font-size: 11px; color: var(--text-3); text-align: center; }
.apl-mrrm-mlbl i { font-style: normal; opacity: .8; }
.apl-mrrm-foot { font-size: 11px; color: var(--text-3); line-height: 1.55; }
.apl-mrrm-foot b { color: var(--text-2); font-weight: 700; }
.apl-mrrm-empty { padding: 8px 2px; color: var(--text-3); font-size: 13px; line-height: 1.5; }
@media (max-width: 720px) {
  .apl-mrrm-chart { gap: 5px; }
  .apl-mrrm-up, .apl-mrrm-dn { height: 46px; }
  .apl-mrrm-net-lbl { font-size: 10px; }
  .apl-mrrm-mlbl { font-size: 10px; }
  .apl-mrrm-mlbl i { display: none; }
}
/* admin client billing */
.bil-wrap { display: flex; flex-direction: column; gap: 18px; }
.bil-head h3 { font-size: 18px; font-weight: 700; letter-spacing: -0.3px; margin: 4px 0 4px; }
.bil-head p { font-size: 13px; color: var(--text-2); max-width: 640px; line-height: 1.55; }
.bil-headtools { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 10px; }
.bil-headtools .bil-sort { margin-top: 0; }
.bil-search-wrap { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--surface); }
.bil-search-wrap svg { width: 14px; height: 14px; color: var(--text-3); flex: none; }
.bil-search { border: 0; background: none; outline: 0; font-size: 13px; font-family: var(--font); color: var(--text); width: 170px; }
.bil-search::placeholder { color: var(--text-3); }
.bil-csm { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px 4px 12px; border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--surface); }
.bil-csm svg { width: 14px; height: 14px; color: var(--text-3); flex: none; }
.bil-sort { display: inline-flex; gap: 3px; margin-top: 10px; background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-md); padding: 3px; }
.bil-sort-chip { border: 0; background: none; color: var(--text-2); font-size: 12.5px; font-weight: 600; padding: 5px 12px; border-radius: var(--radius-sm); cursor: pointer; font-family: var(--font); transition: background var(--dur-1), color var(--dur-1); }
.bil-sort-chip:hover { color: var(--text); }
.bil-sort-chip.on { background: var(--accent); color:var(--text-on-accent,#fff); }
/* run6 W5b: surface props deleted — markup now ships `bil-tablewrap glass-2` (js/app.js, all 4
   sites). Horizontal scroll plumbing kept. */
.bil-tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.bil-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.bil-table thead th { text-align: left; font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-3); padding: 12px 16px; border-bottom: 1px solid var(--glass-border); background: var(--surface-2, rgba(127,127,127,.04)); }
.bil-table tbody td { padding: 11px 16px; border-bottom: 1px solid var(--glass-border); color: var(--text); vertical-align: middle; }
.bil-table tbody tr:last-child td { border-bottom: 0; }
.bil-table tbody tr:hover { background: var(--surface-2, rgba(127,127,127,.03)); }
.bil-co { display: inline-flex; align-items: center; gap: 9px; }
.bil-co b { font-weight: 650; }
.bil-permo { color: var(--text-3); font-weight: 500; font-size: 11.5px; margin-left: 2px; }
.bil-cyc { display: flex; flex-direction: column; line-height: 1.3; }
.bil-cyc b { font-weight: 650; }
.bil-cyc small { color: var(--text-3); font-size: 11px; }
.bil-presets { display: grid; grid-template-columns: repeat(3, 1fr); gap: 7px; }
.bil-preset { display: flex; flex-direction: column; align-items: flex-start; gap: 1px; padding: 9px 11px; border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--surface); color: var(--text); cursor: pointer; transition: border-color var(--dur-1), background var(--dur-1); }
.bil-preset b { font-weight: 650; font-size: 13px; }
.bil-preset small { color: var(--text-3); font-size: 11px; }
.bil-preset:hover { border-color: var(--hairline-strong); }
.bil-preset.on { border-color: var(--accent); background: var(--row-hover); }
.bil-custom { margin-top: 10px; font-size: 13px; color: var(--text-2); display: flex; align-items: center; gap: 8px; }
.bil-custom input { width: 80px; padding: 7px 10px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface); color: var(--text); font-family: var(--font); }
.bil-link a { display: inline-flex; align-items: center; gap: 4px; }
.bil-status { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font); font-size: 12px; font-weight: 700; padding: 5px 11px; border-radius: var(--radius-pill); border: 1px solid var(--glass-border); cursor: pointer; background: var(--surface); transition: filter var(--dur-1); }
.bil-status:hover { filter: brightness(1.05); }
.bil-status .bil-dot { width: 7px; height: 7px; border-radius: 50%; }
.bil-paid { color: var(--green, #1f9d57); border-color: color-mix(in srgb, var(--green, #1f9d57) 35%, transparent); }
.bil-paid .bil-dot { background: var(--green, #1f9d57); }
.bil-due { color: var(--text-2); }
.bil-due .bil-dot { background: var(--text-3); }
.bil-overdue { color: var(--accent, #e5322b); border-color: color-mix(in srgb, var(--accent, #e5322b) 35%, transparent); }
.bil-overdue .bil-dot { background: var(--accent, #e5322b); }
.bil-free { color: var(--green, #1f9d57); border-color: color-mix(in srgb, var(--green, #1f9d57) 35%, transparent); }
.bil-free .bil-dot { background: var(--green, #1f9d57); }
.bil-unset { color: var(--text-3); }
.bil-unset .bil-dot { background: var(--text-3); }

/* ── v534 CLIENT-BILLING HIERARCHY — one client-first tree: expandable client rows (billing lines +
   their FanBasis subs) + an "unlinked subscriptions" section. Mirrors .bil-* + the .home-fold idiom
   (chevron rotate, 0fr↔1fr grid body animated by smoothHomeFold). ── */
.bil-hier { display: flex; flex-direction: column; gap: 8px; }
/* run6 W5b: surface props deleted — markup now ships `bil-hier-item g-solid-2` (js/app.js,
   both sites; repeated accordion, so the opaque twin). overflow:hidden kept. */
.bil-hier-item { overflow: hidden; }
.bil-hier-head { display: flex; align-items: center; gap: 12px; padding: 12px 16px; cursor: pointer; -webkit-user-select: none; user-select: none; transition: background var(--dur-1) ease; }
.bil-hier-head:hover { background: var(--surface-2, rgba(127,127,127,.04)); }
.bil-hier-co { flex: 1 1 auto; min-width: 0; gap: 9px; }
.bil-hier-co b { font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bil-hier-lock { display: inline-flex; align-items: center; color: var(--text-3); flex: 0 0 auto; }
.bil-hier-lock svg { width: 13px; height: 13px; }
.bil-hier-summary { display: inline-flex; align-items: center; gap: 10px; flex: 0 0 auto; flex-wrap: wrap; justify-content: flex-end; }
.bil-hier-mrr { font-weight: 700; font-variant-numeric: tabular-nums; font-size: 14px; color: var(--green, #1f9d57); }
.bil-hier-mrr small { font-weight: 500; font-size: 11px; color: var(--text-3); margin-left: 1px; }
.bil-hier-out { font-size: 12px; font-weight: 650; font-variant-numeric: tabular-nums; color: var(--amber, #e0900b); }
.bil-hier-price { font-weight: 650; font-variant-numeric: tabular-nums; }
.bil-hier-head .home-fold-chev { margin-left: 0; flex: 0 0 auto; }
.bil-hier-head.is-folded .home-fold-chev { transform: rotate(0deg); }
.bil-hier-head:not(.is-folded) .home-fold-chev { transform: rotate(90deg); }
.bil-hier-detail { display: flex; flex-direction: column; border-top: 1px solid var(--glass-border); }
.bil-hier-line { display: grid; grid-template-columns: minmax(0,1.4fr) minmax(0,1.1fr) minmax(0,1.3fr) auto; gap: 12px; align-items: center; padding: 10px 16px; border-bottom: 1px solid var(--glass-border); font-size: 13px; }
.bil-hier-line:last-child { border-bottom: 0; }
.bil-hier-subrow { background: var(--surface-2, rgba(127,127,127,.03)); }
.bil-hier-emptyline { grid-template-columns: 1fr; }
.bil-hier-svc { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.bil-hier-svc b { font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bil-hier-svc small, .bil-hier-cyc small { color: var(--text-3); font-size: 11px; }
.bil-hier-cyc { display: flex; flex-direction: column; line-height: 1.3; min-width: 0; }
.bil-hier-cyc b { font-weight: 600; font-size: 12.5px; }
.bil-hier-fb { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 12px; min-width: 0; }
.bil-hier-st { justify-self: end; }
.bil-hier-subnote { display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; color: var(--text-3); }
.bil-sub-state { font-weight: 600; font-size: 11.5px; color: var(--text-3); white-space: nowrap; }
.bil-sub-state.is-active { color: var(--green, #1f9d57); }
.bil-sub-state.is-pastdue { color: var(--red, #e5322b); }
.bil-warn { display: inline-flex; align-items: center; gap: 3px; font-size: 11px; font-weight: 650; color: var(--amber, #e0900b); background: color-mix(in srgb, var(--amber, #e0900b) 13%, transparent); border-radius: var(--radius-pill); padding: 2px 8px; white-space: nowrap; }
.bil-hier-subhead { padding: 8px 16px 4px; font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--text-3); }
.bil-hier-actions { display: flex; gap: 8px; flex-wrap: wrap; padding: 12px 16px; border-top: 1px solid var(--glass-border); }
.bil-hier-unlinked .bil-hier-item { border: 1px solid color-mix(in srgb, var(--amber, #e0900b) 32%, var(--glass-border)); }   /* run6 W5b: semantic "unlinked" amber ring became a FULL border — the base border it colored is gone */
@media (max-width: 640px) {
  .bil-hier-line { grid-template-columns: 1fr 1fr; }
  .bil-hier-st { grid-column: 2; justify-self: end; }
  .bil-hier-summary { gap: 7px; }
}
.pay-k { font-size: 12px; font-weight: 600; color: var(--text-3); margin-bottom: 9px; }
.pay-v { font-size: 26px; font-weight: 800; letter-spacing: -0.6px; font-variant-numeric: tabular-nums; line-height: 1; }
.pay-sub { font-size: 11.5px; color: var(--text-3); margin-top: 6px; font-weight: 500; }
.pay-progress { height: 8px; border-radius: var(--radius-pill); background: var(--surface-2); overflow: hidden; margin-bottom: 4px; border: 1px solid var(--hairline); }
.pay-progress-bar { height: 100%; background: linear-gradient(90deg, var(--green), #34c759); border-radius: var(--radius-pill); transition: width .5s cubic-bezier(.2,.8,.2,1); }
/* run6 W5b: surface props deleted — markup now ships `pay-list glass-2` (js/app.js, all sites;
   the client portal renders its own .cp-pay-list recipe, untouched). overflow:hidden kept. */
.pay-list { overflow: hidden; }
.pay-row { display: grid; grid-template-columns: 1fr 120px 120px 150px; align-items: center; gap: 14px; padding: 15px 20px; border-bottom: 1px solid var(--hairline); transition: background var(--dur-1) ease; }
.pay-subhead { display: flex; align-items: center; gap: 7px; padding: 11px 16px 7px; font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--text-3); background: var(--surface-2); border-bottom: 1px solid var(--hairline); }
.pay-subhead svg { width: 13px; height: 13px; }
.pay-subhead-amt { margin-left: auto; font-variant-numeric: tabular-nums; color: var(--text-2); font-weight: 700; letter-spacing: 0; text-transform: none; font-size: 12.5px; }
.pay-subhead-paid { color: var(--green); }
.pay-subhead-paid .pay-subhead-amt { color: var(--green); }
.pay-row:last-child { border-bottom: none; }
.pay-row:hover { background: var(--row-hover); }
.pay-row-main { display: flex; align-items: center; gap: 9px; font-size: 13.5px; flex-wrap: wrap; }
.pay-row-amt { font-weight: 700; font-variant-numeric: tabular-nums; font-size: 14px; }
.pay-row-amt-wrap { text-align: left; }
.pay-row-date { font-size: 12.5px; color: var(--text-3); font-weight: 500; text-align: right; display: flex; align-items: center; justify-content: flex-end; gap: 4px; }

/* N4 — per-payment kebab (admin) -> edit/delete */
.pay-kebab { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; flex: 0 0 auto; border-radius: var(--radius-xs); color: var(--text-3); cursor: pointer; opacity: 0; transition: opacity var(--dur-1) ease, color var(--dur-1) ease, background var(--dur-1) ease; }
.pay-row:hover .pay-kebab, .invoice-table tr:hover .pay-kebab { opacity: .55; }
.pay-kebab:hover { opacity: 1; color: var(--text); background: var(--surface-2); }
.pay-kebab .kb-ic { width: 14px; height: 14px; }
.inv-date { display: flex; align-items: center; justify-content: flex-start; gap: 4px; }
.inv-date-txt { flex: 1 1 auto; }

/* N4 — expandable history (admin sees per-line edit/delete under each month) */
.pay-row-monthhead { background: var(--surface-2); }
.pay-row-sub { padding-left: 26px; background: transparent; }
.pay-row-sub .pay-row-main { font-size: 13px; color: var(--text-2); }
.pay-sub-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--text-3); flex: 0 0 auto; }

/* N4 — polished personal pay banner (owner viewing own pay) */
.pay-hero { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; background: linear-gradient(135deg, var(--accent-softer), var(--glass)); border: 1px solid var(--glass-border); border-radius: var(--radius-md); padding: 16px 20px; margin-bottom: 16px; box-shadow: var(--shadow-sm); }
.pay-hero-id { display: flex; align-items: center; gap: 13px; }
.pay-hero-name { font-size: 17px; font-weight: 800; letter-spacing: -0.3px; }
.pay-hero-role { font-size: 12.5px; color: var(--text-3); font-weight: 500; margin-top: 2px; }
.pay-hero-meta { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.pay-cadence-chip { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; font-weight: 700; color: var(--slate); background: var(--slate-bg); border-radius: var(--radius-pill); padding: 5px 11px; }
.pay-cadence-chip svg { width: 13px; height: 13px; }
.pay-hero-lifetime { display: flex; flex-direction: column; align-items: flex-end; }
.pay-hero-lt-k { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-3); font-weight: 700; }
.pay-hero-lt-v { font-size: 17px; font-weight: 800; color: var(--green); font-variant-numeric: tabular-nums; }

/* B4 — Summary | Invoice tabs + add-payment row */
.pay-tabrow { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
/* light inline pay-view toggle (My pay / Team payroll) — replaces the heavy head-controls strip */
.pay-viewtabs { display: flex; align-items: center; gap: 6px; margin-bottom: 10px; overflow-x: auto; scrollbar-width: none; }
.pay-viewtabs::-webkit-scrollbar { display: none; }
.pay-subtabs { flex: 0 0 auto; }
.pay-tabrow .head-spacer { flex: 1; }

/* B4 — editable pay cells (admin) */
.pay-cell-edit { cursor: pointer; border-radius: var(--radius-xs); padding: 2px 5px; margin: -2px -5px; transition: background var(--dur-1) ease, box-shadow var(--dur-1) ease; }
.pay-cell-edit:hover { background: var(--row-hover); box-shadow: inset 0 0 0 1px var(--accent); }
.pay-cell-edit .cell-add { color: var(--accent); font-weight: 600; }

/* B4 — per-payment client chip */
.pay-client-chip { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; font-weight: 600; color: var(--text-2); background: var(--surface-2); border: 1px solid var(--hairline); border-radius: var(--radius-pill); padding: 2px 9px; cursor: default; }
.pay-client-chip svg { width: 12px; height: 12px; }
[data-act="pick-pay-client"].pay-client-chip { cursor: pointer; }
[data-act="pick-pay-client"].pay-client-chip:hover { border-color: var(--accent); color: var(--text); }
.pay-client-add { color: var(--accent); border-style: dashed; }

/* B4 — invoice layout. Document-style — centered + capped for readability even
   though its .pay-wrap is full-width (the invoice-actions row matches it). */
/* run6 W5b: surface + padding deleted — markup now ships `invoice-card glass-2 g-pad`
   (js/app.js). Print + phone overrides below are bumped to (0,2,0). */
.invoice-card { width: 100%; max-width: 860px; margin: 0 auto; }
.invoice-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; padding-bottom: 18px; margin-bottom: 14px; border-bottom: 2px solid var(--hairline); }
.invoice-title { font-size: 19px; font-weight: 800; letter-spacing: -0.4px; }
.invoice-sub { font-size: 13px; color: var(--text-3); margin-top: 3px; font-weight: 500; }
.invoice-meta { text-align: right; }
.invoice-month { font-size: 15px; font-weight: 700; }
.invoice-org { font-size: 12px; color: var(--text-3); margin-top: 3px; font-weight: 600; }
.invoice-table { width: 100%; border-collapse: collapse; }
.invoice-table th { text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-3); font-weight: 700; padding: 8px 10px; border-bottom: 1px solid var(--hairline); }
.invoice-table th.money, .invoice-table td.money { text-align: right; font-variant-numeric: tabular-nums; }
.invoice-table td { padding: 10px; font-size: 13px; border-bottom: 1px solid var(--hairline); vertical-align: top; }
.invoice-table tr.inv-grouphead td { background: var(--surface-2); font-weight: 700; font-size: 12.5px; padding: 8px 10px; }
.inv-gtotal { float: right; color: var(--text-2); font-variant-numeric: tabular-nums; }
.inv-grouphead + tr td, .invoice-table tbody tr:not(.inv-grouphead) .inv-client { color: var(--text-3); }
.inv-label { color: var(--text); }
.inv-date { color: var(--text-3); font-size: 12.5px; }
.inv-empty { text-align: center; color: var(--text-3); padding: 22px 10px; }
.invoice-table tfoot td { padding: 14px 10px 4px; font-size: 15px; font-weight: 800; border-bottom: none; }
.inv-total-lbl { text-transform: uppercase; letter-spacing: .05em; }
.inv-total-amt { text-align: right; color: var(--green); font-variant-numeric: tabular-nums; }
.invoice-actions { display: flex; justify-content: flex-end; margin: 14px auto 0; width: 100%; max-width: 860px; }
.inv-cell { text-align: right; }
.inv-cell-actions { display: inline-flex; gap: 4px; align-items: center; justify-content: flex-end; }
.btn-icon-sm { padding: 5px 7px !important; }
.btn-danger-text { color: var(--red) !important; }
/* invoice month nav */
.invoice-monthnav { display: inline-flex; align-items: center; gap: 6px; justify-content: flex-end; }
.inv-mnav { display: inline-grid; place-items: center; width: 24px; height: 24px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2); cursor: pointer; }
.inv-mnav:hover { border-color: var(--accent); color: var(--accent); }
.inv-mnav:disabled { opacity: .35; cursor: default; }
.inv-mnav svg { width: 13px; height: 13px; }
.inv-thismonth { margin-top: 5px; display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 600; color: var(--accent); background: none; border: none; cursor: pointer; padding: 0; }
.inv-thismonth svg { width: 12px; height: 12px; }
/* clickable history month -> opens that month's invoice */
.pay-month-open { cursor: pointer; transition: background var(--dur-1) ease; }
.pay-month-open:hover { background: var(--row-hover); }
.pay-month-inv { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; color: var(--accent); }
.pay-month-inv svg { width: 12px; height: 12px; }
.mhint { font-size: 12px; color: var(--text-3); margin-top: 10px; line-height: 1.5; }

/* ===== Recurring payroll engine — additive UI ===== */
/* breakdown header row: title left, admin month actions right */
.pay-section-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 6px; }
.pay-month-actions { display: inline-flex; gap: 8px; flex-wrap: wrap; }
/* "recurring pay set up" chip beside a team member's status */
.pay-cfg-chip { display: inline-flex; align-items: center; margin-left: 6px; color: var(--slate); vertical-align: middle; }
.pay-cfg-chip svg { width: 13px; height: 13px; }
/* pay-config "active" toggle (Apple-style switch) */
.pc-toggle { display: flex; align-items: center; gap: 11px; margin-top: 14px; cursor: pointer; user-select: none; }
.pc-toggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.pc-toggle-track { position: relative; flex: 0 0 auto; width: 42px; height: 24px; border-radius: var(--radius-pill); background: var(--hairline); transition: background var(--dur-2) ease; }
.pc-toggle-dot { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%; background: #fff; box-shadow: 0 1px 3px rgba(0,0,0,.3); transition: transform var(--dur-2) ease; }
.pc-toggle input:checked + .pc-toggle-track { background: var(--green); }
.pc-toggle input:checked + .pc-toggle-track .pc-toggle-dot { transform: translateX(18px); }
.pc-toggle input:focus-visible + .pc-toggle-track { box-shadow: 0 0 0 3px var(--accent-softer); }
.pc-toggle-lbl { font-size: 13px; color: var(--text-2); font-weight: 500; }
@media (max-width: 720px){
  .pay-section-head { flex-direction: column; align-items: stretch; gap: 9px; }
  .pay-month-actions { width: 100%; }
  .pay-month-actions .btn { flex: 1; justify-content: center; }
}
@media print { .pay-tabrow, .invoice-actions, .sb-toggle, #sidebar, .head-controls { display: none !important; } .invoice-card.glass-2 { background: #fff; -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: none; border: 1px solid #ccc; } }   /* run6 W5b: print rule bumped to (0,2,0) + de-glassed — glass.css has no print fallback and its later (0,1,0) surface would beat the old rule */

/* Tablet — summary cards go 2-up; invoice header stacks. Pay rows keep full
   detail here (the phone treatment below restructures them into clean 2-line cards). */
@media (max-width: 760px){
  .pay-cards { grid-template-columns: repeat(2,1fr); }
  .pay-row { grid-template-columns: 1fr 100px 110px; }
  .pay-row-st { display:none; }
  .invoice-head { flex-direction: column; }
  .invoice-meta { text-align: left; }
  .invoice-table .inv-client { display: none; }
}

/* ===== iPhone payments (<=720px) — native-app feel =====
   Summary cards 2-up & edge-to-edge; each payment becomes a clean 2-line card
   (label/badges on top, amount + date on the baseline) instead of a cramped grid;
   the invoice goes edge-to-edge with comfortable line items. */
@media (max-width: 720px){
  /* Summary stat cards — 2-up, tighter but breathable */
  .pay-cards { grid-template-columns: repeat(2,1fr); gap: 10px; margin-bottom: 14px; }
  .pay-card.g-pad { padding: 14px 14px; }   /* run6 W5b: bumped to (0,2,0) — .g-pad (glass.css, loads later) would win the (0,1,0) tie */
  .pay-v { font-size: 23px; }

  /* Personal pay banner stacks instead of squeezing */
  .pay-hero { flex-direction: column; align-items: stretch; gap: 13px; padding: 15px 16px; }
  .pay-hero-meta { justify-content: space-between; width: 100%; }
  .pay-hero-lifetime { align-items: flex-start; }

  /* Tab row: tabs on their own line, full-width add button below */
  .pay-tabrow { flex-wrap: wrap; gap: 9px; }
  .pay-tabrow .head-spacer { display: none; }
  .pay-subtabs { width: 100%; }
  .pay-tabrow .btn { flex: 1; justify-content: center; }

  /* Each payment row -> a stacked 2-line card. main spans full top line;
     amount + date share the baseline. Status badge is folded into the date line. */
  .pay-list.glass-2 { border-radius: var(--radius-md); }   /* run6 W5b: phone radius bumped to (0,2,0) — glass.css's later --g-r-card tie would win otherwise */
  .pay-row {
    grid-template-columns: 1fr auto;
    grid-template-areas: "main amt" "meta date";
    row-gap: 6px; column-gap: 10px;
    align-items: center; padding: 14px 15px; min-height: 0;
  }
  .pay-row-main { grid-area: main; font-size: 14px; }
  .pay-row-amt-wrap { grid-area: amt; text-align: right; align-self: start; }
  .pay-row-amt { font-size: 15px; }
  .pay-row-st { grid-area: meta; display: inline-flex; align-self: center; }
  .pay-row-date { grid-area: date; justify-content: flex-end; align-self: center; }
  /* month header in history reads as a single clean line */
  .pay-row-monthhead { grid-template-columns: 1fr auto; grid-template-areas: "main amt" "main date"; }
  .pay-row-monthhead .pay-row-st { display: none; }
  .pay-row-sub { padding-left: 15px; }
  /* per-payment kebab always reachable (no hover on touch) */
  .pay-row .pay-kebab { opacity: .5; }

  /* Invoice — edge-to-edge document */
  .pay-wrap { width: 100%; }
  .invoice-card.glass-2 { max-width: 100%; padding: 18px 16px; border-radius: var(--radius-md); }   /* run6 W5b: phone padding/radius bumped to (0,2,0) — .g-pad and --g-r-card (glass.css, later) would win the (0,1,0) tie */
  .invoice-actions { max-width: 100%; }
  .invoice-actions .btn { flex: 1; justify-content: center; }
  .invoice-title { font-size: 17px; }
  .invoice-table th { padding: 7px 6px; }
  .invoice-table td { padding: 11px 6px; font-size: 13px; }
  .invoice-table tr.inv-grouphead td { padding: 8px 6px; }
  .invoice-table tfoot td { padding: 13px 6px 2px; }
  /* let the line-item label breathe; amount column stays tight & right-aligned */
  .invoice-table .inv-label { white-space: normal; }
}
/* ===== iPhone invoice (<=520px): each line item becomes a clean stacked card
   (label + amount on the top line, status/date below) instead of a cramped 4-col
   table whose header misaligned with the hidden client column. ===== */
@media (max-width: 520px){
  .invoice-table { display: block; }
  .invoice-table thead { display: none; }
  .invoice-table tbody, .invoice-table tfoot { display: block; }
  .invoice-table tbody tr.inv-grouphead { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; border-bottom: none; margin-top: 6px; }
  .invoice-table tbody tr.inv-grouphead td { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; width: 100%; border: none; background: transparent; padding: 12px 2px 4px; font-size: 13px; font-weight: 700; }
  .invoice-table tbody tr.inv-grouphead .inv-gtotal { float: none; margin-left: 0; flex: 0 0 auto; color: var(--text-2); }
  .invoice-table tbody tr:not(.inv-grouphead) {
    display: grid; grid-template-columns: 1fr auto; column-gap: 12px; row-gap: 3px;
    align-items: baseline; padding: 11px 2px; border-bottom: 1px solid var(--hairline);
  }
  .invoice-table tbody tr:not(.inv-grouphead) td { display: block; border: none; padding: 0; font-size: 13.5px; }
  .invoice-table tbody tr .inv-client { display: none; }
  .invoice-table tbody tr .inv-label { grid-column: 1; grid-row: 1; color: var(--text); }
  .invoice-table tbody tr .inv-amt { grid-column: 2; grid-row: 1; text-align: right; font-weight: 700; white-space: nowrap; }
  .invoice-table tbody tr .inv-date { grid-column: 1 / -1; grid-row: 2; font-size: 12px; }
  .invoice-table tfoot tr { display: flex; align-items: baseline; justify-content: space-between; border-top: 2px solid var(--hairline); margin-top: 6px; }
  .invoice-table tfoot td { display: block; border: none; padding: 12px 2px 2px; }
  .invoice-table tfoot td:empty { display: none; }
}

/* Admin / Team */
.admin-wrap { width: 100%; }
.admin-head { display: flex; gap: 16px; align-items: center; justify-content: space-between; margin-bottom: 18px; }
.admin-head h3 { font-size: 18px; font-weight: 700; margin-bottom: 4px; letter-spacing: -0.3px; }
.admin-head p { font-size: 13px; color: var(--text-2); line-height: 1.55; max-width: 560px; }
.admin-head .btn-primary { flex-shrink: 0; }
.admin-roster { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 18px; }
/* Headcount-by-role strip (Team page) — org shape at a glance */
.team-headcount { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 2px 16px; }
.thc-chip { display: inline-flex; align-items: center; gap: 7px; background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-pill); padding: 5px 6px 5px 11px; font-size: 12.5px; }
.thc-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.thc-role { color: var(--text-2); font-weight: 550; }
.thc-n { display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 10px; background: var(--surface-2, var(--hairline)); color: var(--text); font-weight: 700; font-size: 11.5px; font-variant-numeric: tabular-nums; }
/* team / clients split */
.admin-sec-head { display:flex; align-items:center; gap:9px; margin: 28px 2px 12px; }
.team-search-wrap { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; padding: 6px 12px; border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--surface); }
.team-search-wrap svg { width: 15px; height: 15px; color: var(--text-3); flex: none; }
.team-search { border: 0; background: none; outline: 0; font-size: 13.5px; font-family: var(--font); color: var(--text); width: 180px; }
.team-search::placeholder { color: var(--text-3); }
/* PHONE (2026-08-03): the section head is a single non-wrapping flex row and the search box is a
   fixed 180px + padding pinned right with margin-left:auto — on a 402pt screen that pushed the
   Team page 121px wider than the viewport, so the whole page rubber-banded sideways. Let the row
   wrap and give the search its own full-width line instead. */
@media (max-width: 720px) {
  .admin-sec-head { flex-wrap: wrap; }
  .team-search-wrap { margin-left: 0; flex: 1 1 100%; min-width: 0; }
  .team-search { width: 100%; min-width: 0; }
}
.admin-sec-head:first-of-type { margin-top: 6px; }
.admin-sec-t { font-size: 12px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--text-3); }
.admin-sec-c { font-size: 11px; font-weight: 700; color: var(--text-3); background: var(--glass); border:1px solid var(--glass-border); border-radius: var(--radius-pill); padding: 1px 8px; }
.admin-sec-sub { font-size: 12.5px; color: var(--text-3); margin: -6px 2px 12px; }
.client-roster { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 10px; }
/* run6 W5b: surface props deleted — markup now ships `client-mini g-solid-2` (js/app.js;
   repeated chip-cards). Hover retargeted to the system card-hover recipe (edge kept, one
   shadow tier deeper); the border-color half is dead with the border. */
.client-mini { display:flex; align-items:center; gap:10px; padding:10px 12px; cursor:pointer; transition: transform var(--dur-1), border-color var(--dur-1), box-shadow var(--dur-1); }
.client-mini:hover { box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-3); }
.client-mini:active { transform: scale(.99); }
.client-mini-id { min-width:0; flex:1; display:flex; flex-direction:column; }
.client-mini-id b { font-size: 13.5px; font-weight: 650; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.client-mini-id small { font-size: 11.5px; color: var(--text-3); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.client-mini-open { display:inline-flex; color: var(--text-3); flex:none; }
.client-mini-open svg { width:15px; height:15px; }
@media (max-width: 480px){ .client-roster { grid-template-columns: 1fr 1fr; } }
/* registration approvals (CEO) */
.pending-approvals { background: var(--accent-softer); border: 1px solid var(--accent-soft); border-radius: var(--radius-md); padding: 14px 16px; margin-bottom: 18px; }
.pa-head { display: flex; align-items: center; gap: 8px; font-weight: 700; font-size: 13px; color: var(--accent); margin-bottom: 10px; }
.pa-head svg { width: 16px; height: 16px; }
.pa-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 0; border-top: 1px solid var(--hairline); flex-wrap: wrap; }
.pa-id { display: flex; align-items: center; gap: 11px; min-width: 0; }
.pa-meta { display: flex; flex-direction: column; min-width: 0; }
.pa-meta b { font-weight: 600; font-size: 14px; }
.pa-meta small { color: var(--text-3); font-size: 12px; }
.pa-acts { display: flex; gap: 8px; flex-shrink: 0; }
.pa-deny:hover { color: var(--red); }
/* pending-approval login screen */
/* run6 W5a: surface props deleted — markup now ships `pending-box g-solid-2` (js/app.js); it sits
   inside the glass-4 login card, so solid. Bespoke padding kept (no .g-pad). */
.pending-box { padding: 16px 18px; margin: 4px 0 18px; }
.pending-box p { font-size: 14px; line-height: 1.55; }
.pending-box .pending-sub { color: var(--text-3); font-size: 13px; margin-top: 8px; }
.pending-signout { display: block; width: 100%; margin-top: 12px; background: none; border: none; color: var(--text-3); font-size: 13px; cursor: pointer; font-family: var(--font); padding: 8px; }
.pending-signout:hover { color: var(--text); }
/* run6 W5b: surface props deleted — markup now ships `member-card g-solid-2` (js/app.js;
   repeated per teammate, was blurring per card). Bespoke 20px padding kept. */
.member-card { padding: 20px; display: flex; flex-direction: column; gap: 13px; }
.member-top { display: flex; align-items: center; gap: 12px; }
.member-id { min-width:0; flex: 1; }
.member-id b { font-size: 14px; font-weight: 600; display:block; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.member-id small { font-size: 11.5px; color: var(--text-3); display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.member-remove { width: 30px; height: 30px; flex-shrink: 0; color: var(--text-3); border-radius: var(--radius-sm); }
.member-remove:hover { color: var(--red, #ff3b30); background: var(--red-bg, rgba(255,59,48,0.1)); }
.member-remove svg { width: 15px; height: 15px; }
.member-tags { display:flex; gap:5px; flex-wrap:wrap; }
.member-roledesc { font-size: 12.5px; color: var(--text-2); line-height: 1.5; }
/* Team roster — per-member workload strip (open + overdue tasks) */
.member-work { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--text-2); background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-sm); padding: 4px 10px; align-self: flex-start; }
.member-work svg { width: 13px; height: 13px; opacity: .7; }
.member-work .mw-open { font-weight: 700; color: var(--text); }
.member-work .mw-lbl { color: var(--text-3); }
.member-work .mw-od { margin-left: 4px; padding-left: 8px; border-left: 1px solid var(--hairline); color: var(--red, #e5322b); font-weight: 650; }
.member-work .mw-none { color: var(--text-3); }
.member-actions { display:flex; gap:8px; flex-wrap:wrap; margin-top: auto; padding-top: 3px; }
/* owner / you badges — theme-aware */
.badge-owner { color: var(--text); background: var(--surface); }
.badge-owner .b-dot { background: var(--text); }
.badge-you { color: var(--accent); background: var(--accent-softer, rgba(229,50,43,0.12)); }
.badge-you .b-dot { background: var(--accent); }
.badge-incomplete { color: var(--amber, #e0900b); background: color-mix(in srgb, var(--amber, #e0900b) 14%, transparent); }
.badge-incomplete .b-dot { background: var(--amber, #e0900b); }
.admin-online { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 700; color: var(--green, #17915a); background: color-mix(in srgb, var(--green, #17915a) 12%, transparent); border-radius: var(--radius-pill); padding: 2px 9px; font-variant-numeric: tabular-nums; }
.admin-online[hidden] { display: none; }
.admin-online .ao-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--green, #17915a); flex: none; }
.admin-sec-incomplete { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 700; color: var(--amber, #e0900b); background: color-mix(in srgb, var(--amber, #e0900b) 12%, transparent); border-radius: var(--radius-pill); padding: 2px 9px; }
.admin-sec-incomplete svg { width: 12px; height: 12px; }
/* invite modal status line */
.inv-status { font-size: 12.5px; line-height: 1.45; color: var(--text-2); min-height: 1px; margin-top: 6px; }
.inv-status.err { color: var(--red, #ff3b30); font-weight: 600; }
.inv-status.ok { color: var(--green, #34c759); font-weight: 600; }
@media (max-width: 860px){ .admin-roster { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 480px){ .admin-head { flex-direction: column; align-items: stretch; } .admin-head .btn-primary { width: 100%; justify-content: center; } }

/* ===== v541 Team elevation (additive; scoped to .w3-admin) ================= */
/* Member-card polish: line-clamp the role blurb so cards align on a clean grid,
   and give the hover a touch more lift so the roster reads as one dev-built set. */
.w3-admin .member-roledesc { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* run6 W5b: duplicate `.w3-admin .member-card:hover` shadow re-pin deleted — the single
   retargeted .member-card:hover (motion section) now owns the hover. */
/* Clients grid items must be able to shrink inside their track (min-width:0) so the
   name/email ellipsize instead of forcing the row wider than a 375px phone. */
.w3-admin .client-mini { min-width: 0; }
/* Roster empty / guidance state */
/* run6 W5a: background/radius deleted — markup now ships `roster-empty glass-2` (js/app.js, both
   sites). DOCUMENTED PARTIAL: the dashed border is the empty-state idiom the primitives can't
   express, so it survives — bumped to (0,2,0) below because glass.css §19.1 (0,1,0, loads later)
   would otherwise overwrite it with the theme border. Big empty-state padding kept (no .g-pad). */
.roster-empty { grid-column: 1 / -1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 6px; padding: 40px 24px; color: var(--text-3); }
.roster-empty.glass-2 { border: 1px dashed var(--hairline-strong, var(--hairline)); color: var(--text-3); }   /* color re-pinned: .glass-2 sets color:var(--g-text) later at (0,1,0) and would un-mute the hint text */
.roster-empty svg { width: 30px; height: 30px; color: var(--text-3); margin-bottom: 4px; }
.roster-empty b { font-size: 14px; font-weight: 700; color: var(--text); }
.roster-empty span { font-size: 12.5px; max-width: 340px; line-height: 1.5; }
/* Week scoreboard — a proper glass card with rank medals + aligned numeric columns.
   Replaces the old bare .ptable so it never sideways-scrolls and the numbers line up. */
/* run6 W5b: surface props deleted — markup now ships `wkb glass-2` (js/app.js).
   overflow:hidden kept (column-head band clip). */
.wkb { overflow: hidden; }
.wkb-colhead, .wkb-row { display: grid; grid-template-columns: 34px minmax(0, 1fr) 148px 60px 74px; align-items: center; gap: 12px; padding: 11px 16px; }
.wkb-colhead { background: var(--glass-strong); border-bottom: 1px solid var(--hairline); font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--text-3); }
.wkb-ch-rank { text-align: center; }
.wkb-ch-done, .wkb-ch-n { text-align: right; }
.wkb-row { border-bottom: 1px solid var(--hairline); transition: background var(--dur-1, .16s) var(--ease, ease); }
.wkb-row:last-child { border-bottom: none; }
.wkb-row:hover { background: var(--row-hover); }
.wkb-rank { justify-self: center; display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 50%; font-size: 11px; font-weight: 800; color: var(--text-3); background: var(--surface-2, var(--hairline)); font-variant-numeric: tabular-nums; }
.wkb-rank.is-1 { color: #7a5b00; background: color-mix(in srgb, #f5c518 26%, transparent); }
.wkb-rank.is-2 { color: var(--text-2); background: color-mix(in srgb, #9aa0a6 28%, transparent); }
.wkb-rank.is-3 { color: #7a4a24; background: color-mix(in srgb, #cd7f32 24%, transparent); }
.wkb-who { display: flex; align-items: center; gap: 10px; min-width: 0; }
.wkb-id { min-width: 0; display: flex; flex-direction: column; }
.wkb-id b { font-size: 13px; font-weight: 650; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wkb-id small { font-size: 11.5px; color: var(--text-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wkb-done { display: flex; align-items: center; justify-content: flex-end; gap: 9px; }
.wkb-done-n { font-size: 15px; font-weight: 800; color: var(--text-3); font-variant-numeric: tabular-nums; min-width: 14px; text-align: right; }
.wkb-done-n.is-hot { color: var(--green, #138a4e); }
.wkb-done-bar { width: 54px; height: 5px; border-radius: var(--radius-pill); background: var(--surface-2, var(--hairline)); overflow: hidden; flex: none; }
.wkb-done-bar i { display: block; height: 100%; border-radius: var(--radius-pill); background: var(--green, #1f9d57); }
.wkb-n { text-align: right; font-variant-numeric: tabular-nums; font-size: 13.5px; color: var(--text-2); }
.wkb-od { color: var(--red, #e5322b); font-weight: 750; }
.wkb-z { color: var(--text-3); }
@media (max-width: 560px){
  .wkb-colhead, .wkb-row { grid-template-columns: 26px minmax(0, 1fr) 60px 42px 52px; gap: 8px; padding: 10px 12px; }
  .wkb-done-bar { display: none; }
  .wkb-colhead { font-size: 10px; }
}

/* ===== iPhone team payroll (<=720px) — cards, not a sideways-scrolling table =====
   Scoped to .pay-wrap so the Partners table (which uses the same .ptable) is untouched.
   Each member row becomes a self-contained card: name/role header, a labelled stat
   strip (This month / Paid / Pending), then a full-width Invoice button. */
@media (max-width: 720px){
  .pay-wrap .ptable-scroll { overflow-x: visible; }
  .pay-wrap .ptable { min-width: 0; display: block; }
  .pay-wrap .ptable thead { display: none; }
  .pay-wrap .ptable tbody { display: flex; flex-direction: column; gap: 10px; padding: 10px; }
  .pay-wrap .ptable tbody tr {
    display: grid; grid-template-columns: 1fr auto; gap: 10px 12px; align-items: center;
    background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-sm);
    padding: 13px 14px;
  }
  .pay-wrap .ptable tbody tr:last-child td { border-bottom: 1px solid transparent; }
  .pay-wrap .ptable td { display: block; border-bottom: none; padding: 0; white-space: normal; }
  /* name spans the top row; invoice button sits to its right */
  .pay-wrap .ptable td:first-child { grid-column: 1; grid-row: 1; }
  .pay-wrap .ptable td.inv-cell { grid-column: 2; grid-row: 1; align-self: start; }
  .pay-wrap .ptable td.inv-cell .btn { white-space: nowrap; }
  /* the three money cells form a labelled stat strip across the bottom */
  .pay-wrap .ptable td:nth-child(2),
  .pay-wrap .ptable td:nth-child(3),
  .pay-wrap .ptable td:nth-child(4) {
    font-weight: 700; font-size: 15px;
  }
  .pay-wrap .ptable td:nth-child(2) { grid-column: 1; grid-row: 2; padding-top: 10px; margin-top: 2px; border-top: 1px solid var(--hairline); }
  .pay-wrap .ptable td:nth-child(3) { grid-column: 2; grid-row: 2; padding-top: 10px; margin-top: 2px; border-top: 1px solid var(--hairline); text-align: left; }
  .pay-wrap .ptable td:nth-child(4) { grid-column: 1 / -1; grid-row: 3; font-size: 13.5px; }
  .pay-wrap .ptable td:nth-child(2)::before { content: 'This month'; }
  .pay-wrap .ptable td:nth-child(3)::before { content: 'Paid'; }
  .pay-wrap .ptable td:nth-child(4)::before { content: 'Pending'; }
  .pay-wrap .ptable td:nth-child(2)::before,
  .pay-wrap .ptable td:nth-child(3)::before,
  .pay-wrap .ptable td:nth-child(4)::before {
    display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
    color: var(--text-3); font-weight: 700; margin-bottom: 3px;
  }
  /* Next payout + Status are secondary on a phone — hide to keep the card clean */
  .pay-wrap .ptable td:nth-child(5),
  .pay-wrap .ptable td:nth-child(6) { display: none; }
}

/* Responsive */
@media (max-width: 980px) {
  .brand-name { display: none; }
}
/* v739 TOMBSTONE — the three VIEWPORT-keyed task-list templates that used to live right here
   (`@media (max-width:1180px)` 7-col, `@media (max-width:980px)` 6-col, and the `@media
   (max-width:760px)` 5-col block further down) are DELETED, not moved. They keyed the column
   ladder to the window while the thing that clips is the CARD, so they fired at the wrong width
   in both directions at every desktop/tablet size (V738-1b / V738-1d, measured below). The
   container ladder underneath now owns every width ≥721px. They were already 100% dead at
   ≤720px — the phone block restores all 8 columns with `.tlist-inner .trow {…!important}` (0,2,0)
   and `.tlist-inner .col-* {display:flex !important}` (0,2,0), both of which outrank them — which
   is why deleting them is provably a no-op on phones (pixel-diffed at 375/520/620/700/720).
   Only `.brand-name{display:none}` survives from the ≤980 block: it is sidebar chrome, not the
   task list, and it is the one rule in there that really is a viewport question. */
/* ===== V738-1 (+ v739 V738-1b/1c/1d) — the task-list relief valve keys off the CARD ==========
   `.trow` is a FIXED-track grid with a measured 996px floor, and it lives inside `.table-card`
   (`overflow:hidden`, no scrollbar, `text-overflow:clip`). The card is NOT the viewport: it is
   viewport − 352px with the sidebar expanded (264 sidebar + 16 gap + 2×16 layout gutter + 2×20
   .content pad), viewport − 162px when the sidebar is collapsed (74px), and viewport − 56px below
   901px, where the sidebar leaves the flow entirely and becomes an off-canvas drawer. A ladder
   keyed to the WINDOW therefore cannot be right at more than one of those three ratios at a time,
   and the deleted rules above were wrong at all of them:
     · v738 fixed ≥1181px (at 1280 the card was 928 against a 996 grid — Priority clipped 54 of
       84px in all 24 theme combos; at 1181 Priority was 100% gone and Due lost 57px).
     · V738-1b, the SAME bug below 1181: at 981–1180 expanded the card is 629–828px and the old
       7-col template needed 842px — deficit up to 213px, Priority 0–80px of 80px visible; at 980
       expanded the old 6-col template (floor 700px) overflowed a 628px card by 72px. Worst case
       measured anywhere in this regime: viewport 901 expanded, card 549px, deficit 151px.
     · V738-1d, the mirror image: at 1180 COLLAPSED the card is 1018px and holds all 8 columns,
       yet the viewport rule hid Client anyway.
   ONE card-keyed ladder answers all of it. Steps are MEASURED floors, not guesses — headless
   Chrome 139, `.table-card` scrollWidth binary-searched against a pinned template with the ladder
   itself disabled (a live ladder deletes grid ITEMS and reports a fictitiously low floor):
     8 cols = 996px · 7 cols = 868px (v738's number; re-measured at 864 here — kept at 868 so
     ≥1181px stays byte-identical to what shipped) · 6 cols = 748px · 5 cols = 602px.
   Every template is the 8-col one with a column REMOVED — never the old tablet templates, which
   also shaved Status/Dept/Due/Priority by 2–4px each and squeezed the ASSIGNEE header (label +
   its hide-column kebab) into 92px, where it wrapped and made the header row 49.5px instead of
   33px. Measured: the deleted rules produced a 49.5px header at EVERY width ≤1180; this block
   produces 33px everywhere. So the only visible change at any width is which columns are present.
   BOTTOM OF THE LADDER (the deliberate decision). Below the 5-col floor the honest answer is a
   SCROLLBAR, not a sixth template: the next column to drop would be Status, and a task list
   without a status is not a task list. `overflow-x:auto` on the card (below) makes the shortfall
   reachable instead of invisible — nothing is hidden, nothing is clipped. It is only reachable in
   one narrow band, viewport 901–953 with the sidebar expanded (card 549–601px), which is exactly
   where the old rules clipped 151px in silence. A container query cannot style its own container,
   so the `overflow-x` sits on the unconditional rule, where `auto` costs nothing until something
   actually overflows — and that same property is the CSS half of V738-1c (see the note on it).
   GATED ≥721px, and 721 is not a round number: the ≤720px phone block gives `.tlist-inner`
   `width:max-content`, and inline-size containment would collapse that intrinsic width to its
   700px min-width. 721 is the first width at which that rule is not in play, so it is the lowest
   width containment can safely reach. Below it the phone block owns the layout outright (all 8
   columns, `.tlist-scroll` scrolls sideways) and nothing in here applies.
   EVERY template/hide selector is scoped `.table-card:not(.has-hidden-cols)`, and that is
   load-bearing, not tidiness. When an admin hides a built-in column the card carries
   `.has-hidden-cols` and an inline `--trow-tpl !important` whose track list STILL CONTAINS a
   Client track. An unscoped `.col-client{display:none}` deletes the grid ITEM while that template
   keeps the track, so every cell after Client slides one column left. That is not a hypothetical:
   the deleted viewport rules WERE unscoped, and at 721px with Department hidden they measurably
   produced Assignee sitting in the 120px CLIENT track, Priority sitting in the 96px ASSIGNEE
   track, the last two tracks (104px Due, 84px Priority) empty, and the "+ FIELD" chip painted on
   top of the shifted Priority cell. Deleting them fixes that too: the same admin at 721px now
   gets all seven of their own columns in their own tracks, with the 185px shortfall reachable as
   a scroll instead of a wrong layout.
   The two OVERFLOW rules are deliberately NOT scoped `:not(.has-hidden-cols)`: they change no
   track list and delete no grid item, so they cannot cause that shift — they can only turn a
   silent clip into a reachable scroll, which a hidden-columns admin needs just as much as anyone
   else. (The js/app.js lane also puts `has-custom-cols` on `.has-hidden-cols` cards, so the two
   compose; verified.)
   KNOWN RESIDUAL, inherited not introduced. Every step fires at the grid's INK floor, but the row
   reserves a further 78px on the right for the "+ FIELD" chip. Between a step's floor and
   floor+78 the tracks spill into that gutter and the chip (z-index 3, opaque plate) paints over
   the tail of the rightmost column's LABEL — "PRIORIT" instead of "PRIORITY". The column itself
   is fully inside the card and every row's flag is visible; only the header word is shortened.
   This is v738's convention, measured in the SHIPPED build at 1348-1423px expanded before this
   lane touched anything, and the new steps follow it so all four behave the same way. Curing it
   means adding the 78px gutter to every threshold (996→1072 · 868→940 · 748→824 · 602→678),
   which changes ≥1181px rendering, so it is a separate call, not a silent edit here. */
@media (min-width: 721px) {
  .table-card {
    container-type: inline-size; container-name: tasklist;
    /* the ONE narrow-card affordance in this file: the card scrolls, it never silently clips.
       Inert until something overflows (`auto`, and the y axis stays `hidden` from :2071, so no
       vertical scrollbar and no change to the group-collapse/radius clip). Safe next to
       inline-size containment: the container's queried width is its content box, which
       containment fixes independently of its contents, so there is no resize loop. */
    overflow-x: auto;
  }
  /* V738-1c, CSS half. With custom task columns the grid needs more width than ANY static
     threshold can know (one custom field pushes the 8-col floor from 996px to 1114px, so the
     card clips at 1348–1466px expanded). The js/app.js lane puts `has-custom-cols` on the
     `.table-card` emitter for exactly this. The unconditional `overflow-x` above already covers
     it; this named rule is the durable contract, so a future re-gating of that line cannot
     silently un-fix V738-1c. Dormant and harmless until the class exists. */
  .table-card.has-custom-cols { overflow-x: auto; }
  /* card can't hold the 8-col grid -> drop Client, every other track unchanged */
  @container tasklist (width < 996px) {
    .table-card:not(.has-hidden-cols) .trow { grid-template-columns: 26px minmax(200px,2.2fr) 122px 134px 96px 104px 84px; }
    .table-card:not(.has-hidden-cols) .col-client { display: none !important; }
    /* custom columns only ride the widest template (the narrower ones omit the --tcc tracks) */
    .table-card:not(.has-hidden-cols) .task-col-custom { display: none !important; }
  }
  /* still short -> drop Due as well */
  @container tasklist (width < 868px) {
    .table-card:not(.has-hidden-cols) .trow { grid-template-columns: 26px minmax(200px,2.2fr) 122px 134px 96px 84px; }
    .table-card:not(.has-hidden-cols) .col-client,
    .table-card:not(.has-hidden-cols) .col-due { display: none !important; }
  }
  /* still short -> drop Department. Last template: Status is the floor of what a task row means. */
  @container tasklist (width < 748px) {
    .table-card:not(.has-hidden-cols) .trow { grid-template-columns: 26px minmax(200px,2.2fr) 122px 96px 84px; }
    .table-card:not(.has-hidden-cols) .col-client,
    .table-card:not(.has-hidden-cols) .col-due,
    .table-card:not(.has-hidden-cols) .col-dept { display: none !important; }
  }
  /* Under the 5-col floor the card is scrolling (see `overflow-x` above). Hold the ROW at that
     floor so the header band, the row hairlines and the hover/zebra fills reach the end of the
     scrolled content instead of stopping at the card edge. 602px is the measured 5-col floor, so
     the row is exactly as wide as its own ink — never wider. (`min-content` is NOT usable here:
     the row reserves 78px of right padding for the "+ FIELD" chip, which makes its min-content
     1072px on the 8-col template and would force a scrollbar onto every desktop.) */
  @container tasklist (width < 602px) {
    .table-card:not(.has-hidden-cols) .trow { min-width: 602px; }
  }
}
/* iPhone (G13): native form controls MUST be ≥16px or iOS Safari auto-zooms the whole page on
   focus (the owner's "inputs zoom in" complaint). Scoped to phone widths so desktop's compact
   inputs/selects stay as-is. Catches EVERY native control regardless of class — login, search,
   pickers, group-by select, modal fields, textareas. */
@media (max-width: 720px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="color"]),
  textarea,
  select { font-size: 16px; }
}
/* v739: the `@media (max-width:760px)` 5-col task template that sat here is DELETED — see the
   tombstone above the container ladder. 721–760px now gets the SAME 5-col step off the card's own
   width (with the desktop track widths, so the header stops wrapping at 49.5px), and ≤720px was
   already overriding every line of it from the phone block below. */
@media (max-width: 620px) {
  .content { padding: 12px; }
  .crumb-space, .crumb-sep, .crumb-meta { display: none; }
  .demo-banner { margin: 10px 12px 0; }
}
/* Clean, TIGHT toolbar on phones: tabs scroll on their own row, then ONE tidy
   row of [group-by] ........ [New]. Power chrome (+Field, Save-view/Filter) is
   desktop-only so the phone header stays short and content shows immediately. */
@media (max-width: 720px) {
  /* run5 §1.2 — phones: the head floats with a tighter inset. The MARGIN owns the notch
     clearance (safe insets come off the margin so the box can only SHRINK — the 402pt
     rubber-band lesson; padding-top no longer carries safe-top, the sticky top offset does).
     .layout's desktop gutter is zeroed here so the inset isn't doubled on a small screen.
     `header.mainhead` (0-1-1) on purpose: it must beat BOTH the later base .mainhead rule
     and glass.css's .g-chrome (both 0-1-0, and glass.css loads after this <style>). */
  /* div.layout (0-1-1), NOT .layout: this media block sits BEFORE the base .layout rule
     (~:4543) in the same stylesheet, so at equal specificity the base would win by source
     order and keep its 16px desktop gutter — which is exactly what stacked with the head's
     own margin and produced three different phone gutters (head 24 / content 16 / bar 12). */
  div.layout { padding: 0; }
  header.mainhead {
    /* 12px, matching .content's padding and the tab bar's left/right — ONE phone gutter.
       Safe insets come off the margin so the box can only shrink (402pt lesson). */
    margin: var(--g-s-3, 12px) var(--g-s-3, 12px) 0;
    margin-left: calc(var(--safe-left) + var(--g-s-3, 12px));
    margin-right: calc(var(--safe-right) + var(--g-s-3, 12px));
    top: calc(var(--safe-top) + var(--g-s-3, 12px));
    border-radius: var(--g-r-chrome);
    padding: 10px 14px 0;
  }
  /* run6 W5c (R6-5): scrolled row content (the blue tcheck ring) showed through the transparent
     gutter ABOVE the floating sticky header card. A fixed canvas strip pinned just under the
     head's z-index (89 < 90) masks the top gutter plus the head's radius-corner notches; the
     side gutters need nothing — content is inset to the same 12px gutter (R5-8). Unscrolled the
     strip is invisible (it IS the canvas colour). */
  /* R6-47 (v726): the phone-only mask that lived here moved to a top-level app-wide plate next
     to .mainhead — see the R6-47 block there. The old height read var(--g-r-chrome), which is a
     4-VALUE list in terra → invalid calc() → height 0 (R6-5 was silently regressed on terra
     phones; verified live). Do not re-add a copy here — two .main::before rules must not coexist. */
  .crumb { margin-bottom: 10px; }
  .head-controls { gap: 8px; row-gap: 8px; padding-bottom: 10px; align-items: center; }
  .head-controls .head-spacer { display: none; }
  .head-controls .tabset { order: -1; flex: 1 0 100%; max-width: 100%; }
  .head-controls .groupby { order: 1; }
  .head-controls .btn-refresh { order: 2; }
  /* +Field (add custom column) is a desktop power-task — hide on phones */
  .head-controls > .btn-ghost[data-act="add-field-menu"] { display: none; }
  /* primary action fills the remaining space on its row — no dead gap to its
     left (esp. on Partners, which has no group-by to share the row with) */
  .head-controls .btn-primary { order: 3; flex: 1 1 auto; justify-content: center; padding: 11px 16px; font-size: 14px; }
  .head-controls .groupby { flex: 0 0 auto; }
  .head-controls .groupby select { padding: 8px 26px 8px 11px; }
  /* Save-view / Filter chip row: desktop-only — keeps the phone header brief */
  .viewfilter-row { display: none !important; }
}

/* ===== iPhone MASTER TASK LIST — scroll the WHOLE table sideways =====
   Instead of hiding columns, every column (all 8 + any custom --tcc tracks)
   stays intact and the .tlist-scroll wrapper scrolls horizontally, exactly
   like the partner table (.ptable-scroll). The kebab stays reachable at the end. */
@media (max-width: 720px) {
  .tlist-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    /* contained, rounded card with breathing room from the screen edge (NOT edge-to-edge).
       run6 W5c: this surface only exists ≤720px, so a markup class would card it on desktop
       too — the .glass-2 recipe is restated here from the same tokens instead (documented
       deviation from the additive method). Legacy border deleted; the edge is in the stack. */
    margin: 0; border-radius: var(--g-r-card);
    background-color: var(--g-fill-2); background-image: var(--g-sheen-2);
    -webkit-backdrop-filter: var(--g-blur-2); backdrop-filter: var(--g-blur-2);
    box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-2);
  }
  .tlist-scroll::-webkit-scrollbar { height: 6px; }
  .tlist-inner { min-width: 700px; width: max-content; }
  .tlist-inner .group { margin-bottom: 0; }
  .tlist-inner .table-card { border: none; box-shadow: none; background: transparent; border-radius: 0; }

  /* Restore the FULL 8-column grid on phones — the horizontal scroll handles
     overflow instead of dropping columns. Higher specificity + !important beat
     the tablet breakpoints above. */
  .tlist-inner .trow {
    /* FIXED widths (not fr) so width:max-content stays bounded (~900px) and the task name
       truncates with an ellipsis instead of stretching the table to thousands of px */
    grid-template-columns: 24px 232px 112px 122px 150px 92px 96px 78px var(--tcc, ) !important;
    /* 521-720px is TOUCH: the row stays a full 44px target (--ctl-touch), never the
       36px desktop --row-h. Density never buys itself out of tap ergonomics. */
    min-height: var(--ctl-touch); padding-top: var(--space-1); padding-bottom: var(--space-1);
  }
  .tlist-inner .tname-wrap { overflow: hidden; min-width: 0; }
  .tlist-inner .col-client,
  .tlist-inner .col-due,
  .tlist-inner .col-dept,
  .tlist-inner .col-assignee,
  .tlist-inner .col-prio,
  .tlist-inner .task-col-custom { display: flex !important; }
  /* status badge cell isn't a .col-* but is grid child 3 — already visible */
  .tlist-inner .col-prio { justify-content: flex-start; }
  .tlist-inner .col-prio .prio { display: inline-flex !important; }
  .tlist-inner .row-kebab { opacity: .85; }
}

/* ===== ≤520px — MASTER TASK LIST: rows collapse into stacked CARDS =====
   Mirrors the Partner Tracker's phone cards (below). Uses the data-label attrs
   already on every task cell — additive only; sits AFTER the ≤720px scroll block
   so it wins by higher specificity. Desktop + tablet (521–720px) are untouched. */
@media (max-width: 520px) {
  .tlist-inner .trow.thead { display: none !important; }
  .tlist-scroll { overflow-x: visible; background: transparent; border: none; box-shadow: none; border-radius: 0; }
  .tlist-inner { min-width: 0; width: 100%; }
  .tlist-inner .group { margin-bottom: 0; }
  .tlist-inner .table-card { background: transparent; border: none; box-shadow: none; border-radius: 0; }
  /* each task row -> a self-contained card. v639: same token values as the winning
     ≤520 block further down (the "MASTER TASK LIST" section), so whichever one the
     cascade resolves to, the card measures the same. Card language: opaque --card,
     one hairline, --radius-md, NO blur, NO shadow (§3.4). */
  .tlist-inner .trow:not(.thead) {
    display: block; overflow: hidden; grid-template-columns: none !important;
    background: var(--card);
    border: 1px solid var(--hairline); border-radius: var(--radius-md);
    box-shadow: none; padding: var(--space-2) var(--space-3) var(--space-1); margin-bottom: var(--space-2); min-height: 0; gap: 0;
  }
  .tlist-inner .row-grip { display: none; }   /* the weaker (0,2,0) half of the pair that hides the V1 task-list handle on phones. OVERRIDDEN at (max-width:520px) and (pointer:coarse) by the injected sheet #v670-griptouch-css (_gripTouchEnsureCss, js/app.js, v671) — see the full note on its (0,3,0) twin at :4455, which is the one the override actually ties. */
  /* status circle -> leading checkbox in the card header */
  .tlist-inner .tcheck { float: left; margin: 1px var(--space-2) 0 0; }
  /* task name -> bold card header */
  .tlist-inner .tname-wrap { display: block; overflow: hidden; padding: 0 0 var(--space-2); margin: 0; border-bottom: var(--hairline-w) solid var(--hairline); min-width: 0; }
  .tlist-inner .tname { font-size: var(--fs-body); font-weight: var(--fw-semi); white-space: normal; }
  /* every data cell already carries data-label -> label / value row. --row-h-compact
     (30px) is the dense-row token: these field rows are LABELS, not tap targets —
     the tappable things inside them (badge, kebab) keep their own sizes. */
  .tlist-inner .trow:not(.thead) > [data-label] {
    clear: both; display: flex !important; align-items: center; justify-content: flex-start !important;
    gap: var(--space-3); padding: var(--space-1) 0; border-bottom: var(--hairline-w) solid var(--hairline); white-space: normal;
    font-size: var(--fs-body); min-height: var(--row-h-compact); width: auto; text-align: right;
  }
  .tlist-inner .trow:not(.thead) > [data-label]:last-child { border-bottom: none; }
  /* the label sits left; margin-right:auto on it pushes the value — a text node OR a group of
     elements (avatars, badge+kebab) — to the right edge together (verified at 375px). !important
     beats a base .assignees rule that otherwise gives the 2nd avatar an auto-margin (spreads them). */
  .tlist-inner .trow:not(.thead) > [data-label]::before {
    content: attr(data-label); flex: 0 0 auto; color: var(--text-3); font-size: var(--fs-small); font-weight: var(--fw-medium); text-align: left; margin-right: auto !important;
  }
  /* zero any competing auto-margins on value children (the flex gap handles spacing) so multi-avatar
     assignee cells + badge-with-kebab priority cells stay grouped on the right instead of spreading. */
  .tlist-inner .trow:not(.thead) > [data-label] > * { margin-left: 0 !important; margin-right: 0 !important; text-align: right; }
  .tlist-inner .trow:not(.thead) > .col-prio > .row-kebab { margin-left: var(--space-1) !important; }
  .tlist-inner .col-assignee { flex-wrap: wrap; }
  /* standalone kebab cell (only when the Priority column is hidden) -> its own right-aligned row */
  .tlist-inner .trow-kebab-cell { clear: both; justify-content: flex-end; padding: var(--space-1) 0 0; border-bottom: none; }
}

/* ===== TABLET / large-phone (521–768px) — PARTNER TRACKER scroll-card =====
   Mirrors the Master Task List's tablet treatment: instead of a raw 1080px
   table bleeding sideways, the .ptable-scroll becomes a contained, rounded,
   horizontally-scrollable card with breathing room from the screen edge.
   Stays a table (cards take over below 520px). Desktop is untouched. */
@media (min-width: 521px) and (max-width: 768px) {
  /* run6 W5c: width-scoped surface — .glass-2 recipe restated from tokens (same deviation +
     reason as .tlist-scroll ≤720); legacy border deleted */
  .pt-partners .ptable-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
    border-radius: var(--g-r-card);
    background-color: var(--g-fill-2); background-image: var(--g-sheen-2);
    -webkit-backdrop-filter: var(--g-blur-2); backdrop-filter: var(--g-blur-2);
    box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-2);
  }
  .pt-partners .ptable-scroll::-webkit-scrollbar { height: 6px; }
}

/* =====================================================================
   iPhone (≤520px) — PARTNER TRACKER + MASTER TASK LIST become STACKED CARDS
   No horizontal scrolling, no page overflow. Each row = one clean card:
   a bold header (company / task title) + labelled field rows
   (label muted on the left, value on the right). Mirrors the Payments
   invoice-card pattern. DESKTOP IS UNTOUCHED — everything is scoped to this
   query + the partner table is scoped to .pt-partners so the payroll table
   (.pay-wrap .ptable) keeps its own card treatment.
   ===================================================================== */
/* SIM-01: the phone fold chevron is a real <button> (data-act="pt-mchev") so it can toggle instead of
   falling through to the name cell's open-the-drawer act. These are the button-vs-span resets only —
   the visual box, position and rotation below are unchanged. */
.pt-mchev { display: none; background: none; border: 0; font: inherit; cursor: pointer; -webkit-appearance: none; appearance: none; }
@media (max-width: 520px){
  /* ---------- PARTNER TRACKER ---------- */
  /* run6 W5c: (0,2,0) bump + full primitive strip — the wrap now carries .glass-2, and a plain
     .pt-partners (0,1,0) tie is won by glass.css (loads after this <style>); sheen/blur/radius
     strips added so the card-mode switch actually un-cards the primitive */
  .ptable-wrap.pt-partners { overflow: visible; background: transparent; background-image: none; -webkit-backdrop-filter: none; backdrop-filter: none; border: none; box-shadow: none; border-radius: 0; }
  .pt-partners .ptable-scroll { overflow-x: visible; }
  .pt-partners .ptable { min-width: 0; display: block; }
  .pt-partners .ptable thead { display: none; }
  .pt-partners .ptable tbody { display: flex; flex-direction: column; gap: 12px; }
  /* each partner row -> a self-contained card. run6 W5c: per-row BLUR was the scroll-perf trap —
     restated as the .g-solid-2 recipe (opaque twin) from the same tokens (width-scoped surface,
     same deviation + reason as .tlist-scroll ≤720). */
  .pt-partners .ptable tbody tr {
    display: block; cursor: pointer;
    background-color: var(--g-solid-2); border-radius: var(--g-r-card);
    box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-2);
    padding: 6px 14px 8px; overflow: hidden;
  }
  .pt-partners .ptable tbody tr:hover { background-color: var(--g-solid-3); }
  .pt-partners .ptable tr:last-child td { border-bottom: none; }
  /* generic field cell -> label/value row */
  .pt-partners .ptable td {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    padding: 9px 0; border-bottom: 1px solid var(--hairline); white-space: normal;
    font-size: 13.5px; min-height: 40px;
  }
  .pt-partners .ptable td:last-child { border-bottom: none; }
  .pt-partners .ptable td::before {
    content: attr(data-label); flex: 0 0 auto; color: var(--text-3);
    font-size: 12px; font-weight: 600; letter-spacing: .01em;
  }
  /* the value side hugs the right edge and stays legible */
  .pt-partners .ptable td > * { margin-left: auto; text-align: right; }
  .pt-partners .ptable td .cs-labels { flex-wrap: wrap; justify-content: flex-end; gap: 5px; }
  .pt-partners .ptable td .assignees { justify-content: flex-end; }
  .pt-partners .ptable td.money { font-variant-numeric: tabular-nums; }
  /* COMPANY-NAME cell = card header: full width, bold, logo, no label, no flex-split */
  .pt-partners .ptable td.pt-namecell {
    display: flex; justify-content: flex-start; gap: 0; padding: 8px 0 10px;
    border-bottom: 1px solid var(--hairline); min-height: 0;
  }
  .pt-partners .ptable td.pt-namecell::before { content: none; }
  .pt-partners .ptable td.pt-namecell > * { margin-left: 0; text-align: left; }
  .pt-partners .ptable .p-name { gap: 11px; min-width: 0; width: 100%; }
  .pt-partners .ptable .p-name .pgrip { display: none; }   /* STALE CLAIM DELETED (was: "native DnD doesn't fire from touch; reclaim the space"). True when written, false since wirePartnerDnD went pointer-based — it binds pointerdown/pointermove/pointerup on .trow-grip-ic and sets touch-action:none, so touch and pen commit through the SAME Store.reorderPartners call as the mouse. This rule is now OVERRIDDEN at (max-width:520px) and (pointer:coarse) by the injected sheet #v670-griptouch-css (_gripTouchEnsureCss, js/app.js, v670), which restores the handle as `display:grid` at 16px. A fine pointer under 520px still reclaims the space exactly as before. Do not "clean up" this rule: the injected override is a deliberate specificity TIE with it and relies on it existing. */
  .pt-partners .ptable .p-name > span:last-child { min-width: 0; flex: 1; }
  /* FOLD (owner 2026-07-19): default = header-only card; .is-mopen expands. Accordion via State.ptMobOpen. */
  .pt-partners .ptable tbody tr.is-mfold td { display: none; }
  .pt-partners .ptable tbody tr.is-mfold td.pt-namecell { display: flex; border-bottom: none; padding: 8px 0; }
  /* SIM-01: padding grows the TAP TARGET to ~36px; the matching negative margins keep the icon on the
     exact pixel it sat on before, so the card header does not move. */
  .pt-partners .pt-mchev { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto; margin: -10px -10px -10px -4px; padding: 10px; color: var(--text-3); transition: transform var(--dur-2) ease; }
  .pt-partners .pt-mchev svg { width: 16px; height: 16px; }
  .pt-partners .ptable tbody tr.is-mopen .pt-mchev { transform: rotate(180deg); }
  /* run6 W5c: the open-card accent signal was a border tint — restated as an inset ring on the
     g-solid-2 shadow stack (the border died with the surface conversion above) */
  .pt-partners .ptable tbody tr.is-mopen { box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-2), inset 0 0 0 1.5px color-mix(in srgb, var(--accent, #e5322b) 35%, transparent); }
  .pt-partners .ptable .p-name b { font-size: 15px; white-space: normal; }
  .pt-partners .ptable .p-name small { white-space: normal; }
  .pt-partners .ptable .p-logo { width: 34px; height: 34px; }
  /* kebab cell -> a labelled "Actions" row so it stays reachable */
  .pt-partners .ptable td.p-kebab-cell { width: auto; text-align: left; padding: 9px 0 2px !important; }
  .pt-partners .ptable td.p-kebab-cell::before { content: 'Actions'; }
  .pt-partners .ptable td.p-kebab-cell .row-kebab { opacity: 1; width: 32px; height: 32px; }
  /* keep "+ set" / "+ date" hints visible on touch (no hover) */
  .pt-partners .ptable td .cell-add { opacity: 1 !important; }
  /* totals footer -> a static stacked glass card (NOT sticky) so it can't
     overlap the iPhone tab bar and mangle the live MRR/ad-spend numbers.
     Mirrors the Payments invoice-card tfoot pattern. */
  .pt-partners .ptable tfoot { display: block; }
  .pt-partners .ptable tfoot tr.pt-totals { display: block; }
  /* run6 W5c: full legacy-glass re-pin → .g-solid-2 recipe (static stacked card, no blur needed;
     width-scoped surface, same deviation + reason as the row-cards above) */
  .pt-partners .ptable tfoot tr.pt-totals td {
    position: static; bottom: auto; display: flex; flex-wrap: wrap; gap: 8px 18px;
    background-color: var(--g-solid-2); border-radius: var(--g-r-card);
    border: none;   /* the base .pt-totals td 2px border-top is the DESKTOP sticky separator — a free-standing card draws its edge via the g stack */
    box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-2);
    padding: 13px 14px; margin-top: 4px;
  }
  .pt-partners .ptable tfoot .pt-tot { margin-left: 0 !important; }
  .pt-partners .ptable tfoot .pt-tot-sep { margin-left: 0 !important; }

  /* ---------- MASTER TASK LIST ---------- */
  /* override the ≤720px horizontal-scroll block: cards instead of a sideways table */
  .tlist-scroll {
    overflow-x: visible !important; width: 100%;
    margin: 0; border: none !important; background: transparent !important;
    box-shadow: none !important; border-radius: 0 !important;
  }
  .tlist-inner { min-width: 0 !important; width: 100% !important; }
  .tlist-inner .group { margin-bottom: var(--space-4); }
  .tlist-inner .table-card { background: transparent !important; border: none !important; box-shadow: none !important; }
  .tlist-inner .table-card .trow.thead { display: none !important; }   /* column header row makes no sense as a card */
  .tlist-inner .table-card { display: flex; flex-direction: column; gap: var(--space-2); }
  /* each task row -> a card. Flatten the depth indent to one subtle step.
     Covers both the normal table-card and the .has-hidden-cols variant whose
     base rule (line ~478) sets grid-template-columns:var(--trow-tpl)!important.
     v639: this is the block that WINS the ≤520 cascade (3 classes + !important),
     so it owns the real phone card height. Card language per §3.4 — opaque
     --card, one hairline, --radius-md, no blur, no shadow. */
  .tlist-inner .table-card .trow,
  .tlist-inner .table-card.has-hidden-cols .trow {
    display: grid !important;
    grid-template-columns: auto 1fr auto !important;   /* check | title | (kebab handled inside cols) */
    grid-auto-rows: min-content; align-items: center;
    column-gap: var(--space-2); row-gap: 0;
    padding: var(--space-2) var(--space-3) var(--space-1) !important; min-height: 0 !important;
    background: var(--card);
    border: 1px solid var(--hairline) !important; border-radius: var(--radius-md);
    box-shadow: none;
  }
  /* header line: status-check + title span the top row */
  .tlist-inner .trow .tcheck { grid-column: 1; grid-row: 1; position: relative; }
  /* keep the 18px circle but extend the touch target to ~32px on phones */
  .tlist-inner .trow .tcheck::before { content: ""; position: absolute; inset: -7px; border-radius: var(--radius-pill); }
  .tlist-inner .trow .tname-wrap { grid-column: 2 / -1; grid-row: 1; overflow: hidden; min-width: 0; }
  .tlist-inner .trow .row-grip { display: none; }     /* STALE CLAIM DELETED (was: "native DnD doesn't fire from touch"). True when written, false since wireListDnD went pointer-based in v548 — it binds pointerdown/pointermove/pointerup, so touch and mouse drive ONE path. This rule (and its 0,2,0 twin at :4287) is now OVERRIDDEN at (max-width:520px) and (pointer:coarse) by the injected sheet #v670-griptouch-css (_gripTouchEnsureCss, js/app.js — partner block v670, this task-list block v671), which restores the handle as `display:grid` in the card's left gutter. A fine pointer under 520px still gets the hidden-handle layout byte-for-byte. Do not "clean up" this rule: the injected override is a deliberate specificity TIE with it and relies on it existing. */
  .tlist-inner .trow .tname { white-space: normal; font-size: var(--fs-body); font-weight: var(--fw-semi); }
  /* subtasks: one subtle indent step (don't cascade deep nesting on a phone) */
  .tlist-inner .trow[style*="padding-left"] { padding-left: var(--space-3) !important; }
  .tlist-inner .trow[style*="padding-left"] .tname-wrap { box-shadow: -10px 0 0 -8px var(--accent-soft); padding-left: var(--space-2); }
  /* every built-in field becomes a full-width labelled row below the title.
     :not(.task-col-custom) keeps user-added custom columns desktop-only (parity
     with the wider breakpoints) — they'd otherwise match span[data-label].
     --row-h-compact (30px) + --space-1 padding is what takes the card from 305px
     to ~230px: six 41-49px field rows were the whole cost. These rows are labels,
     not tap targets — the badge / kebab inside keep their own hit sizes. */
  .tlist-inner .trow > span[data-label]:not(.task-col-custom){
    grid-column: 1 / -1; display: flex !important; align-items: center; justify-content: space-between;
    gap: var(--space-3); padding: var(--space-1) 0; margin: 0; border-top: var(--hairline-w) solid var(--hairline);
    font-size: var(--fs-body); min-height: var(--row-h-compact);
  }
  .tlist-inner .trow > span[data-label]:not(.task-col-custom)::before{
    content: attr(data-label); flex: 0 0 auto; color: var(--text-3);
    font-size: var(--fs-small); font-weight: var(--fw-medium);
  }
  .tlist-inner .trow > span[data-label]:not(.task-col-custom) > *{ margin-left: auto; }
  .tlist-inner .trow .col-assignee.assignees { justify-content: flex-end; }
  .tlist-inner .trow .col-due { font-variant-numeric: tabular-nums; }
  /* Priority row holds the kebab too — keep both, push kebab to the far right */
  .tlist-inner .trow .col-prio { justify-content: space-between; }
  .tlist-inner .trow .col-prio .prio { margin-left: auto; }
  .tlist-inner .trow .col-prio .row-kebab { opacity: 1; margin-left: var(--space-2); width: var(--ctl-md); height: var(--ctl-md); }
  /* if Priority is hidden, the trailing kebab cell still gets a row */
  .tlist-inner .trow .trow-kebab-cell {
    grid-column: 1 / -1; justify-content: flex-end; padding: var(--space-1) 0 0; border-top: var(--hairline-w) solid var(--hairline);
  }
  .tlist-inner .trow .trow-kebab-cell .row-kebab { opacity: 1; width: var(--ctl-md); height: var(--ctl-md); }
  /* custom task columns stay desktop-only (parity with the wider breakpoints) */
  .tlist-inner .trow .task-col-custom { display: none !important; }
  .tlist-inner .trow .cell-add { opacity: 1 !important; }
  /* phone: the "+ Add task" row is a real touch target */
  .tlist-inner .add-row { padding: 0 var(--space-3); min-height: var(--ctl-touch); }
}
.hidden { display: none !important; }

/* ===================== Sidebar + layout (ClickUp-style) ===================== */
/* run5 §1.1 — inset shell: the theme canvas/mesh frames every floating chrome panel.
   Horizontal gutter only; the panels own their vertical insets via sticky top + margin.
   The gutter absorbs safe-left/right (0 on desktop) because the head/content no longer pad
   for the notch themselves — matters on 721-900px landscape phones where the notch is lateral. */
.layout { display: flex; min-height: 100vh; min-height: 100dvh; gap: var(--g-s-4, 16px);
  padding: 0 calc(var(--safe-right) + var(--g-s-4, 16px)) 0 calc(var(--safe-left) + var(--g-s-4, 16px)); }
/* The drawer scrim div sits BETWEEN the two flex children. On desktop it was an unstyled 0-wide
   block, invisible — but .layout's new gap would count it and silently double the gutter to 32px.
   Hidden until the ≤900px drawer block re-enables it (that rule sets display:block itself). */
.sb-scrim { display: none; }
.sidebar {
  width: 264px; flex-shrink: 0; position: sticky; top: var(--g-s-4, 16px); z-index: 120;
  /* run5 §1.1 — floating panel: inset height matches the sticky top so the canvas shows on all
     sides. .g-chrome (added in js/app.js renderSidebar) owns background/blur/radius/shadow, so
     the legacy glass paint + border-right are gone: two backgrounds = muddy tint in dark themes,
     and a floating panel has no attachment edge for a border to sit on. */
  height: calc(100vh - 2*var(--g-s-4, 16px)); height: calc(100dvh - 2*var(--g-s-4, 16px));
  display: flex; flex-direction: column;
  padding-left: var(--safe-left);
}
.sb-brand { display: flex; align-items: center; gap: 11px; padding: 18px 18px 14px; padding-top: calc(18px + var(--safe-top)); }
.sb-brand .brand-name { font-size: 14.5px; }
.sb-bell { margin-left: auto; position: relative; width: 36px; height: 36px; display: grid; place-items: center; border-radius: var(--radius-md); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2); cursor: pointer; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; flex-shrink: 0; }
.sb-bell:hover { color: var(--text); background: var(--glass-strong); }
.sb-bell svg { width: 18px; height: 18px; }
/* collapse-to-icons (desktop) */
.sb-collapse { width: 30px; height: 30px; display: grid; place-items: center; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-3); cursor: pointer; flex-shrink: 0; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; }
.sb-collapse:hover { color: var(--text); background: var(--glass-strong); }
.sb-collapse svg { width: 15px; height: 15px; transition: transform var(--dur-2) ease; transform: rotate(180deg); }
.sidebar.collapsed .sb-collapse svg { transform: rotate(0deg); }
@media (max-width: 900px) { .sb-collapse { display: none; } }
@media (min-width: 901px) {
  .sidebar.collapsed { width: 74px; }
  .sidebar.collapsed .sb-brand { padding: 16px 8px 12px; padding-top: calc(16px + var(--safe-top)); gap: 4px; justify-content: center; }
  .sidebar.collapsed .brand-name, .sidebar.collapsed .sb-bell { display: none; }
  .sidebar.collapsed .sb-nav { padding-left: 6px; padding-right: 6px; }
  .sidebar.collapsed .sb-list { font-size: 0; justify-content: center; gap: 0; padding: 11px 0; }
  .sidebar.collapsed .sb-list .sb-ic { width: 19px; height: 19px; }
  .sidebar.collapsed .sb-list .sb-ct { display: none; }
  .sidebar.collapsed .theme-seg { flex-direction: column; gap: 4px; }
  .sidebar.collapsed .theme-seg button { font-size: 0; gap: 0; padding: 9px 0; justify-content: center; }
  .sidebar.collapsed .theme-seg button svg { width: 16px; height: 16px; }
  .sidebar.collapsed .sb-install-row, .sidebar.collapsed .viewas-meta, .sidebar.collapsed .sb-viewas-btn, .sidebar.collapsed #viewasMenu { display: none; }
  .sidebar.collapsed .sb-signout { font-size: 0; gap: 0; justify-content: center; padding: 9px 0; }
  .sidebar.collapsed .sb-signout svg { width: 16px; height: 16px; }
  .sidebar.collapsed .sb-userbar, .sidebar.collapsed .sb-user { justify-content: center; padding: 6px; }
  .sidebar.collapsed .sb-foot { padding-left: 8px; padding-right: 8px; }
}
.sb-bell-badge { position: absolute; top: -4px; right: -4px; min-width: 17px; height: 17px; padding: 0 4px; border-radius: 9px; background: var(--accent); color:var(--text-on-accent,#fff); font-size: 11px; font-weight: 800; display: grid; place-items: center; border: 2px solid var(--surface); }
.notif-head { align-items: center; }
.notif-brand { display: flex; align-items: center; gap: 11px; }
.notif-logo { width: 30px; height: 30px; border-radius: var(--radius-sm); overflow: hidden; position: relative; flex-shrink: 0; background: #0b0b0e; }
.notif-body { display: flex; flex-direction: column; gap: 7px; max-height: 56vh; overflow-y: auto; }
/* run6 W5b: surface props deleted — markup now ships `notif-item g-solid-2` (js/app.js;
   repeated rows inside the glass-4 notifications modal — solid twice over). Hover retargeted
   to the solid ramp; urgent/.is-standing child tints below are untouched. */
.notif-item { display: flex; align-items: center; gap: 6px; width: 100%; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; }
.notif-item:hover { background-color: var(--g-solid-3); }
.notif-item.is-read { opacity: .55; }
.notif-main { display: flex; align-items: center; gap: 12px; flex: 1; min-width: 0; text-align: left; padding: 13px 4px 13px 14px; background: none; border: none; cursor: pointer; color: var(--text); font-family: var(--font); }
.notif-read-btn { width: 32px; height: 32px; margin-right: 8px; flex-shrink: 0; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface-2); color: var(--text-3); cursor: pointer; display: grid; place-items: center; transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease; }
.notif-read-btn svg { width: 14px; height: 14px; }
.notif-read-btn:hover { color: var(--green); border-color: var(--green); }
.notif-read-btn.done { background: var(--green-bg); color: var(--green); border-color: transparent; }
.notif-head-acts { display: flex; align-items: center; gap: 6px; }
/* run7 W4: `.notif-sub-label` deleted — DEAD. Zero hits app-wide, and nothing builds a `notif-`
   class dynamically. The notification panel's section headings never landed; its live siblings
   (.notif-head-acts above, .notif-item/.notif-ic/.notif-tx below) are untouched. */
.notif-item.urgent .notif-ic { color: var(--accent); background: var(--red-bg); }
.notif-ic { width: 36px; height: 36px; border-radius: var(--radius-md); display: grid; place-items: center; background: var(--surface-2); color: var(--text-2); flex-shrink: 0; }
.notif-ic svg { width: 17px; height: 17px; }
.notif-tx { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
/* SIM-22 · the title was `nowrap` + ellipsis, so a real release-note headline was chopped
   mid-word ("…the Partner Tracker is a real Cli…") while two empty lines of card sat under it.
   Two lines of wrap uses the space that was already there; the clamp keeps a pathological title
   from pushing the row's controls around. */
.notif-tx b { font-weight: 600; font-size: 14px; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden; overflow-wrap: anywhere; }
/* …and the BODY was rendered raw. CONFIG.reviewReady.body is ~1,800 characters of bulleted
   changelog: one notification ran about six phone screens and pushed every other notification
   out of reach. Three lines is the preview; .is-expanded (js/app.js _notifToggleMore) is the
   full text. `pre-line` only in the expanded state, so the author's blank lines and bullets
   render as written once you have actually asked to read it. */
.notif-tx small { color: var(--text-3); font-size: 12px; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; line-clamp: 3; overflow: hidden; overflow-wrap: anywhere; }
.notif-item.is-expanded .notif-tx small { -webkit-line-clamp: unset; line-clamp: unset; display: block; white-space: pre-line; line-height: 1.55; }
/* the expander is a THIRD child of the row; flex-wrap gives it its own full-width line without
   disturbing the existing two (which together still fill 100%). */
.notif-item { flex-wrap: wrap; }
.notif-more {
  flex: 1 0 100%; text-align: left; padding: 0 14px 11px; margin-top: -4px;
  border: none; background: none; cursor: pointer; font-family: var(--font);
  font-size: 12px; font-weight: 700; color: var(--accent);
}
.notif-more:hover { text-decoration: underline; }
.notif-empty { text-align: center; padding: 32px 16px; color: var(--text-3); }
.notif-empty svg { width: 28px; height: 28px; color: var(--green); margin-bottom: 8px; }
.notif-foot-note { font-size: 12px; color: var(--text-3); margin-right: auto; }
/* v552 — NOTIFICATION CENTER (grouped sections · timestamps · unread dots · quiet standing tray) */
.notif-group-label { display: flex; align-items: baseline; gap: 8px; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--text-3); padding: 14px 4px 5px; }
.notif-body > .notif-group-label:first-child { padding-top: 2px; }
.notif-group-count { font-size: 11px; font-weight: 800; color: var(--accent); letter-spacing: 0; }
.notif-group-sub { font-size: 10.5px; font-weight: 600; text-transform: none; letter-spacing: 0; color: var(--text-3); }
.notif-standing-label { color: var(--text-3); opacity: .85; }
.notif-standing-wrap { display: flex; flex-direction: column; gap: 7px; }
.notif-meta { display: flex; align-items: center; gap: 8px; flex-shrink: 0; margin-left: auto; padding-left: 6px; align-self: flex-start; padding-top: 2px; }
.notif-time { font-size: 11px; color: var(--text-3); white-space: nowrap; }
.notif-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--accent); flex-shrink: 0; box-shadow: 0 0 0 3px var(--accent-soft, transparent); }
.notif-item.urgent:not(.is-read) .notif-dot { background: var(--red, var(--accent)); box-shadow: 0 0 0 3px var(--red-bg, transparent); }
.notif-item.is-standing { opacity: .68; }
.notif-item.is-standing .notif-ic { background: var(--surface-2); color: var(--text-3); }
.notif-item.is-standing.urgent .notif-ic { color: var(--text-2); background: var(--surface-2); }
/* END v552 NOTIFICATION CENTER */
/* SIM-09 — .sb-nav has always scrolled, with zero sign that it did. On a phone the drawer
   cut the list off cleanly at the fold and SOP Library / Team / Payment Tracker were simply
   invisible: nothing faded, nothing was half-shown, no scrollbar existed (iOS overlay
   scrollbars are hidden at rest). The mask below fades whichever edge has content past it,
   driven by --sbf-t / --sbf-b, which _syncSbNavCue() sets from real scroll geometry. At the
   0px default the mask is a hard stop at each edge — i.e. no visual change at all when the
   list fits. NOTE (not fixed here, by instruction): the drawer and the bottom tab bar still
   expose DIFFERENT nav sets; that is a design decision, not this bug. */
.sb-nav {
  flex: 1; overflow-y: auto; padding: 10px 12px 12px;
  --sbf-t: 0px; --sbf-b: 0px;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 var(--sbf-t), #000 calc(100% - var(--sbf-b)), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 var(--sbf-t), #000 calc(100% - var(--sbf-b)), transparent 100%);
  transition: --sbf-b var(--dur-2) ease;
  scrollbar-width: thin;
}
.sb-nav::-webkit-scrollbar { width: 4px; }
.sb-nav::-webkit-scrollbar-track { background: transparent; }
.sb-nav::-webkit-scrollbar-thumb { background: var(--hairline-strong, rgba(128,128,128,.35)); border-radius: var(--radius-xs); }
/* The cue itself must survive reduced-motion — it is information, not decoration. */
@media (prefers-reduced-motion: reduce) { .sb-nav { transition: none; } }
.sb-section-label { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--text-3); font-weight: 700; padding: 10px 8px 6px; }
.sb-space { margin-bottom: 6px; }
.sb-space-head { display: flex; align-items: center; gap: 8px; padding: 7px 8px; font-size: 12.5px; font-weight: 700; color: var(--text-2); }
.sb-space-head svg { width: 15px; height: 15px; color: var(--text-3); }
.sb-list {
  display: flex; align-items: center; gap: 11px; width: 100%; padding: 10px 12px 10px 13px; margin: 2px 0;
  border-radius: var(--radius-md); border: none; background: transparent; cursor: pointer; text-align: left;
  font-size: 13.5px; font-weight: 600; color: var(--text-2); font-family: var(--font); transition: background-color var(--dur-1) ease, color var(--dur-1) ease, border-color var(--dur-1) ease, box-shadow var(--dur-1) ease, opacity var(--dur-1) ease, transform var(--dur-1) ease;
}
.sb-list:hover { background: var(--row-hover); color: var(--text); }
/* sidebar Search / ⌘K trigger */
.sb-search { color: var(--text-3); border: 1px solid var(--hairline); margin-bottom: 4px; }
.sb-search:hover { color: var(--text); border-color: var(--hairline-strong); }
.sb-kbd { margin-left: auto; font-size: 11px; font-weight: 700; color: var(--text-3); background: var(--surface-2); border: 1px solid var(--hairline); border-radius: var(--radius-xs); padding: 1px 6px; letter-spacing: .02em; }
.sidebar.collapsed .sb-kbd { display: none; }
.sb-list.active { background: var(--accent-soft); color: var(--accent); }
.sb-list .sb-ic { width: 17px; height: 17px; flex-shrink: 0; }
.sb-list .sb-ct { margin-left: auto; font-size: 11px; font-weight: 700; color: var(--text-3); background: var(--surface); padding: 1px 8px; border-radius: var(--radius-pill); }
.sb-list.active .sb-ct { color: var(--accent); background: var(--accent-soft); }
.sb-foot { position: relative; border-top: 1px solid var(--hairline); padding: 11px 12px; padding-bottom: calc(11px + var(--safe-bottom)); display: flex; flex-direction: column; gap: 10px; }
.theme-seg { display: flex; gap: 3px; background: var(--surface-2); border: 1px solid var(--hairline); border-radius: var(--radius-md); padding: 3px; }
.theme-seg button { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px; padding: 7px; border-radius: var(--radius-sm); border: none; background: transparent; color: var(--text-3); font-size: 12px; font-weight: 600; cursor: pointer; font-family: var(--font); transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; }
.theme-seg button.active { background: var(--glass); color: var(--text); box-shadow: var(--shadow-sm); }
.theme-seg svg { width: 14px; height: 14px; }
.sb-user { display: flex; align-items: center; gap: 9px; padding: 7px 9px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface); cursor: pointer; transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; color: var(--text); font-family: var(--font); }
.sb-user:hover { background: var(--glass-strong); box-shadow: var(--shadow-sm); }
.sb-user .viewas-meta { flex: 1; min-width: 0; }
.sb-user .viewas-meta b { font-size: 12.5px; }
.sb-user .chev { width: 15px; height: 15px; color: var(--text-3); }
/* unified profile card: avatar + name/role on the left, a divider, the view-as caret on the right */
.sb-userbar { display: flex; align-items: stretch; border: 1px solid var(--hairline); background: var(--surface); border-radius: var(--radius-sm); overflow: hidden; }
.sb-userbar .sb-user { flex: 1; min-width: 0; border: none; background: transparent; border-radius: 0; }
.sb-userbar .sb-user:hover { background: var(--row-hover); box-shadow: none; }
.sb-viewas-btn { display: grid; place-items: center; width: 40px; flex-shrink: 0; border: none; border-left: 1px solid var(--hairline); background: transparent; color: var(--text-3); cursor: pointer; transition: background var(--dur-2) ease, color var(--dur-2) ease; }
.sb-viewas-btn:hover { background: var(--row-hover); color: var(--text); }
.sb-viewas-btn svg { width: 15px; height: 15px; }
.menu.menu-up { top: auto; bottom: calc(100% + 8px); left: 0; right: 0; transform-origin: bottom center; }
.menu.menu-up.open { transform: translateY(0) scale(1); }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; }
/* R6-47 (v726) · headroom plate. The floating header card let page content slide through the
   transparent gutter around it (owner: "the page goes behind the top menu thing"). This fixed
   plate paints canvas+mesh (viewport-anchored — identical pixels to the ground the card floats
   on) from the viewport top to the card's live bottom edge (--cc-head-band, published by
   _ccHeadBandApply in js/app.js; the fallback covers the pre-JS frame and terra, whose 4-value
   --g-r-chrome made the old phone mask compute height:0). z-index 89 sits under the head's 90,
   so the head's backdrop-filter samples the plate — glass recipe untouched, 0.0px drift at rest
   in all 48 prototype cells. Sealed 24/24 desktop leak cells (was ~250 leaked rows on cobalt).
   Also covers the funnel's sticky .ppf-progress bar that parked in the bare gutter. */
:root { --cc-gutter: var(--g-s-4, 16px); }
@media (max-width: 720px) { :root { --cc-gutter: var(--g-s-3, 12px); } }
.main::before {
  content: ''; position: fixed; top: 0; left: 0; right: 0; z-index: 89; pointer-events: none;
  height: var(--cc-head-band, calc(var(--safe-top) + var(--cc-gutter) + 26px));
  background-color: var(--g-canvas, var(--bg));
  background-image: var(--g-mesh, none);
  background-attachment: fixed;
  background-size: cover;
}
.mainhead {
  /* run5 §1.1 — the head floats like the sidebar (the owner's "homepage at the top is sharp"
     complaint was this bar). .g-chrome owns background/blur/shadow; the radius is declared here
     too so the geometry never depends on JS class timing. Legacy border-bottom is gone — a
     floating panel has no attachment edge. Safe-left/right padding dropped on desktop: the
     .layout gutter owns the horizontal inset now (phones re-add safe insets via margin, §1.2). */
  position: sticky; top: var(--g-s-4, 16px); z-index: 90;
  margin: var(--g-s-4, 16px) 0 0;
  border-radius: var(--g-r-chrome);
  padding: 14px 22px 0;
}
.crumb { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.crumb .sb-toggle { display: none; }
.crumb-space { font-size: 12.5px; color: var(--text-3); font-weight: 600; }
.crumb-sep { color: var(--text-3); }
.crumb-list { font-size: 19px; font-weight: 800; letter-spacing: -0.4px; color: var(--text); }
.crumb-editable { cursor: pointer; border-radius: var(--radius-xs); padding: 2px 5px; margin: -2px -5px; transition: background var(--dur-1), box-shadow var(--dur-1); }
.crumb-editable:hover { background: var(--surface); }
.crumb-editable:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--accent-soft); }
.crumb-emoji { width: 22px; height: 22px; border-radius: var(--radius-sm); display: inline-grid; place-items: center; color: #fff; }
.crumb-emoji svg { width: 14px; height: 14px; }
.crumb-meta { margin-left: auto; font-size: 12px; color: var(--text-3); font-weight: 600; }
.head-controls { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding-bottom: 8px; }
.tabset { display: flex; gap: 2px; overflow-x: auto; max-width: 100%; scrollbar-width: none; }
.tabset::-webkit-scrollbar { display: none; }
.tab { padding: 7px 13px; border-radius: var(--radius-sm); font-size: 13px; font-weight: 600; color: var(--text-2); cursor: pointer; border: 1px solid transparent; background: transparent; white-space: nowrap; display: inline-flex; align-items: center; gap: 7px; font-family: var(--font); transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease; }
.tab:hover { background: var(--surface); color: var(--text); }
.tab.active { background: var(--glass-strong); color: var(--text); border-color: var(--hairline); box-shadow: var(--shadow-sm); }
/* per-status manage kebab (ClickUp-style: rename / recolor / delete) */
.tab-kebab { display: inline-grid; place-items: center; width: 18px; height: 18px; margin: 0 -4px 0 3px; border-radius: var(--radius-xs); color: var(--text-3); opacity: 0; transition: opacity var(--dur-1) ease, background var(--dur-1) ease; }
.tab:hover .tab-kebab, .tab.active .tab-kebab, .pview:hover .tab-kebab, .pview.active .tab-kebab { opacity: .55; }
.tab-kebab:hover { opacity: 1; background: var(--surface-2); color: var(--text); }
.tab-kebab .kb-ic { width: 13px; height: 13px; }
@media (hover: none) and (pointer: coarse) { .tab-kebab { opacity: .5; } }
.tab .tdot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.tab svg { width: 15px; height: 15px; }
.head-spacer { flex: 1; }
.groupby { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--text-3); font-weight: 600; }
.groupby select { -webkit-appearance: none; appearance: none; padding: 7px 26px 7px 11px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface); color: var(--text); font-size: 12.5px; font-weight: 600; font-family: var(--font); cursor: pointer; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2386868b' stroke-width='2.5'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 9px center; outline: none; }
.groupby select:focus { border-color: var(--accent); }

/* Saved custom views chip-row (B6) */
.views-bar { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; padding: 0 0 11px; }
.view-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; border-radius: var(--radius-sm);
  border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2);
  font-size: 12px; font-weight: 600; cursor: pointer; font-family: var(--font); transition: background-color var(--dur-2) ease, color var(--dur-2) ease, border-color var(--dur-2) ease, box-shadow var(--dur-2) ease, opacity var(--dur-2) ease, transform var(--dur-2) ease;
  white-space: nowrap;
}
.view-chip svg { width: 13px; height: 13px; }
.view-chip:hover { color: var(--text); background: var(--glass-strong); }
.view-chip.active { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-soft); }
.view-chip-x { display: inline-grid; place-items: center; width: 16px; height: 16px; border-radius: var(--radius-xs); color: var(--text-3); margin: -2px -3px -2px 1px; }
.view-chip-x svg { width: 11px; height: 11px; }
.view-chip-x:hover { background: var(--red-bg); color: var(--red); }
.view-chip-edit { display: inline-grid; place-items: center; width: 16px; height: 16px; border-radius: var(--radius-xs); color: var(--text-3); margin: -2px 0 -2px 1px; opacity: 0; }
.view-chip:hover .view-chip-edit { opacity: 1; }
.view-chip-edit svg { width: 11px; height: 11px; }
.view-chip-edit:hover { background: var(--accent-soft); color: var(--accent); }
@media (hover: none) and (pointer: coarse) { .view-chip-edit { opacity: 1; } }
.view-chip-add { border-style: dashed; color: var(--text-3); }
.view-chip-add:hover { border-color: var(--accent); color: var(--accent); background: var(--accent-softer); }
/* custom filter chips (Feature 5) */
.filter-bar { padding-top: 0; }
.filter-chip { background: var(--surface) !important; color: var(--text) !important; border-color: var(--hairline) !important; }
.filter-chip .filter-chip-k { font-weight: 700; }
.filter-chip .filter-chip-eq { color: var(--text-3); font-weight: 500; font-size: 11px; }
.filter-clear { color: var(--text-3); }
.filter-clear:hover { color: var(--red); border-color: var(--red); }

@media (max-width: 900px) {
  /* run5 §1.2 — a drawer is ATTACHED by definition: full height restored (the desktop rule now
     insets it 16px), square left corners, rounded right corners. `aside.sidebar` (0-1-1) so the
     radius beats glass.css's .g-chrome all-corner 22px (0-1-0, loaded after this <style>).
     That same win forces the g-chrome shadow stack to be restated here: edge+spec rims kept,
     drop shadow deepened to the sheet tier because the drawer covers content. */
  aside.sidebar { position: fixed; left: 0; top: 0; z-index: 140; height: 100vh; height: 100dvh; border-radius: 0 var(--g-r-chrome) var(--g-r-chrome) 0; transform: translateX(-100%); transition: transform var(--dur-3) cubic-bezier(.32,.72,0,1); box-shadow: var(--g-edge-1), var(--g-spec-1), var(--g-shadow-3); }
  .sidebar.open { transform: translateX(0); }
  .sb-scrim { display: block; position: fixed; inset: 0; background: var(--scrim); z-index: 135; opacity: 0; visibility: hidden; transition: opacity var(--dur-2) ease; }
  .sb-scrim.open { opacity: 1; visibility: visible; }
  .crumb .sb-toggle { display: grid; place-items: center; width: 34px; height: 34px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface); color: var(--text-2); cursor: pointer; }
  .crumb .sb-toggle svg { width: 18px; height: 18px; }
  .content { padding: 12px; }
}

/* ===================== iOS app shell — bottom tab bar + bottom-sheet (B6) ===================== */
.tabbar { display: none; }
@media (max-width: 720px) {
  /* run5 §1.2 — floating pill. .g-chrome owns fill/blur/shadow/radius (radius restated so the
     shape never depends on JS class timing). Safe-area insets ride the OFFSETS, not padding —
     offsets can only shrink the box (402pt lesson). padding-bottom:0 because the bar no longer
     touches the home-indicator strip; --tabbar-safe grew by the same gap (see token block). */
  .tabbar {
    display: flex; position: fixed; z-index: 130;
    left: calc(var(--safe-left) + var(--g-s-3, 12px));
    right: calc(var(--safe-right) + var(--g-s-3, 12px));
    bottom: calc(var(--safe-bottom) + var(--g-s-2, 8px));
    border-radius: var(--g-r-chrome);
  }
  .tabbar-btn {
    flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    min-height: var(--tabbar-h); padding: 7px 2px 6px; border: none; background: transparent; cursor: pointer;
    color: var(--text-3); font-family: var(--font); font-size: 11px; font-weight: 600; letter-spacing: -0.1px;
    transition: color var(--dur-2) ease; -webkit-tap-highlight-color: transparent;
  }
  .tabbar-btn svg { width: 21px; height: 21px; }
  .tabbar-btn.active { color: var(--accent); }
  .tabbar-btn span { line-height: 1; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  /* keep content clear of the fixed bar */
  .main { padding-bottom: var(--tabbar-safe); }
  /* SIM-14 · .main's padding only protects content that flows in the PAGE. Anything that owns its
     own scroller — the module content column, the task/partner lists, a mounted space — scrolled
     its last rows underneath the fixed bar, where they are visible through the blur, look tappable,
     and are not: the tap lands on a nav button instead, which navigates you away. Every in-app
     scroller therefore ends above the bar, not behind it. `padding-bottom` (not margin) so the
     reserved strip still scrolls with the content instead of clipping it.
     (The #panel drawer is deliberately NOT in this list: it is z-index 901 and covers the bar
     outright, so its own safe-area padding at the bottom of this file is already correct.) */
  .content { padding-bottom: calc(var(--content-pad) + var(--tabbar-safe)); }
  /* Belt-and-braces: the bar is the topmost thing at the viewport floor, so a stray high z-index
     in page content can never surface an interactive control on top of the nav. */
  .tabbar { isolation: isolate; }
  /* the desktop sidebar nav list is reachable via the hamburger; tab bar is primary nav */
}

/* ===================== Live sync — refresh button + pull-to-refresh (Stage 3) ===================== */
.btn-refresh { gap: 7px; }
.btn-refresh svg { width: 15px; height: 15px; transition: transform .4s ease; }
.btn-refresh:hover svg { transform: rotate(-90deg); }
.btn-refresh.is-refreshing svg { animation: ptr-spin .7s linear infinite; }
@media (max-width: 720px) { .btn-refresh .btn-refresh-lbl { display: none; } .btn-refresh { padding-left: 10px; padding-right: 10px; } }

/* pull-to-refresh spinner that drops in from the top on touch devices */
/* run6 W5a: surface props deleted — the element ships `ptr-indicator glass-1` (js/app.js
   attachPullToRefresh). The 50% circle radius is layout-critical, so it moved to the (0,2,0)
   rule below — glass-1's --g-r-chrome (0,1,0, loads later) must never square the spinner. */
.ptr-indicator {
  position: fixed; top: calc(8px + var(--safe-top)); left: 50%;
  transform: translateX(-50%) translateY(-44px); opacity: 0; z-index: 200;
  width: 36px; height: 36px;
  display: grid; place-items: center;
  color: var(--accent); pointer-events: none;
  transition: transform var(--dur-2) cubic-bezier(.32,.72,0,1), opacity var(--dur-2) ease;
}
.ptr-indicator.glass-1 { border-radius: 50%; color: var(--accent); }   /* color re-pinned too: .glass-1 sets color:var(--g-text) later at (0,1,0) and would grey the accent spinner */
.ptr-indicator .ptr-spinner { display: grid; place-items: center; }
.ptr-indicator .ptr-spinner svg { width: 18px; height: 18px; transition: transform var(--dur-2) ease; }
.ptr-indicator.ptr-pulling { transition: opacity var(--dur-1) ease; }
.ptr-indicator.ptr-pulling .ptr-spinner svg { transform: rotate(180deg); }
.ptr-indicator.ptr-ready .ptr-spinner svg { transform: rotate(360deg); }
.ptr-indicator.ptr-loading .ptr-spinner svg { animation: ptr-spin .7s linear infinite; }
@keyframes ptr-spin { to { transform: rotate(360deg); } }

/* Side panel becomes a bottom-sheet on phones. run6 W5c: aside.panel (0,1,1) so the sheet's
   top-only radius beats .glass-3's all-corner var(--g-r-sheet) (a plain-class tie is won by
   glass.css); the legacy border-top/border-left lines died with the surface — the primitive
   draws the edge via box-shadow. */
@media (max-width: 720px) {
  aside.panel {
    top: auto; left: 0; right: 0; bottom: 0; width: 100%; max-width: 100%;
    height: 90vh; height: 90dvh; max-height: 90dvh;
    border-radius: var(--g-r-sheet, var(--radius-lg)) var(--g-r-sheet, var(--radius-lg)) 0 0;
    transform: translateY(100%);
    padding-bottom: var(--safe-bottom);
  }
  .panel.open { transform: translateY(0); }
  .panel-head { padding-top: 18px; }
  /* clear the home indicator inside the scrollable sheet body */
  .panel-body { padding: 20px 20px calc(40px + var(--safe-bottom)); }
  /* detail-panel field rows: narrower label column so values (URLs, chips, names) aren't cramped */
  .field-grid { grid-template-columns: 104px 1fr; gap: 6px 12px; }
  /* SIM-12 · the grabber pill is GONE from this sheet, on purpose. It promised drag-to-dismiss
     and never delivered one, and it cannot deliver one here: SIM-07 gave .panel-head's vertical
     drag to scroll-forwarding (the drawer's upper third is not the scroller, so a drag there has
     to be relayed into .panel-body or the drawer reads as frozen). Two owners for one gesture
     means neither works. The drawer keeps three honest exits — the X, the backdrop, and Back.
     The calendar's read-only detail sheet, which has no competing gesture, got a WORKING handle
     instead (see wireSheetDrag in js/app.js). */
  .panel-head { position: relative; }
  /* larger tap targets on phones.
     v639 CASCADE NOTE — this block is a SECOND @media (max-width:720px) that sits
     ~2500 lines below the task-list one, at identical specificity, so SOURCE ORDER
     makes it the winner. Re-valued here, not only up there: a rule that merely
     EXISTS is not a rule that WINS (measured — 700px reported 52px, not 44px,
     until this line changed). --ctl-touch is the 44px floor; nothing above it. */
  .trow { min-height: var(--ctl-touch); }
  .tlist-inner .trow { min-height: var(--ctl-touch); }
  /* the "+ Add task" row is a tap target at every touch width, not just <=520 */
  .add-row { min-height: var(--ctl-touch); }
  /* horizontal filter chips can be a touch shorter than primary controls —
     keeps the (sometimes doubled) filter rows from eating the screen top */
  .tab, .view-tab, .pview, .chip { min-height: 38px; }
  /* ORCH-1: `.sb-list, .menu-item`, `.btn` and `.icon-btn` used to sit here. They are tap
     targets, not layout, so they MOVED to the union block ~80 lines below (search
     "ORCH-1 union — close / tap targets"), which also fires on a >720px coarse-pointer
     device (iPad, touch laptop) that this width-only predicate misses. `.menu-item` is
     additionally covered by the union block near the top of this stylesheet. Nothing else
     in this block moved — everything left here is genuinely width-scoped. */
  .pay-row { min-height: 52px; }
  /* touch keeps a taller cell than the 36px desktop rhythm (--space-3 => ~42px row).
     Horizontal stays 18px on purpose — see the ZONE A4 note. */
  .ptable td { padding: var(--space-3) 18px; }

  /* ══ PHONE-01 · THE DETAIL SHEET SCROLLS AS ONE UNIT ══════════════════════
     Physical iPhone finding (402x874, prod v666): the partner detail sheet's
     NON-SCROLLING chrome — .panel-head + the V2 setup rail (.pf-v2rail) +
     .panel-tabs — ate ~70% of the sheet, leaving .panel-body (the ONLY scroller)
     a measured clientHeight 428 against scrollHeight 2662. "Add field",
     Management Notes and the Delete-partner foot were not reachable by thumb.
     The controls were all in the DOM; the sheet was the problem.

     The fix is structural, and PURE CSS on purpose — the markup is identical in
     both eras, so nothing in partnerPanel()/taskPanel() moves and the desktop
     drawer keeps its exact DOM:
       · .panel itself becomes the ONE scroller here,
       · .panel-body stops being a nested scroller (it just flows),
       · .pf-v2rail drops its 40vh cap AND its own scroller, so it scrolls AWAY
         with the content — that is the ~200-350px the thumb was losing,
       · .panel-head stays pinned (sticky) and shrinks to crumb + title + X,
       · .panel-tabs pins directly under it at --panel-headh, which renderPanel()
         measures on phones only (js/app.js _panelStickyOffset).

     THE GATE. Every rule lives inside this phone media query — the SAME
     (max-width:720px) gate that turns .panel into a bottom sheet ~40 lines up.
     Gating the fix at 700px instead would leave 701-720px rendering as a bottom
     sheet WITHOUT the fix: a band that reads as shipped and isn't. The real
     desktop side-drawer (>720px) is not touched by one byte here.

     .pf-v2rail is overridden HERE, at (0,2,0), rather than in v2/partners.css:
     that file is <link>ed after this <style> and its .pf-v2rail cap is (0,1,0)
     and unconditional, so a same-specificity override over there would win only
     while its ?v= buster is fresh. A stale CSS buster must not be able to
     half-land this fix (the v497 lesson). */
  .panel { overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch;
    /* focus-scroll clearance: without this, tapping an input mid-sheet scrolls it UNDER the
       sticky head+tabs (scroll-padding is the scroller's job, not the input's) */
    scroll-padding-top: calc(var(--panel-headh, 76px) + 52px); }
  /* REVIEW-F1 (v667) · the chat composer is `position:sticky; bottom:0` (index.html ~2799) and
     pre-PHONE-01 it stuck to .panel-body's bottom edge, which sat ABOVE the sheet's
     padding-bottom: var(--safe-bottom). Now .panel is the scroller, so bottom:0 resolves to the
     PHYSICAL screen edge — the send row sat behind the iOS home indicator and fought the
     swipe-up gesture. Re-aim the sticky inset at the safe area. Phone block only; desktop
     keeps bottom:0 (no home indicator, .panel-body still the scroller there). */
  .panel .ppmc-composer-wrap { bottom: var(--safe-bottom); }
  .panel .panel-body { flex: 0 0 auto; overflow: visible; }
  .panel .pf-v2rail { max-height: none; overflow: visible; }
  .panel > .panel-head {
    position: sticky; top: 0; z-index: 3;
    /* the same glass, composited over itself → ~0.99 alpha, so scrolling text
       cannot ghost through. Deliberately NOT a third backdrop-filter: .panel
       already carries one and stacking blurs on a live scroller is exactly the
       jank this repo keeps paying for. */
    /* v668 · SOLID, not glass. On the real device the composited-glass trick still bled the
       content under the head through at ~10% (a GHL token was readable inside the head band —
       iOS renders the var()-in-gradient layer unreliably). A sticky bar over a live scroller
       wants an opaque ground anyway; --bg-solid is themed for both modes. */
    background: var(--bg-solid, var(--bg, #fff));
    /* small: crumb line, then [logo] title, with the X spanning both rows on the
       right. Grid + display:contents keeps BOTH head shapes working — the
       partner head wraps its title in .panel-title-row, the task head does not. */
    display: grid; grid-template-columns: minmax(0,1fr) auto;
    align-items: center; column-gap: 8px; row-gap: 2px;
    padding: 10px 16px 8px;
  }
  .panel > .panel-head > .panel-head-row { display: contents; }
  .panel > .panel-head .panel-crumb { grid-column: 1; grid-row: 1; min-width: 0; }
  .panel > .panel-head .panel-head-row .icon-btn { grid-column: 2; grid-row: 1 / span 2; align-self: center; }
  .panel > .panel-head > .panel-title-row,
  .panel > .panel-head > .panel-title { grid-column: 1; grid-row: 2; min-width: 0; }
  /* v668 · sticky lives on the WRAPPER (.panel-tabsbar), not the strip: .panel-tabs is its own
     overflow-x:auto scroller and iOS WebKit refuses to pin a sticky element that is also a scroll
     container (Chrome pins it — the pane showed a pinned strip while the real device scrolled it
     away with the rail; physically confirmed v667). The wrapper is a plain block on desktop. */
  .panel > .panel-tabsbar {
    position: sticky; top: var(--panel-headh, 76px); z-index: 2;
    background: var(--bg-solid, var(--bg, #fff));
  }
}

/* ===== ORCH-1 union — close / tap targets (>=44x44px) =====
   Covers modal/popover/panel/picker close (X) buttons so they're easy to tap on
   iPhone ("had to go back to computer"), PLUS the primary controls that used to live on
   the width-only query. Predicate is the ORCH-1 union (see the ONE TAP-TARGET PREDICATE
   note at the top of this stylesheet): this block was coarse-pointer-only, which meant a
   desktop window dragged under 720px kept 38px close buttons and modal-footer buttons. */
@media (max-width: 720px), (hover: none) and (pointer: coarse) {
  /* moved here from the (max-width:720px) block above — same 44px floors, wider predicate */
  .btn { min-height: 44px; }
  .sb-list { min-height: 44px; }
  .icon-btn,
  .modal-head .icon-btn,
  .panel-head .icon-btn,
  .panel-head-row .icon-btn,
  [data-act="close-modal"].icon-btn,
  [data-act="close-panel"].icon-btn,
  [data-pf="close"] {
    min-width: 44px; min-height: 44px; width: 44px; height: 44px; border-radius: var(--radius-sm);
  }
  .icon-btn svg, [data-pf="close"] svg { width: 19px; height: 19px; }
  /* text Cancel/Close buttons in modal footers stay a full-height tap target.
     ── OB4/E4 TOMBSTONE (do not restore the old selector) ──────────────────
     This list used to end in `[data-act="ui-prompt-cancel"]`. That attribute is
     emitted NOWHERE in the app — measured live, `document.querySelectorAll(
     '[data-act="ui-prompt-cancel"]').length === 0` with a uiPrompt open — so the
     rule was permanently dead. uiPrompt (js/app.js) builds its footer as
     `.ui-prompt-back > .g-modal > .g-modal-ft > button.g-btn.g-btn--ghost[data-pcancel]`,
     which matches none of `.modal-foot .btn` / `.icon-btn` / the two `data-act` arms.
     Measured at rest before this fix: Cancel 38px, Save 38px, X 38x38 — all under 44pt.
     `.ui-prompt-back .g-modal-ft .g-btn` covers BOTH footer buttons (the audit named only
     Cancel; Save was equally short) and keeps working if app.js ever adds the data-act.
     Its sibling `[data-act="ui-confirm-cancel"]` below IS live (uiConfirm emits it) —
     that is why this went unnoticed. Owner-visible surfaces: Cash on hand, Monthly
     revenue goal, Rename view, New tag, Add <option>. */
  .modal-foot .btn,
  [data-act="close-modal"]:not(.icon-btn),
  [data-act="ui-confirm-cancel"],
  .ui-prompt-back .g-modal-ft .g-btn { min-height: 44px; }
  /* uiPrompt's own close (X). It is a `.g-icon-btn`, NOT `.icon-btn`, so the icon group
     above never reached it either — measured 38x38 at rest. Its own rule, not a member of
     that group, because the group forces `border-radius: var(--radius-sm)` and .g-icon-btn
     is a PILL (--g-r-pill, 999px measured) — folding it in would reshape the control. */
  .ui-prompt-back .g-modal-hd .g-icon-btn {
    min-width: 44px; min-height: 44px; width: 44px; height: 44px;
  }
  /* per-row + per-item kebabs are easier to hit */
  .row-kebab, .pay-kebab, .rel-x { min-width: 32px; min-height: 32px; }
}

/* ============================================================
   GLOBAL DESIGN-SYSTEM POLISH PASS — Linear/Stripe bar (additive)
   The six microstates + motion + craft on every shared control.
   Pure refinement: rings, pressed states, motion tokens, tap
   targets, tabular-nums, skeletons. Drives off existing vars so
   light + dark stay correct (token swap only).
   ============================================================ */

/* --- motion + skeleton tokens (additive; extend, don't override) --- */
:root {
  --ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);   /* 2 layers — the 7px outer glow is gone (§2.8) */
  --ring-strong: 0 0 0 3px var(--accent-softer);     /* input-focus halo */
  --dur-1: 120ms; --dur-2: 160ms; --dur-3: 240ms;    /* §2.10 — snappier: was 120/200/320 */
  /* friendly aliases for per-page agents (same values, clearer names) */
  --dur-fast: var(--dur-1); --dur-med: var(--dur-2); --dur-slow: var(--dur-3);
  --ease: cubic-bezier(.2,0,0,1);                    /* THE ease — Stripe/Raycast standard */
  --ease-out: cubic-bezier(.16,1,.3,1);              /* enter/exit of floating layers only */
  --ease-spring: var(--ease);                        /* ALIASED AWAY — overshoot is banned (§2.10) */
  --press: var(--ease);                              /* aliased */
  /* skeleton shimmer — theme-aware via existing surfaces */
  --skel-base: rgba(15,23,42,0.07);
  --skel-shine: rgba(15,23,42,0.13);
}
[data-theme="dark"] {
  --skel-base: rgba(255,255,255,0.06);
  --skel-shine: rgba(255,255,255,0.12);
}

/* Retina hairlines (§2.5) — a 1px divider reads heavy at 2dppx+; halve it. Definition-only,
   like the other Phase-1 tokens: --hairline-w gets wired to call-sites in Phase 2. */
@media (min-resolution: 2dppx) { :root { --hairline-w: 0.5px; } }

/* ===== 1. FOCUS-VISIBLE RINGS — keyboard users always see focus =====
   line 929 zeroed the outline with no replacement; restore a consistent,
   theme-aware ring on every interactive surface. Composes with elements
   that already carry a box-shadow so we never clobber their depth. */
.btn:focus-visible,
.btn-primary:focus-visible,
.btn-ghost:focus-visible,
.btn-danger:focus-visible,
.btn-sm:focus-visible,
.icon-btn:focus-visible,
.mod-tab:focus-visible,
.tab:focus-visible,
.view-tab:focus-visible,
.panel-tab:focus-visible,
.pview:focus-visible,
.chip:focus-visible,
.view-chip:focus-visible,
.sb-list:focus-visible,
.sb-search:focus-visible,
.sb-signout:focus-visible,
.sb-install:focus-visible,
.sb-install-x:focus-visible,
.sb-bell:focus-visible,
.sb-collapse:focus-visible,
.sb-user:focus-visible,
.sb-viewas-btn:focus-visible,
.theme-seg button:focus-visible,
.tabbar-btn:focus-visible,
.home-stat:focus-visible,
.home-act:focus-visible,
.home-task:focus-visible,
.home-next:focus-visible,
.home-more:focus-visible,
.home-pending:focus-visible,
.home-cd:focus-visible,
.menu-item:focus-visible,
.cmdk-item:focus-visible,
.viewas-btn:focus-visible,
.send-btn:focus-visible,
.ig-cta:focus-visible,
.ig-tab:focus-visible,
.ig-btn:focus-visible,
.bil-status:focus-visible,
.bil-preset:focus-visible,
.adsv-tab:focus-visible,
.adsv-back:focus-visible,
.pf-times-del:focus-visible,
.pf-danger-btn:focus-visible,
.addfield-btn:focus-visible,
.nv-fbtn:focus-visible,
.nv-opt:focus-visible,
.nv-addrow:focus-visible,
.uis-trigger:focus-visible,
.fv-trigger:focus-visible,
.crumb-bell:focus-visible,
.bil-hier-head:focus-visible,
.sb-toggle:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}
/* small glyph controls — ring sits flush around the padded hit area */
.row-kebab:focus-visible,
.cf-kebab:focus-visible,
.pay-kebab:focus-visible,
.tab-kebab:focus-visible,
.opt-kebab:focus-visible,
.col-field-menu:focus-visible,
.cf-del:focus-visible,
.rel-x:focus-visible,
/* run7 W4: `.pview-x:focus-visible` dropped from this list — that rule was deleted as DEAD.
   `.pview-edit` stays: js/app.js:6661 styles it at runtime, so it is a real focusable control. */
.pview-edit:focus-visible,
.view-chip-x:focus-visible,
.view-chip-edit:focus-visible,
.nv-row-x:focus-visible,
.cf-opt-x:focus-visible,
.restore-purge:focus-visible,
.inv-mnav:focus-visible,
.notif-read-btn:focus-visible,
.ian-x:focus-visible,
.kebab-sw:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}
/* elements whose default already shows a 3px brand glow — keep theirs on
   keyboard focus (compose ring + their inset/glow) for a crisper edge */
.fv-edit:focus-visible,
.minput:focus-visible, .mselect:focus-visible, .mtext:focus-visible,
.login-input:focus-visible, .login-btn:focus-visible,
.nv-input:focus-visible, .cmdk-input:focus-visible,
.cell-inline-input:focus-visible,
.picker-search input:focus-visible,
.chat-composer textarea:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-softer), 0 0 0 1px var(--accent);
}
/* inputs/selects/textareas that have no decorated focus of their own:
   give the global ring so the bare line 929 rule never leaves them naked */
input:focus-visible, select:focus-visible, textarea:focus-visible,
button:focus-visible, [contenteditable]:focus-visible,
[role="button"]:focus-visible, [tabindex]:focus-visible {
  outline: none;
  box-shadow: var(--ring);
}
/* v811 a11y wave: the tab stop moved from the row/card onto its name child. The global ring above is a
   box-shadow, which an ancestor overflow:hidden (.tname-wrap) clips to nothing, so these name targets use an
   OUTLINE at higher specificity than the global rule (critic B1). */
.tname[role="button"]:focus-visible, .p-nametext[role="button"]:focus-visible, .dv-top b[role="button"]:focus-visible,
.member-id[role="button"]:focus-visible, .cr-title[role="button"]:focus-visible, .home-fold-h span[role="button"]:focus-visible {
  outline: var(--g-focus-w, 2px) solid var(--g-focus-color, var(--accent));
  outline-offset: 2px;
  box-shadow: none;
  border-radius: var(--radius-sm);
}


/* ===== 2 + 3. PRESSED MICRO-STATES + consistent fast transitions ===== */
.btn, .btn-primary, .btn-ghost, .btn-danger, .btn-sm {
  transition: transform var(--dur-1) var(--ease), background var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.btn:active { transform: translateY(.5px); }
.btn-primary:active, .btn-danger:active, .ig-cta:active, .login-btn:active { transform: scale(.98); }
.btn-ghost:active, .btn-sm:active { transform: translateY(.5px); }
/* icon + glyph buttons press a touch deeper */
.icon-btn:active, .sb-bell:active, .sb-collapse:active, .send-btn:active,
.inv-mnav:active, .crumb-bell:active, .sb-toggle:active,
.tabbar-btn:active { transform: scale(.94); }
.row-kebab:active, .cf-kebab:active, .pay-kebab:active, .tab-kebab:active,
.rel-x:active, .restore-purge:active,
.notif-read-btn:active, .ian-x:active { transform: scale(.92); }
/* .opt-kebab (the per-status 3-dots) is vertically centered with translateY(-50%);
   the press-scale must KEEP that translate or the dots physically drop ~half their
   height on tap and the mouseup misses the target (owner: "3-dots jump down"). */
.opt-kebab:active { transform: translateY(-50%) scale(.92); }
/* clickable surfaces get a quick, consistent press feedback too */
.chip:active, .tab:active, .view-tab:active, .pview:active, .panel-tab:active,
.view-chip:active, .mod-tab:active, .home-stat:active, .home-act:active,
.sb-list:active, .menu-item:active, .cmdk-item:active, .ig-tab:active,
.nv-fbtn:active, .nv-opt:active,
.cell-edit:active, .pay-cell-edit:active { transform: scale(.985); }
/* larger clickable rows/cards press a touch more gently */
.pay-month-open:active, .member-card:active { transform: scale(.99); }
/* clickable Team member card: lift on hover (transition already declared above) */
.member-card:hover { box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-3); }   /* run6 W5b: retargeted to the system card-hover recipe; border-color half dead with the border */
/* ensure every clickable surface has SOME transition (snap any instant jumps) */
.home-task, .home-next, .home-more, .home-pending, .home-cd, .pay-row,
.pay-month-open, .notif-item, .rel-item, .link-item, .member-card {
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
              box-shadow var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}

/* ===== 4. TAP TARGETS ≥ 32px for small glyph controls (always) =====
   Padded, centered hit area; the glyph keeps its own small size so nothing
   looks visually enlarged — just easier to land on (mouse + touch). */
.row-kebab, .cf-kebab, .pay-kebab, .tab-kebab, .col-field-menu,
.rel-x, .restore-purge, .inv-mnav, .nv-row-x, .cf-opt-x,
/* run7 W4: `.pview-x` dropped from this tap-target list — that rule was deleted as DEAD */
.view-chip-x, .ian-x, .notif-read-btn {
  min-width: 32px; min-height: 32px;
  display: inline-grid; place-items: center;
}
/* the very tiny inline glyphs (column-header dels) — give them room without
   forcing 32px into a tight header row; 22px keeps them tappable + tidy */
.cf-del, .pview-edit, .view-chip-edit { min-width: 22px; min-height: 22px; place-items: center; }

/* ===== 5. MOTION — menus scale+fade from origin, modals rise, toasts slide.
   These mostly already exist; normalize the timing onto the shared token and
   add origins where missing so popovers grow from their trigger. ===== */
.menu { transition: opacity var(--dur-2) var(--ease), visibility var(--dur-2) var(--ease), transform var(--dur-2) var(--ease); }
.opt-kebab-menu, .row-menu, .uis-menu { transform-origin: top left; }
.menu.menu-up { transform-origin: bottom center; }
.modal { transition: transform var(--dur-2) var(--ease), opacity var(--dur-2) var(--ease); }
/* toasts already slide up via @keyframes toastIn — keep; just align easing */

/* ===== 6. TABULAR-NUMS everywhere numbers live (alignment) ===== */
.sb-ct, .sb-bell-badge, .crumb-bell-badge, .group-count, .bcol-count,
.pview-ct, .tab-ct, .sub-count, .panel-tab .cnt, .home-card-meta,
.pay-k, .pay-sub, .pay-row-date, .pay-subhead-amt, .pay-row-monthhead,
.pay-hero-lt-v, .home-next-time b, .ig-step-n, .badge, .due, .prio,
.menu-item small, .cmdk-foot kbd, .sb-kbd {
  font-variant-numeric: tabular-nums;
}

/* ===== 7. SKELETON LOADERS — layout-matching placeholders, not spinners.
   JS sets these classes on real-shaped nodes during first loads. ===== */
.skel {
  position: relative; overflow: hidden;
  background: var(--skel-base);
  border-radius: var(--radius-sm);
}
.skel::after {
  content: ''; position: absolute; inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, var(--skel-shine), transparent);
  animation: skelSweep 1.25s var(--ease) infinite;
}
/* run7 W2: `.skel-line` (+ ::after), `.skel-line.w-40/.w-60/.w-80` and `.skel-card` deleted — DEAD.
   Zero hits for all five app-wide. `.skel` above is NOT dead and stays: every module builds its
   own shaped placeholder off it or off a private namespace — `skel-row/-head/-body` (js/calendar.js
   1679-1683), `skel-l`/`skel-l-sm` (js/sops.js:1771), `skel-date`/`skel-cell` (v2/home.js:913-914),
   `skeleton--line/--block/--circle` (js/activity.js:712-714,1005). `.w-40/-60/-80` only ever existed
   compounded onto `.skel-line`, so they die with it — there is no free-standing width utility here.
   `@keyframes skelSweep` is KEPT: `.skel::after` still drives it. */
@keyframes skelSweep { to { transform: translateX(100%); } }

/* ===== 8b. REUSABLE MICRO-ANIMATION UTILITIES (v235) =====
   Opt-in classes the per-page agents can drop onto cards/sections/modals
   for slight, clean reveals. ~150–250ms, cubic-bezier, GPU-friendly
   (opacity + transform only). All disabled under prefers-reduced-motion. */
@keyframes uFadeIn   { from { opacity: 0; }                         to { opacity: 1; } }
@keyframes uFadeUp   { from { opacity: 0; transform: translateY(8px); }  to { opacity: 1; transform: translateY(0); } }
@keyframes uFadeDown { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } }
@keyframes uScaleIn  { from { opacity: 0; transform: scale(.97); }       to { opacity: 1; transform: scale(1); } }
@keyframes uSlideInR { from { opacity: 0; transform: translateX(10px); } to { opacity: 1; transform: translateX(0); } }
/* run7 W3: the five opt-in reveal utilities `.u-fade-in` / `.u-fade-up` / `.u-fade-down` /
   `.u-scale-in` / `.u-slide-in` deleted — DEAD. Zero hits for any of the five app-wide; the
   "per-page agents can drop these on" plan above never landed a single caller. `.u-stagger`,
   `.u-fold` and `.u-fold-inner` below are LIVE (js/*.js) and are untouched. All FIVE keyframes
   (uFadeIn/uFadeUp/uFadeDown/uScaleIn/uSlideInR) are deliberately KEPT above: js/calendar.js
   injects `animation:uFadeIn|uFadeUp` by name at 6743-6763, and `.home-hero`/`.wsite-root .ws-grid`
   here still reference them — a keyframe sweep is a separate, JS-aware pass. */
/* staggered list reveals: parent .u-stagger > children fade-up in sequence */
.u-stagger > * { animation: uFadeUp var(--dur-3) var(--ease-out) both; }

/* ===== G2 / R1 — no full-app re-animate on background refresh =====
   Silent background re-renders (the 20s poll, tab-focus/visibility re-pull, realtime echoes,
   and the time-tracker's 60s flip) rebuild the DOM to keep data fresh — but must NOT replay
   the entry "reveal" animations, or the WHOLE app (sidebar rail, every card/row/tile) visibly
   re-animates every 20s and each time you return to the tab ("it reloads the whole app, esp.
   iPhone"). render() adds body.cc-bg-render ONLY for those background renders; genuine navigation
   leaves it off so reveals still play. Finite reveals only — spinners/skeletons/pulses use their
   own keyframes and keep moving. */
body.cc-bg-render #mainhead,
body.cc-bg-render .sb-list.active::before,
body.cc-bg-render .home > *,
body.cc-bg-render .home-stats > *,
body.cc-bg-render .pt-partners .ptable tbody tr,
body.cc-bg-render .tlist-inner .table-card .trow:not(.thead),
body.cc-bg-render .w3-reveal,
body.cc-bg-render .w3-scale,
body.cc-bg-render .w3-stagger > *,
body.cc-bg-render .w3-card,
body.cc-bg-render .w3-pipe .w3-board,
body.cc-bg-render .w3-pipe .w3-pipe-col,
body.cc-bg-render .w3-pipe .pipe-card,
/* run7 W3: the `.w6-reveal` / `.w6-stagger > *` and `.u-fade-in/-up/-down` / `.u-scale-in` /
   `.u-slide-in` selectors dropped from this list — all seven rules deleted as DEAD. The live
   `.w3-*` and `.u-stagger > *` entries around them are untouched, so background re-renders are
   still silenced exactly as before. */
body.cc-bg-render .ig-grid,
body.cc-bg-render .ig-card,
body.cc-bg-render .wsite-root .ws-grid,
body.cc-bg-render .pf-audit,
body.cc-bg-render .pf-times-user,
body.cc-bg-render .pf-modal .pf-hero,
body.cc-bg-render .ig-chip,
body.cc-bg-render .ig-gcal-chip,
body.cc-bg-render .u-stagger > * {
  animation: none !important;
}
.u-stagger > *:nth-child(1){animation-delay:.02s} .u-stagger > *:nth-child(2){animation-delay:.06s}
.u-stagger > *:nth-child(3){animation-delay:.10s} .u-stagger > *:nth-child(4){animation-delay:.14s}
.u-stagger > *:nth-child(5){animation-delay:.18s} .u-stagger > *:nth-child(6){animation-delay:.22s}
.u-stagger > *:nth-child(7){animation-delay:.26s} .u-stagger > *:nth-child(8){animation-delay:.30s}
/* fold-down expand/collapse: animate grid-template-rows 0fr↔1fr (no JS height calc).
   Wrap collapsible content: <div class="u-fold"><div class="u-fold-inner">…</div></div>
   toggle .open on .u-fold. */
.u-fold { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--dur-3) var(--ease); }
.u-fold.open { grid-template-rows: 1fr; }
.u-fold > .u-fold-inner { overflow: hidden; min-height: 0; }
/* run7 W3: the opt-in hover-lift `.u-lift` (+ :hover, + :active) deleted — DEAD. Zero hits
   app-wide: every clickable card that wanted a lift named itself instead (`.home-card:hover`,
   `.w3-card:hover`, `.member-card:hover`, `.adsm-card:hover`, `.ws-card:hover`, `.dops-card:hover`
   — all still listed in the reduced-motion blocks). Nothing constructs a `u-` class dynamically. */

/* ===== 8. HAIRLINE + RADIUS — snap a couple of off-scale shared values =====
   (refinement only — borders already use the hairline vars app-wide). */
.chat-msg:not(.mine) .chat-text { border-radius: var(--radius-lg); border-bottom-left-radius: var(--radius-xs); }   /* others: iMessage tail on run-start */
.cmdk-foot kbd, .sb-kbd { border-color: var(--hairline); }
/* ===== Task/Partner chat — premium grouped bubbles (mirrors the Client Delivery thread) ===== */
.chat-msg.grouped { padding-top: 2px; }
.chat-msg.mine { flex-direction: row-reverse; }
.chat-av { flex: 0 0 auto; align-self: flex-end; }
.chat-av-spacer { flex: 0 0 auto; width: 34px; }
.chat-msg.mine .chat-bubble { align-items: flex-end; }
.chat-msg .chat-meta { margin: 0 0 4px 12px; }
.chat-line { display: flex; align-items: center; gap: 6px; min-width: 0; max-width: 100%; }
.chat-msg.mine .chat-line { flex-direction: row-reverse; }
.chat-bubblewrap { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; min-width: 0; max-width: 100%; }
.chat-msg.mine .chat-bubblewrap { align-items: flex-end; }
.chat-msg.mine .chat-text { background: var(--accent-fill, var(--accent)); color:var(--text-on-accent,#fff); border-color: transparent; border-radius: var(--radius-lg); border-bottom-right-radius: var(--radius-xs); }
.chat-msg.grouped:not(.mine) .chat-text { border-bottom-left-radius: var(--radius-lg); }
.chat-msg.mine.grouped .chat-text { border-bottom-right-radius: var(--radius-lg); }
/* day separator pill (Today / Yesterday / Weekday, Mon D — LOCAL time) */
.chat-daysep { display: flex; align-items: center; justify-content: center; margin: 14px 0 8px; }
.chat-daysep-pill { font-size: 11px; font-weight: 700; letter-spacing: .02em; color: var(--text-3); background: var(--surface); border: 1px solid var(--hairline); padding: 4px 12px; border-radius: var(--radius-pill); white-space: nowrap; font-variant-numeric: tabular-nums; }

/* ===== prefers-reduced-motion — disable transforms + shimmer ===== */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .btn:active, .btn-primary:active, .btn-danger:active, .ig-cta:active,
  .login-btn:active, .btn-ghost:active, .btn-sm:active, .icon-btn:active,
  .sb-bell:active, .sb-collapse:active, .send-btn:active, .inv-mnav:active,
  .crumb-bell:active, .sb-toggle:active, .tabbar-btn:active, .row-kebab:active,
  .cf-kebab:active, .pay-kebab:active, .tab-kebab:active,
  .rel-x:active, .restore-purge:active, .notif-read-btn:active, .ian-x:active,
  .chip:active, .tab:active, .view-tab:active, .pview:active, .panel-tab:active,
  .view-chip:active, .mod-tab:active, .home-stat:active, .home-act:active,
  .sb-list:active, .menu-item:active, .cmdk-item:active, .ig-tab:active,
  .nv-fbtn:active, .nv-opt:active { transform: none !important; }
  /* .opt-kebab is centered with translateY(-50%); a blanket transform:none drops it ~half its
     height on tap even for reduce-motion users (review 2026-07-14). Keep the translate, drop the scale. */
  .opt-kebab:active { transform: translateY(-50%) !important; }
  .skel::after { animation: none !important; display: none; }   /* run7 W2: `.skel-line::after` dropped from this list — that rule was deleted as DEAD */
  /* reveal utilities resolve to their final state instantly.
     run7 W3: the `.u-fade-in/-up/-down`, `.u-scale-in`, `.u-slide-in` selectors and the whole
     `.u-lift:hover` rule dropped — those rules were deleted as DEAD. `.u-stagger`/`.u-fold` are
     live and keep their reduce-motion freeze. */
  .u-stagger > * { animation: none !important; opacity: 1 !important; transform: none !important; }
  .u-fold { transition: none !important; }
}

/* ============================================================
   HOME + GLOBAL CHROME — v236 refinement (wave 1)
   Pure additive layer on top of the v235 design system. Applies the
   display face (--font-display) to greetings/section titles, tabular numerals
   to stat/clock/log digits, a smooth grid-fold for collapsible Home
   sections (replacing the instant [hidden] swap), staggered load-in,
   hover-lift + press states, and chrome polish (sidebar active rail,
   cmdk craft, profile card, theme toggle). No :root token changes,
   no markup-structure changes — class hooks + value tweaks only.
   prefers-reduced-motion is honored via the shared block above.
   ============================================================ */

/* ---- HOME: type hierarchy — the type + weight token ladder (the display face is gone) ---- */
.home-greet { font-weight: var(--fw-medium); letter-spacing: 0; }
.home-name { font-weight: var(--fw-bold); letter-spacing: -0.020em; }
.home-date { font-variant-numeric: tabular-nums; }
.home-roleline { font-size: var(--fs-small); color: var(--text-2); font-weight: var(--fw-normal); margin-top: var(--space-1); max-width: 52ch; }
.home-card-h span:not(.home-card-meta):not(.clock-live):not(.clock-onmark),
.home-fold-h > span:first-child,
.home-risk-title { font-weight: var(--fw-semi); font-size: var(--fs-micro); letter-spacing: .05em; }
/* digits that should never jitter */
.home-stat-n, .home-pulse-n, .clock-hn, .home-next-time b,
.weeklog-cell b, .weeklog-total b, .home-card-meta { font-variant-numeric: tabular-nums; }

/* ---- HOME: view-mount reveal — ONE entrance animation, on the header only ----
   DESIGN_LANGUAGE 2.10 "reveal budget": the staggered per-card and per-tile cascades
   (10 + 4 animation-delay steps) are deleted. Cards and tiles paint instantly; that is
   what fast software feels like, and it kills the "whole app re-animates" jitter.
   .home-hero is still a direct child of .home, so body.cc-bg-render .home > * still
   suppresses this reveal on background re-renders. */
.home-hero { animation: uFadeUp var(--dur-3) var(--ease-out) both; }

/* ---- HOME: press states on clickable surfaces (no lift, no shadow — 2.10) ---- */
.home-stat, .home-card, .home-eod, .home-pending, .home-cd, .home-next, .home-pulse-tile {
  transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.home-stat:active, .home-eod:active, .home-pending:active, .home-cd:active { transform: scale(.985); }
button.home-card { cursor: pointer; }
/* run6 W5b: button.home-card:hover border-color re-pin deleted — dead once .home-card's border went */
button.home-card:active { transform: scale(.99); }
.home-stat:focus-visible, .home-pulse-tile:focus-visible, .home-act:focus-visible,
.home-task:focus-visible, .home-client:focus-visible, .home-risk-row:focus-visible,
.home-more:focus-visible, button.home-card:focus-visible { outline: none; box-shadow: var(--ring); }
/* rows change background only — padding is a layout property and is never animated (2.10) */
.home-task, .home-client, .home-risk-row { transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease); }
.home-act { transition: background-color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.home-act:active { transform: scale(.98); }

/* ---- HOME: smooth grid-fold for collapsible sections ----
   The JS toggles .is-open on .home-fold-body (a 0fr↔1fr grid, like .u-fold)
   for an animated collapse. On first paint the body is rendered already-open
   (no [hidden]) when expanded, so there is zero layout jank on load. The old
   [hidden] attribute is still respected as the collapsed initial state. */
.home-fold-body { display: grid; grid-template-rows: 1fr; transition: grid-template-rows var(--dur-3) var(--ease); }
.home-fold-body.is-folding { grid-template-rows: 0fr; }
/* v815: visibility:hidden takes the collapsed rows out of the tab order and the hit-test stack. Before, a
   folded section's buttons kept keyboard focus and Enter still fired them while nothing was on screen
   (Sales verification SD-2). The 0fr->1fr slide is unaffected: hidden is removed before the expand runs. */
.home-fold-body[hidden] { display: grid !important; grid-template-rows: 0fr; visibility: hidden; }
/* single inner wrapper holds all content in ONE collapsible track (multi-child safe) */
.home-fold-body > .home-fold-inner { overflow: hidden; min-height: 0; }
/* fallback for any fold body whose content isn't wrapped: still clip its children */
.home-fold-body > *:not(.home-fold-inner) { overflow: hidden; min-height: 0; }
.home-fold-chev svg { transition: transform var(--dur-2) var(--ease); }

/* ---- GLOBAL CHROME: sidebar polish ---- */
.brand-name { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.015em; }
/* active nav item gets a left accent rail + slightly stronger weight */
.sb-list { position: relative; }
.sb-list.active { font-weight: 650; }
.sb-list.active::before {
  content: ""; position: absolute; left: 3px; top: 50%; transform: translateY(-50%);
  width: 3px; height: 17px; border-radius: 3px; background: var(--accent);
  animation: uFadeIn var(--dur-2) var(--ease-out) both;
}
.sidebar.collapsed .sb-list.active::before { left: 2px; }
.sb-list:active { transform: scale(.98); }
.sb-list .sb-ic { transition: transform var(--dur-1) var(--ease); }
.sb-list:hover .sb-ic { transform: scale(1.06); }
.sb-list.active .sb-ic { color: var(--accent); }
/* SIM-15 · STICKY HOVER ON THE DRAWER NAV.
   A finger has no hover, but a touch browser fakes one: it applies :hover on tap and leaves it
   applied until you touch something else. In the nav drawer that painted a row highlighted and
   KEPT it highlighted, so after tapping around, two or three rows all looked selected and none
   of them was the real .active one — the drawer stopped telling you where you are.
   `hover: none` is the exact test for "this pointer cannot hover", so this block only ever runs
   on the devices that have the bug; mouse and trackpad keep every hover state untouched.
   PLACEMENT IS LOAD-BEARING: it sits BELOW every .sb-list:hover rule it neutralises (there are
   three, ~700 lines apart) because a media query adds no specificity — an override written next
   to the first rule would have lost to the later `.sb-list:hover .sb-ic` on source order alone.
   `.active` is deliberately re-asserted, not cleared: that is real selection, not a phantom.
   :active is untouched, so a tap still confirms itself. */
@media (hover: none) {
  .sb-list:hover { background: transparent; color: var(--text-2); }
  .sb-list.active:hover { background: var(--accent-soft); color: var(--accent); }
  .sb-list:hover .sb-ic { transform: none; }
  .sb-list.active:hover .sb-ic { color: var(--accent); }
  .sb-search:hover { color: var(--text-3); border-color: var(--hairline); }
  .sb-list.active:hover .sb-ct { color: var(--accent); background: var(--accent-soft); }
}
.sb-ct { font-variant-numeric: tabular-nums; }
.sb-bell:active, .sb-collapse:active { transform: scale(.92); }
/* profile card — lift + press, display face on the name */
.sb-user .viewas-meta b { font-family: var(--font-display); font-weight: 650; }
.sb-user:active { transform: scale(.98); }
.sb-user:focus-visible { outline: none; box-shadow: var(--ring); }
/* theme toggle — pressed feedback + active swap craft */
.theme-seg button:active { transform: scale(.95); }
.theme-seg button { transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.theme-seg button.active svg { color: var(--accent); }

/* ---- GLOBAL CHROME: ⌘K command palette craft ---- */
.cmdk-ov { animation: uFadeIn var(--dur-2) var(--ease-out) both; }
.cmdk-ov.is-closing { animation: uFadeIn var(--dur-2) var(--ease) reverse forwards; }
.cmdk-ov.is-closing .cmdk { animation: cmdkOut var(--dur-2) var(--ease) forwards; }
@keyframes cmdkOut { from { opacity: 1; transform: none; } to { opacity: 0; transform: scale(.97) translateY(-6px); } }
.cmdk-input { font-family: var(--font); }
.cmdk-item { transition: background var(--dur-1) var(--ease), transform var(--dur-1) var(--ease); }
.cmdk-item:hover { background: var(--surface); }
.cmdk-item.sel { background: var(--accent-softer); box-shadow: inset 2px 0 0 var(--accent); }
.cmdk-item:active { transform: scale(.99); }
.cmdk-foot kbd {
  font-family: var(--font); font-size: 11px; font-weight: 700; color: var(--text-3);
  background: var(--surface-2); border: 1px solid var(--hairline); border-radius: var(--radius-xs);
  padding: 1px 5px; margin-right: 2px;
}

/* ---- responsive polish (tablet + iPhone) for the v236 Home/chrome ---- */
@media (max-width: 1024px) and (min-width: 521px){
  /* tablet: roleline stays readable, cards keep breathing room */
  .home-roleline { max-width: none; }
}
@media (max-width: 520px){
  /* iPhone: tighter hero rhythm, comfortable tap targets, no overflow */
  .home-roleline { font-size: var(--fs-small); margin-top: var(--space-1); max-width: none; }
  .home-fold-chev svg { width: var(--icon-md); height: var(--icon-md); }   /* easier to hit */
  .home-card-h.home-fold-h { padding-top: var(--space-3); padding-bottom: var(--space-3); }   /* ≥44px tap row */
}
/* the ⌘K palette already goes near-full-width <=720px; ensure it never clips on a notch */
@media (max-width: 520px){
  .cmdk-ov { padding-top: max(8vh, var(--safe-top)); }
}

/* ============================================================
   WEBSITES × FORGE — publish modal "shows everything" (Phase 3)
   Global .ws-* classes for the new publish surfaces (live URL, deploy
   pill, domain DNS/verify, favicon+OG preview, model toggle). All built
   on existing CC tokens + brand accent (#E5322B via --accent). The base
   ws- modal/field styles ship in js/websites.js injectStyle(); these add
   only the NEW publish pieces, so there is no override conflict. iPhone
   375px rules at the bottom make the sheet full-screen + stacked.
   ============================================================ */
/* model selector (Opus/Sonnet) — mirrors .ws-kind */
.wsite-root .ws-prompt-bar-l{display:flex;align-items:center;gap:8px;flex-wrap:wrap;min-width:0;}
.wsite-root .ws-model{display:inline-flex;gap:4px;padding:3px;border-radius:var(--radius-pill);background:var(--surface-2);border:1px solid var(--hairline);}
.wsite-root .ws-model button{display:inline-flex;align-items:center;gap:5px;border:0;background:transparent;color:var(--text-3);font-family:var(--font);font-size:12.5px;font-weight:600;padding:5px 11px;border-radius:var(--radius-pill);cursor:pointer;transition:background var(--dur-1),color var(--dur-1);}
.wsite-root .ws-model button.on{background:var(--accent);color:var(--text-on-accent,#fff);}
.wsite-root .ws-model button svg{width:13px;height:13px;}
/* scrollable tab row (6 tabs) */
.ws-modal-tabs-scroll{overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;flex-wrap:nowrap;}
.ws-modal-tabs-scroll::-webkit-scrollbar{display:none;}
.ws-modal-tabs-scroll .ws-modal-tab{white-space:nowrap;flex:0 0 auto;}
.ws-modal-pub{max-width:600px;}
/* publish status pill (extends .ws-pill states) */
.ws-pub-status{margin-bottom:4px;}
.ws-pill.deploying{background:var(--amber-bg);color:var(--amber);}
.ws-pill.deploying .ws-dot{background:var(--amber);animation:ws-pulse 1s ease-in-out infinite;}
.ws-pill.ready{background:var(--green-bg);color:var(--green);}
.ws-pill.ready .ws-dot{background:var(--green);}
@keyframes ws-pulse{0%,100%{opacity:1;}50%{opacity:.35;}}
/* live URL row */
.ws-live-row{display:flex;align-items:center;gap:9px;flex-wrap:wrap;padding:12px 14px;border-radius:var(--radius-sm);background:var(--green-bg);border:1px solid var(--hairline);}
.ws-live-url{display:inline-flex;align-items:center;gap:8px;min-width:0;flex:1 1 auto;color:var(--green);font-weight:800;font-size:13.5px;text-decoration:none;overflow:hidden;}
.ws-live-url span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.ws-live-url svg{width:16px;height:16px;flex:0 0 auto;}
.ws-pub-badge{flex:0 0 auto;padding:3px 9px;border-radius:var(--radius-pill);font-size:11px;font-weight:800;letter-spacing:.03em;text-transform:uppercase;}
.ws-pub-badge.ok{background:var(--green-bg);color:var(--green);}
.ws-pub-badge.warn{background:var(--amber-bg);color:var(--amber);}
/* run6 W5b: surface props deleted — markup now ships `ws-pub-empty g-solid-2` (js/websites.js,
   both sites; lives inside the glass-4 ws-modal, so solid). Muted ink re-pinned at (0,2,0):
   .g-solid-2 sets color:var(--g-text) later at (0,1,0) and would un-mute the hint. */
.ws-pub-empty{padding:14px 16px;font-size:13px;line-height:1.55;}
.ws-pub-empty.g-solid-2{color:var(--text-3);}
.ws-pub-err{display:flex;align-items:flex-start;gap:9px;padding:11px 14px;border-radius:var(--radius-md);background:var(--accent-soft);border:1px solid var(--accent-soft);color:var(--text);font-size:12.5px;line-height:1.5;}
.ws-pub-err svg{width:15px;height:15px;color:var(--accent);flex:0 0 auto;margin-top:1px;}
/* domain status + DNS */
.ws-domain-input{display:flex;gap:8px;}
.ws-domain-input input{flex:1 1 auto;}
.ws-domain-input .ws-btn-primary{white-space:nowrap;}
.ws-domain-status{display:flex;align-items:center;gap:9px;padding:11px 14px;border-radius:var(--radius-md);font-size:12.5px;line-height:1.45;font-weight:600;}
.ws-domain-status svg{width:15px;height:15px;flex:0 0 auto;}
.ws-domain-status.ok{background:var(--green-bg);color:var(--green);}
.ws-domain-status.pending{background:var(--surface-2);color:var(--text-2);border:1px solid var(--hairline);}
.ws-domain-status.conflict{background:var(--amber-bg);color:var(--text);}
.ws-dns-issues{margin:2px 0 0;font-size:12px;color:var(--text-2);line-height:1.6;}
.ws-dns-row.ok span{color:var(--green);}
.ws-dns-row span svg{width:12px;height:12px;vertical-align:-1px;}
/* favicon + OG (brand) */
.ws-brand-row{display:flex;align-items:center;gap:12px;}
.ws-fav-prev{width:44px;height:44px;border-radius:var(--radius-md);border:1px solid var(--hairline);background:var(--surface-2);display:inline-flex;align-items:center;justify-content:center;overflow:hidden;flex:0 0 auto;}
.ws-fav-prev img{width:100%;height:100%;object-fit:contain;}
.ws-fav-prev.empty{color:var(--text-3);}
.ws-fav-prev.empty img{display:none;}
.ws-fav-prev.empty svg{width:20px;height:20px;}
/* client chip */
.ws-client-chip-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;}
.ws-client-chip{display:inline-flex;align-items:center;gap:7px;padding:7px 12px;border-radius:var(--radius-pill);background:var(--accent-softer);color:var(--text);font-size:13px;font-weight:700;border:1px solid var(--accent-soft);}
.ws-client-chip .ws-cav,.ws-client-chip .ws-cav-f{width:18px;height:18px;border-radius:var(--radius-xs);}
.ws-client-chip .ws-cav-f{font-size:11px;display:inline-flex;align-items:center;justify-content:center;background:var(--surface-2);color:var(--text-2);box-shadow:inset 0 0 0 1px var(--hairline);} /* V724-1: same pair as the js/websites.js base rule — this (0,2,0) copy beats the unscoped fix, so it must carry the fix itself */
/* inline mini spinner reused on busy buttons */
.ws-mini-spin{display:inline-flex;}
.ws-mini-spin svg{width:14px;height:14px;animation:ws-spin 1s linear infinite;}
@keyframes ws-spin{to{transform:rotate(360deg);}}
/* iPad/large-phone + iPhone — bottom-sheet at the app-wide 720px breakpoint
   (matches Tasks/Partners/Calendar modals so Websites doesn't float centered) */
@media (max-width:720px){
  .ws-modal-backdrop{padding:0;align-items:flex-end;}
  .ws-modal,.ws-modal-pub{max-width:100%;width:100%;max-height:94vh;border-radius:var(--radius-lg) var(--radius-lg) 0 0;}
  .ws-modal-body{padding:16px 14px 24px;}
  .ws-live-row{flex-direction:column;align-items:stretch;}
  .ws-live-url{flex:1 1 auto;}
  .ws-domain-input{flex-direction:column;}
  .ws-domain-input .ws-btn-primary{width:100%;justify-content:center;}
  .ws-modal-actions{flex-direction:column;}
  .ws-modal-actions>button,.ws-modal-actions>a{width:100%;justify-content:center;}
  .ws-client-chip-row{width:100%;}
  .ws-client-chip-row .ws-btn-soft{flex:1 1 auto;justify-content:center;}
  .ws-dns-row{grid-template-columns:52px 1fr 1.3fr auto;}
}
/* ORCH-1 union — the tap-target half of the three rules above. Full-width STACKING is a width
   concern and stays in the block above; the 44px floor is a pointer concern and belongs here,
   so an iPad/touch-laptop at >720px gets a real target on the Websites modal buttons too. */
@media (max-width: 720px), (hover: none) and (pointer: coarse){
  .ws-domain-input .ws-btn-primary{min-height:44px;}
  .ws-modal-actions>button,.ws-modal-actions>a{min-height:44px;}
  .ws-client-chip-row .ws-btn-soft{min-height:44px;}
}

/* ===============  PPM LOADER OVERLAY (v237 — real lion + wordmark, no ring)  =============== */
#ppm-loader{
  position:fixed; inset:0; z-index:99999;
  display:flex; align-items:center; justify-content:center;
  background:#0a0a0d; /* matches the mp4 fallback bg => seamless */
  opacity:1; transition:opacity .55s cubic-bezier(.4,0,.2,1);
  -webkit-tap-highlight-color:transparent;
  font-family:'Inter',-apple-system,BlinkMacSystemFont,'SF Pro Display','Helvetica Neue',sans-serif;
  -webkit-font-smoothing:antialiased;
}
#ppm-loader.ppm-loader--hide{ opacity:0; pointer-events:none; }
.ppm-loader__stage{
  position:relative; width:min(60vmin,420px);
  display:flex; flex-direction:column; align-items:center; justify-content:center;
}
.ppm-loader__video{ width:min(48vmin,340px); height:min(48vmin,340px); object-fit:contain; display:block; }

/* ── CSS/SVG fallback (real lion path; identical motion; hidden until data-mode="css") ── */
.ppm-loader__css{ position:absolute; inset:0; display:none; flex-direction:column; align-items:center; justify-content:center; }
#ppm-loader[data-mode="css"] .ppm-loader__video{ display:none; }
#ppm-loader[data-mode="css"] .ppm-loader__css{ display:flex; }

.ppm-loader__mark{
  position:relative; width:min(22vmin,150px); aspect-ratio:1/1;
  animation:ppmMarkIn 1.1s cubic-bezier(.22,.61,.36,1) both;
}
.ppm-loader__lion{ width:100%; height:100%; display:block; overflow:visible; position:relative; z-index:1; }
.ppm-loader__glow{
  position:absolute; inset:-22%; border-radius:50%; z-index:0;
  background:radial-gradient(closest-side, rgba(229,50,43,1), rgba(229,50,43,0) 72%);
  opacity:.16; filter:blur(26px); animation:ppmGlow 4s ease-in-out infinite;
}
.ppm-loader__shimmer{
  position:absolute; inset:0; z-index:2; mix-blend-mode:screen; pointer-events:none; opacity:.5;
  -webkit-mask:var(--ppm-lionmask); mask:var(--ppm-lionmask);
  -webkit-mask-size:contain; mask-size:contain;
  -webkit-mask-repeat:no-repeat; mask-repeat:no-repeat;
  -webkit-mask-position:center; mask-position:center;
  background:linear-gradient(115deg,transparent 38%,rgba(255,255,255,.85) 48%,
    #E5322B 50%,rgba(255,255,255,.85) 52%,transparent 62%);
  background-size:300% 300%; animation:ppmShimmer 4s linear infinite;
}
.ppm-loader__word{ text-align:center; margin-top:7%;
  animation:ppmWordIn 1s cubic-bezier(.22,.61,.36,1) .5s both; }
.ppm-loader__name{ color:#fff; font-weight:600; letter-spacing:.005em; font-size:clamp(16px,3.2vw,30px); }
.ppm-loader__by{ margin-top:.5em; font-weight:400; font-size:clamp(9px,1.1vw,13px);
  letter-spacing:.18em; text-transform:uppercase; color:rgba(255,255,255,.42); }

@keyframes ppmMarkIn{ from{opacity:0;transform:scale(.9);} 55%{opacity:1;} to{opacity:1;transform:scale(1);} }
@keyframes ppmWordIn{ from{opacity:0;transform:translateY(12px);} to{opacity:1;transform:translateY(0);} }
@keyframes ppmGlow{ 0%,100%{opacity:.16;} 50%{opacity:.255;} }
@keyframes ppmShimmer{ from{background-position:140% 140%;} to{background-position:-40% -40%;} }

@media (prefers-reduced-motion: reduce){
  .ppm-loader__mark,.ppm-loader__word{ animation:none; opacity:1; transform:none; }
  .ppm-loader__shimmer,.ppm-loader__glow{ animation:none; }
}
/* ===============  END PPM LOADER OVERLAY  =============== */

/* ===================================================================================================
   v551 — WEEKLY CLIENT REPORT. Two surfaces share this block so they never drift:
   (a) the owner's draft/review UI in the partner-panel Report tab (.creport-tab / tiles / toggle / note);
   (b) the client-facing card (.creport-card) rendered by window.creportClientCard — used by the owner's
       Preview modal, the client portal's Reports section, AND matched by the Home teaser (.cpd-rep-teaser).
   All colors come from the app's theme variables, so both light + dark render correctly.
   =================================================================================================== */
/* --- (a) owner draft --- */
.creport-tab { display:flex; flex-direction:column; gap:16px; }
.creport-draft-head h4 { display:flex; align-items:center; gap:7px; margin:0 0 5px; font-size:15px; font-weight:700; color:var(--text); }
.creport-draft-head h4 svg { width:16px; height:16px; color:var(--accent); }
.creport-draft-sub { margin:0; font-size:12.5px; line-height:1.5; color:var(--text-3); }
.creport-tiles { display:grid; grid-template-columns:repeat(2,1fr); gap:10px; }
/* run6 W5a: surface props deleted — markup now ships `creport-tile g-solid-2` (js/app.js draft
   composer, all 4 tiles). The hero's green tint is bumped to (0,2,0): glass.css's .g-solid-2
   background-color loads later at (0,1,0) and would erase it otherwise. */
.creport-tile { display:flex; flex-direction:column; gap:3px; padding:13px 14px; min-height:64px; }
.creport-tile.creport-tile-hero { background:var(--green-bg,rgba(31,157,87,.1)); border-color:transparent; }
.creport-tile-num { font-size:22px; font-weight:800; line-height:1.05; letter-spacing:-.02em; color:var(--text); font-variant-numeric:tabular-nums; }
.creport-tile-hero .creport-tile-num { color:var(--green,#1f9d57); }
.creport-tile-lbl { display:flex; align-items:center; gap:6px; font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:.04em; color:var(--text-3); }
.creport-tile-spend.creport-tile-noacct .creport-tile-num,
.creport-tile-spend.creport-tile-failed .creport-tile-num,
.creport-tile-spend.creport-tile-nodaily .creport-tile-num { font-size:14px; font-weight:700; color:var(--text-3); }
.creport-tile-spend.creport-tile-loading .creport-tile-num { font-size:14px; font-weight:700; color:var(--text-3); }
.creport-mini { display:inline-flex; align-items:center; justify-content:center; min-width:24px; min-height:24px; padding:0; border:none; border-radius:var(--radius-sm); background:transparent; color:var(--text-3); cursor:pointer; transition:color .15s, background .15s; }
.creport-mini svg { width:13px; height:13px; }
.creport-mini:hover { color:var(--accent); background:var(--surface-2,var(--surface)); }
.creport-toggle { display:flex; align-items:flex-start; gap:12px; width:100%; min-height:44px; padding:12px 14px; border:1px solid var(--hairline); border-radius:var(--radius-sm); background:var(--surface); cursor:pointer; text-align:left; font:inherit; transition:border-color .15s, background .15s; }
.creport-toggle:hover:not(.is-disabled) { border-color:var(--accent-soft,var(--hairline-strong)); }
.creport-toggle.is-disabled { cursor:not-allowed; opacity:.7; }
.creport-toggle-sw { flex:0 0 auto; position:relative; width:38px; height:22px; margin-top:1px; border-radius:var(--radius-pill); background:var(--hairline-strong,#9993); transition:background .18s; }
.creport-toggle-sw::after { content:""; position:absolute; top:2px; left:2px; width:18px; height:18px; border-radius:50%; background:#fff; box-shadow:0 1px 3px rgba(0,0,0,.28); transition:transform .18s; }
.creport-toggle.on .creport-toggle-sw { background:var(--green,#1f9d57); }
.creport-toggle.on .creport-toggle-sw::after { transform:translateX(16px); }
.creport-toggle-tx { display:flex; flex-direction:column; gap:2px; }
.creport-toggle-tx b { font-size:13px; font-weight:700; color:var(--text); }
.creport-toggle-tx small { font-size:11.5px; line-height:1.45; color:var(--text-3); }
.creport-note-wrap { display:flex; flex-direction:column; gap:6px; }
.creport-note-lbl { font-size:12px; font-weight:700; color:var(--text-2); }
.creport-note-lbl small { font-weight:500; color:var(--text-3); }
.creport-note-input { width:100%; box-sizing:border-box; padding:11px 12px; border:1px solid var(--hairline); border-radius:var(--radius-sm); background:var(--surface); color:var(--text); font:inherit; font-size:13.5px; line-height:1.5; resize:vertical; min-height:66px; }
.creport-note-input:focus { outline:none; border-color:var(--accent); }
.creport-summary-prev { padding:12px 14px; border-radius:var(--radius-sm); background:var(--surface); border:1px dashed var(--hairline-strong,var(--hairline)); }
.creport-summary-prev .creport-summary-k { display:block; font-size:10.5px; font-weight:700; text-transform:uppercase; letter-spacing:.06em; color:var(--text-3); margin-bottom:5px; }
.creport-summary-prev p { margin:0; font-size:13.5px; line-height:1.55; color:var(--text); }
.creport-actions { display:flex; gap:10px; flex-wrap:wrap; }
.creport-actions .btn { min-height:40px; }
.creport-hist { display:flex; flex-direction:column; gap:2px; border-top:1px solid var(--hairline); padding-top:14px; }
.creport-hist-h { display:flex; align-items:center; gap:7px; font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.04em; color:var(--text-3); margin-bottom:6px; }
.creport-hist-h svg { width:14px; height:14px; }
.creport-hist-h i { font-style:normal; padding:1px 7px; border-radius:var(--radius-pill); background:var(--surface); border:1px solid var(--hairline); font-size:11px; color:var(--text-2); }
.creport-hist-row { display:flex; align-items:center; justify-content:space-between; gap:12px; padding:9px 2px; border-bottom:1px solid var(--hairline); }
.creport-hist-row:last-child { border-bottom:none; }
.creport-hist-wk b { display:block; font-size:13px; font-weight:700; color:var(--text); }
.creport-hist-wk small { font-size:11px; color:var(--text-3); }
.creport-hist-nums { display:flex; flex-direction:column; align-items:flex-end; gap:1px; font-size:12px; color:var(--text-2); font-variant-numeric:tabular-nums; }

/* --- (b) shared client-facing card --- */
/* run6 W5a: surface props deleted — the shared renderer (js/app.js creportClientCard, used by BOTH
   the staff panel and the client portal) now ships `creport-card g-solid-2`. Padding kept bespoke
   (also keeps the portal's rarely-hit fallback renderer readable if app.js ever fails to load).
   is-preview became a FULL dashed border: it only re-pinned border-STYLE before, and §19.1's theme
   border (transparent in most themes) would have made the dash invisible. */
.creport-card { padding:20px; }
.creport-card.is-preview { border:1px dashed var(--hairline-strong,var(--hairline)); }
.creport-top { display:flex; align-items:center; justify-content:space-between; gap:12px; flex-wrap:wrap; margin-bottom:16px; }
.creport-wk { display:inline-flex; align-items:center; gap:7px; font-size:12px; font-weight:600; color:var(--text-3); }
.creport-wk svg { width:15px; height:15px; color:var(--accent); }
.creport-wk span { text-transform:uppercase; letter-spacing:.05em; }
.creport-wk b { color:var(--text-2); font-weight:700; letter-spacing:0; text-transform:none; }
.creport-when { font-size:11.5px; font-weight:600; color:var(--text-3); }
.creport-card.is-preview .creport-when { color:var(--accent); }
.creport-hero { display:flex; flex-direction:column; align-items:center; text-align:center; gap:2px; padding:8px 0 18px; }
.creport-hero-num { font-size:56px; font-weight:800; line-height:1; letter-spacing:-.03em; color:var(--green,#1f9d57); font-variant-numeric:tabular-nums; }
.creport-hero-lbl { font-size:13px; font-weight:600; color:var(--text-2); }
.creport-metrics { display:flex; flex-wrap:wrap; gap:10px; }
.creport-metric { flex:1 1 0; min-width:96px; display:flex; flex-direction:column; align-items:center; gap:3px; padding:13px 10px; border-radius:var(--radius-sm); background:var(--surface); text-align:center; }
.creport-m-num { font-size:21px; font-weight:800; line-height:1.05; letter-spacing:-.02em; color:var(--text); font-variant-numeric:tabular-nums; }
.creport-m-lbl { font-size:11px; font-weight:600; color:var(--text-3); }
.creport-summary { margin:16px 0 0; font-size:14.5px; line-height:1.6; color:var(--text); }
.creport-note { display:flex; gap:10px; margin-top:14px; padding:12px 14px; border-radius:var(--radius-sm); background:var(--accent-softer,rgba(229,50,43,.08)); border-left:3px solid var(--accent); }
.creport-note svg { flex:0 0 auto; width:16px; height:16px; margin-top:2px; color:var(--accent); }
.creport-note p { margin:0; font-size:13.5px; line-height:1.55; color:var(--text); }
.creport-foot { display:flex; align-items:center; gap:7px; margin-top:18px; padding-top:14px; border-top:1px solid var(--hairline); font-size:12px; color:var(--text-3); }
.creport-foot svg { width:14px; height:14px; color:var(--accent); }
.creport-foot b { color:var(--text-2); font-weight:700; }
.creport-preview-body { max-width:440px; }

/* --- (b') portal Reports section + Home teaser --- */
.cp-rep-list { display:flex; flex-direction:column; gap:16px; margin-top:6px; }
/* run6 W5b: surface props deleted — markup now ships `cpd-rep-teaser g-solid-2`
   (js/client-portal.js). Hover retargeted to the system card-hover recipe (edge kept, one
   shadow tier deeper); the hardcoded-rgba border/shadow pins are gone with it. */
.cpd-rep-teaser { display:flex; align-items:center; gap:13px; width:100%; padding:15px 16px; cursor:pointer; text-align:left; font:inherit; transition:transform .15s, border-color .15s, box-shadow .15s; }
.cpd-rep-teaser:hover { box-shadow: var(--g-edge-2), var(--g-spec-2), var(--g-shadow-3); }
.cpd-rep-ic { flex:0 0 auto; display:inline-flex; align-items:center; justify-content:center; width:42px; height:42px; border-radius:var(--radius-md); background:var(--green-bg,rgba(31,157,87,.12)); color:var(--green,#1f9d57); }
.cpd-rep-ic svg { width:20px; height:20px; }
.cpd-rep-tx { flex:1 1 auto; display:flex; flex-direction:column; gap:2px; min-width:0; }
.cpd-rep-tx b { font-size:14px; font-weight:700; color:var(--text); }
.cpd-rep-tx span { font-size:12.5px; line-height:1.4; color:var(--text-3); }
.cpd-rep-go { flex:0 0 auto; color:var(--text-3); }
.cpd-rep-go svg { width:18px; height:18px; }
@media (max-width:480px){ .creport-tiles { grid-template-columns:1fr 1fr; } .creport-hero-num { font-size:48px; } }
/* ===============  END v551 WEEKLY CLIENT REPORT  =============== */

/* ============================================================================
   V2-FOUNDATION (2026-07-26)  —  global iOS foundation, benefits V1 today.
   Spec: .agents/v2/DESIGN_SYSTEM.md "iOS foundation" + research-raw §iosPlaybook 1-5.
   Additive only: nothing above this comment was changed.
   Already verified as present elsewhere, so NOT repeated here:
     . viewport-fit=cover ......................... line 6
     . apple-mobile-web-app-status-bar-style ...... line 8
     . .tabbar padding-bottom: var(--safe-bottom) . line 4559 (safe area already handled)
     . .toasts bottom offset incl. --safe-bottom .. line 2994
   ============================================================================ */

/* --- V2F.1  Safe-area insets. Short aliases for V2 markup; --safe-* (already
   defined in :root above) stays the V1 name. Both read the same env() values,
   so neither depends on the other. env() only resolves non-zero because the
   viewport meta carries viewport-fit=cover. */
:root {
  --sat: env(safe-area-inset-top, 0px);
  --sar: env(safe-area-inset-right, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  --sal: env(safe-area-inset-left, 0px);
}

/* --- V2F.2  Kill the gray tap flash and the long-press callout on interactive
   CHROME only. Form fields are excluded explicitly: 18 <input>/<textarea> and 2
   contenteditable nodes in js/app.js carry data-act, and killing callout/select
   on those breaks the iOS magnifier, copy/paste and the selection handles. */
button,
.tab,
.sb-list,
[data-act]:not(input):not(textarea):not(select):not([contenteditable]) {
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}

/* Selection is disabled ONLY in the installed app. In a Safari tab the user
   keeps normal selection/copy on content text (research-raw §iosPlaybook 2:
   don't apply native-app restrictions site-wide). */
@media (display-mode: standalone) {
  button,
  .tab,
  .sb-list,
  [data-act]:not(input):not(textarea):not(select):not([contenteditable]) {
    user-select: none;
    -webkit-user-select: none;
  }
}

/* --- V2F.3  Press feedback — the haptic illusion. WebKit exposes no Vibration
   API on iOS, so this transform is doing 100% of the tactile work.
   Wrapped in :where() ON PURPOSE: :where() contributes ZERO specificity, so this
   whole rule sits at (0,1,0) and LOSES to every existing tuned `.foo:active`
   rule above (the ~40 at lines 4809-4830). That is the point — it fills in the
   tappables that have no press state yet without overriding any that do,
   including .opt-kebab, whose translateY(-50%) must survive or the 3-dots drop
   half their height on tap (documented regression, review 2026-07-14). */
:where(button, .tab, .sb-list,
       [data-act]:not(input):not(textarea):not(select):not([contenteditable])):active {
  transform: scale(.97);
  transition: transform var(--dur-1) var(--ease);
}

/* Drag handles must not shrink while a drag is in progress — :active stays true
   for the whole gesture. These beat the rule above on specificity (0,2,0). */
.row-grip:active,
.bcard-grip:active,
.pipe-card:active { transform: none; }

@media (prefers-reduced-motion: reduce) {
  :where(button, .tab, .sb-list,
         [data-act]:not(input):not(textarea):not(select):not([contenteditable])):active {
    transform: none;
  }
}

/* --- V2F.4  Overscroll discipline. Native apps don't rubber-band the whole
   screen. The custom pull-to-refresh (js/app.js ~16707) already calls
   preventDefault() on its own touchmove and explicitly wants the page to stop
   rubber-banding behind the indicator, so this reinforces it rather than
   fighting it. .panel-body is the real internal scroller for .panel. */
body { overscroll-behavior-y: none; }

.content,
.panel,
.panel-body,
.sidebar { overscroll-behavior: contain; }

/* ════════════════════════════════════════════════════════════════════════════════════
   OB-14 §2 (v752) · PROSE MEASURE CAP — the wide end.
   Owner, verbatim: "MacBook Pro and TV sizes and everything… it needs to work perfect
   and every screen size." TV widths had never been tested in this mission.

   THE SHELL IS UNCAPPED. `.main` (:5305) declares only flex / min-width / min-height —
   no max-width — and the 1640px cap sitting at :294 is the DEAD RULE tombstoned there
   (nothing in the app carries `class="app"`). So the content column runs 2248px @2560
   and 3528px @3840, and every full-width descriptive paragraph becomes a ribbon.

   MEASURED LIVE, signed in on prod v750 (.agents/mission/wave-ob/OB14-viewport-ladder-live.md §2),
   characters per line — comfortable measure is 45–90 ch; past ~120 the eye loses the
   next line on the return sweep:
     Ads Manager   .adsm-trend-foot          393 ch @2560    626 ch @3840  (3442px)
     Team          .admin-sec-sub            353 ch @2560    557 ch @3840
     Delivery      .dops-explain-lead        336 ch @2560    533 ch @3840
     SOP Library   .ppm-sop-lib-rm-stepsub   201 ch @2560

   THIS CAPS THE TEXT, NOT THE COLUMN. Tables, boards, charts and stat grids legitimately
   want the width; only prose is damaged. Home already proves the pattern — `.home` is
   capped at 760px (:533) and 1000px above 1100px (:2073) — and this file already ships a
   measure cap of exactly this kind on `.pipe-sub` (`max-width:60ch`, :1212). Same
   discipline, applied to the blocks that were actually measured plus four verified
   siblings on the same surfaces.

   `ch` (not px) is the correct unit here: the cap must scale with each block's own
   font-size, and these run 11px (.adsm-trend-foot) → 14.5px (.creport-summary). MEASURED
   below, 72ch lands 78 / 86 / 99 characters on the three blocks that were profiled — the
   top of the comfortable band, down from 181 / 176 / 181 at his own 1512.

   EVERY SELECTOR BELOW WAS READ BEFORE BEING LISTED. None declares `text-align:center`
   and none is a centred empty state, so a shortened box stays flush-left under the
   heading above it instead of drifting:
     .adsm-trend-foot          index.html:1835
     .admin-sec-sub            index.html:4482
     .adsv-hint                index.html:1933
     .tde-hint                 index.html:751
     .mo-hint                  index.html:2168
     .creport-summary          index.html:6376
     .dops-explain-lead        js/daily-ops.js:4707  (+ v2/delivery.css:452)
     .ppm-sop-lib-rm-stepsub   sops.css:179
   The two cross-file selectors are reachable from HERE even though this <style> loads
   BEFORE sops.css, v2/*.css and daily-ops.js's injected sheet: a cascade-order tiebreak
   only fires on a DECLARED conflict, and none of those rules declares `max-width` on
   these classes (grepped, all three files).

   MEASURED BEFORE → AFTER in a real browser, on the same calibrated fixture described in
   the OB-3 block at :2544 (this file's <style> extracted verbatim, real Inter). Numbers are
   px width / characters per line, where "characters" is the block's own average rendered
   advance — the same metric OB-14 used, which is why the BEFORE column tracks its live
   figures (fixture 345/335/344 @2560 vs live 393/353/336; 545/529 @3840 vs live 626/557):

     viewport   .adsm-trend-foot     .admin-sec-sub      .dops-explain-lead
     1024        672px/105ch          668px/101ch         672px/105ch
     1280        928px/145ch          924px/140ch         928px/144ch
     1512       1160px/181ch         1156px/176ch        1160px/181ch
     1728       1376px/215ch         1372px/208ch        1376px/214ch
     2560       2208px/345ch         2204px/335ch        2208px/344ch
     3840       3488px/545ch         3484px/529ch        3488px/543ch
     AFTER,      500px/ 78ch          568px/ 86ch         590px/ 99ch   ← identical at EVERY
     ≥1600                                                               width ≥1600, by construction

   [.dops-explain-lead's AFTER was first written as 636px. CORRECTED: 636px is 14px Inter,
    the fixture's value. Prod gives that block `font-size: var(--fs-body)` (js/daily-ops.js:4707)
    and `--fs-body: 13px` (index.html:121), so 72ch resolves to 590.484px and it renders 590px.
    A fixture number must never be shipped as a prod number.]

   ⚠️ SCOPE — GATED TO ≥1600px BY THE ORCHESTRATOR, deliberately overriding the lane.
   The lane shipped this UNGATED and argued, correctly, that the brief was self-contradictory:
   a 72ch cap cannot both apply and "change nothing at ≤1512", because these blocks already run
   176–181 characters at 1512 — well past the ~120 at which the eye loses the return sweep. Its
   reasoning that `max-width` can only REMOVE width (so nothing can break, overflow or hide) was
   verified and holds. It was gated anyway, for a reason that is not about correctness:

     Verification found the ungated rule first engaged at roughly a 525px VIEWPORT — not "a
     little under 1024" as first written — because `.adsm-trend-foot` is 11px, so 72ch is only
     ~500px. Ungated, this reshapes prose on phones, tablets, and both of his laptops.

   The owner asked for TV sizes to work. He did not ask for his daily working view to be
   redesigned overnight, and taking .adsm-trend-foot from 1160px to 500px at 1512 is a large,
   visible change he cannot see until morning. Fixing what he named, at zero risk to what he
   didn't, is the right split — and 181ch at 1512 is now a documented finding for HIM to rule on.
   TO EXTEND IT TO HIS LAPTOPS: delete the `@media` wrapper below. That is the whole change.

   NOT DONE, deliberately: a content-column cap on `.content` / `.mainhead`. It is a taste
   call only the owner can make (at 3840 it means a centred column with ~860px of dead
   margin per side and the sidebar stranded far left), and it barely moves the measured
   metric anyway — scaling the measured 345 ch @2560 by a 2100px column gives ~321 ch, still
   3.5× over the comfortable band. Filed for him rather than guessed at here.
   ════════════════════════════════════════════════════════════════════════════════════ */
@media (min-width: 1600px){
  .adsm-trend-foot,
  .admin-sec-sub,
  .adsv-hint,
  .tde-hint,
  .mo-hint,
  .creport-summary,
  .dops-explain-lead,
  .ppm-sop-lib-rm-stepsub { max-width: 72ch; }
}
/* ===============  END V2-FOUNDATION  =============== */

/* D8 / CS-08 (v817): phone chrome hit targets - bell, drawer toggle, profile row, sign out at 44px; theme
   segments at 38px (three-up in a 240px drawer, documented exception). SD-11: skip link, visible on focus only. */
@media (max-width: 720px){
  .crumb-home .crumb-bell { width: 44px; height: 44px; }
  .crumb .sb-toggle { width: 44px; height: 44px; }
  .sb-user { min-height: 44px; }
  .sb-signout { min-height: 44px; }
  .sb-install-x { width: 44px; min-height: 44px; }
  .theme-seg button { min-height: 38px; }
}
.skip-link { position: fixed; top: 8px; left: 8px; z-index: 9999; padding: 10px 14px; border-radius: 10px; border: 1px solid var(--hairline); background: var(--surface); color: var(--text); font-family: var(--font); font-size: 13px; font-weight: 600; transform: translateY(-200%); opacity: 0; pointer-events: none; }
.skip-link:focus-visible { transform: none; opacity: 1; pointer-events: auto; outline: 2px solid var(--accent); outline-offset: 2px; }
/* CS-04 (v817): the hover-revealed column kebab sat INLINE after the label at opacity 0, so a click at the
   centre of a short header (STATUS, POD, CSM, BILLING, PHONE...) hit the invisible kebab and opened the
   column menu instead of sorting. Pin it to the header's right edge, outside the label. */
.th-sort { position: relative; }
.th-sort:has(.cf-kebab) { padding-right: 30px; min-width: 88px; }
/* a later touch-target rule grows the kebab to 32px; at that size it overlapped the centre of a 69px header
   (CSM). 22px here, and the header reserves 30px + a floor width, so the label's centre is never the kebab. */
table th.th-sort .cf-kebab, .th-sort .cf-kebab { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); margin-left: 0; width: 22px; height: 22px; min-width: 22px; min-height: 22px; }

/* D10: the "Roles & permissions" header button lands here; a one-shot ring shows WHERE it landed. */
.roles-admin.is-jumped { animation: ppm-jump-ring 1.4s ease-out 1; border-radius: var(--radius, 12px); }
@keyframes ppm-jump-ring { 0% { box-shadow: 0 0 0 3px var(--accent); } 100% { box-shadow: 0 0 0 0 transparent; } }
@media (prefers-reduced-motion: reduce) { .roles-admin.is-jumped { animation: none; box-shadow: 0 0 0 2px var(--accent); } }

/* CS-08 content half (v823): the phone 44px rule inside Home CONTENT (the chrome half shipped in v817).
   Measured on production v822 at 390x844, cs seat: 18 of 35 interactive elements in #content under 44x44
   (wave-verify/REPORT_prodproof_v822.md). Same 720px breakpoint as the chrome rule. */
@media (max-width: 720px){
  .weeklog-print, [data-act="timesheet-print"] { min-height: 44px; min-width: 44px; display: inline-flex; align-items: center; justify-content: center; }
  .cr-title[role="button"] { min-height: 44px; display: inline-flex; align-items: center; }
  .clock-sc-toggle { min-height: 44px; display: inline-flex; align-items: center; }
  .home-fold-h { min-height: 44px; }
  .home-fold-h span[role="button"], .home-fold-h span[data-act="home-fold"] { min-height: 44px; display: inline-flex; align-items: center; }
  .clock-btn { min-height: 44px; }
  .home-cfilter { height: auto; min-height: 44px; }
  .home-more { min-height: 44px; }
  .weeklog-edit, .weeklog-del { width: 44px; height: 44px; }
  .home-hs-item { min-width: 44px; min-height: 44px; }
  /* v824 (REGRESS_v823_admin_cs R2-R4): admin Home content, drawer/crumb chrome, Partner Tracker rows */
  .home-pp-btn, .home-ov-alert, .home-newleads, .cr-cash-btn, .rg-edit { min-height: 44px; }
  .sb-bell { width: 44px; height: 44px; }
  .sb-viewas-btn { min-width: 44px; min-height: 44px; }
  .crumb-list { min-height: 44px; }
  .pt-rowact { width: 44px; height: 44px; }
  .pt-mchev { width: 44px; height: 44px; }
  .p-nametext { min-height: 44px; }
  .pt-rowacts { opacity: 1; flex-direction: column; gap: 2px; }   /* hover-revealed row actions have no hover on a phone; stacked so 44px targets do not eat the name column */  /* v824 (REGRESS_v823_sales_mkt_cc R-03b): the daily surfaces beyond Home - Day View, delivery thread, Ads Manager
     sort headers, SOP status, refresh - by data-act so class churn cannot silently undo it */
  [data-act="dv-dial-start"], [data-act="dv-mine"], [data-act="dv-seg"], [data-act="dv-client"], .dv-callnext, .dv-mine-btn,
  [data-act="open-delivery-thread"], [data-act="refresh-data"], .dops-fchip, .sop-status, [data-act="sop-status"] { min-height: 44px; }
  [data-act="open-delivery-thread"], [data-act="refresh-data"], .dops-fchip { min-width: 44px; }
  th.adsv-th-sort, .adsv-th-sort { height: 44px; }
  /* v824 sweep (qa/verify/v824-phone-sweep.js, marketing + callcenter at 390): the rest of the daily surfaces */
  .dops-roleprog { min-height: 44px; }
  .ppm-sop-lib-hero button, .ppm-sop-lib-hero input, .sop-herostat-offline { min-height: 44px; }
  /* the Ads Manager injects its own sheet at runtime (later in the cascade), so these carry #content */
  #content .adsm-ql, #content .adsv-range-btn, #content .adsm-retry-sm { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; }
  .sla-cli, .sla-oldest, .dv-search-inp { min-height: 44px; }
  .adsm-trend-col { min-width: 44px; }
  [data-act="kind"], [data-act="model"] { min-height: 44px; }
  .paygate-cancel { min-height: 44px; }
  /* v824 (REGRESS_v823_doo_jarvis_client R-05): delivery thread (module sheet injected later -> #content), tasks, client shell */
  #content .dops-back, #content .dops-copy3, #content .dops-cov-navbtn { min-height: 44px; min-width: 44px; }
  #content .tq-chip, .tq-chip { min-height: 44px; }
  #search { min-height: 44px; }
  .cl-menu { width: 44px; height: 44px; }
  .btn-refresh { min-width: 44px; min-height: 44px; }
  /* v825 (VERIFY_v824 REG-5 / REG-7): client nav links 41 -> 44; tasks chrome Status select + table-shade width */
  .cl-navlink { min-height: 44px; }
  .uis-trigger, #mainhead .uis-trigger, .mainhead .uis-trigger { min-height: 44px; height: auto; max-height: none; }
  [data-act="table-shade"] { min-width: 44px; }
  /* v825 (VERIFY_v824 REG-8): admin-only screens at 390 - Day View analytics window, Ads Manager pace controls,
     Funnel Stats controls (lazy module, its own sheet -> #content), SOP library controls, Admin team screen */
  .dv-ana-wbtn { min-height: 44px; }
  #content .adsm-pace-edit { width: 44px; height: 44px; }
  #content .adsm-pace-setbtn { min-height: 44px; }
  /* the Funnel sheet prefixes every rule with its root id (1,1,0) and lands later; [id] lifts these to (1,2,0) */
  #content [id] .ppf-btn, #content [id] .ppf-drp-trigger, #content [id] .ppf-chip-preset, #content [id] .ppf-chip, #content [id] .ppf-tab, #content [id] .ppf-link, #content [id] .ppf-fv-bar, #content [id] .ppf-trend-chip, #content [id] .ppf-src-pill { min-height: 44px; height: auto; max-height: none; }
  #content [id] .ppf-src-row > td { height: 44px; }
  /* v826 (VERIFY_v825 R-B): the Funnel lead table rows, sort headers, search and outcome select, and the Team pod chips */
  #content [id] .ppf-row-edit > td { height: 44px; }
  #content [id] th.ppf-th-sort, #content [id] th.ppf-ssm-src { height: 44px; }
  #content [id] .ppf-search { min-height: 44px; height: auto; }
  #content [id] .uis-trigger { min-height: 44px !important; height: auto !important; }   /* v827: the Funnel sheet sets the Outcomes select's height with a deeper selector; phone-only override */
  .pod-mchip { min-height: 44px; }
  /* v826 (VERIFY_v825 R-E): client portal at 390 - the client OS search boxes, the pipeline card's name and phone link,
     and the message edit / delete actions (the portal and client OS sheets load later, hence #content) */
  #content .cos-search input, #content .cos-search .cos-input { min-height: 44px; }
  #content .cp-pl-name { display: flex; align-items: center; min-height: 44px; }
  #content .cp-pl-call { display: inline-flex; align-items: center; min-height: 44px; }
  #content .ppm-act-btn { width: 44px; height: 44px; }
  [class^="ppm-sop-lib"] button, [class^="ppm-sop-lib"] input, [class*=" ppm-sop-lib"] button, .ppm-sop-lib-edbtn { min-height: 44px; }
  [data-act="role-edit"] { min-width: 44px; }
  .team-search { min-height: 44px; }
  .member-card-click, .member-top, .member-id[role="button"] { min-height: 44px; }
}

/* REG-3 (v825): sortable headers are keyboard targets now - show where focus is */
th.th-sort:focus-visible, .th-sortable:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; border-radius: var(--radius-sm); }

/* v826: Partner Tracker phone sort (the fold list has no headers to tap) */
.pt-msort { display: none; }
@media (max-width: 720px){
  .pt-msort { display: flex; align-items: center; gap: 8px; padding: 8px 12px 0; }
  .pt-msort label { font-size: 12px; font-weight: 700; color: var(--text-3); text-transform: uppercase; letter-spacing: .04em; }
  .pt-msort select { flex: 1 1 auto; min-height: 44px; min-width: 0; padding: 8px 10px; border-radius: var(--radius-sm); border: 1px solid var(--hairline); background: var(--surface); color: var(--text); font: inherit; }
  .pt-msort-flip { min-height: 44px; white-space: nowrap; }
}

/* R-D (v826): a collapsed (or empty) group's card is 0 wide but its header cells stayed tabbable - seven dead Tab stops */
.group.collapsed .table-card, .group.is-empty.collapsed .table-card { visibility: hidden; }

/* v827: visually hidden, read by assistive tech (page headings on screens whose title lives in the crumb) */
.sr-only { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* AUDIT_dark_v828 (v829): dark-only inks - the light-theme medal chip and the week-log interval counter on a white-wash chip */
[data-theme="dark"] .wkb-rank.is-1 { color: #f5c518; background: color-mix(in srgb, #f5c518 18%, transparent); }
[data-theme="dark"] .wkb-rank.is-2 { color: #d8dce6; background: color-mix(in srgb, #d8dce6 18%, transparent); }
[data-theme="dark"] .wkb-rank.is-3 { color: #e0a06a; background: color-mix(in srgb, #e0a06a 18%, transparent); }
[data-theme="dark"] .weeklog-iv-n { color: var(--text-2); }
