/* ============ VVT Hub design system ============ */
/* RESTYLE 2026-07-11 — self-hosted brand faces (assets/ already present; $0, offline, no CDN),
   metric-matched fallbacks so the swap is ~zero-CLS. Activates --font (Inter) + --font-serif
   (Fraunces display) so the Hub speaks the marketing site's editorial voice, not system default. */
@font-face { font-family:'Fraunces'; src:url('assets/fraunces-var.woff2') format('woff2'); font-weight:100 900; font-style:normal; font-display:swap; }
@font-face { font-family:'Inter'; src:url('assets/inter-var.woff2') format('woff2'); font-weight:100 900; font-style:normal; font-display:swap; unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+2074,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family:'Inter-fallback'; src:local('Arial'); size-adjust:107%; ascent-override:90%; descent-override:22%; line-gap-override:0%; }
@font-face { font-family:'Fraunces-fallback'; src:local('Georgia'); size-adjust:104%; ascent-override:92%; descent-override:24%; line-gap-override:0%; }

/* SPEC267 quick-wins — a11y utilities: screen-reader-only text + keyboard skip link */
.sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0; }
.skip-link { position:fixed; top:8px; left:8px; z-index:200; transform:translateY(-150%); background:var(--panel); color:var(--text); border:1px solid var(--border-strong); border-radius:8px; padding:10px 16px; font-weight: var(--fw-semibold); box-shadow:0 6px 20px rgba(0,0,0,.18); transition:transform .15s ease; }
.skip-link:focus { transform:translateY(0); outline:2px solid var(--accent); outline-offset:2px; }
.sched-drive { font-size:10.5px; padding:1px 0 1px 8px; display:flex; align-items:center; gap:3px; opacity:.8; }
:root {
  --bg: #f6f6f4;        /* SPEC175 — a whisper-warmer page neutral so cards read as paper, not cold screen */
  --bg-2: #eef0f4;
  --panel: #ffffff;
  --card: var(--panel);  /* SPEC198 — alias used by stat cards/chips/dividers; was undefined → transparent */
  --text-soft: var(--muted);  /* SPEC198 — secondary-label ink alias (was undefined) */
  --subtle: #fbfbfa;    /* SPEC175 — warmer soft fill (table headers, input wells) */
  --hover: #f2f4f7;
  --chip-ink: #0b0d13;
  --border: #e4e7ec;
  --border-strong: #d0d5dd;
  --text: #101828;
  --muted: #565e6b;   /* AA on all three light surfaces: 6.54 on --panel, 6.05 on --bg, 5.74 on --bg-2 */
  --faint: #656d7b;   /* AA on all three light surfaces: 5.22 on --panel, 4.82 on --bg, 4.57 on --bg-2; stays a visible step lighter than --muted */
  --accent: #2b608f;          /* RESTYLE 2026-07-11 — Deep Harbor steel-blue (from the VVT logo); was the AI-tell indigo #4f46e5 */
  --accent-hover: #1e3f66;    /* deeper cube navy — also the primary-button fill */
  --accent-soft: #eaf1f7;     /* soft steel wash (matches order.html exactly) */
  --accent-warm: #b18f52;     /* champagne — DECORATIVE ONLY (hairlines/dividers/delight edges), never text-on-fill */
  --accent-warm-soft: #f0e6d4;
  --gold: #c19a4e;            /* review stars / celebratory ticks ONLY */
  --danger: #d92d20;
  --danger-soft: #fef3f2;
  --danger-ink: #b42318;
  /* RESILIENCE 07-30 — ink that sits ON a --danger FILL (toasts, unread badges).
     Light: white is fine (4.83:1). Dark: --danger flips to a LIGHT red (#f97066) but the
     text stayed #fff, measuring 2.79:1 — a FAIL on the error messages that matter most.
     Dark uses a near-black instead (6.12:1). --danger-ink stays text-on-surface; this is
     text-on-fill, which is the opposite problem. */
  --on-danger: #ffffff;   /* text-only red ink — AA on light (6.05 on --danger-soft, 6.57 on --panel). --danger stays the fill/stroke red. */
  --ok: #079455;
  --ok-soft: #ecfdf3;
  --warn: #dc6803;
  --warn-soft: #fffaeb;
  --ok-ink: #067647;    /* text-only green ink — AA on light (5.69 on --panel, 5.50 on --subtle, 5.40 on --ok-soft). --ok stays the fill/stroke green. */
  --warn-ink: #b54708;  /* text-only amber ink — AA on light (5.43 on --panel, 5.24 on --subtle, 5.20 on --warn-soft). --warn stays the fill/stroke amber. */
  /* LAW-A 2026-08-15 (#19) — --info was the only state colour missing its text-ink sibling
     (--ok-ink/--warn-ink/--danger-ink already existed). Measured, WCAG relative-luminance:
     5.99 on --panel, 5.53 on --bg, 5.78 on --subtle, 5.57 on --info-soft, 5.25 on --bg-2 — all AA.
     --info stays the fill/stroke blue; use --info-ink for text on a light/neutral surface. */
  --info-ink: #175cd3;
  --info: #2e90fa;       /* SPEC208 — a distinct blue for "healthy/neutral" status (was hardcoded #0ea5e9/#3b82f6) */
  --info-soft: #eff8ff;
  --code-bg: #f6f8fa;    /* SPEC208 — tokenized code blocks (were hardcoded dark, invisible in light mode) */
  --code-text: #1a1a1a;
  --radius: 10px;
  --radius-sm: 7px;
  --radius-lg: 14px;
  /* accent channel → theme-aware focus rings/glows (one RGB triple drives every ring) */
  --ring-rgb: 43, 96, 143;
  --focus-ring: 0 0 0 3px rgba(var(--ring-rgb), .35);
  --focus-ring-soft: 0 0 0 3px rgba(var(--ring-rgb), .15);
  /* motion — one ease + a fast/base/slow scale by element heft */
  --ease: cubic-bezier(.4, 0, .2, 1);
  --ease-spring: cubic-bezier(.22, 1, .36, 1);
  --t-fast: 120ms;
  --t-base: 160ms;
  --t-slow: 260ms;
  /* elevation — SPEC175: a soft wide ambient layer under the contact shadow so every
     surface reads as floating paper, not flat. Real depth still in --shadow-lg. */
  --shadow-sm: 0 1px 2px rgba(16,24,40,.04), 0 1px 1px rgba(16,24,40,.03);
  --shadow: 0 1px 2px rgba(16,24,40,.05), 0 2px 6px -1px rgba(16,24,40,.08);
  --shadow-lg: 0 18px 40px -12px rgba(16,24,40,.18), 0 6px 14px -6px rgba(16,24,40,.08);
  --card-hi: inset 0 1px 0 rgba(255,255,255,.5);   /* paper top-highlight */
  --sidebar-hover: rgba(255,255,255,.06);          /* SPEC175 — stepped below the accent-tinted active */
  --sidebar-active-bg: color-mix(in srgb, var(--accent) 16%, transparent);   /* SPEC175 — current location is unmistakable yet calm */
  --font-serif: 'Fraunces', 'Fraunces-fallback', Georgia, Cambria, "Times New Roman", serif;   /* RESTYLE — editorial display face (self-hosted, $0); marketing-site parity */
  --sidebar-bg: #16202e;   /* RESTYLE — the logo's blue-black ground (was neutral #11131f) */
  --sidebar-border: #232639;
  --sidebar-text: #9aa1b9;
  --sidebar-active: #ffffff;
  /* SPEC267 — Inter first (self-host the woff2 in assets/ to activate; see GO-LIVE.md),
     gracefully degrading to the system stack until then so this is render-safe today. */
  --font: 'Inter var', 'Inter', 'Inter-fallback', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* ---- SPEC119: dimensional scales (theme-independent → 100% dark-mode-safe).
     4px spacing grid + ~7-role type scale + line-height/weight/tracking, the
     shared vocabulary Linear/Stripe/Notion/Vercel/M3 all converge on. ---- */
  --space-1: 4px; --space-2: 8px; --space-3: 12px; --space-4: 16px; --space-5: 24px; --space-6: 32px; --space-7: 48px;
  --fs-micro: 11px; --fs-meta: 12px; --fs-caption: 13px; --fs-body: 14px; --fs-md: 16px; --fs-lg: 18px; --fs-h1: 22px; --fs-display: 28px; --fs-hero: 34px;
  --lh-tight: 1.2; --lh-snug: 1.35; --lh-normal: 1.5;
  --fw-medium: 500; --fw-semibold: 600; --fw-bold: 700; --fw-black: 800; --fw-heavy: 900;
  --ls-tight: -.02em; --ls-body: 0; --ls-label: .04em;
  --icon-sm: 16px; --icon-md: 24px; --icon-lg: 32px;
  --focus-offset: 2px;
  --shadow-xs: 0 0 0 1px var(--border);
  --shadow-pop: var(--shadow-lg);
  --ghost-border: transparent;   /* D2 */
  color-scheme: light;
}

/* ============ Dark mode — set html[data-theme="dark"]; everything reflows off
   these tokens. Surfaces step bg → bg-2 → panel → subtle → hover so depth still
   reads on a dark screen; accent is Deep Harbor steel (#5f92b4) — AA both as a button fill
   (white text) and as link text on the dark background. ============ */
html[data-theme="dark"] {
  --bg: #101722;         /* RESTYLE — anchor the dark ground to logo navy (matches order.html) */
  --bg-2: #16202e;       /* logo blue-black */
  --panel: #1f2433;       /* D1 — was #1a1d27; lifts card:page contrast 1.07:1 → 1.16:1 */
  --card: var(--panel);  /* SPEC198 — re-aliased per theme so dark cards aren't transparent */
  --text-soft: var(--muted);  /* SPEC198 */
  --subtle: #252b3c;      /* D1 — was #20242f */
  --hover: #2c3346;       /* D1 — was #272c39 */
  --chip-ink: #ffffff;
  --border: #333b4e;      /* D1 — was #2a2f3c */
  --border-strong: #47516a;  /* D1 — was #3a4151 */
  --text: #e7e9ee;
  --muted: #9aa1b3;
  --faint: #939bad;   /* 6.03 on --panel, 6.45 on --bg, 5.88 on --bg-2; still dimmer than dark --muted #9aa1b3, so the hierarchy holds */
  --accent: #5f92b4;         /* RESTYLE — lighter steel, AA on dark for links/icons (was indigo #6366f1) */
  --accent-hover: #7fadc9;
  --accent-soft: #182634;    /* navy-black wash (matches order.html) */
  --accent-warm: #c2a367;    /* champagne, nudged lighter for AA on dark; DECORATIVE only */
  --accent-warm-soft: #2a2318;
  --gold: #c9a659;
  --danger: #f97066;
  --danger-soft: #2b1a1a;
  --danger-ink: var(--danger);
  --on-danger: #2a0a08;
  --ok: #3ccb7f;
  --ok-soft: #13251d;
  --warn: #f5a524;
  --warn-soft: #2a2012;
  --ok-ink: var(--ok);
  --warn-ink: var(--warn);
  /* LAW-A 2026-08-15 (#19) — dark-mode sibling. Aliasing --info (matches how --ok-ink/
     --warn-ink alias their fill colour on dark). Measured: 6.68 on --panel, 7.77 on --bg,
     6.09 on --subtle — all AA. */
  --info-ink: var(--info);
  --info: #53b1fd;       /* SPEC208 */
  --info-soft: #102a43;
  --code-bg: #14161f;    /* SPEC208 */
  --code-text: #e7eaf2;
  --ring-rgb: 95, 146, 180;
  --shadow-sm: 0 1px 2px rgba(0,0,0,.4);
  --shadow: 0 1px 2px rgba(0,0,0,.45), 0 1px 3px rgba(0,0,0,.5);
  --shadow-lg: 0 18px 40px -12px rgba(0,0,0,.6), 0 6px 14px -6px rgba(0,0,0,.45);   /* SPEC175 — wider, softer ambient */
  --card-hi: inset 0 1px 0 rgba(255,255,255,.07);   /* D1 — was .04 */
  --sidebar-bg: #0f1722;   /* RESTYLE — navy-black, not neutral-black */
  --sidebar-border: #1c2030;
  --sidebar-text: #9aa1b9;
  --sidebar-active: #ffffff;
  --sidebar-active-bg: color-mix(in srgb, var(--accent) 22%, transparent);   /* SPEC175 — deeper accent tint on the dark rail */
  --ghost-border: #3a4254;   /* D2 — ghost buttons need a visible edge on dark */
  color-scheme: dark;
}
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; height: 100%; }
body { font-family: var(--font); background: var(--bg); color: var(--text); font-size: var(--fs-body); line-height: var(--lh-normal);
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility;
  font-variant-numeric: tabular-nums; letter-spacing: var(--ls-body); }
/* running prose keeps proportional figures + natural spacing */
.markdown-body, .view-sub, .chat-text, p { font-variant-numeric: normal; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
/* RESTYLE — editorial serif display at the TOP of the hierarchy only (restraint): page
   titles. Fraunces at a light weight + negative tracking against the Inter body is the
   single strongest "a person designed this" signal, and unifies the Hub with the
   marketing site.
   DESIGNA 2026-08-19 (RULING — Vincent: "aligned look") — the big money/KPI FIGURES moved
   OFF Fraunces and back to Inter: fraunces-var.woff2 ships NO `tnum` GSUB feature, so the
   tabular-nums declared below silently never worked ($1,111 vs $8,000 measured 23.4px
   apart in a stacked KPI column). Inter's tnum is real. Serif stays on titles/headings
   only — NEVER on numerals; do not route a numeric class back to var(--font-serif). */
.view-title { font-family: var(--font-serif); font-weight: 400; letter-spacing: var(--ls-tight); }
.kpi-value, .stat-n, .cstatus-impact-n, .fin-n, .metric-big, .scoreboard-n { font-family: var(--font); font-weight: var(--fw-medium); letter-spacing: var(--ls-tight); font-variant-numeric: tabular-nums; }
::placeholder { color: var(--faint); }
::selection { background: var(--accent-soft); color: var(--text); }
/* keyboard-only focus ring (mouse clicks stay clean); never strip outline without this */
:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); transition: box-shadow var(--t-fast) var(--ease); }
/* refined scrollbars on the main scroll area */
#main { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
#main::-webkit-scrollbar { width: 10px; height: 10px; }
#main::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
#main::-webkit-scrollbar-thumb:hover { background: var(--faint); background-clip: padding-box; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
}

/* slick pick — 120ms cross-fade on view switches (App.refresh / App._canViewTransition
   in core.js). Uses the existing --t-fast motion token so it matches every other
   quick transition in the app. The pseudo-element tree the View Transitions API
   creates lives outside the normal DOM, so the *,*::before,*::after reduced-motion
   net above doesn't reach it — hence the explicit rule below. */
::view-transition-old(root), ::view-transition-new(root) { animation-duration: var(--t-fast); }
@media (prefers-reduced-motion: reduce) {
  ::view-transition-old(root), ::view-transition-new(root) { animation: none !important; }
}

/* ============ layout ============ */
#app { display: flex; height: 100vh; height: 100dvh; }   /* SAFPOLISH 2026-08-25 D3 — dvh fallback, same two-line pattern as .chat-layout (:2603) */
#sidebar {
  width: 232px; flex: 0 0 232px; background: var(--sidebar-bg); color: var(--sidebar-text);
  display: flex; flex-direction: column; padding: 14px 10px; gap: 6px;
  /* SPEC175 — a crisp inner edge + a faint cast shadow so the rail reads as a
     separate, slightly-raised surface (the expensive-app cue). */
  box-shadow: inset -1px 0 0 var(--sidebar-border), 2px 0 14px -6px rgba(0,0,0,.4);
  z-index: 2;
  border-top: 3px solid var(--role-tint);   /* SPEC209 L2 — ambient per-role context band */
}
/* SPEC209 L2 — per-role context tint (calm ambient signal; Arc "Spaces" idea). Owner =
   brand accent (default, subtle), Manager = teal, Crew = amber. Never competes with the
   single primary accent — it's just a hairline that says which context you're in. */
:root { --role-tint: var(--accent); }
html[data-tier="manager"] { --role-tint: #1e3f66; }   /* RESTYLE — deep harbor (was teal #14a8a0) */
html[data-tier="crew"]    { --role-tint: #b18f52; }   /* RESTYLE — champagne (was amber #e0871d); one navy+brass system */
#main { flex: 1; overflow-y: auto; min-width: 0; }
#view { padding: 26px 30px 60px; max-width: 1340px; margin: 0 auto; }

.brand { display: flex; align-items: center; gap: 10px; padding: 6px 8px 16px; }
.brand-logo {
  width: 34px; height: 34px; border-radius: 9px; background: linear-gradient(150deg, #3f77ab, #2b608f 55%, #1e3f66);   /* RESTYLE — the logo cube navies (was indigo→violet) */
  color: #fff; font-weight: var(--fw-black); font-size: 17px; display: flex; align-items: center; justify-content: center;
}
.brand-logo--img { background: #fff !important; } /* SPEC235 — a logo image overrides the gradient letter-mark */
.brand-name { color: #fff; font-weight: var(--fw-bold); font-size: 15px; letter-spacing: .2px; }
.brand-sub { font-size: var(--fs-micro); color: var(--sidebar-text); }
/* SPEC235 — subtle "Powered by [studio]" credit for client-facing pages (toggle-gated) */
.powered-by { font-size: var(--fs-micro); color: var(--muted); text-align: center; letter-spacing: var(--ls-label); opacity: .8; margin-top: 8px; }

/* SPEC236 — demo-mode ribbon: an always-visible, non-dismissible safety signal. Fixed to
   the bottom-center so it never reflows the fixed shell; floats above everything. */
.demo-ribbon {
  position: fixed; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: 9000;
  display: flex; align-items: center; gap: 10px; max-width: calc(100vw - 24px);
  padding: 8px 10px 8px 14px; border-radius: 999px;
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 92%, #000 8%), var(--accent));
  color: #fff; box-shadow: 0 8px 28px rgba(0,0,0,.28), 0 0 0 1px rgba(255,255,255,.12) inset;
  font-size: 12.5px; backdrop-filter: saturate(1.2); -webkit-backdrop-filter: saturate(1.2);   /* SAFPOLISH 2026-08-25 D4 */
}
.demo-ribbon-dot { width: 8px; height: 8px; border-radius: 50%; background: #fff; flex: 0 0 auto; box-shadow: 0 0 0 4px rgba(255,255,255,.25); animation: demoPulse 2s ease-in-out infinite; }
@keyframes demoPulse { 0%,100% { box-shadow: 0 0 0 3px rgba(255,255,255,.22); } 50% { box-shadow: 0 0 0 6px rgba(255,255,255,.08); } }
.demo-ribbon-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.demo-ribbon-txt strong { font-weight: var(--fw-black); letter-spacing: .02em; }
.demo-ribbon-sub { opacity: .9; }
.demo-ribbon-acts { display: flex; gap: 6px; flex: 0 0 auto; }
.demo-ribbon-acts .btn { background: rgba(255,255,255,.16); color: #fff; border-color: rgba(255,255,255,.28); }
.demo-ribbon-acts .btn:hover { background: rgba(255,255,255,.28); }
.demo-ribbon-acts .btn-primary { background: #fff; color: var(--accent); border-color: #fff; font-weight: var(--fw-bold); }
.demo-ribbon-acts .btn-primary:hover { background: #fff; opacity: .92; }
@media (max-width: 640px) { .demo-ribbon-sub { display: none; } .demo-ribbon { bottom: calc(12px + env(safe-area-inset-bottom, 0px)); } }
@media (prefers-reduced-motion: reduce) { .demo-ribbon-dot { animation: none; } }

#nav, #nav-bottom { display: flex; flex-direction: column; gap: 1px; }
#nav { flex: 0 0 auto; }
.nav-item {
  display: flex; align-items: center; gap: 11px; padding: 9px 10px; border-radius: 8px;
  color: var(--sidebar-text); cursor: pointer; font-weight: var(--fw-medium); font-size: 13.5px;
  border: none; background: none; width: 100%; text-align: left; font-family: inherit;
}
.nav-item { position: relative; transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }
.nav-item:hover { background: var(--sidebar-hover); color: #fff; }
.nav-item.active { background: var(--sidebar-active-bg); color: var(--sidebar-active); font-weight: var(--fw-semibold); }
/* SPEC175 — the active rail is a confident accent tab flush to the edge + an accent-lit icon */
.nav-item.active::before { content: ""; position: absolute; left: 0; top: 50%; transform: translateY(-50%); width: 3px; height: 18px; border-radius: 0 999px 999px 0; background: var(--accent); }
.nav-item svg { width: 17px; height: 17px; flex: 0 0 17px; }
.nav-item.active svg { color: var(--accent); }

/* SPEC28 D — grouped sidebar (App.NAV_GROUPS).
   A .nav-group wraps a small uppercase label + that group's nav-items. */
.nav-group { display: flex; flex-direction: column; gap: 1px; }
.nav-group + .nav-group { margin-top: 11px; }
.nav-group-label {
  font-size: 10px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .8px;
  /* LAW-A 2026-08-15 (#22) — was var(--faint), a PAGE ink meant for the light --panel/--bg
     surfaces. The sidebar rail is #16202e in BOTH themes (--sidebar-bg), so the light-theme
     --faint (#656d7b) landed on it too. Measured on --sidebar-bg: --faint 3.15:1 (FAIL) →
     --sidebar-text 6.38:1 (PASS). Dark theme was already fine (--faint dark 6.46:1 →
     --sidebar-text 7.01:1) so this is a light-mode-only fix, no dark regression. */
  color: var(--sidebar-text); padding: 2px 10px 4px; user-select: none;
}
/* first label hugs the search/brand a little less than inter-group gaps */
#nav > .nav-group:first-child { margin-top: 2px; }

/* FLOWDROP 2026-08-20 — the nav 'More' fold (navMoreFold, core.js). .nav-group-body
   holds the folded items with the SAME rhythm as .nav-group itself; .nav-more-toggle
   is a plain .nav-item reused as the fold's own row so it costs nothing new visually. */
.nav-group-body { display: flex; flex-direction: column; gap: 1px; }
.nav-more-toggle { opacity: .82; }
.nav-more-toggle .nav-ico { font-weight: var(--fw-bold); font-size: 15px; justify-content: center; display: inline-flex; }
.sidebar-footer { margin-top: auto; display: flex; flex-direction: column; gap: 6px; }
.sync-pill {
  display: flex; align-items: center; gap: 7px; font-size: 11.5px; padding: 7px 10px;
  border-radius: 8px; background: rgba(255,255,255,.05); cursor: default;
}
.sync-pill .dot { width: 8px; height: 8px; border-radius: 50%; background: #6b7280; flex: 0 0 8px; }
.sync-pill.ok .dot { background: var(--ok); }
.sync-pill.syncing .dot { background: var(--warn); animation: pulse 1s infinite; }
.sync-pill.error .dot { background: var(--danger); }
/* SPEC237 — offline is EXPECTED, not broken: a calm slate dot, never alarming red. */
.sync-pill.offline .dot { background: #64748b; }
@keyframes pulse { 50% { opacity: .5; } }

/* SPEC237 — Field connectivity banner: honest "saved on your phone" reassurance. */
.field-conn-wrap { display: flex; flex-direction: column; gap: 8px; margin: 0 0 12px; }
.field-conn {
  display: flex; align-items: flex-start; gap: 9px; padding: 10px 13px; border-radius: 12px;
  font-size: var(--fs-caption); line-height: var(--lh-normal); font-weight: var(--fw-semibold);
}
.field-conn-dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 9px; margin-top: 4px; }
.field-conn.offline { background: color-mix(in srgb, #64748b 16%, var(--card)); color: var(--text); border: 1px solid color-mix(in srgb, #64748b 30%, transparent); }
.field-conn.offline .field-conn-dot { background: #64748b; }
.field-conn.pending { background: var(--accent-soft); color: var(--accent-hover); border: 1px solid color-mix(in srgb, var(--accent) 30%, transparent); }
.field-conn.pending .field-conn-dot { background: var(--accent); animation: pulse 1.2s infinite; }
/* AUDIT 08-01 — "stalled": the phone thinks it is online but sync is not getting through
   (basement/garage/dying cell). Amber, not the calm grey of a known offline stint and not
   the red of a broken app — something IS wrong and only this person can act on it. */
.field-conn.stalled { background: var(--warn-soft); color: var(--warn-ink); border: 1px solid color-mix(in srgb, var(--warn) 34%, transparent); }
.field-conn.stalled .field-conn-dot { background: var(--warn); }
.field-conn-body { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; flex: 1 1 auto; min-width: 0; }
.field-conn-retry { min-height: 44px; flex: 0 0 auto; }   /* a11y — ≥44px touch target, one-handed in the field */
.field-wrap.field-sun .field-conn.stalled { background: #ffffff; color: #7c2d12; border: 2px solid #b45309; }

/* SPEC237 — Install-to-phone chip (Android prompt / iOS Add-to-Home-Screen hint). */
.install-chip {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  padding: 10px 13px; border-radius: 12px; font-size: var(--fs-caption); line-height: 1.45;
  background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
}
.install-chip-txt { display: flex; align-items: center; gap: 4px; flex: 1 1 220px; min-width: 0; color: var(--text); }
.install-chip-acts { display: flex; gap: 6px; flex: 0 0 auto; }
.install-chip-acts .btn { min-height: 44px; }   /* SPEC237 a11y — ≥44px touch target on the field install chip */
/* SPEC31 — "View as" role previewer (sidebar footer, login-off only) */
.view-as {
  display: flex; align-items: center; gap: 7px; font-size: 11.5px; padding: 6px 10px;
  border-radius: 8px; background: rgba(255,255,255,.05);
}
.view-as-label { color: var(--faint); white-space: nowrap; }
.view-as-select {
  flex: 1; min-width: 0; font-size: 11.5px; padding: 4px 6px; border-radius: 6px;
  background-color: rgba(255,255,255,.07); color: inherit; border: 1px solid rgba(255,255,255,.12);
  cursor: pointer;
}
.view-as-select:focus { outline: none; border-color: var(--accent); }

/* SPEC39 — back/forward nav arrows */
.nav-arrows { display: flex; gap: 6px; padding: 0 2px 6px; }
.nav-arrow {
  flex: 1; height: 30px; border: 1px solid var(--sidebar-border); background: rgba(255,255,255,.04);
  color: var(--sidebar-text); border-radius: 7px; cursor: pointer; font-size: var(--fs-lg); line-height: 1;
}
.nav-arrow:hover:not(:disabled) { background: rgba(255,255,255,.1); color: #fff; }
.nav-arrow:disabled { opacity: .5; cursor: not-allowed; }

/* ============ view header & toolbar ============ */
/* SPEC175 — every view opens with a calm editorial masthead (serif title + hairline)
   echoing the freshly-cinematic client surfaces; this header IS the per-view chrome. */
.view-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: var(--space-5); padding-bottom: var(--space-3); border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.view-title { display: inline-flex; align-items: center; gap: 10px; font-family: var(--font-serif); font-size: var(--fs-display); font-weight: var(--fw-semibold); margin: 0; letter-spacing: var(--ls-tight); line-height: var(--lh-tight); }
.view-title svg { color: var(--accent); }   /* SPEC208 — title icons carry the brand accent for one consistent header language */
.view-sub { color: var(--muted); font-size: var(--fs-caption); margin-top: var(--space-2); }
.toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 16px; }
.toolbar .spacer { flex: 1; }
/* WORLD-CLASS ② — the tucked "More filters" row: reads as a secondary shelf under the
   toolbar (subtle inset panel) so revealing it feels like opening a drawer, not adding clutter. */
.toolbar-more { margin-top: -6px; margin-bottom: 14px; padding: 9px 11px; background: var(--bg-2);
  border: 1px solid var(--border); border-radius: var(--radius); animation: tile-in .2s var(--ease) both; }

/* ============ buttons ============ */
.btn {
  display: inline-flex; align-items: center; gap: 6px; padding: 8px 14px; border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong); background: var(--panel); color: var(--text);
  font-size: var(--fs-caption); font-weight: var(--fw-semibold); cursor: pointer; font-family: inherit; white-space: nowrap;
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.btn:hover { background: var(--subtle); }
.btn:active { transform: translateY(.5px); box-shadow: inset 0 2px 4px rgba(0,0,0,.12); }   /* black darkens in both themes */
/* SPEC208 — clean, modern primary: a flat top-to-bottom accent gradient + a single
   soft tinted shadow (the old inset-white gloss read skeuomorphic / "templated"). */
.btn-primary { background: linear-gradient(180deg, var(--accent), var(--accent-hover)); border-color: transparent; color: #fff; box-shadow: 0 1px 2px rgba(var(--ring-rgb), .28); }
.btn-primary:hover { background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 88%, #fff), var(--accent)); box-shadow: 0 4px 12px -3px rgba(var(--ring-rgb), .45); transform: translateY(-.5px); }
.btn-primary:active { background: var(--accent-hover); box-shadow: inset 0 2px 5px rgba(0,0,0,.18); transform: translateY(.5px); }
.btn-primary:disabled { background: var(--bg-2); }
/* RESTYLE — on dark the steel --accent is too light for white button text; fill with a
   deep harbor navy so white stays AA (9.6:1) and the button still pops off the dark ground. */
/* RESILIENCE 07-30 — a pure specificity bug with a real consequence. This selector is
   (0,2,1) and beat `.btn-primary:disabled` at (0,2,0), so in DARK MODE a disabled primary
   button painted pixel-identical to an enabled one (measured: both
   `linear-gradient(rgb(39,80,127), rgb(30,63,102))`). Every incomplete-form Save button
   in the app looked clickable and silently did nothing — light mode was fine, which is
   exactly why it survived. `:not(:disabled)` scopes the dark paint to enabled buttons and
   lets the disabled rule win, without touching either colour. */
html[data-theme="dark"] .btn-primary:not(:disabled) { background: linear-gradient(180deg, #27507f, #1e3f66); box-shadow: 0 1px 2px rgba(0,0,0,.45); }
html[data-theme="dark"] .btn-primary:hover { background: linear-gradient(180deg, #2f5c90, #234978); }
html[data-theme="dark"] .btn-primary:active { background: #1a3557; }
.btn-danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 40%, var(--border)); background: var(--panel); }
.btn-danger:hover { background: var(--danger-soft); }
.btn-ghost { border-color: var(--ghost-border); background: transparent; color: var(--muted); }
.btn-ghost:hover { background: var(--hover); color: var(--text); }
.btn-sm { padding: 6px 12px; font-size: var(--fs-meta); }
.btn-icon { padding: 8px; line-height: 0; min-width: 32px; min-height: 32px; justify-content: center; }
.btn svg { width: 15px; height: 15px; }
.btn:disabled { color: var(--muted); background: var(--bg-2); border-color: var(--border); cursor: not-allowed; box-shadow: none; }

/* ============ inputs ============ */
/* SPEC175 — fields rest as a soft inset well, then lift to white paper on focus */
.input, .select, .textarea {
  padding: 7px 10px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  font-size: var(--fs-caption); font-family: inherit; background-color: var(--subtle); color: var(--text); outline: none; min-width: 0;
}
/* background-color (not the `background` shorthand) — a shorthand here would reset
   .select's custom chevron background-image to `none` on every rest/focus repaint */
.input:focus, .select:focus, .textarea:focus { border-color: var(--accent); background-color: var(--panel); box-shadow: var(--focus-ring-soft); outline: none; }
.input, .select, .textarea { transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), background var(--t-fast) var(--ease); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--muted); }
.textarea { resize: vertical; min-height: 70px; line-height: var(--lh-normal); }
.select { cursor: pointer; }
.field { display: flex; flex-direction: column; gap: 5px; }
.field > label { font-size: var(--fs-meta); font-weight: var(--fw-semibold); color: var(--muted); }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.form-grid .full { grid-column: 1 / -1; }
.search-input { min-width: 200px; }

/* ============ custom form controls — checkboxes, radios, selects, date/time, range ============
   AUDIT-UI-FORMS-2026-07-30 — every checkbox/select/date/range in the Hub painted with
   the browser's own OS-native widget (a different look on macOS/Windows/iOS/Android,
   unmistakably default). Pure CSS, zero markup/JS changes: appearance:none + hand-drawn
   chrome built entirely from the existing token set — every fill/border below is a
   `var(--…)` reference, contrast-checked in both themes (numbers in the audit report).
   Targets the bare element (input[type=…], select) rather than a class, since these
   controls are created all over the codebase with different or no wrapper class — this
   way every existing call site inherits the new look for free, no JS/markup touched. */

/* ---- checkboxes + radios (206 checkbox call sites, 0 radios today but styled the same
   for whenever one appears) ---- */
input[type="checkbox"], input[type="radio"] {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  width: 18px; height: 18px; min-width: 18px; min-height: 18px; margin: 0; padding: 0;
  flex: 0 0 auto; position: relative;
  /* --border-strong (the usual card/table hairline) reads too faint here — 1.47:1 /
     1.65:1 against --panel, the exact kind of number this audit flags. A checkbox's
     whole job is showing on/off, so it gets the stricter --muted (6.54:1 / 6.50:1,
     clears the WCAG 1.4.11 3:1 non-text floor with real margin — see report). */
  border: 1.5px solid var(--muted);
  border-radius: 5px;
  background-color: var(--panel);
  display: inline-grid; place-content: center;
  vertical-align: middle;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
input[type="radio"] { border-radius: 50%; }
input[type="checkbox"]:not(:disabled):hover, input[type="radio"]:not(:disabled):hover { border-color: var(--accent); }

/* checkmark — a two-border "tick" (no icon font, no SVG needed here), scaled to 0 at
   rest and springing in on check so the state change reads as a deliberate tap */
input[type="checkbox"]::before {
  content: '';
  width: 5px; height: 9px;
  border: solid #fff; border-width: 0 2px 2px 0;   /* white ink on a filled accent square — the same #fff-on-accent convention .btn-primary already uses */
  transform: rotate(45deg) translate(-1px, -1px) scale(0);
  transition: transform var(--t-fast) var(--ease-spring);
}
input[type="checkbox"]:checked, input[type="checkbox"]:indeterminate { background-color: var(--accent); border-color: var(--accent); }
input[type="checkbox"]:checked::before { transform: rotate(45deg) translate(-1px, -1px) scale(1); }
input[type="checkbox"]:indeterminate::before { width: 9px; height: 0; border-width: 0 0 2px 0; transform: scale(1); }
/* dark theme: bare --accent only clears 3.36:1 for the white tick — a thin margin.
   Darken via color-mix (never a second hardcoded hex) so it stays 100% token-derived;
   lands at 5.15:1. */
html[data-theme="dark"] input[type="checkbox"]:checked,
html[data-theme="dark"] input[type="checkbox"]:indeterminate {
  background-color: color-mix(in srgb, var(--accent) 78%, black);
  border-color: color-mix(in srgb, var(--accent) 78%, black);
}

/* radio — a ringed dot, not a filled square (the near-universal on/off-vs-choose-one
   visual split): the dot paints in --accent sitting on --panel, so the white-on-accent
   contrast question above never even arises here */
input[type="radio"]::before {
  content: ''; width: 9px; height: 9px; border-radius: 50%;
  background-color: var(--accent);
  transform: scale(0);
  transition: transform var(--t-fast) var(--ease-spring);
}
input[type="radio"]:checked { border-color: var(--accent); }
input[type="radio"]:checked::before { transform: scale(1); }

input[type="checkbox"]:disabled, input[type="radio"]:disabled { cursor: not-allowed; opacity: .55; }   /* WCAG exempts inactive controls from the contrast floor — opacity is signal enough */

input[type="checkbox"]:focus-visible { box-shadow: var(--focus-ring); border-radius: 5px; }
input[type="radio"]:focus-visible { box-shadow: var(--focus-ring); border-radius: 50%; }

/* ---- selects (431 call sites) — kill the native arrow, draw our own ---- */
select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  /* chevron stroked with currentColor so it always matches the select's own text ink —
     zero hex baked into the icon, so it re-tints correctly in dark mode (and on the
     sidebar's `.view-as-select`, which uses `color: inherit` on a dark rail) with no
     extra rule. Verified 12.76–17.75:1 against every rest/focus background this select
     can sit on — nowhere close to the 3:1 floor (see report). */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1.5 2L6 6.2 10.5 2' stroke='currentColor' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 11px center;
  background-size: 11px 7px;
}
/* padding-right has to out-specificity .input/.select/.textarea's padding SHORTHAND
   above, so this matches it class-for-class rather than relying on the bare tag */
select.select, select.input, select.cell-input, select.view-as-select { padding-right: 30px; }
select:disabled { background-color: var(--bg-2); color: var(--muted); cursor: not-allowed; border-color: var(--border); }

/* ---- date / time — the OS still draws the calendar/clock GLYPH itself; we own its
   affordance (pointer cursor, a soft hover/focus halo) so it reads as part of the same
   field system as every text input, not a bolted-on OS widget. The field SHELL itself
   (border/padding/background) already comes free from the shared .input class every
   date/time site already carries. WebKit-only pseudo-element (Chrome/Edge/Safari);
   Firefox's compact date/time widget has no equivalent hook and already inherits the
   field's own border/background/color from .input. ---- */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator {
  cursor: pointer; border-radius: 4px; padding: 3px; margin-right: -3px;
  opacity: .7;
  transition: opacity var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
input[type="date"]:not(:disabled):hover::-webkit-calendar-picker-indicator,
input[type="time"]:not(:disabled):hover::-webkit-calendar-picker-indicator,
input[type="date"]:focus::-webkit-calendar-picker-indicator,
input[type="time"]:focus::-webkit-calendar-picker-indicator {
  opacity: 1; background-color: var(--hover);
}
input[type="date"]:disabled, input[type="time"]:disabled { background-color: var(--bg-2); color: var(--muted); cursor: not-allowed; border-color: var(--border); }

/* ---- range (7 call sites) — track + thumb, both engines. Excludes the two special
   image-comparison drag-handles (order.js's before/after slider, cstatus's revision
   slider) — those are already fully custom, invisible-track overlays for a completely
   different interaction (a full-bleed drag handle, not a value slider); this
   track/thumb design is for genuine VALUE sliders (Conditions' time-of-day dial, the
   self-review comfort/tone sliders). ---- */
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range) {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  width: 100%; height: 6px; padding-block: 12px; background: transparent; cursor: pointer; margin: 0;
}
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range)::-webkit-slider-runnable-track { height: 6px; border-radius: 999px; background-color: var(--border-strong); }
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range)::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 18px; height: 18px; margin-top: -6px; border-radius: 50%;
  background-color: var(--accent); border: 2px solid var(--panel); box-shadow: 0 1px 3px rgba(0,0,0,.2);
  cursor: pointer;
  transition: transform var(--t-fast) var(--ease);
}
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range)::-moz-range-track { height: 6px; border-radius: 999px; background-color: var(--border-strong); }
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range)::-moz-range-progress { height: 6px; border-radius: 999px; background-color: var(--accent); }
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range)::-moz-range-thumb {
  width: 18px; height: 18px; border-radius: 50%; box-sizing: border-box;
  background-color: var(--accent); border: 2px solid var(--panel); box-shadow: 0 1px 3px rgba(0,0,0,.2);
  cursor: pointer;
  transition: transform var(--t-fast) var(--ease);
}
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range):not(:disabled):hover::-webkit-slider-thumb,
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range):not(:disabled):hover::-moz-range-thumb { transform: scale(1.1); }
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range):focus-visible { box-shadow: none; }   /* suppress the sitewide bare :focus-visible ring on the (transparent, 6px-tall) outer element — the thumb below carries its own ring instead */
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range):focus-visible::-webkit-slider-thumb,
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range):focus-visible::-moz-range-thumb { box-shadow: var(--focus-ring); }
/* dark theme: the plain --accent thumb only clears 3.05:1 against the (dark)
   --border-strong track — thin margin. Swap to --accent-hover (dark theme's LIGHTER
   variant — an existing token, not a new color) for 4.25:1 instead. */
html[data-theme="dark"] input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range)::-webkit-slider-thumb,
html[data-theme="dark"] input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range)::-moz-range-thumb { background-color: var(--accent-hover); }
input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range):disabled { opacity: .5; cursor: not-allowed; }

/* ============ cards & KPIs ============ */
/* SPEC175 — cards read as floating paper: larger radius (matches kpi/modal) + the
   softened two-layer resting shadow. */
.card { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow), var(--card-hi); transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-base) var(--ease); }
.card.is-clickable { cursor: pointer; transition: transform var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }
.card.is-clickable:hover { border-color: var(--border-strong); box-shadow: var(--shadow-lg); transform: translateY(-1px); }
.card-pad { padding: 18px 20px; }
.card-title { display: flex; align-items: center; gap: 7px; font-size: var(--fs-caption); font-weight: var(--fw-bold); color: var(--muted); text-transform: uppercase; letter-spacing: .4px; margin: 0 0 12px; }
.card-title svg { flex: 0 0 auto; }   /* SPEC208 — card icons inherit the muted title color (calm secondary-header hierarchy) */
.kpi-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 12px; margin-bottom: 18px; }
/* WORLD-CLASS ① — a fixed 4-metric scoreboard row lays out 4-up on wide screens and a
   clean 2×2 on narrower ones, never an orphaned 3+1 (the mobile rules below take over ≤400). */
.kpi-row--quad { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1120px) { .kpi-row--quad { grid-template-columns: repeat(2, 1fr); } }
.kpi-card { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius-lg); box-shadow: var(--shadow-sm), var(--card-hi); padding: 15px 17px; transition: box-shadow var(--t-base) var(--ease), border-color var(--t-base) var(--ease); }
.kpi-card:hover { box-shadow: var(--shadow), var(--card-hi); border-color: var(--border-strong); }
/* ④ fix — a KPI card must be able to shrink inside its grid track (grid items floor at
   min-content by default) and its embedded revenue sparkline (a fixed 140px span) must
   scale down, so two-up never forces a horizontal scroll on ~360px phones. */
.kpi-card { min-width: 0; }
.kpi-card .spark, .kpi-card .spark svg { max-width: 100%; }
.kpi-label { font-size: 11.5px; font-weight: var(--fw-semibold); color: var(--muted); text-transform: uppercase; letter-spacing: .4px; }
.kpi-value { font-size: 26px; font-weight: var(--fw-black); letter-spacing: var(--ls-tight); margin-top: 4px; }
.kpi-hint { font-size: 11.5px; color: var(--faint); margin-top: 3px; }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
/* let cards shrink with their track instead of forcing min-content width
   (otherwise narrow viewports get horizontal page scroll) */
.grid-2 > *, .grid-3 > *, .settings-grid > * { min-width: 0; }

/* ============ tables ============ */
.table-wrap { overflow-x: auto; background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow-sm), var(--card-hi); }
/* D17(a)/D22 — right-edge scroll affordance (App.wireScrollFade, core.js) so a
   horizontally-clipped mobile table/board signals "more this way" instead of
   just cutting content off mid-badge with no cue. Mobile-only: at desktop widths
   these containers rarely overflow, and the base table/board layout doesn't
   change here. */
@media (max-width: 640px) {
  .scroll-fade-x { position: relative; }
  .scroll-fade-x::after {
    content: ''; position: absolute; top: 0; right: 0; bottom: 0; width: 24px;
    background: linear-gradient(to right, transparent, var(--panel));
    pointer-events: none; opacity: 1; transition: opacity var(--t-fast) var(--ease);
  }
  /* the mobile task board sits directly on the page ground, not a panel card */
  .tk-board.scroll-fade-x::after { background: linear-gradient(to right, transparent, var(--bg)); }
  .scroll-fade-x.at-end::after { opacity: 0; }
  @media (prefers-reduced-motion: reduce) { .scroll-fade-x::after { transition: none; } }
}
table.table { border-collapse: collapse; width: 100%; font-size: var(--fs-caption); }
/* SPEC175 — calmer, taller rows + crisper hairlines + a soft accent-tinted hover rail */
.table th {
  text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .4px; color: var(--muted);
  padding: 11px 14px; border-bottom: 1px solid var(--border); background: var(--subtle); white-space: nowrap; position: relative;
}
.table td { padding: 12px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.table th:first-child, .table td:first-child { padding-left: 18px; }
.table th:last-child, .table td:last-child { padding-right: 18px; }
/* CONSOL-3 — row DENSITY presets (comfortable = the default above). The differences are
   REAL: compact shrinks padding + font + line-height AND the in-row controls (the status/
   priority selects + chips dominate row height, so they must shrink too); big is roomy and
   expands the services. */
.table-wrap.density-compact table.table { font-size: 11.5px; line-height: var(--lh-tight); }
.table-wrap.density-compact table.table td { padding: 1px 6px; }
.table-wrap.density-compact table.table th { padding: 3px 6px; }
.table-wrap.density-compact table.table th:first-child, .table-wrap.density-compact table.table td:first-child { padding-left: 10px; }
.table-wrap.density-compact .btn, .table-wrap.density-compact .btn-sm,
.table-wrap.density-compact select, .table-wrap.density-compact .select,
.table-wrap.density-compact .chip, .table-wrap.density-compact .pill,
.table-wrap.density-compact .status-select, .table-wrap.density-compact .svc-menu-trigger {
  font-size: var(--fs-micro); padding-top: 1px; padding-bottom: 1px; min-height: 0; line-height: 1.25; }
.table-wrap.density-compact .clip-mini, .table-wrap.density-compact .row-sub, .table-wrap.density-compact .cell-sub { font-size: 10px; }

.table-wrap.density-big table.table { font-size: 14.5px; line-height: 1.6; }
.table-wrap.density-big table.table td { padding: 16px 16px; }
.table-wrap.density-big table.table th { padding: 15px 16px; }
.table-wrap.density-big select, .table-wrap.density-big .select, .table-wrap.density-big .btn-sm { font-size: 13.5px; }
/* CONSOL-3 — Excel-style column resize grip on the right edge of each header cell */
.col-resizable { position: relative; }
.col-resize { position: absolute; top: 0; right: -4px; width: 9px; height: 100%; cursor: col-resize; z-index: 3; touch-action: none; }
.col-resize::after { content: ''; position: absolute; top: 22%; bottom: 22%; right: 4px; width: 2px; border-radius: 2px; background: transparent; transition: background var(--t-fast) var(--ease); }
.col-resizable:hover .col-resize::after { background: var(--border-strong); }
.table tbody tr:last-child td { border-bottom: none; }
.table tbody tr { transition: background var(--t-fast) var(--ease); }
.table tbody tr:hover { background: var(--hover); box-shadow: inset 2px 0 0 color-mix(in srgb, var(--accent) 55%, transparent); }
.table td.editable { cursor: pointer; }
.table td.editable:hover { box-shadow: inset 0 0 0 1px var(--border-strong); border-radius: 4px; }
.table .row-click { cursor: pointer; }
.cell-input { width: 100%; border: 1px solid var(--accent); border-radius: 4px; padding: 4px 6px; font: inherit; outline: none; }
.th-x { position: absolute; top: 2px; right: 2px; font-size: 10px; color: var(--faint); cursor: pointer; padding: 2px 4px; border-radius: 4px; display: none; background: none; border: none; font-family: inherit; line-height: 1; }
.table th:hover .th-x { display: inline; }
.th-x:hover { background: var(--danger-soft); color: var(--danger); }

/* ============ chips & badges ============ */
.chip {
  display: inline-flex; align-items: center; gap: 5px; padding: 4px 11px; border-radius: 999px;
  font-size: 11.5px; font-weight: var(--fw-semibold); letter-spacing: .1px; white-space: nowrap; line-height: 1.4;
  /* SPEC175 — a hairline ring in the chip's own hue (currentColor) → printed-label tactility */
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 20%, transparent);
}
.chip.is-ok { background: var(--ok-soft); color: var(--ok-ink); }  /* SPEC-A11Y — was var(--ok) (3.70:1 in light, fails AA); ink token is 5.40:1. Dark theme unaffected: --ok-ink aliases var(--ok) there. */
.chip.is-danger { background: var(--danger-soft); color: var(--danger-ink); }  /* was var(--danger) (4.44:1 in light, fails AA); ink token is 6.05:1. Dark theme unaffected: --danger-ink aliases var(--danger) there. */
.chip.is-warn { background: var(--warn-soft); color: var(--warn-ink); }  /* was var(--warn) (3.34:1 in light, fails AA); ink token is 5.20:1. Dark theme unaffected: --warn-ink aliases var(--warn) there. */
.chip.is-info { background: var(--accent-soft); color: var(--accent-hover); }  /* SPEC198 — AA in dark (accent-on-accent-soft was 3.6:1) */
.chip .chip-dot { width: 6px; height: 6px; border-radius: 50%; }
/* SPEC127 — chip-x / view-chip-x are now <button>s (keyboard-focusable, Enter/Space
   activate). Reset native button chrome so they render exactly like the old spans. */
.chip-x, .view-chip-x { background: none; border: 0; padding: 0; color: inherit; font: inherit; line-height: 1; }
.chip-x { cursor: pointer; opacity: .55; font-weight: var(--fw-bold); margin-left: 2px; }
.chip-x:hover { opacity: 1; }
.view-chip-x { cursor: pointer; }
.chip-x:focus-visible, .view-chip-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; opacity: 1; }
.badge { display: inline-block; padding: 1px 7px; border-radius: 999px; background: var(--hover); color: var(--muted); font-size: var(--fs-micro); font-weight: var(--fw-semibold); }
.tag { display: inline-block; padding: 2px 8px; border-radius: 5px; background: var(--accent-soft); color: var(--accent-hover); font-size: var(--fs-micro); font-weight: var(--fw-semibold); margin: 1px 3px 1px 0; }  /* SPEC198 — AA in dark */

/* ============ kanban ============ */
.kanban { display: flex; gap: 12px; overflow-x: auto; align-items: flex-start; padding-bottom: 14px; }
.kanban-col { flex: 0 0 260px; background: var(--bg-2); border-radius: var(--radius); padding: 10px; min-height: 120px; }
.kanban-col.drag-over { outline: 2px dashed var(--accent); outline-offset: -2px; background: var(--accent-soft); }
.kanban-col-head { display: flex; align-items: center; gap: 8px; padding: 2px 4px 10px; font-weight: var(--fw-bold); font-size: var(--fs-caption); }
.kanban-col-head .count { margin-left: auto; }
.kanban-card {
  background: var(--panel); border: 1px solid var(--border); border-radius: 8px; box-shadow: var(--shadow);
  padding: 10px 12px; margin-bottom: 8px; cursor: grab; font-size: 12.5px;
  transition: transform var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
/* SPEC215 — render within a frame at scale: skip layout/paint of OFF-SCREEN tracker
   rows + kanban cards. CSS-only on the leaf node, so the full DOM stays intact —
   drag-and-drop, filters, select-all, group-collapse, Ctrl-F all keep working. The
   `auto` keyword in contain-intrinsic-size makes the browser remember each element's
   real height after first paint, so the scrollbar settles (no jitter). Headers, group
   rows, and kanban columns are deliberately left un-contained. */
.table tbody tr.cv-row { content-visibility: auto; contain-intrinsic-size: auto 96px; }
.kanban-card.cv-card { content-visibility: auto; contain-intrinsic-size: auto 140px; }
.kanban-card:focus-visible { border-color: var(--accent); }
.kanban-card:active { cursor: grabbing; }
.kanban-card.dragging { opacity: .45; }
.kanban-card .kc-title { font-weight: var(--fw-bold); font-size: var(--fs-caption); margin-bottom: 3px; }
.kanban-card .kc-meta { color: var(--muted); display: flex; flex-wrap: wrap; gap: 4px 10px; align-items: center; }
.kanban-card .task-link { display: block; margin-top: 7px; font-size: 11.5px; color: var(--accent); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kanban-card .task-link:hover { text-decoration: underline; }

/* ============ progress ============ */
.progress { height: 5px; border-radius: 999px; background: var(--border); overflow: hidden; min-width: 50px; }
.progress-bar { height: 100%; border-radius: 999px; background: var(--accent); transition: width var(--t-slow) var(--ease); }
.progress-row { display: flex; align-items: center; gap: 8px; font-size: 11.5px; color: var(--muted); white-space: nowrap; }

/* ============ modal & toast ============ */
.modal-overlay {
  position: fixed; inset: 0; background: rgba(16,18,28,.55); display: flex; align-items: flex-start;
  justify-content: center; padding: 6vh 16px 16px; z-index: 100; overflow-y: auto;
}
.modal {
  background: var(--panel); border-radius: var(--radius-lg); box-shadow: var(--shadow-lg), var(--card-hi); width: 100%; max-width: 560px;
  animation: modal-in var(--t-base) var(--ease-spring);
}
.modal.wide { max-width: 760px; }
@keyframes modal-in { from { transform: translateY(8px) scale(.99); opacity: 0; } to { transform: none; opacity: 1; } }
.modal-head { display: flex; align-items: center; justify-content: space-between; padding: 16px 20px 0; }
.modal-head h3 { margin: 0; font-size: var(--fs-lg); font-family: var(--font-serif); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); }
.modal-close { border: none; background: none; font-size: 20px; color: var(--faint); cursor: pointer; padding: 2px 8px; border-radius: 6px; }
.modal-close:hover { background: var(--hover); color: var(--text); }
.modal-body { padding: 16px 20px; }
.modal-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 0 20px 18px; }
.modal-foot .left { margin-right: auto; }

/* SPEC211 — right-docked slide-over panel (App.slideOver). Shares the modal scrim
   colour + elevation language; slides in from the right with a spring ease. z 112/115
   sits above modals (100), below toasts (200) — a free slot in the layering map. */
.slideover-scrim {
  position: fixed; inset: 0; background: rgba(16,18,28,.55); z-index: 112;
  display: flex; justify-content: flex-end; align-items: stretch;
  opacity: 0; transition: opacity var(--t-base) var(--ease);
}
.slideover-scrim.open { opacity: 1; }
.slideover-scrim.closing { opacity: 0; }
.slideover-panel {
  background: var(--panel); box-shadow: var(--shadow-lg), var(--card-hi);
  border-left: 1px solid var(--border); border-radius: var(--radius-lg) 0 0 var(--radius-lg);
  width: 420px; max-width: 100%; height: 100%; display: flex; flex-direction: column;
  position: relative; z-index: 115; transform: translateX(100%);
  transition: transform var(--t-base) var(--ease-spring);
}
.slideover-scrim.open .slideover-panel { transform: none; }
.slideover-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 15px 18px; border-bottom: 1px solid var(--border); flex: 0 0 auto; }
.slideover-head h3 { margin: 0; font-size: var(--fs-lg); font-family: var(--font-serif); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); }
.slideover-body { flex: 1 1 auto; overflow-y: auto; -webkit-overflow-scrolling: touch; padding: 14px 18px; }
.slideover-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 18px; border-top: 1px solid var(--border); flex: 0 0 auto; }
.slideover-foot:empty { display: none; }
@media (max-width: 860px) {
  /* full-width sheet on phones (mirror the full-screen modal rule) */
  .slideover-panel { width: 100%; border-radius: 0; border-left: none; }
  .slideover-head { padding: calc(13px + env(safe-area-inset-top, 0px)) 16px 13px; }
  .slideover-body { padding-bottom: calc(14px + env(safe-area-inset-bottom, 0px)); }
  .slideover-foot { padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px)); }
}
@media (prefers-reduced-motion: reduce) {
  .slideover-scrim, .slideover-panel { transition: none; }
}
/* SPEC211 — chat quick-reply peek inside the slide-over */
.chat-peek-bar { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
.chat-peek-ch { flex: 1 1 auto; min-width: 0; }
.chat-peek-list { display: flex; flex-direction: column; gap: 2px; }
.chat-peek-list .chat-msg { padding: 4px 4px; }
.chat-peek-composer { flex: 1 1 auto; width: 100%; }
.chat-peek-composer .chat-composer-row { display: flex; gap: 8px; align-items: flex-end; }
.chat-peek-composer .chat-input { flex: 1 1 auto; }
/* SPEC213 — record peek (job/client/lead glance in the slide-over) */
.peek-head { display: flex; align-items: center; gap: 10px; justify-content: space-between; margin-bottom: 14px; }
.peek-title { font-size: var(--fs-md); font-weight: var(--fw-bold); font-family: var(--font-serif); letter-spacing: var(--ls-tight); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.peek-facts { display: flex; flex-direction: column; }
.peek-fact { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; padding: 8px 0; border-bottom: 1px solid var(--border); font-size: var(--fs-caption); }
.peek-fact:last-child { border-bottom: none; }
.peek-fact-l { flex: 0 0 auto; color: var(--muted); }
.peek-fact-v { min-width: 0; text-align: right; font-weight: var(--fw-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.peek-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; width: 100%; }
/* SPEC214 — live health dot/pill (peeks, ⌘K rows, lists) */
.health-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.health-pill { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-meta); font-weight: var(--fw-semibold); }
.peek-healthline { margin: 2px 0 14px; }
.peek-head { margin-bottom: 10px; }
/* SPEC217 — listing performance (analytics), visually simple */
.sa-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 14px; }
.sa-stat { background: var(--subtle); border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; }
.sa-big { font-size: 26px; font-weight: var(--fw-black); letter-spacing: -.5px; line-height: 1.1; }
.sa-stat-l { font-size: var(--fs-micro); color: var(--muted); margin-top: 2px; text-transform: uppercase; letter-spacing: .4px; font-weight: var(--fw-bold); }
.sa-stat-h { font-size: var(--fs-meta); color: var(--muted); margin-top: 3px; }
.sa-card { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px 14px; margin-bottom: 12px; background: var(--panel); }
.sa-card-h { font-size: var(--fs-micro); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .4px; color: var(--muted); margin-bottom: 8px; }
.sa-media { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.sa-media-thumb { position: relative; aspect-ratio: 4 / 3; background-color: var(--hover); background-size: cover; background-position: center; border-radius: 8px; display: flex; align-items: center; justify-content: center; color: var(--muted); }
.sa-media-play { color: #fff; font-size: var(--fs-lg); text-shadow: 0 1px 4px rgba(0,0,0,.6); }
.sa-media-meta { display: flex; justify-content: space-between; align-items: baseline; margin-top: 4px; font-size: 11.5px; }
.sa-rank { font-weight: var(--fw-black); color: var(--muted); }
.sa-clicks { color: var(--text); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; }
.sa-city { display: flex; align-items: center; gap: 10px; padding: 4px 0; font-size: 12.5px; }
.sa-city-name { flex: 0 0 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sa-city-bar { flex: 1; height: 7px; background: var(--hover); border-radius: 4px; overflow: hidden; }
.sa-city-fill { display: block; height: 100%; background: var(--accent); border-radius: 4px; }
.sa-city-n { flex: 0 0 auto; color: var(--muted); font-variant-numeric: tabular-nums; font-weight: var(--fw-semibold); }
.sa-sources { display: flex; flex-direction: column; gap: 4px; }
.sa-source { display: flex; align-items: center; gap: 8px; font-size: var(--fs-caption); padding: 3px 0; }
.sa-source-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--ok); flex: 0 0 auto; }
.sa-source-link { color: var(--accent); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
.sa-source-clicks { color: var(--muted); font-size: var(--fs-meta); flex: 0 0 auto; }
.sa-insight { border: 1px solid var(--border); border-left: 3px solid var(--accent); border-radius: var(--radius); padding: 12px 14px; margin-bottom: 14px; background: var(--accent-soft); }
.sa-insight--hot { border-left-color: var(--ok); background: var(--ok-soft); }
.sa-insight--cool { border-left-color: var(--warn); background: var(--warn-soft); }
.sa-insight-h { font-weight: var(--fw-black); font-size: var(--fs-body); }
.sa-insight-n { font-size: 12.5px; color: var(--muted); margin-top: 4px; }
.sa-lead { display: flex; align-items: flex-start; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.sa-lead:last-child { border-bottom: none; }
.sa-lead-main { flex: 1; min-width: 0; }
.sa-lead-top { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.sa-lead-name { font-weight: var(--fw-bold); font-size: var(--fs-caption); }
.sa-lead-contact { font-size: var(--fs-meta); color: var(--accent); }
.sa-lead-when { font-size: var(--fs-micro); color: var(--faint); }
.sa-lead-msg { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.sa-lead-act { flex: 0 0 auto; }
@media (max-width: 560px) { .sa-stats, .sa-media { grid-template-columns: repeat(2, 1fr); } }
/* SPEC219 — Marketing Kit (lives in the slide-over): editable copy-ready blocks. */
.mkit-sub { margin-bottom: 14px; }
.mkit-addr { font-weight: var(--fw-black); font-size: 15px; color: var(--text); }
.mkit-hint { font-size: 12.5px; color: var(--muted); margin-top: 3px; line-height: var(--lh-normal); }
.mkit-card { background: var(--bg); border: 1px solid var(--border); border-radius: 12px; padding: 12px 12px 14px; margin-bottom: 12px; }
.mkit-card-h { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.mkit-card-l { font-weight: var(--fw-bold); font-size: 11.5px; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); }
.mkit-ta { width: 100%; box-sizing: border-box; resize: vertical; min-height: 56px; border: 1px solid var(--border); border-radius: 9px; padding: 10px 12px; font: inherit; font-size: 13.5px; line-height: 1.6; color: var(--text); background: var(--panel); white-space: pre-wrap; }
.mkit-ta:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft, rgba(14,124,90,.14)); }
.mkit-ai { margin-top: 8px; color: var(--accent); }
.mkit-more { margin: 2px 0 14px; }
.mkit-more > summary { cursor: pointer; font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--accent); padding: 6px 0; list-style: none; }
.mkit-more > summary::-webkit-details-marker { display: none; }
.mkit-more > summary::before { content: '▸ '; color: var(--muted); }
.mkit-more[open] > summary::before { content: '▾ '; }
.mkit-section-h { font-weight: var(--fw-bold); font-size: 11.5px; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); margin: 6px 0 8px; }
.mkit-actions { display: flex; flex-wrap: wrap; gap: 7px; margin-bottom: 8px; }
#toast-zone { position: fixed; bottom: calc(20px + env(safe-area-inset-bottom, 0px)); left: 50%; transform: translateX(-50%); z-index: 200; display: flex; flex-direction: column; gap: 8px; align-items: center; }
/* SPEC208 — theme-aware toast (was hardcoded #1f2433/16px): a high-contrast ink chip
   that reads on both themes, on the body type scale. */
.toast {
  background: var(--chip-ink); color: var(--panel); padding: 10px 16px; border-radius: var(--radius); font-size: var(--fs-caption); font-weight: var(--fw-semibold);
  box-shadow: var(--shadow-lg); animation: modal-in var(--t-base) var(--ease-spring); display: flex; align-items: center; gap: 8px;
}
.toast svg { width: 16px; height: 16px; }
.toast.error { background: var(--danger); color: var(--on-danger); }
.toast.toast-action { display: flex; align-items: center; gap: 14px; padding-right: 8px; }
/* UI-FEEDBACK 07-30 — this is the UNDO button: the only recovery path for every
   App.softDelete, and it lives inside a toast that disappears after ~6 seconds. It
   rendered ~25px tall, well under the 44px minimum the rest of the app now meets — so
   the one control with a hard deadline and a data-loss consequence was the hardest to
   hit on a phone. min-height + centred content; padding unchanged so short toasts keep
   their shape. */
.toast-btn { background: color-mix(in srgb, currentColor 16%, transparent); color: inherit; border: none; border-radius: 7px; padding: 5px 12px;
  min-height: 44px; display: inline-flex; align-items: center; justify-content: center;
  font-size: 12.5px; font-weight: var(--fw-black); cursor: pointer; white-space: nowrap; }
.toast-btn:hover { background: color-mix(in srgb, currentColor 28%, transparent); }

/* ============ empty state ============ */
.empty-state { text-align: center; padding: 48px 20px; color: var(--muted); }
.empty-state .es-icon, .empty-state .es-ico { font-size: 32px; margin-bottom: 8px; line-height: 1; }
/* SPEC208 — when an empty state uses a line-icon instead of an emoji, render it large + soft
   (unscoped: some es-icon/es-ico divs render outside .empty-state) */
.es-icon svg, .es-ico svg { width: 34px; height: 34px; opacity: .75; color: var(--muted); }
.es-icon, .es-ico { display: flex; justify-content: center; }
.empty-state h4 { margin: 0 0 4px; color: var(--text); }
.empty-state p { margin: 0 0 14px; font-size: var(--fs-caption); }

/* ============ SPEC208 — line-icon system base ============ */
.icon { display: inline-flex; align-items: center; justify-content: center; vertical-align: -.18em; flex: 0 0 auto; line-height: 0; }
.icon svg { display: block; }
/* icons sit on the text baseline + inherit color in the common chrome */
.chip svg { width: 13px; height: 13px; }
.view-title svg { width: .92em; height: .92em; vertical-align: -.06em; }
.btn-primary:disabled { color: var(--muted); }

/* ============ SOP hub ============ */
.sops-layout { display: flex; gap: 16px; align-items: flex-start; }
.sops-side { flex: 0 0 264px; position: sticky; top: 0; }
.sops-main { flex: 1; min-width: 0; }
.doc-list { display: flex; flex-direction: column; gap: 1px; }
.doc-cat { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .5px; color: var(--faint); padding: 12px 10px 4px; }
.doc-item {
  display: flex; align-items: center; gap: 8px; padding: 7px 10px; border-radius: 7px; cursor: pointer;
  font-size: var(--fs-caption); font-weight: var(--fw-medium); color: var(--text);
}
.doc-item:hover { background: var(--hover); }
.doc-item.active { background: var(--accent-soft); color: var(--accent); font-weight: var(--fw-bold); }
.doc-item .doc-pin { margin-left: auto; font-size: var(--fs-micro); }
.editor-title {
  width: 100%; border: none; outline: none; font-size: 24px; font-weight: var(--fw-black); font-family: inherit;
  padding: 4px 0; background: transparent; color: var(--text); letter-spacing: -.3px;
}
.editor-meta { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 6px 0 14px; border-bottom: 1px solid var(--border); margin-bottom: 14px; }
.editor-meta .right { margin-left: auto; display: flex; gap: 6px; align-items: center; }
.md-editor {
  width: 100%; min-height: 56vh; border: none; outline: none; resize: vertical; font-family: var(--mono);
  font-size: var(--fs-caption); line-height: 1.7; color: var(--text); background: transparent;
}
.seg { display: inline-flex; border: 1px solid var(--border-strong); border-radius: 8px; overflow: hidden; }
.seg button { border: none; background: var(--panel); padding: 5px 12px; font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--muted); cursor: pointer; font-family: inherit; transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }
.seg button:not(.active):hover { background: var(--hover); color: var(--text); }
.seg button:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* SPEC175 — selected segment uses the elegant accent-soft pill (solid accent reserved
   for .btn-primary). Text is --accent-hover (not --accent) so it clears AA on the soft
   fill in BOTH themes — dark #818cf8/#1e2030 = 5.4:1, light #4338ca/#eef2ff ≈ 6.5:1. */
.seg button.active { background: var(--accent-soft); color: var(--accent-hover); }
/* segmented controls glide on switch (snap → smooth highlight) */
.seg button, .subtab, .range-preset { transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }
@media (max-width: 640px) { .seg button { min-height: 44px; padding: 9px 12px; } }   /* SPEC126 — touch target */

/* ============ login screen ============ */
.login-screen { position: fixed; inset: 0; z-index: 300; display: flex; align-items: center; justify-content: center; padding: 20px; background: linear-gradient(135deg, #11131f, #1e2235); }
.login-card { width: 100%; max-width: 360px; background: var(--panel); border-radius: 16px; box-shadow: var(--shadow-lg); padding: 26px 24px; }
.login-brand { display: flex; align-items: center; gap: 12px; }
.login-title { font-weight: var(--fw-black); font-size: var(--fs-lg); letter-spacing: .2px; }
.login-sub { color: var(--muted); font-size: 12.5px; }
.login-card .input { width: 100%; }
.login-err { color: var(--danger); font-size: 12.5px; margin-top: 10px; min-height: 16px; }
.login-foot { color: var(--faint); font-size: 11.5px; margin-top: 14px; text-align: center; }

/* TRUTH 2026-08-18 (§B) — the not-connected wall + the connection-wall additions to
   the existing sign-in wall (W1/W2). min-height: 44px on every new tappable control —
   TAPFLOOR_CEIL may only go DOWN (tests/suite.js), so nothing new here may add to it. */
.wall-body { color: var(--text); font-size: 13.5px; line-height: 1.55; margin: 14px 0 0; text-align: left; }
.wall-cta { width: 100%; min-height: 44px; justify-content: center; margin-top: 14px; }
.wall-cta-sm { min-height: 44px; width: 100%; justify-content: center; }
.wall-note { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); text-align: left; }
.wall-note .login-foot { text-align: left; margin: 0 0 8px; }
.wall-escape-row { margin-top: 16px; text-align: center; }
.wall-escape { display: inline-flex; align-items: center; justify-content: center; min-height: 44px; padding: 6px 10px; background: transparent; border: none; color: var(--faint); font-size: 11.5px; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.wall-escape:hover { color: var(--muted); }

/* TRUTH 2026-08-18 (§A) — App.recordReachMark's quiet-by-default mark. Renders
   nothing for the happy path ('team'); these three cover 'device' / 'waiting' /
   'failed'. Text only, no chrome pictograph (ICONGRAM) — colour carries the state. */
.record-reach { font-size: 11px; font-weight: var(--fw-semibold); padding: 1px 6px; border-radius: 999px; white-space: nowrap; }
.record-reach-off { color: var(--muted); background: var(--subtle); }
.record-reach-offline { color: var(--warn-ink); background: var(--warn-soft); }
.record-reach-error { color: var(--danger-ink); background: var(--danger-soft); }

/* ============ markdown body ============ */
.markdown-body { font-size: var(--fs-body); line-height: 1.7; max-width: 760px; }
.markdown-body h1 { font-size: var(--fs-h1); margin: 18px 0 8px; letter-spacing: -.3px; }
.markdown-body h2 { font-size: var(--fs-lg); margin: 18px 0 6px; }
.markdown-body h3 { font-size: 15px; margin: 14px 0 4px; }
.markdown-body p { margin: 8px 0; }
.markdown-body ul, .markdown-body ol { margin: 8px 0; padding-left: 24px; }
.markdown-body li { margin: 3px 0; }
.markdown-body li.md-check { list-style: none; margin-left: -20px; }
.markdown-body li.md-check input { margin-right: 7px; accent-color: var(--accent); cursor: pointer; }
.markdown-body code { background: var(--hover); border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px; font-family: var(--mono); font-size: var(--fs-meta); }
.markdown-body pre { background: var(--code-bg); color: var(--code-text); border: 1px solid var(--border); padding: 12px 14px; border-radius: 8px; overflow-x: auto; }  /* SPEC208 — tokenized: light-gray code block in light mode, dark in dark mode */
.markdown-body pre code { background: none; border: none; color: inherit; padding: 0; }
.markdown-body blockquote { margin: 8px 0; padding: 6px 14px; border-left: 3px solid var(--accent); background: var(--accent-soft); border-radius: 0 6px 6px 0; color: var(--accent); }
.markdown-body hr { border: none; border-top: 1px solid var(--border); margin: 16px 0; }
.markdown-body a { font-weight: var(--fw-semibold); }

/* ============ bar chart ============ */
.bar-chart { display: flex; align-items: flex-end; gap: 10px; height: 150px; padding-top: 18px; }
.bar-wrap { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 5px; height: 100%; justify-content: flex-end; }
.bar { width: 100%; max-width: 46px; background: linear-gradient(180deg, var(--accent), var(--accent-hover)); border-radius: 6px 6px 2px 2px; min-height: 3px; }
.bar-val { font-size: 10.5px; font-weight: var(--fw-bold); color: var(--muted); }
.bar-label { font-size: var(--fs-micro); color: var(--faint); font-weight: var(--fw-semibold); }

/* ============ misc lists ============ */
.list-row { display: flex; align-items: center; gap: 10px; padding: 9px 4px; border-bottom: 1px solid var(--bg-2); font-size: var(--fs-caption); }
.list-row:last-child { border-bottom: none; }
.list-row .grow { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.list-row .grow > div { overflow: hidden; text-overflow: ellipsis; }
.list-row .muted { color: var(--muted); font-size: var(--fs-meta); }
.overdue { color: var(--danger); font-weight: var(--fw-bold); }
.muted { color: var(--muted); }
.faint { color: var(--faint); }
.mono { font-family: var(--mono); font-size: var(--fs-meta); }
.nowrap { white-space: nowrap; }
.mt0 { margin-top: 0; } .mb0 { margin-bottom: 0; }
.settings-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; align-items: start; }
.settings-grid .full { grid-column: 1 / -1; }
.row-line { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; flex-wrap: wrap; }
.color-swatch { width: 26px; height: 26px; padding: 0; border: 1px solid var(--border-strong); border-radius: 6px; cursor: pointer; background: none; }
pre.code-snippet { background: #14161f; color: #e7eaf2; font-family: var(--mono); font-size: 11.5px; padding: 12px; border-radius: 8px; overflow-x: auto; user-select: all; }  /* SPEC198 — fixed light ink (was var(--border-strong) → near-invisible in dark) */

/* ============ responsive ============ */
/* SPEC86 — mobile top bar (☰ + title + search). Hidden on desktop. */
#mobile-topbar { display: none; }
#mobile-topbar { position: fixed; top: 0; left: 0; right: 0; z-index: 50; height: 52px; align-items: center; gap: 10px; padding: 0 12px; background: var(--sidebar-bg); border-bottom: 1px solid var(--sidebar-border); }
#mobile-topbar .mt-burger, #mobile-topbar .mt-search { width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--sidebar-border); background: rgba(255,255,255,.05); border-radius: 9px; font-size: 19px; line-height: 1; cursor: pointer; color: var(--sidebar-active); }
#mobile-topbar .mt-search { font-size: var(--fs-md); color: var(--sidebar-text); }
/* D9(a) — was a static 15px/black "VVT Hub" literal; now carries "Section › View"
   (App.refreshMobileTitle, core.js) so it can run longer — smaller/semibold + an
   end-ellipsis so it never wraps or overflows the bar. (Middle-ellipsis would need
   JS text-measurement; end-ellipsis is the standard $0 CSS pattern and reads fine
   here since the SECTION word is always the leading, most-recognizable part.) */
#mobile-topbar .mt-title { flex: 1; font-weight: var(--fw-semibold); font-size: 13.5px; color: var(--sidebar-active); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
#nav-backdrop { display: none; }

@media (max-width: 860px) {
  /* SPEC86 — the sidebar becomes a LABELED off-canvas drawer (no more bare-icon rail).
     It slides in over a backdrop from the ☰ button, so every destination keeps its
     name and is easy to scan + tap. Desktop is untouched (rules are inside this query). */
  #app { display: block; }
  #mobile-topbar { display: flex; height: calc(52px + env(safe-area-inset-top, 0px)); padding-top: env(safe-area-inset-top, 0px); }

  #sidebar {
    position: fixed; top: 0; left: 0; bottom: 0; z-index: 70;
    width: 270px; max-width: 84vw; flex: 0 0 auto; flex-direction: column;
    padding: 12px 10px; overflow-y: auto;
    transform: translateX(-102%); transition: transform .24s var(--ease-spring);   /* DESIGNA 2026-08-19 — the most-felt motion on mobile ran on default `ease`; settle, don't snap */
    box-shadow: 6px 0 34px rgba(0,0,0,.45);
  }
  body.nav-open #sidebar { transform: translateX(0); }
  #nav-backdrop { display: block; position: fixed; inset: 0; z-index: 65; background: rgba(0,0,0,.5); opacity: 0; visibility: hidden; transition: opacity .24s var(--ease); }   /* DESIGNA 2026-08-19 — token, not default ease */
  body.nav-open #nav-backdrop { opacity: 1; visibility: visible; }

  /* drawer shows the FULL labeled, grouped nav + comfy touch targets */
  .brand-text { display: block; }
  #nav { flex-direction: column; }
  .nav-group { flex-direction: column; }
  .nav-group + .nav-group { margin-top: 11px; margin-left: 0; }
  .nav-group-label { display: block; }
  .nav-item { padding: 11px 12px; font-size: 14.5px; }
  .nav-item span:not(.nav-ico) { display: inline; }
  .sidebar-footer { margin-top: auto; flex-direction: column; align-items: stretch; }
  .sync-pill .sync-label { display: inline; }
  .help-btn { justify-content: flex-start; }
  .help-btn span:not(.help-q):not(.notif-bell-badge) { display: inline; }

  #main { padding-top: calc(52px + env(safe-area-inset-top, 0px)); }
  #view { padding: 16px 14px 50px; }
  .form-grid, .grid-2, .grid-3, .settings-grid { grid-template-columns: 1fr; }
  .sops-layout { flex-direction: column; }
  .sops-side { position: static; flex: 1 1 auto; width: 100%; }

  /* C2 — the sidebar bell/chat badges (.notif-bell-badge / .nav-badge) live inside this
     off-canvas drawer, so a phone had NO unread indicator anywhere. App.refreshNotifBadge
     / App.refreshChatBadge (core.js) now mirror the same .notif-bell-badge span onto the
     burger and the tab bar; it needs a positioned ancestor + a sane offset here since the
     base rule (.notif-bell-badge { position: absolute; top: -7px; right: -8px; }, tuned
     for the bell's .help-q anchor) would float above these hosts' top edge otherwise.
     #tabbar .tb-item already declares position: relative — only the burger needs it. */
  #mobile-topbar .mt-burger { position: relative; overflow: visible; }
  #tabbar .tb-more .notif-bell-badge,
  #tabbar .tb-item[data-tab="chat"] .notif-bell-badge { top: 4px; right: 18%; }
  #tabbar .tb-item[data-tab="chat"] .notif-bell-badge { background: #475569; }
  #tabbar .tb-item[data-tab="chat"] .notif-bell-badge.mention { background: var(--danger); }
}

/* ============================================================
   SPEC2 additions — Goals rings · Calendar · Insight bars
   (appended block; existing rules above untouched)
   ============================================================ */

/* ---- goal rings (dashboard "This month's goals") ---- */
.goal-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.goal-card {
  display: flex; align-items: center; gap: 14px;
  border: 1px solid var(--border); border-radius: var(--radius); padding: 14px 16px; background: var(--panel);
}
.ring { width: 92px; height: 92px; flex: 0 0 92px; position: relative; transform: rotate(-90deg); }
.ring-track { fill: none; stroke: var(--bg-2); }
.ring-fill { fill: none; stroke: var(--accent); stroke-linecap: round; transition: stroke-dasharray .4s ease; }
.ring-fill.ok { stroke: var(--ok); }
.ring-center {
  position: absolute; inset: 0; transform: rotate(90deg);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-md); font-weight: var(--fw-black); color: var(--text);
}
.goal-meta { min-width: 0; }
.goal-meta .goal-name { font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--muted); text-transform: uppercase; letter-spacing: .3px; }
.goal-meta .goal-value { font-size: 20px; font-weight: var(--fw-black); letter-spacing: -.3px; margin-top: 2px; }
.goal-meta .goal-of { font-size: var(--fs-meta); color: var(--faint); }
.goal-pace { font-size: 11.5px; color: var(--muted); margin-top: 4px; }
.goal-pace.ok { color: var(--ok); font-weight: var(--fw-bold); }

/* ---- calendar ---- */
.cal-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
.cal-toolbar .cal-month { font-size: var(--fs-md); font-weight: var(--fw-black); letter-spacing: -.2px; }
.cal-toolbar .spacer { flex: 1; }
.cal-dow { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin-bottom: 6px; }
.cal-dow > div { font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--faint); text-transform: uppercase; letter-spacing: .4px; text-align: center; padding: 2px 0; }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.cal-cell {
  min-height: 92px; max-height: 150px; overflow-y: auto; border: 1px solid var(--border);
  border-radius: var(--radius-sm); background: var(--panel); padding: 5px 6px; display: flex; flex-direction: column; gap: 3px;
}
.cal-cell.other-month { background: var(--subtle); opacity: .6; }
.cal-cell.today { outline: 2px solid var(--accent); outline-offset: -2px; }
.cal-daynum { font-size: 11.5px; font-weight: var(--fw-bold); color: var(--muted); }
.cal-cell.today .cal-daynum { color: var(--accent); }
.cal-event {
  font-size: var(--fs-micro); font-weight: var(--fw-semibold); padding: 2px 6px; border-radius: 5px; cursor: pointer;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: 1.4;
  border-left: 3px solid var(--accent);
}
.cal-event:hover { filter: brightness(.97); }
.cal-more { font-size: 10.5px; font-weight: var(--fw-bold); color: var(--muted); cursor: pointer; padding: 1px 4px; }
.cal-more:hover { color: var(--accent); }
/* week view: taller columns, full event list (SPEC19 §D) */
.cal-cell-week { min-height: 180px; max-height: 420px; }
.cal-empty-day { font-size: var(--fs-micro); color: var(--faint); text-align: center; padding: 6px 0; }
/* SPEC21 §C — async weather chip on upcoming shoots (today..+7d) */
.cal-wx {
  display: inline-block; margin-left: 5px; font-size: 10px; font-weight: var(--fw-bold);
  color: var(--muted); white-space: nowrap; vertical-align: baseline;
}
.cal-wx-loading { opacity: .45; }
.cal-event .cal-wx { color: inherit; opacity: .85; }

/* ---- insight bars (dashboard "Upsell & client insights") ---- */
.insight-bars { display: flex; flex-direction: column; gap: 8px; }
.bar-row { display: flex; align-items: center; gap: 10px; font-size: 12.5px; }
.bar-row .lbl { flex: 0 0 120px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: var(--fw-semibold); }
.bar-row .track { flex: 1; height: 8px; border-radius: 999px; background: var(--bg-2); overflow: hidden; min-width: 40px; }
.bar-row .fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--accent), var(--accent-hover)); min-width: 2px; transition: width .3s; }
.bar-row .val { flex: 0 0 auto; color: var(--muted); font-weight: var(--fw-bold); white-space: nowrap; }

@media (max-width: 860px) {
  .goal-grid { grid-template-columns: 1fr; }
  .cal-dow > div { font-size: 9.5px; }
  .cal-cell { min-height: 68px; padding: 3px 4px; }
  .cal-daynum { font-size: 10.5px; }
  .cal-event { font-size: 9.5px; padding: 1px 4px; }
  .bar-row .lbl { flex-basis: 84px; }
}

/* ============================================================
   SPEC3 additions — Quick Search · Sidebar search button
   (appended block; existing rules above untouched)
   ============================================================ */

/* ---- sidebar "Search…" button (under .brand) ---- */
.sidebar-search {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 8px 10px; margin: 0 0 8px; border-radius: 8px;
  border: 1px solid var(--sidebar-border); background: rgba(255,255,255,.05);
  color: var(--sidebar-text); cursor: pointer; font-family: inherit;
  font-size: var(--fs-caption); font-weight: var(--fw-medium); text-align: left;
}
.sidebar-search:hover { background: rgba(255,255,255,.1); color: var(--sidebar-active); }
.sidebar-search .ss-mag { font-size: 15px; line-height: 1; flex: 0 0 auto; }
.sidebar-search .ss-label { flex: 1; min-width: 0; }
.sidebar-search .ss-kbd {
  font-family: var(--mono); font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--sidebar-text);
  background: rgba(255,255,255,.08); border: 1px solid var(--sidebar-border);
  border-radius: 5px; padding: 1px 6px; flex: 0 0 auto;
}

/* ---- quick search overlay (command palette) ---- */
.qs-overlay {
  position: fixed; inset: 0; z-index: 250; background: rgba(16,18,28,.5);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 12vh 16px 16px; overflow-y: auto;
}
.qs-panel {
  width: 100%; max-width: 560px; background: var(--panel); border-radius: 14px;
  box-shadow: var(--shadow-lg); overflow: hidden; animation: modal-in var(--t-base) var(--ease-spring);
}
.qs-inputwrap {
  display: flex; align-items: center; gap: 10px; padding: 14px 16px;
  border-bottom: 1px solid var(--border);
}
.qs-mag { font-size: var(--fs-lg); color: var(--faint); line-height: 1; flex: 0 0 auto; }
.qs-input {
  flex: 1; min-width: 0; border: none; outline: none; background: transparent;
  font-family: inherit; font-size: var(--fs-md); color: var(--text);
}
.qs-esc {
  font-family: var(--mono); font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--faint);
  background: var(--hover); border: 1px solid var(--border); border-radius: 5px; padding: 2px 6px; flex: 0 0 auto;
}
.qs-list { max-height: 56vh; overflow-y: auto; padding: 6px; }
/* CMDK-5 — drill-in (Tab-to-act) transition; the prefers-reduced-motion net (line ~160) flattens it */
.qs-list.qs-slide { animation: qs-slide-in .16s var(--ease, ease) both; }
@keyframes qs-slide-in { from { opacity: .35; transform: translateX(7px); } to { opacity: 1; transform: none; } }
.qs-hint { padding: 22px 14px; text-align: center; color: var(--faint); font-size: var(--fs-caption); }
.qs-group {
  font-size: 10.5px; font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .5px;
  color: var(--faint); padding: 10px 10px 4px;
}
.qs-row {
  display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: 8px;
  cursor: pointer;
}
.qs-row.active { background: var(--accent-soft); }
/* SPEC211 — the keycap hint on a view row (e.g. "G J"); quiet, hidden on small phones */
.qs-kbd { flex: 0 0 auto; display: inline-block; padding: 2px 7px; border-radius: 5px; font-family: var(--mono);
  font-size: var(--fs-micro); background: var(--hover); border: 1px solid var(--border); color: var(--muted); white-space: nowrap; letter-spacing: .5px; }
@media (max-width: 480px) { .qs-kbd { display: none; } }
.qs-type {
  flex: 0 0 auto; font-size: 9.5px; font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .4px;
  color: var(--muted); background: var(--hover); border-radius: 5px; padding: 2px 6px; min-width: 46px; text-align: center;
}
.qs-type-job { color: var(--accent); background: var(--accent-soft); }
.qs-type-client { color: var(--ok); background: var(--ok-soft); }
.qs-type-sop { color: var(--warn); background: var(--warn-soft); }
/* ⌘K command verbs — soft accent badge; the glyph centers in the chip */
.qs-type-command { color: var(--accent); background: var(--accent-soft); }
.qs-type svg { display: block; margin: 0 auto; }
.qs-text { flex: 1; min-width: 0; }
.qs-label { font-size: 13.5px; font-weight: var(--fw-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qs-sub { font-size: var(--fs-meta); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qs-row .chip { flex: 0 0 auto; }

@media (max-width: 860px) {
  .sidebar-search { width: auto; margin: 0 4px 0 0; padding: 8px; flex: 0 0 auto; }
  .sidebar-search .ss-label, .sidebar-search .ss-kbd { display: none; }
}
@media (max-width: 480px) {
  .qs-overlay { padding: 8vh 10px 10px; }
  .qs-input { font-size: 15px; }
}

/* ============ roles, comments, login extras (SPEC4) ============ */

/* --- team & roles (Settings) --- */
.roles-list { display: flex; flex-direction: column; gap: 6px; margin-top: 4px; }
.role-row {
  display: flex; align-items: center; gap: 8px; padding: 7px 4px;
  border-bottom: 1px solid var(--bg-2);
}
.role-row:last-child { border-bottom: none; }
.role-email { flex: 1; min-width: 0; font-size: var(--fs-caption); font-weight: var(--fw-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.role-select { flex: 0 0 auto; min-width: 96px; }
.role-badge {
  display: inline-flex; align-items: center; flex: 0 0 auto;
  font-size: 10.5px; font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .4px;
  color: var(--accent); background: var(--accent-soft); border-radius: 999px; padding: 2px 9px;
}
.role-badge.crew { color: var(--muted); background: var(--hover); }

/* --- job comments --- */
.cmt-wrap { display: flex; flex-direction: column; gap: 10px; }
.cmt-list {
  max-height: 240px; overflow-y: auto; display: flex; flex-direction: column; gap: 10px;
  padding: 4px 2px;
}
.cmt-empty { color: var(--faint); font-size: var(--fs-caption); padding: 14px 4px; text-align: center; }
.cmt-row {
  background: var(--subtle); border: 1px solid var(--border); border-radius: 9px;
  padding: 8px 11px;
}
.cmt-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 3px; }
.cmt-author { font-size: 12.5px; font-weight: var(--fw-bold); color: var(--text); }
.cmt-time { font-size: var(--fs-micro); color: var(--faint); }
.cmt-text { font-size: var(--fs-caption); color: var(--text); white-space: pre-wrap; word-break: break-word; }
.cmt-box { display: flex; align-items: flex-end; gap: 8px; }
.cmt-box .cmt-input { flex: 1; min-width: 0; resize: vertical; }
.cmt-box .btn { flex: 0 0 auto; }

/* --- collapsible section (SPEC28 A3 · App.collapsibleSection) ---
   Structure: .collapse > button.collapse-head ( .collapse-title + .collapse-chevron )
   followed by .collapse-body. Open state is signalled by an `.open` class on the
   wrapper and/or head, or aria-expanded="true" on the head button — all handled. */
.collapse { border-top: 1px solid var(--border); margin-top: 4px; }
.collapse:first-child { border-top: none; margin-top: 0; }
.collapse-head {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 11px 2px; border: none; background: none; cursor: pointer;
  font-family: inherit; font-size: var(--fs-caption); font-weight: var(--fw-bold); color: var(--text);
  text-align: left; letter-spacing: -.1px;
}
.collapse-head:hover { color: var(--accent); }
.collapse-head:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
.collapse-title { flex: 1; min-width: 0; }
.collapse-chevron {
  flex: 0 0 auto; color: var(--faint); font-size: var(--fs-meta); line-height: 1;
  /* default (collapsed) points right; rotates down when open */
  transition: transform .15s ease; transform: rotate(-90deg);
}
.collapse.open > .collapse-head .collapse-chevron,
.collapse-head.open .collapse-chevron,
.collapse-head[aria-expanded="true"] .collapse-chevron { transform: none; }
.collapse-body { padding: 0 2px 12px; }
/* collapsed body is hidden by JS (display:none) or by these fallbacks */
.collapse:not(.open) > .collapse-body[hidden],
.collapse-head[aria-expanded="false"] + .collapse-body[hidden] { display: none; }
/* the wrapped section already carries its own borderTop in the job modal —
   neutralize the doubled rule so the collapse owns the divider */
.collapse-body > .full { border-top: none !important; padding-top: 0 !important; margin-top: 0 !important; }

/* --- login extras --- */
/* GOLIVE 2026-08-07 — the row can hold TWO links ("Forgot password?" +
   "Use a one-time code instead") and text-align:center alone ran them together with no
   space: "Forgot password?Use a one-time code instead". Flex + gap separates them at any
   width and wraps cleanly on a phone; a single link still centres exactly as before. */
.login-linkrow { margin-top: 12px; display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 6px 16px; text-align: center; }
.login-link { font-size: 12.5px; font-weight: var(--fw-semibold); color: var(--accent); cursor: pointer; }
.login-link:hover { text-decoration: underline; }

@media (max-width: 860px) {
  .role-row { flex-wrap: wrap; }
  .role-email { flex: 1 1 100%; }
  .cmt-list { max-height: 200px; }
}

/* ============================================================
   SPEC5 additions — Finances (expenses · profit · forecast)
   (appended block; existing rules above untouched)
   ============================================================ */

/* profit/loss number coloring (green ≥ 0, red < 0) */
/* LAW-A 2026-08-15 (#21) — was var(--ok)/var(--danger) (fill colours meant for swatches/
   dots, not body text). Measured on --panel (light): --ok 3.91:1 (FAIL AA) / --ok-ink
   5.69:1 (PASS); --danger 4.83:1 (borderline PASS) / --danger-ink 6.57:1 (PASS, more
   headroom). Dark theme unaffected — both ink tokens alias their fill colour there
   (--ok 7.39:1, --danger 5.55:1 on dark --panel), so this is a light-mode-only fix that
   costs nothing on dark. Same pattern already shipped at styles.css:647-649 (.chip.is-ok
   etc). */
.fin-pos { color: var(--ok-ink); font-weight: var(--fw-bold); }
.fin-neg { color: var(--danger-ink); font-weight: var(--fw-bold); }

/* compact finance/profit table — reuses .table look but right-aligns numbers */
.fin-table { width: 100%; border-collapse: collapse; font-size: var(--fs-caption); }
.fin-table th {
  text-align: left; font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .4px;
  color: var(--muted); padding: 7px 10px; border-bottom: 1px solid var(--border); white-space: nowrap;
}
.fin-table td { padding: 7px 10px; border-bottom: 1px solid var(--bg-2); vertical-align: middle; }
.fin-table tbody tr:last-child td { border-bottom: none; }
.fin-table .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.fin-table th.num { text-align: right; }
/* profit cell: sign-colored number + a small fixed-width bar, right-aligned so the
   figure and bar never overlap inside the nowrap .num column */
.fin-table .fin-bar-cell { display: inline-flex; align-items: center; gap: 8px; justify-content: flex-end; width: 100%; }
.databar.db-mini { width: 64px; min-width: 64px; flex: 0 0 auto; }

/* two-row revenue-vs-expenses mini chart for "profit over time" */
.fin-months { display: flex; align-items: stretch; gap: 10px; }
.fin-month {
  flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center;
  gap: 4px; justify-content: flex-end; text-align: center;
}
.fin-month .fin-bars { display: flex; align-items: flex-end; gap: 3px; height: 120px; }
.fin-month .fin-bar { width: 14px; border-radius: 4px 4px 2px 2px; min-height: 2px; }
.fin-month .fin-bar.rev { background: linear-gradient(180deg, var(--accent), var(--accent-hover)); }
.fin-month .fin-bar.exp { background: linear-gradient(180deg, color-mix(in srgb, var(--danger) 60%, var(--card)), var(--danger)); }
.fin-month .fin-mlabel { font-size: var(--fs-micro); color: var(--faint); font-weight: var(--fw-semibold); }
.fin-month .fin-mprofit { font-size: var(--fs-micro); font-weight: var(--fw-bold); }
.fin-legend { display: flex; gap: 14px; align-items: center; font-size: 11.5px; color: var(--muted); margin-bottom: 12px; }
.fin-legend .lg { display: inline-flex; align-items: center; gap: 5px; }
.fin-legend .sw { width: 10px; height: 10px; border-radius: 3px; }
.fin-legend .sw.rev { background: var(--accent); }
.fin-legend .sw.exp { background: var(--danger); }

@media (max-width: 860px) {
  .fin-month .fin-bars { height: 92px; }
  .fin-month .fin-bar { width: 11px; }
}

/* ============================================================
   SPEC6 — job costing: labor lines · cost summary · rate settings
   (appended; existing rules above untouched)
   ============================================================ */

/* one editable labor line in the job-modal costing block: who + hours + cost
   + remove. (Rendered by tracker.js in Phase B; styles live here.) */
.labor-line {
  display: flex; align-items: center; gap: 8px; flex-wrap: nowrap;
  padding: 5px 0; border-bottom: 1px solid var(--bg-2);
}
.labor-line:last-of-type { border-bottom: none; }
.labor-line .ll-who { flex: 1 1 auto; min-width: 0; }
.labor-line .ll-hours { width: 78px; flex: 0 0 78px; }
.labor-line .ll-cost { width: 72px; flex: 0 0 72px; text-align: right;
  font-variant-numeric: tabular-nums; color: var(--muted); font-size: var(--fs-caption); white-space: nowrap; }
.labor-line .ll-x { flex: 0 0 auto; }

/* label/value rows for the costing summary (labor, expenses, total, profit…) */
.cost-summary { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
.cost-summary .cs-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  font-size: var(--fs-caption); padding: 3px 0;
}
.cost-summary .cs-row.total { border-top: 1px solid var(--border); margin-top: 2px; padding-top: 7px; font-weight: var(--fw-semibold); }
.cost-summary .cs-label { color: var(--muted); }
.cost-summary .cs-val { font-variant-numeric: tabular-nums; white-space: nowrap; }
.cost-note { font-size: 11.5px; color: var(--faint); margin-top: 8px; line-height: 1.4; }

/* Settings → Rates & estimating */
.rate-row { display: flex; align-items: center; gap: 8px; padding: 5px 0; }
.rate-row .rate-name { flex: 1 1 auto; min-width: 0; font-weight: var(--fw-semibold); }
.tpl-list { display: flex; flex-direction: column; gap: 2px; }
.tpl-row { display: flex; align-items: center; gap: 8px; padding: 3px 0; }
.tpl-row .tpl-name { flex: 1 1 auto; min-width: 0; font-size: var(--fs-caption); }
.tpl-row .tpl-input { width: 70px; flex: 0 0 70px; }
.tpl-row.tpl-head { padding-bottom: 2px; }
.tpl-row.tpl-head .tpl-h { width: 70px; flex: 0 0 70px; font-size: var(--fs-micro); text-transform: uppercase;
  letter-spacing: .4px; color: var(--faint); font-weight: var(--fw-bold); text-align: center; }

@media (max-width: 860px) {
  .labor-line { flex-wrap: wrap; }
  .labor-line .ll-who { flex: 1 1 100%; }
  .tpl-row .tpl-input, .tpl-row.tpl-head .tpl-h { width: 56px; flex-basis: 56px; }
}

/* ============================================================
   SPEC9 — Retainers hub + shared Brand Profile editor
   (used by retainers.js and clients.js; foundation classes)
   ============================================================ */

/* shared brand-profile editor (App.renderBrandEditor) */
.brand-editor { display: flex; flex-direction: column; gap: 18px; }
.brand-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 14px; }
.brand-grid .brand-field.full { grid-column: 1 / -1; }
.brand-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.brand-field > label { font-size: var(--fs-meta); font-weight: var(--fw-semibold); color: var(--muted); }
.brand-field .textarea { resize: vertical; min-height: 58px; }
.brand-field .asset-open { font-size: 11.5px; font-weight: var(--fw-semibold); margin-top: 2px; }

.brand-subhead {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: var(--fs-caption); font-weight: var(--fw-bold); color: var(--text); margin-bottom: 8px;
}
.brand-hint { font-size: 11.5px; color: var(--faint); margin: 0 0 10px; line-height: 1.45; }

/* end-card contact block — grouped, lightly tinted to read as one unit */
.endcard-block, .assets-block {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--subtle); padding: 12px 14px;
}
.endcard-grid { gap: 10px 14px; }

/* brand asset link rows (label + url + open + remove) */
.asset-list { display: flex; flex-direction: column; gap: 8px; margin-top: 4px; }
.asset-link { display: flex; align-items: center; gap: 8px; }
.asset-link .asset-label { flex: 0 0 34%; min-width: 0; }
.asset-link .asset-url { flex: 1 1 auto; min-width: 0; }
.asset-link .asset-go { flex: 0 0 auto; white-space: nowrap; }
.asset-link .asset-go-ph { flex: 0 0 auto; color: var(--faint); padding: 0 6px; }
.asset-link .asset-x { flex: 0 0 auto; }

/* social stats before/after table */
.social-table { width: 100%; border-collapse: collapse; font-size: var(--fs-caption); }
.social-table th {
  text-align: left; font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .4px;
  color: var(--muted); padding: 7px 10px; border-bottom: 1px solid var(--border); white-space: nowrap;
}
.social-table td { padding: 7px 10px; border-bottom: 1px solid var(--bg-2); vertical-align: middle;
  font-variant-numeric: tabular-nums; }
.social-table tbody tr:last-child td { border-bottom: none; }

/* script pipeline rows */
.script-row {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--panel);
}
.script-row .script-title { flex: 1 1 auto; min-width: 0; font-weight: var(--fw-semibold);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.script-row .script-meta { color: var(--faint); font-size: var(--fs-meta); white-space: nowrap; }

/* retainer roster card */
.retainer-card {
  display: flex; flex-direction: column; gap: 8px; padding: 14px 16px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel);
  box-shadow: var(--shadow); cursor: pointer; transition: border-color .12s, box-shadow .12s;
}
.retainer-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow); }
.retainer-card .rc-name { font-size: 15px; font-weight: var(--fw-bold); }
.retainer-card .rc-company { font-size: 12.5px; color: var(--muted); }
.retainer-card .rc-meta { display: flex; flex-wrap: wrap; gap: 6px 14px;
  font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.retainer-card .rc-fee { font-weight: var(--fw-bold); color: var(--text); font-variant-numeric: tabular-nums; }

/* social delta arrows (▲/▼) — green up, red down */
.delta-up { color: var(--ok); font-weight: var(--fw-bold); }
.delta-down { color: var(--danger); font-weight: var(--fw-bold); }

@media (max-width: 860px) {
  .brand-grid { grid-template-columns: 1fr; }
  .asset-link { flex-wrap: wrap; }
  .asset-link .asset-label, .asset-link .asset-url { flex: 1 1 100%; }
}

/* ============ per-service production progress (SPEC10) ============
   Operational, NOT money — shown to everyone incl. crew. */

/* the "Service progress" section in the job modal */
.svc-prog { display: flex; flex-direction: column; gap: 8px; }
.svc-prog-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.svc-prog-head .svc-prog-label { font-size: 12.5px; font-weight: var(--fw-bold); color: var(--text); white-space: nowrap; font-variant-numeric: tabular-nums; }

/* one service row: name on the left, stage picker on the right */
.svc-step { display: flex; align-items: center; gap: 10px; padding: 6px 0; border-top: 1px solid var(--border); }
.svc-step:first-of-type { border-top: none; }
.svc-step .svc-step-name { flex: 1 1 auto; min-width: 0; font-size: var(--fs-caption); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svc-step .svc-step-select { flex: 0 0 auto; width: 140px; max-width: 45%; }

/* compact mini progress bar for the table cell / kanban card / modal head.
   Reuses the .progress track look; the fill is green (delivered share). */
.svc-bar { display: inline-flex; align-items: center; gap: 7px; white-space: nowrap; vertical-align: middle; }
.svc-bar .svc-bar-track { height: 5px; width: 54px; border-radius: 999px; background: var(--border); overflow: hidden; flex: 0 0 auto; }
.svc-bar .svc-bar-fill { height: 100%; border-radius: 999px; background: var(--ok); transition: width .25s; }
.svc-bar .svc-bar-text { font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--muted); font-variant-numeric: tabular-nums; }

/* dashboard "Production pipeline" card — one row per stage with a bar sized
   to that stage's share of all in-flight service-pieces */
.prod-pipeline { display: flex; flex-direction: column; gap: 9px; }
.prod-pipeline .pp-row { display: grid; grid-template-columns: 88px 1fr 28px; align-items: center; gap: 10px; }
.prod-pipeline .pp-label { font-size: var(--fs-meta); font-weight: var(--fw-semibold); color: var(--muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.prod-pipeline .pp-track { height: 8px; border-radius: 999px; background: var(--bg-2); overflow: hidden; }
.prod-pipeline .pp-fill { height: 100%; border-radius: 999px; transition: width .25s; min-width: 2px; }
.prod-pipeline .pp-count { font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--text); text-align: right; font-variant-numeric: tabular-nums; }
.prod-pipeline .pp-empty { font-size: 12.5px; color: var(--muted); padding: 4px 0; }

@media (max-width: 480px) {
  .svc-step { flex-wrap: wrap; }
  .svc-step .svc-step-select { width: 100%; max-width: none; }
  .prod-pipeline .pp-row { grid-template-columns: 76px 1fr 26px; gap: 8px; }
}

/* ============ birthdays/gifts + QA grading (SPEC11) ============
   Admin-only surfaces. The view files mostly inline-style these for resilience;
   these classes give the required structure/spacing and a mobile-friendly
   fallback. Inline styles (e.g. the QA segmented control's selected colors)
   intentionally win where set. */

/* QA scorecard rubric in the job modal: one row per factor + a 1–5 control */
.qa-rubric { display: flex; flex-direction: column; gap: 6px; }
.qa-factor { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; padding: 4px 0; }
.qa-factor .qa-factor-name { flex: 1 1 160px; min-width: 0; font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--text);
  overflow: hidden; text-overflow: ellipsis; }
/* 1–5 segmented control */
.qa-score { display: inline-flex; gap: 3px; flex: 0 0 auto; }
.qa-score .qa-score-btn { width: 30px; height: 28px; line-height: 1; padding: 0; font: inherit; font-size: 12.5px;
  font-weight: var(--fw-bold); cursor: pointer; border: 1px solid var(--border-strong); border-radius: 6px;
  background: var(--panel); color: var(--muted); }
.qa-score .qa-score-btn:hover { border-color: var(--accent); }

/* AUDIT-2026-07-25 [16] — .grade-badge deleted: App.gradeLabel is used 5x but always
   renders through App.chip or an inline-styled span, never this class; zero emitters. */

/* a single logged gift row (client detail) — date · gift · note + remove */
.gift-row { display: flex; align-items: flex-start; gap: 8px; padding: 6px 0; border-top: 1px solid var(--border); }
.gift-row:first-of-type { border-top: none; }
.gift-row .gift-date { flex: 0 0 auto; min-width: 92px; font-size: var(--fs-meta); color: var(--muted); white-space: nowrap; }
.gift-row .gift-body { flex: 1 1 auto; min-width: 0; white-space: normal; }

/* an upcoming-birthday row (dashboard) — date · name/company · when · gift btn */
.bday-row { display: flex; align-items: center; gap: 10px; }
.bday-row .bday-date { flex: 0 0 56px; font-weight: var(--fw-bold); white-space: nowrap; font-variant-numeric: tabular-nums; }
.bday-row .bday-when { flex: 0 0 52px; text-align: right; font-size: var(--fs-meta); color: var(--muted); white-space: nowrap; }

@media (max-width: 480px) {
  .qa-factor { flex-direction: column; align-items: stretch; gap: 5px; }
  .qa-score { align-self: flex-start; }
  .gift-row { flex-wrap: wrap; }
}

/* ============ client journey + consult-prep (SPEC12) ============
   Admin-only surfaces. The job-modal journey checklist mostly inline-styles its
   rows for resilience; these classes give the consult-prep panel its structure
   + spacing and a mobile-friendly fallback. */

/* one journey step row in the job modal: check + label + date + note */
.journey { display: flex; flex-direction: column; gap: 8px; }
.journey-step { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 0; }
.journey-step .journey-label { flex: 1 1 150px; font-size: var(--fs-caption); font-weight: var(--fw-semibold); }
.journey-step .journey-date { flex: 0 0 auto; min-width: 64px; text-align: right; font-size: 11.5px; color: var(--muted); }

/* read-only consult-prep panel (shared: clients detail + tracker modal) */
.consult-prep { display: block; }
.consult-prep .cp-who { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.consult-prep .cp-name { font-weight: var(--fw-black); font-size: 15px; }
.cp-stat-strip { display: flex; gap: 8px; flex-wrap: wrap; }
.cp-stat { flex: 1; min-width: 108px; padding: 9px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 8px; }
.cp-stat .cp-stat-value { font-size: 17px; font-weight: var(--fw-black); letter-spacing: -.3px; margin-top: 2px; }
.cp-section { margin-top: 14px; }
.cp-section .cp-section-title { font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--muted); text-transform: uppercase; letter-spacing: .4px; margin-bottom: 6px; }
.cp-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip.cp-chip { background: var(--hover); color: var(--text); }  /* SPEC198 — theme-aware ink (was hard #3a4256 → dark-on-dark) */

@media (max-width: 480px) {
  .journey-step { align-items: flex-start; }
  .cp-stat { min-width: calc(50% - 4px); }
}

/* ============ Sales command-center (SPEC13, admin-only) ============
   Mobile-first: this tab is used live on a phone during sales calls. Reuses
   the design tokens; the segmented section control scrolls horizontally on
   narrow screens, scripts/templates copy with one tap. */

/* segmented control across the 7 sections (scrolls on phone) */
.sales-tabs {
  display: flex; gap: 6px; flex-wrap: nowrap; overflow-x: auto;
  -webkit-overflow-scrolling: touch; padding-bottom: 6px; margin-bottom: 16px;
  scrollbar-width: thin;
}
.sales-tab {
  flex: 0 0 auto; padding: 8px 14px; border-radius: 999px;
  border: 1px solid var(--border-strong); background: var(--panel); color: var(--muted);
  font-size: var(--fs-caption); font-weight: var(--fw-semibold); cursor: pointer; font-family: inherit; white-space: nowrap;
  transition: background .12s, color .12s, border-color .12s;
}
.sales-tab:hover { background: var(--subtle); color: var(--text); }
.sales-tab.active { background: var(--accent); border-color: var(--accent); color: #fff; }

.sales-section { display: flex; flex-direction: column; gap: 12px; }
.sales-hint { color: var(--muted); font-size: var(--fs-caption); margin: 0 0 4px; }

/* consultation wizard: progress bar, step pills, step card */
.wizard { display: flex; flex-direction: column; gap: 12px; }
.wizard-progress { display: flex; gap: 4px; }
.wizard-progress .wp-seg {
  flex: 1; height: 5px; border-radius: 3px; background: var(--border);
  cursor: pointer; transition: background .2s;
}
.wizard-progress .wp-seg.done { background: var(--accent); }
.wizard-pills { display: flex; gap: 6px; flex-wrap: wrap; }
.wizard-pill {
  padding: 6px 11px; border-radius: 999px; border: 1px solid var(--border-strong);
  background: var(--panel); color: var(--muted); font-size: var(--fs-meta); font-weight: var(--fw-semibold);
  cursor: pointer; font-family: inherit; white-space: nowrap;
}
.wizard-pill.active { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.wizard-step { border-left: 3px solid var(--accent); }
.wizard-step-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap; margin-bottom: 6px; }
.wizard-step-title { font-size: var(--fs-md); font-weight: var(--fw-black); letter-spacing: -.2px; }
.wizard-time { font-size: 11.5px; font-weight: var(--fw-bold); color: var(--accent); background: var(--accent-soft); padding: 3px 10px; border-radius: 999px; white-space: nowrap; }
.wizard-prompt { color: var(--muted); font-size: var(--fs-caption); margin: 0 0 12px; }
.wizard-nav { display: flex; gap: 8px; }
.wizard-tip { font-size: 12.5px; color: var(--muted); padding: 5px 9px; background: var(--bg); border-radius: 6px; }

/* a copy-able script / template block: text + copy button */
.script-block {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 10px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px;
}
.script-block .script-text { flex: 1; font-size: 13.5px; line-height: var(--lh-normal); color: var(--text); }

/* copy button — turns green on success */
.copy-btn {
  flex: 0 0 auto; padding: 5px 12px; border-radius: 6px; border: 1px solid var(--accent);
  background: var(--accent); color: #fff; font-size: var(--fs-meta); font-weight: var(--fw-bold); cursor: pointer;
  font-family: inherit; white-space: nowrap; transition: background .15s, border-color .15s, color .15s;
}
.copy-btn:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.copy-btn.copied { background: var(--ok); border-color: var(--ok); color: #fff; }

/* objection cards */
.objection-card { border-left: 3px solid var(--accent); }
.objection-card .obj-title { font-size: 15px; font-weight: var(--fw-black); margin-bottom: 10px; }
.obj-script { background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; margin-bottom: 8px; }
.obj-script .obj-name { font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--accent); margin-bottom: 5px; }
.obj-why { font-size: var(--fs-meta); color: var(--muted); font-style: italic; margin-top: 6px; }

/* text templates */
.text-tpl .tpl-label { font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--accent); margin-bottom: 6px; }

/* calculators */
.calc-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; }
.calc-cell { background: var(--panel); border: 1px solid var(--border); border-radius: 8px; padding: 10px 12px; border-left: 3px solid var(--accent); }
.calc-cell .calc-name { font-size: var(--fs-meta); font-weight: var(--fw-bold); }
.calc-cell .calc-price { font-size: 19px; font-weight: var(--fw-black); letter-spacing: -.4px; margin-top: 2px; }
.calc-cell .calc-over { font-size: var(--fs-micro); color: var(--warn); margin-top: 2px; }

/* upsell flow nodes */
.upsell-node { border-left: 3px solid var(--accent); }
.upsell-node .upsell-trigger { font-size: var(--fs-caption); font-weight: var(--fw-black); margin-bottom: 8px; }
.upsell-branches { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.upsell-branch { font-size: 11.5px; padding: 4px 9px; border-radius: 6px; line-height: 1.4; }
.upsell-branch.yes { color: var(--ok); background: var(--ok-soft); }
.upsell-branch.no { color: var(--warn); background: var(--warn-soft); }

/* quick-ref rows */
.qref-row { display: flex; justify-content: space-between; gap: 12px; padding: 6px 0; border-bottom: 1px solid var(--border); }
.qref-row:last-child { border-bottom: none; }
.qref-row .qref-label { font-size: 12.5px; color: var(--muted); flex: 0 0 auto; }
.qref-row .qref-val { font-size: 12.5px; font-weight: var(--fw-semibold); text-align: right; }

/* quick-links — copy-paste by price tier */
.qlink-tier { font-size: var(--fs-body); font-weight: var(--fw-black); letter-spacing: -.2px; margin-bottom: 4px; }
.qlink-rec { font-size: var(--fs-caption); font-weight: var(--fw-bold); color: var(--accent); margin-bottom: 4px; }
.qlink-why { font-size: 12.5px; line-height: var(--lh-normal); margin-bottom: 10px; }

/* SOD/EOD report preview */
.report-preview {
  font-family: var(--mono); font-size: 12.5px; white-space: pre-wrap; line-height: 1.6;
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; margin: 0;
}

@media (max-width: 480px) {
  .wizard-step-title { font-size: 15px; }
  .script-block { flex-direction: column; }
  .script-block .copy-btn { align-self: flex-end; }
  .calc-grid { grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); }
}

/* ---------------- Today command-center (SPEC21 A) ---------------- */
.today-group { margin-bottom: 18px; }
.today-group > .card-title { margin-bottom: 10px; }
.today-shoot { margin-bottom: 10px; cursor: pointer; transition: border-color .12s, box-shadow .12s, transform .12s; }
.today-shoot:hover { border-color: var(--accent); box-shadow: var(--shadow); }
.today-shoot:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.today-shoot-addr { font-size: 14.5px; font-weight: 650; letter-spacing: -.1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.today-line { font-size: 12.5px; line-height: 1.6; margin-top: 4px; display: flex; flex-wrap: wrap; gap: 4px 7px; align-items: center; }
.today-line .today-dot { color: var(--border-strong); }
.today-shoot-actions { margin-top: 10px; display: flex; gap: 8px; flex-wrap: wrap; }

/* FRONT-DOOR 2026-08-09 — the editor "Your edits" hero card (today.js
   editHeroCard). Same clickable-card hover/focus treatment as .today-shoot,
   deliberately WITHOUT its 2-column time-gutter grid (this card has no time
   gutter — applying .today-shoot squeezed the address into an implicit 54px
   column and shoved the "Start here" button up beside it). */
.edit-hero { margin-bottom: 10px; cursor: pointer; transition: border-color .12s, box-shadow .12s, transform .12s; }
.edit-hero:hover { border-color: var(--accent); box-shadow: var(--shadow); }
.edit-hero:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ONE-3/ONE-4 (RESEARCH-ONE-TODAY-2026-07-28.md) — the Focus-order ladder + its
   Layer-2 collapse. Each ladder section is a plain heading + one card of rows
   (reuses .list-row); a zero-item section never reaches the DOM at all (decided
   in JS, not hidden via CSS). */
.today-section { margin-bottom: 18px; }
.today-section-head { margin-bottom: 8px; }
.today-section-head h3 { display: flex; align-items: center; gap: 7px; margin: 0; }

/* Layer-2 "one-line link" — collapsed by default (native <details>, no JS
   needed to toggle). The summary reads as a single row; the full, unchanged
   card only renders once it's opened — nothing is deleted, just tucked one
   click deeper (NN/g's 2-level progressive-disclosure limit). */
.today-collapse { margin-bottom: 10px; }
.today-collapse > summary { cursor: pointer; list-style: none; display: flex; align-items: center; gap: 8px; padding: 10px 14px; background: var(--bg-2); border: 1px solid var(--border); border-radius: 10px; font-weight: 650; font-size: var(--fs-caption); }
.today-collapse > summary::-webkit-details-marker { display: none; }
.today-collapse > summary::after { content: '›'; margin-left: auto; color: var(--muted); font-size: var(--fs-md); transition: transform .15s; }
.today-collapse[open] > summary { border-radius: 10px 10px 0 0; }
.today-collapse[open] > summary::after { transform: rotate(90deg); }
.today-collapse-body { margin-top: 8px; }
.today-collapse.card > summary { background: none; border: none; padding: 0; margin-bottom: 4px; }

/* ============================================================
   SPEC28 D — subtle density / calm pass
   Polish only: nudge secondary text down a hair, calm a few borders,
   and trim roomy card padding. NO color-identity changes, no layout
   restructuring. Kept last so it gently refines earlier rules.
   ============================================================ */

/* Secondary/supporting text reads a touch quieter on busy screens.
   (Primary text, KPI values, titles and the accent are untouched.) */
.view-sub { font-size: 12.5px; }
.kpi-hint { font-size: var(--fs-micro); }
.card-title { letter-spacing: .35px; }

/* SPEC175 — refined, calmer rows: a touch more air than the old dense pass for an
   expensive feel, but not bloated on long tracker lists. The accent-tinted hover rail
   from the base .table rule now shows through (this no longer flattens it). */
.table th { padding: 10px 14px; }
.table td { padding: 10px 14px; }

/* SPEC175 — card padding is now a single source of truth (.card-pad = 18px 20px);
   the old 15px shave is removed so cards breathe like the client surfaces. */

/* Calmer borders where two strong edges stack (cards in tight grids).
   Uses the existing --border token — no new colors. */
.grid-2 > .card, .grid-3 > .card { box-shadow: var(--shadow-sm), var(--card-hi); }

/* Chips/badges: a touch less shouty in dense rows (weight only, colors kept). */
.badge { font-weight: var(--fw-semibold); }

/* Faint helper text settles a hair smaller in supporting roles. */
.list-row .muted { font-size: 11.5px; }

/* ============ SPEC32 — onboarding + inline help ============ */

/* sidebar "?" Help button (footer) — quiet until hovered */
.help-btn {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 7px 9px; border-radius: var(--radius-sm); border: 1px solid transparent;
  background: transparent; color: var(--sidebar-text); cursor: pointer;
  font: inherit; font-size: 12.5px; text-align: left;
}
.help-btn:hover { background: rgba(255,255,255,.06); color: var(--sidebar-active); }
.help-btn .help-q {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; flex: 0 0 18px; border-radius: 50%;
  background: rgba(255,255,255,.1); font-weight: var(--fw-bold); font-size: var(--fs-meta);
}

/* AUDIT-2026-07-25 [16] — .help-hint (+hover/:focus-visible) deleted along with its
   only emitter, App.helpHint (core.js) — zero callers anywhere, no test coverage. */

/* empty-state block — "nothing here yet" with an optional action */
.empty-state {
  text-align: center; padding: 34px 20px; color: var(--muted);
  display: flex; flex-direction: column; align-items: center; gap: 7px;
}
.empty-state .es-ico { font-size: 30px; line-height: 1; opacity: .9; }
/* old-convention children (.es-icon/h4/p) carry their own margins; this block adds
   flex gap to the parent, so zero those margins to avoid double vertical spacing. */
.empty-state .es-icon, .empty-state h4, .empty-state p { margin: 0; }
.empty-state .es-title { font-weight: var(--fw-bold); color: var(--text); font-size: 15px; }
.empty-state .es-msg { font-size: var(--fs-caption); max-width: 360px; }
.empty-state .es-action { margin-top: 6px; }

/* keyboard shortcut cheatsheet */
.shortcut-table { width: 100%; border-collapse: collapse; }
.shortcut-table td { padding: 7px 8px; border-bottom: 1px solid var(--border); font-size: var(--fs-caption); vertical-align: middle; }
.shortcut-table tr:last-child td { border-bottom: none; }
.sc-kbd, .help-tip kbd {
  display: inline-block; padding: 3px 8px; border-radius: 6px; font-family: var(--mono);
  font-size: var(--fs-meta); background: var(--hover); border: 1px solid var(--border-strong);
  color: var(--text); white-space: nowrap;
}
.help-actions { display: flex; flex-wrap: wrap; gap: 10px; margin: 4px 0 14px; }
.help-tip { font-size: 12.5px; margin: 0; }

/* first-run welcome overlay */
.modal-body.welcome { padding-top: 4px; }
.welcome-hero { text-align: center; padding: 6px 6px 4px; }
.welcome-wave { font-size: 38px; line-height: 1; }
.welcome-h { margin: 8px 0 4px; font-size: 23px; }
.welcome-tag {
  display: inline-block; padding: 3px 11px; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent); font-weight: var(--fw-bold);
  font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .5px;
}
.welcome-lead { margin: 11px auto 4px; max-width: 480px; color: var(--muted); font-size: var(--fs-body); }
.welcome-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 11px; margin: 16px 0 6px;
}
.welcome-card {
  display: flex; gap: 11px; align-items: flex-start; padding: 13px 14px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--subtle);
}
/* WELCOME-REWORK 2026-08-10 — highlight cards are real buttons (tap → jump there) */
.welcome-card.clickable {
  width: 100%; font: inherit; color: inherit; text-align: left; cursor: pointer;
  transition: border-color .12s, background .12s;
}
.welcome-card.clickable:hover, .welcome-card.clickable:focus-visible { border-color: var(--accent); background: var(--accent-soft); }
.welcome-card.clickable:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.welcome-card .wc-ico { font-size: 21px; line-height: 1.1; flex: 0 0 auto; }
.welcome-card .wc-name { font-weight: var(--fw-bold); font-size: 13.5px; }
.welcome-card .wc-desc { font-size: 12.5px; color: var(--muted); margin-top: 2px; line-height: 1.4; }
.welcome-add {
  margin: 12px 0 2px; padding: 11px 13px; border-radius: var(--radius-sm);
  background: var(--accent-soft); color: var(--text); font-size: var(--fs-caption); text-align: center;
}
.welcome-add b { color: var(--accent); }
@media (max-width: 560px) {
  .welcome-grid { grid-template-columns: 1fr; }
}

/* floating ＋ Quick-Add button — add from anywhere */
.quick-add-fab {
  position: fixed; right: 22px; bottom: 22px; z-index: 60;
  width: 52px; height: 52px; border-radius: 50%; border: none; cursor: pointer;
  background: var(--accent); color: #fff; font-size: var(--fs-display); line-height: 1;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 6px 18px -3px rgba(var(--ring-rgb),.5), 0 2px 6px rgba(16,24,40,.2);
  transition: transform .12s ease, background .12s ease;
}
.quick-add-fab:hover { background: var(--accent-hover); transform: translateY(-2px) scale(1.03); }
.quick-add-fab:active { transform: scale(.96); }

/* SPEC303 — global voice mic FAB; stacks above the ＋ FAB when it's present */
.voice-fab {
  position: fixed; right: 22px; bottom: 22px; z-index: 60;
  width: 52px; height: 52px; border-radius: 50%; border: 1px solid var(--border); cursor: pointer;
  background: var(--panel); color: var(--accent);
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 6px 18px -3px rgba(16,24,40,.26), 0 2px 6px rgba(16,24,40,.16);
  transition: transform .12s ease, background .12s ease, color .12s ease;
}
.voice-fab.stacked { bottom: 86px; }
.voice-fab:hover { transform: translateY(-2px) scale(1.03); background: var(--accent-soft); }
.voice-fab:active { transform: scale(.96); }
.voice-fab.listening { background: var(--accent); color: #fff; border-color: transparent; animation: voicePulse 1.4s ease-in-out infinite; }
@keyframes voicePulse { 0%,100% { box-shadow: 0 0 0 0 rgba(var(--ring-rgb),.5); } 50% { box-shadow: 0 0 0 10px rgba(var(--ring-rgb),0); } }
.voice-pill {
  position: fixed; left: 50%; bottom: 92px; transform: translateX(-50%); z-index: 70;
  max-width: 80vw; padding: 9px 16px; border-radius: 999px;
  background: var(--ink, #14140f); color: #fff; font-size: 13.5px; font-weight: var(--fw-semibold);
  box-shadow: 0 8px 24px -6px rgba(0,0,0,.4);
}
/* SPEC303 — small inline mic dropped inside a field's row (job brief, notes, chat) */
.voice-mic {
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: 30px; height: 30px; border-radius: 50%; border: 1px solid var(--border);
  background: var(--panel); color: var(--muted); cursor: pointer;
  transition: color .12s ease, border-color .12s ease, background .12s ease;
}
.voice-mic:hover { color: var(--accent); border-color: var(--accent); }
.voice-mic.listening { color: #fff; background: var(--accent); border-color: transparent; animation: voicePulse 1.4s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) { .voice-fab.listening, .voice-mic.listening { animation: none; } }
@media (max-width: 640px) {
  .voice-fab { right: 16px; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); width: 56px; height: 56px; }
  .voice-fab.stacked { bottom: calc(80px + env(safe-area-inset-bottom, 0px)); }
}

/* SPEC310 — bug reporter
   The floating "Report" pill (stacks ABOVE the ＋/mic FABs), the devtools-style
   pick-mode overlay (transparent capture layer + accent outline + type label + top
   banner), and the report-form chips + screenshot thumb. Token-driven + theme-aware. */
.bug-fab {
  position: fixed; right: 22px; bottom: 150px; z-index: 61;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 16px; border-radius: 999px; border: 1px solid var(--border); cursor: pointer;
  background: var(--panel); color: var(--accent); font: inherit; font-size: 13.5px; font-weight: var(--fw-bold);
  box-shadow: 0 6px 18px -3px rgba(16,24,40,.26), 0 2px 6px rgba(16,24,40,.16);
  transition: transform .12s ease, background .12s ease, color .12s ease;
}
.bug-fab:hover { transform: translateY(-2px) scale(1.03); background: var(--accent-soft); }
.bug-fab:active { transform: scale(.96); }
@media (max-width: 640px) {
  .bug-fab { right: 16px; bottom: calc(150px + env(safe-area-inset-bottom, 0px)); padding: 9px 13px; }
}
@media (prefers-reduced-motion: reduce) { .bug-fab { transition: none; } }

/* D7 — mobile FAB dial (fab-dial.js): ONE expandable control replaces the five-deep
   floating cluster (Report pill / mic / phone / ＋ / FRIDAY pill) that clipped content
   on 6+ screens at 375×812.
   STAGE1 2026-08-14 (design item 10 / D1) — the dial now covers DESKTOP too: the four
   individual FABs stacked bottom-right on every desktop view, overlapping the tracker's
   Payment column, the chat feed, and the video table (parity-feel.md D1). Desktop keeps
   the same right:22px/bottom:22px slot the old cluster's bottom-most button (quick-add)
   used, so nothing moves for muscle memory — it's just ONE circle now, not four. The
   four originals stay in the DOM (their own JS still creates/wires them, other callers
   still reference the ids) but never paint, at any width. */
.fab-dial-btn {
  position: fixed; right: 22px; bottom: 22px;
  z-index: 60; width: 56px; height: 56px; border-radius: 50%; border: 0; cursor: pointer;
  background: var(--accent); color: #fff; display: flex; align-items: center; justify-content: center;
  box-shadow: 0 6px 18px -3px rgba(var(--ring-rgb),.5), 0 2px 6px rgba(16,24,40,.2);
  transition: transform var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.fab-dial-btn .icon { transition: transform var(--t-fast) var(--ease); }
.fab-dial-btn.open .icon { transform: rotate(45deg); }
.fab-dial-btn:hover { background: var(--accent-hover); }
.fab-dial-btn:active { transform: scale(.96); }
/* STAGE1 2026-08-14 — explicit ring shaped to the circle; the sitewide bare
   :focus-visible (styles.css:169) already fires here (real <button>, native tab
   order — no JS change needed for reachability), this just matches the shape. */
.fab-dial-btn:focus-visible { outline: none; box-shadow: var(--focus-ring); border-radius: 50%; }
.fab-dial-btn-dot {
  position: absolute; top: 3px; right: 3px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--ok); border: 2px solid var(--panel); display: none;
}
.fab-dial-btn.has-live .fab-dial-btn-dot { display: block; }
.fab-dial-scrim { position: fixed; inset: 0; z-index: 59; background: rgba(16,24,40,.32); display: none; border: 0; padding: 0; }
.fab-dial-scrim.open { display: block; }
.fab-dial-menu {
  position: fixed; right: 22px; z-index: 61; display: none; flex-direction: column; gap: var(--space-2);
  bottom: calc(22px + 68px); align-items: flex-end;
}
.fab-dial-menu.open { display: flex; }
.fab-dial-item {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 16px 0 14px;
  border-radius: var(--radius, 999px); border: 1px solid var(--border); background: var(--panel);
  color: var(--text); box-shadow: var(--shadow-lg); font: inherit; font-size: 13.5px; font-weight: var(--fw-semibold);
  cursor: pointer;
}
.fab-dial-item:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.fab-dial-item .icon { flex: 0 0 auto; color: var(--accent); }
@media (prefers-reduced-motion: reduce) { .fab-dial-btn, .fab-dial-btn .icon { transition: none; } }
/* STAGE1 2026-08-14 — the four originals never paint at any width now (were previously
   only hidden ≤860px, with the dial taking over just on mobile). */
#quick-add-fab, #voice-fab, #bug-fab, #callFab { display: none !important; }
@media (max-width: 860px) {
  .fab-dial-btn { right: 16px; bottom: calc(16px + env(safe-area-inset-bottom, 0px) + 62px); }
  .fab-dial-menu { right: 16px; bottom: calc(16px + env(safe-area-inset-bottom, 0px) + 62px + 68px); }
}
/* chat: dial clears the composer at every width — nothing floats over an input
   (SPEC328's rule, index.html:120-121 / core.js:18613). MEASURED live (1280×800,
   #general): .chat-composer's top sits a constant 142px above the viewport bottom
   (the chat layout's own `calc(100vh - 104px)` math, independent of window height).
   The old desktop cluster's SPEC336 offset (140px) left only a 2px gap there — a
   real, if hairline, violation of the same SPEC328 rule it was named for — so this
   is 152px, not a re-derivation of that value: a true ~10px clear margin instead of
   reproducing the near-miss. */
body[data-view="chat"] .fab-dial-btn { bottom: 152px; }
body[data-view="chat"] .fab-dial-menu { bottom: calc(152px + 68px); }
/* BUG4-FABCOMPOSER 2026-08-18 — the 152px above only clears a SINGLE-LINE composer.
   `.chat-input` (styles.css ~2652) auto-grows with the message — min-height:42px,
   max-height:140px — and on a phone the growth eats straight into that margin.
   MEASURED live at an explicit 375×812 (#general): empty composer top sits 134px
   above the viewport bottom (matching the desktop-tuned offset); typing an 8-line
   message grows `.chat-input` from 37px to its 140px cap and pulls the composer's
   top up to 23px from the bottom — a 103px swing. A hit-test at that point
   (elementFromPoint over the now-taller textarea) returned the FAB button, not the
   textarea: a real "floats over an input" violation, not just close boxes.
   `.chat-input`'s 140px cap makes this a BOUNDED, provable worst case, so a static
   +134px (103px of real growth + a ~30px margin, re-measured after a first pass at
   +120px left only ~1px of hairline clearance at the textarea's actual top — the
   exact near-miss shape the 152px comment above was written to avoid) guarantees
   real clearance at every message length, not just the common one-line case.
   Scoped to the two mobile tiers only (desktop's extra vertical room made this
   untestable as an on-screen violation there); the 152px desktop rule above is
   unchanged. */
@media (max-width: 860px) {
  body[data-view="chat"] .fab-dial-btn { bottom: calc(152px + 62px + 134px); }
  body[data-view="chat"] .fab-dial-menu { bottom: calc(152px + 62px + 134px + 68px); }
}
@media (max-width: 640px) {
  body[data-view="chat"] .fab-dial-btn { bottom: calc(152px + env(safe-area-inset-bottom, 0px) + 62px + 134px); }
  body[data-view="chat"] .fab-dial-menu { bottom: calc(152px + env(safe-area-inset-bottom, 0px) + 62px + 134px + 68px); }
}
body.kb-open .fab-dial-btn, body.kb-open .fab-dial-scrim, body.kb-open .fab-dial-menu { display: none; }
/* STAGE1-FIX 2026-08-14 (checker 2) — "nothing floats over data" was only half kept.
   The chat rule above lifts the dial off the composer, but the two BOARD views scroll
   their last row straight under it: MEASURED at 1024x800, Job Tracker scrolled to the
   bottom, the last row's box is 708-749 and the dial's is 722-778, and a hit-test at
   (989, 728) and (969, 728) — inside that row — returns the FAB, not the row. At 1024
   the table's right edge is 992px, so what the circle is sitting on is the Due cell:
   the row's urgency, covered on exactly the row a person scrolled down to read. Same
   geometry on the Video Tracker. The fix is a bottom gutter on the scroll container so
   the last row can always clear the dial (78px of occupied corner -> 88px), rather than
   moving the dial per-view: the board's bottom-right is data at every scroll position,
   the chat composer is only ever in one place. Desktop only — <=860px keeps the mobile
   tab-bar offsets above untouched. */
@media (min-width: 861px) {
  body[data-view="jobs"] main,
  body[data-view="video"] main { padding-bottom: 88px; }
}

/* pick mode — a transparent full-viewport layer that captures the click/hover */
.bugpick-overlay { position: fixed; inset: 0; z-index: 2147483000; background: transparent; cursor: crosshair; }
.bugpick-outline {
  position: fixed; z-index: 2147483001; pointer-events: none;
  border: 2px solid var(--accent); border-radius: 4px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 28%, transparent);
  transition: top .06s ease, left .06s ease, width .06s ease, height .06s ease;
}
.bugpick-label {
  position: fixed; z-index: 2147483002; pointer-events: none;
  padding: 3px 8px; border-radius: 6px; font-size: var(--fs-meta); font-weight: var(--fw-bold); white-space: nowrap;
  background: var(--accent); color: #fff; box-shadow: 0 2px 8px rgba(0,0,0,.3);
}
.bugpick-banner {
  position: fixed; top: 0; left: 50%; transform: translateX(-50%); margin-top: 14px;
  z-index: 2147483003; pointer-events: auto;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; justify-content: center;
  max-width: 92vw; padding: 11px 18px; border-radius: 999px;
  background: var(--ink, #14140f); color: #fff; font-size: 13.5px; font-weight: var(--fw-semibold);
  box-shadow: 0 10px 30px -6px rgba(0,0,0,.5);
}
/* D15 — was an underlined text link ("Skip — just describe it"); now a real
   button so the escape hatch reads as an equal option, not an afterthought.
   The banner is always dark (var(--ink)) regardless of app theme, so this is
   styled directly rather than through .btn's light/dark tokens. */
.bugpick-skip {
  background: transparent; border: 1px solid rgba(255,255,255,.4); border-radius: 999px;
  color: #fff; cursor: pointer; padding: 5px 13px;
  font: inherit; font-size: 12.5px; font-weight: var(--fw-bold);
  transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease);
}
.bugpick-skip:hover { background: rgba(255,255,255,.14); border-color: #fff; }
@media (prefers-reduced-motion: reduce) { .bugpick-skip { transition: none; } }
@media (prefers-reduced-motion: reduce) { .bugpick-outline { transition: none; } }

/* report form — kind/severity toggle chips, pinpoint row, screenshot thumb */
.bugrep-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px; border-radius: 999px; border: 1px solid var(--border); cursor: pointer;
  background: var(--panel); color: var(--text); font: inherit; font-size: var(--fs-caption); font-weight: var(--fw-semibold);
  transition: background .12s ease, border-color .12s ease, color .12s ease;
}
.bugrep-chip:hover { border-color: var(--accent); }
.bugrep-chip.active { background: var(--accent); border-color: var(--accent); color: #fff; }
.bugrep-pin {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 9px 12px; border-radius: var(--radius-sm, 8px);
  background: var(--accent-soft); border: 1px solid var(--border);
  font-size: 12.5px; color: var(--text);
}
.bugrep-shot-thumb {
  display: block; max-width: 240px; max-height: 140px;
  border-radius: 8px; border: 1px solid var(--border); cursor: zoom-in;
}
.bugrep-where { margin-top: 4px; font-size: var(--fs-meta); }
.bugrep-where > summary { cursor: pointer; color: var(--muted); font-weight: var(--fw-semibold); list-style: revert; }
.bugrep-where .bugrep-tech {
  margin-top: 6px; padding: 8px 10px; border-radius: 8px; background: var(--hover);
  font-size: 11.5px; line-height: 1.55; color: var(--muted); word-break: break-word;
}
.bugrep-where .bugrep-tech strong { color: var(--text); font-weight: var(--fw-semibold); }
@media (prefers-reduced-motion: reduce) { .bugrep-chip { transition: none; } }

/* the ＋ menu (compact modal) */
.modal-body.quick-add { display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
.qa-item {
  display: flex; align-items: center; gap: 13px; width: 100%; text-align: left;
  padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--panel); cursor: pointer; font: inherit; transition: all .1s ease;
}
.qa-item:hover { border-color: var(--accent); background: var(--accent-soft); }
.qa-item .qa-ico { font-size: var(--fs-h1); line-height: 1; flex: 0 0 auto; }
.qa-item .qa-text { display: flex; flex-direction: column; }
.qa-item .qa-label { font-weight: var(--fw-bold); font-size: var(--fs-body); }
.qa-item .qa-sub { font-size: var(--fs-meta); color: var(--muted); }

/* quick-note client picker */
.qn-chosen { font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--ok); margin-top: 5px; }
.qn-drop {
  margin-top: 5px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--panel); box-shadow: var(--shadow); max-height: 220px; overflow-y: auto;
}
.qn-opt {
  display: flex; flex-direction: column; gap: 1px; width: 100%; text-align: left;
  padding: 8px 11px; border: none; border-bottom: 1px solid var(--border);
  background: transparent; cursor: pointer; font: inherit;
}
.qn-opt:last-child { border-bottom: none; }
.qn-opt:hover { background: var(--accent-soft); }
.qn-opt .qn-opt-name { font-weight: var(--fw-semibold); font-size: var(--fs-caption); }
.qn-opt .qn-opt-sub { font-size: 11.5px; color: var(--muted); }
.qn-head { font-size: 10.5px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .5px; color: var(--faint); padding: 7px 11px 3px; }

/* SPEC39 — type-ahead job/client picker */
.linkpick { position: relative; }
.linkpick .qn-drop { position: absolute; left: 0; right: 0; z-index: 30; margin-top: 2px; }
.linkpick-chosen { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 9px 11px; border: 1px solid var(--accent); border-radius: var(--radius-sm); background: var(--accent-soft); font-size: var(--fs-caption); font-weight: var(--fw-semibold); }

/* ⌘K palette: new "action" + "view" row types */
.qs-type-action { background: var(--accent); color: #fff; }
.qs-type-view { background: var(--accent); color: #fff; }

/* on phones the FAB sits a touch inward so it clears the collapsed rail, and
   respects the iPhone home-indicator safe area */
@media (max-width: 640px) {
  .quick-add-fab {
    right: 16px; bottom: calc(16px + env(safe-area-inset-bottom, 0px));
    width: 56px; height: 56px; font-size: 30px;
  }
}

/* ============ SPEC32 — mobile / touch polish (field shooters on phones) ============
   The sidebar becomes a LABELED off-canvas drawer ≤860px (SPEC86 — no more bare-icon
   rail; comment corrected DESIGNA 2026-08-19). These rules make
   the phone experience genuinely touch-first: 44px+ tap targets, sheet-style modals,
   16px form fields (so iOS doesn't zoom on focus), momentum-scrolling tables, and a
   decluttered top rail. Desktop is untouched. */
@media (max-width: 640px) {
  /* never let the FAB cover the last row of content */
  #view { padding: 16px 13px calc(96px + env(safe-area-inset-bottom, 0px)); }

  /* top rail: smooth momentum scroll, no scrollbar, comfy tap targets */
  #sidebar { -webkit-overflow-scrolling: touch; scrollbar-width: none; gap: 2px; }
  #sidebar::-webkit-scrollbar { display: none; }
  /* DESIGNA 2026-08-19 — dropped justify-content:center: a leftover from the pre-SPEC86
     bare-icon rail that centred every LABELED drawer row against its own group labels. */
  .nav-item { min-width: 44px; min-height: 44px; padding: 11px; }
  .nav-item svg { width: 20px; height: 20px; flex-basis: 20px; }

  /* 16px form fields prevent iOS auto-zoom; roomier hit areas */
  /* SAFARI 07-30 — `.chat-input` was missing from this list, so the ONE input the team
     uses most (the chat composer, 14px) still triggered iOS auto-zoom on every tap while
     every other field was already protected. Same fix, same reason. */
  .input, .select, .textarea, .cell-input, .qs-input, .view-as-select, .chat-input { font-size: var(--fs-md); }
  .input, .select, .textarea { padding: 10px 12px; min-height: 44px; }
  textarea.textarea { min-height: 80px; }
  /* LAW-A 2026-08-15 (#24) — 42px and 40px were both under the 44px mobile tap-target
     floor this SAME file already documents on .btn-sm one line below (and enforces in
     32 other places — .input/.textarea/.select two lines up, .nav-item, etc). Raised
     both to close the gap; ~14 tap-target violations per screen clear on these two
     numbers alone. */
  .btn { min-height: 44px; padding: 9px 15px; font-size: var(--fs-body); }
  .btn-sm { min-height: 44px; }   /* SPEC-A11Y — was 36px, 8px under the 44px mobile touch-target floor used everywhere else (.input/.nav-item/SPEC202) */
  select.select, .table select { min-height: 44px; }

  /* checkboxes/radios: a real 44px tap catch-zone via an invisible ::after halo — not a
     bigger visual box (the glyph only grows to 20px; a 44px SQUARE glyph would read as
     decorative bulk next to 13px label text). Scoped off dense .table rows (bulk-select
     checkboxes): those run as tight as 1px vertical padding in compact table density
     (.density-compact), and a 44px zone centered on an 18-20px box would overlap the
     row above/below — a real miscl-ick risk, not a theoretical one. Table checkboxes
     still get the bigger 20px glyph above, just not the invisible expanded catch-zone. */
  input[type="checkbox"], input[type="radio"] { width: 20px; height: 20px; }
  input[type="checkbox"]:not(.table *), input[type="radio"]:not(.table *) { position: relative; }
  input[type="checkbox"]:not(.table *)::after, input[type="radio"]:not(.table *)::after {
    content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
    width: 44px; height: 44px;
  }
  /* LAW-A 2026-08-15 (#25) — a reusable version of the halo trick two rules up, for any
     small icon-only control that can't grow its own visual box (a chip's "×", a row's
     "⋯"). Apply class="tap" to the control itself (or a wrapper around it) to get an
     invisible centered 44×44 catch-zone without changing how it looks.
     Ships pre-wired for .jarvis-chip-x — the one flagged violation this closes
     (measured 13.1×14px at 375×812, permanent + destructive, "never show this again").
     CORRECTION 2026-08-15 (checker, LAW-A) — an earlier version of this comment claimed
     `.jarvis-chip` / `.jarvis-chip-x` had ZERO live call sites. THAT WAS WRONG. Both are
     live at dailybrief.js:146 and :205 (SPEC334's weekly Feature Spotlight chip and its
     forever-dismiss "✕"); the ✕ only renders when App.featureSpotlight() returns a card,
     which is why a grep-by-eye missed it. Verified live on Home at 375×812: the ✕ paints
     at 13.1×14 and this halo hit-tests as the ✕ out to ±22px from its centre. The
     aria-label the plan also asked for now ships at dailybrief.js:205.
     ⚠ KNOWN TRADE-OFF, measured: the 44×44 zone is centred on a ✕ that sits INSIDE its
     parent .jarvis-chip--spot button (315×58 there), so it now covers ~22px of the chip's
     own label. A tap in that strip dismisses the tip instead of opening the feature. That
     is the cost of the 44 floor on a control this small; the cleaner shape is a padded
     WRAPPER outside the chip, or a same-tap undo — flag for the next round. */
  .tap, .jarvis-chip-x { position: relative; }
  .tap::after, .jarvis-chip-x::after {
    content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
    width: 44px; height: 44px;
  }
  /* LAW-A 2026-08-15 (#26) — label.qc-check is the shooter's most-tapped control (×9 per
     job sheet's checklist). Effective height was ~29px (5px padding + a ~19px text line
     at --fs-caption/1.45 line-height) — under the 44px floor. padding 5px→11px per the
     plan; min-height:44px is the actual guarantee (padding math depends on font metrics
     this file can't fully control) — belt + suspenders, not a visual change beyond the
     padding bump. The row is a <label> wrapping the checkbox, so this whole box (not
     just the 20px glyph) is the real tap target.
     LIVE-VERIFIED CASCADE BUG, then fixed: a bare `.qc-check` here is (0,1,0), the SAME
     specificity as the base rule (styles.css, non-mobile), which sits LATER in the file
     and so won the padding tiebreak on source order — min-height still applied (the base
     rule never sets it, so there was no conflict there), but the padding silently stayed
     5px 2px. Built the real DOM shape checklistplay.js:120 creates and measured it via
     getBoundingClientRect to catch this. `.qc-check` is always applied to a <label>
     (checklists.js:83, checklistplay.js:114/120) so adding the tag raises this to
     (0,1,1), which reliably wins regardless of source order. */
  label.qc-check { padding: 11px 2px; min-height: 44px; }
  /* range: the visual track/thumb stay slim (restrained, matches desktop) — padding-block
     grows the drag CATCH area to ~44px tall without thickening the line itself */
  input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range) { padding-block: 19px; }
  input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range)::-webkit-slider-thumb { width: 22px; height: 22px; margin-top: -8px; }
  input[type="range"]:not(.order-ba-range):not(.cstatus-lb-rev-range)::-moz-range-thumb { width: 22px; height: 22px; }

  /* modals become full-screen sheets — far better for the long job/task forms */
  .modal-overlay { padding: 0; align-items: stretch; }
  .modal, .modal.wide {
    max-width: 100%; min-height: 100%; border-radius: 0;
    display: flex; flex-direction: column;
  }
  .modal-head { padding: calc(14px + env(safe-area-inset-top, 0px)) 18px 0; }
  .modal-body { flex: 1 1 auto; overflow-y: auto; -webkit-overflow-scrolling: touch; padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px)); }
  .modal-foot {
    position: sticky; bottom: 0; background: var(--panel); margin-top: auto;
    padding: 12px 18px calc(14px + env(safe-area-inset-bottom, 0px));
    border-top: 1px solid var(--border);
  }
  .modal-close { font-size: 26px; padding: 4px 10px; }

  /* tables: momentum scroll + a hair tighter so more fits before scrolling */
  .table-wrap { -webkit-overflow-scrolling: touch; }
  .table th, .table td { padding: 9px 10px; }

  /* toolbars wrap and breathe; pagers/segmented controls easier to thumb */
  .toolbar { gap: 7px; }
  /* LAW-A 2026-08-15 (#24 follow-up) — LIVE-VERIFIED GAP: this selector (.toolbar .btn,
     2 classes) beats the plain .btn rule above (1 class) regardless of source order, so
     the #24 fix silently never reached the highest-traffic buttons in the app — every
     list screen's own toolbar (Filters/Display/+New job measured at 40px, not 44px,
     via getBoundingClientRect at 375×812 before this line was found and fixed). */
  .toolbar .btn, .pager button { min-height: 44px; }

  /* two-up card grids go single-column for readability */
  .kpi-row { grid-template-columns: 1fr 1fr; }
}

/* WORLD-CLASS ④ — small phones keep KPI tiles TWO-UP for density (one giant metric
   per screenful was too sparse for field crew); tighten padding + numerals so two fit
   cleanly. Only the tiniest phones fall back to a single column. */
@media (max-width: 400px) {
  .kpi-row { grid-template-columns: 1fr 1fr; gap: 8px; }
  .kpi-card { padding: 12px 13px; }
  .kpi-value { font-size: 21px; }
}
@media (max-width: 330px) {
  .kpi-row { grid-template-columns: 1fr; }
}

/* ============ SPEC33 — consolidated admin tabs (parent sub-tabs) ============
   A segmented control under a parent tab (Home/Jobs/Clients/Growth/Library) that
   swaps between the existing child views. Quietly distinct from the dark sidebar
   nav so there's no "which level am I on" confusion. */
/* D9(b) — a persistent "Parent › Child" line ABOVE .subtabs, so a view can never
   render looking orphaned under a stale sub-tab bar (FRIDAY opened from anywhere
   reads "Business › FRIDAY" before .subtabs even paints). */
.crumb { font-size: 12px; color: var(--faint); text-transform: uppercase; letter-spacing: var(--ls-label); margin: 0 0 var(--space-2); }

.subtabs {
  display: flex; gap: 4px; flex-wrap: wrap; align-items: center;
  margin: 0 0 18px; padding-bottom: 12px; border-bottom: 1px solid var(--border);
}
.subtab {
  appearance: none; border: 1px solid transparent; background: transparent;
  color: var(--muted); font: inherit; font-size: 13.5px; font-weight: var(--fw-semibold);
  padding: 7px 14px; border-radius: 999px; cursor: pointer; white-space: nowrap;
  transition: background .12s, color .12s, border-color .12s;
}
.subtab:hover { background: var(--hover); color: var(--text); }
.subtab.active { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); }
.subtab-body { min-height: 40px; }

/* phones: let the segmented control scroll sideways instead of wrapping into a wall */
@media (max-width: 640px) {
  .subtabs {
    flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch;
    scrollbar-width: none; gap: 6px; margin-bottom: 14px;
  }
  .subtabs::-webkit-scrollbar { display: none; }
  .subtab { padding: 9px 15px; flex: 0 0 auto; min-height: 40px; }
}

/* ============ SPEC34 — SOP/Training role audience ============ */
/* "★ For you" section header — accented so the viewer's own docs stand out */
.doc-cat-foryou { color: var(--accent); font-weight: var(--fw-black); }
/* "Other roles" collapsible toggle in the SOP list */
.doc-cat-toggle { color: var(--faint); user-select: none; }
.doc-cat-toggle:hover { color: var(--text); }
/* audience picker (modal) */
.audience-picker { display: flex; flex-direction: column; gap: 4px; margin-top: 10px; }
.audience-opt {
  display: flex; align-items: center; gap: 10px; padding: 9px 11px;
  border: 1px solid var(--border); border-radius: var(--radius-sm); cursor: pointer; font-size: var(--fs-body);
}
.audience-opt:hover { background: var(--accent-soft); border-color: var(--accent); }
.audience-opt input { width: 17px; height: 17px; flex: 0 0 auto; accent-color: var(--accent); }

/* ============ SPEC35 — Shot List ============ */
.shotlist-rule {
  margin: 12px 0 4px; padding: 10px 13px; border-radius: var(--radius-sm);
  background: var(--accent-soft); color: var(--text); font-size: var(--fs-caption);
}
.shotlist-zone {
  margin: 18px 0 6px; font-size: 11.5px; font-weight: var(--fw-bold); text-transform: uppercase;
  letter-spacing: .5px; color: var(--muted);
}
.shot-row {
  display: flex; align-items: flex-start; gap: 12px; padding: 9px 4px;
  border-bottom: 1px solid var(--border);
}
.shot-row:last-child { border-bottom: none; }
.shot-num {
  flex: 0 0 auto; width: 24px; height: 24px; border-radius: 50%;
  background: var(--hover); color: var(--muted); font-size: var(--fs-meta); font-weight: var(--fw-bold);
  display: flex; align-items: center; justify-content: center; margin-top: 1px;
}
.shot-body { flex: 1; min-width: 0; }
.shot-name { font-weight: var(--fw-semibold); font-size: var(--fs-body); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.shot-core {
  font-size: 10px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .4px;
  color: var(--accent); background: var(--accent-soft); padding: 1px 7px; border-radius: 999px;
}
.shot-example { font-size: var(--fs-micro); font-weight: var(--fw-semibold); color: var(--accent); }

/* ============ SPEC42 — date-range bar + delta badges ============ */
.range-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 16px; }
.range-presets { display: inline-flex; gap: 2px; background: var(--bg-2); border-radius: 999px; padding: 3px; }
.range-preset {
  border: none; background: transparent; color: var(--muted); font: inherit; font-size: 12.5px; font-weight: var(--fw-semibold);
  padding: 5px 12px; border-radius: 999px; cursor: pointer; white-space: nowrap;
}
.range-preset:hover { color: var(--text); }
.range-preset.active { background: var(--panel); color: var(--accent); box-shadow: var(--shadow); }
.range-custom { display: inline-flex; align-items: center; gap: 6px; }
.range-custom .input { padding: 5px 8px; font-size: 12.5px; }
.range-label { font-size: var(--fs-meta); color: var(--muted); }
.delta { display: inline-flex; align-items: center; gap: 3px; font-size: var(--fs-meta); font-weight: var(--fw-bold); padding: 1px 7px; border-radius: 999px; white-space: nowrap; }
.delta.good { color: var(--ok); background: var(--ok-soft); }
.delta.bad { color: var(--danger); background: var(--danger-soft); }
.delta.flat { color: var(--muted); background: var(--hover); }
@media (max-width: 640px) {
  .range-presets { overflow-x: auto; max-width: 100%; }
}

/* SPEC43 — outreach day-sheet (spreadsheet-like inline editing) */
.day-sheet td { vertical-align: middle; padding: 4px 8px; }
.day-sheet .cell-bare { border: none !important; background: transparent !important; box-shadow: none !important; padding: 5px 6px; width: 100%; min-width: 90px; }
.day-sheet .cell-bare:focus { background: var(--accent-soft) !important; border-radius: 6px; }
.day-sheet td:nth-child(4) .cell-bare { min-width: 200px; }
.shot-detail { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.shot-actions { flex: 0 0 auto; display: flex; gap: 2px; }
.icon-btn {
  border: none; background: transparent; color: var(--faint); cursor: pointer;
  font-size: var(--fs-body); padding: 4px 7px; border-radius: 6px; line-height: 1;
}
.icon-btn:hover { background: var(--hover); color: var(--text); }
.shotlist-foot { margin-top: 16px; font-size: 12.5px; padding: 10px 12px; background: var(--subtle); border-radius: var(--radius-sm); }

/* per-job shot checklist (job modal) */
.jobshots-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.jobshots-progress { font-size: 12.5px; font-weight: var(--fw-bold); color: var(--accent); }
.jobshot {
  display: flex; align-items: flex-start; gap: 10px; padding: 7px 2px; cursor: pointer;
  border-bottom: 1px solid var(--border);
}
.jobshot:last-child { border-bottom: none; }
.jobshot input { width: 18px; height: 18px; flex: 0 0 auto; margin-top: 1px; accent-color: var(--ok); cursor: pointer; }
.jobshot.done .js-name { text-decoration: line-through; color: var(--muted); }
.js-name { font-size: 13.5px; font-weight: var(--fw-semibold); }
.js-detail { font-size: var(--fs-meta); color: var(--muted); margin-top: 1px; }

/* ============ SPEC36 — private "you're improving" QA trend card ============ */
.improve-card { display: flex; align-items: center; gap: 16px; margin-bottom: 16px; }
.improve-ring {
  flex: 0 0 auto; width: 62px; height: 62px; border-radius: 50%;
  display: flex; align-items: baseline; justify-content: center; gap: 1px;
  background: var(--accent-soft); border: 2px solid var(--accent);
}
.improve-ring.up { background: var(--ok-soft); border-color: var(--ok); }
.improve-ring.flat { background: var(--hover); border-color: var(--border-strong); }
.improve-score { font-size: var(--fs-h1); font-weight: var(--fw-black); color: var(--text); }
.improve-of { font-size: var(--fs-meta); font-weight: var(--fw-semibold); color: var(--muted); }
.improve-body { min-width: 0; }
.improve-title { font-weight: var(--fw-bold); font-size: 15px; display: flex; align-items: center; gap: 7px; }
.improve-arrow { font-size: var(--fs-caption); }
.improve-arrow.up { color: var(--ok); }
.improve-arrow.flat { color: var(--muted); }
.improve-line { font-size: var(--fs-caption); color: var(--text); margin-top: 2px; }
.improve-sub { font-size: 11.5px; color: var(--faint); margin-top: 3px; }

/* ============ SPEC155 — growth / coaching ============ */
.growth-node { display: flex; flex-direction: column; gap: 8px; }
.growth-signals { display: flex; flex-wrap: wrap; gap: 6px; }
.growth-chip { display: inline-flex; align-items: baseline; gap: 5px; padding: 3px 9px; border-radius: 999px;
  background: var(--subtle); border: 1px solid var(--border); font-size: var(--fs-meta); }
.growth-chip-k { color: var(--muted); font-size: var(--fs-micro); }
.growth-chip-v { font-weight: var(--fw-bold); }
.growth-group { display: flex; flex-direction: column; gap: 4px; }
.growth-group-title { font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--muted); }
.growth-item { display: flex; align-items: baseline; gap: 7px; font-size: var(--fs-caption); line-height: 1.4; }
.growth-item-text { flex: 1 1 auto; min-width: 0; }
.growth-tag { font-size: var(--fs-micro); flex: 0 0 auto; }
.growth-by { color: var(--faint); font-size: 11.5px; white-space: nowrap; flex: 0 0 auto; }
.growth-empty { font-size: 12.5px; line-height: 1.45; }
.growth-ai-card { margin-top: 8px; padding: 10px 12px; border-radius: var(--radius-sm);
  background: var(--accent-soft); border: 1px solid var(--accent); }
.growth-ai-label { font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--accent); margin-bottom: 4px; }
.growth-ai-text { font-size: var(--fs-caption); line-height: var(--lh-normal); white-space: pre-wrap; }
.growth-summary { cursor: pointer; font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--accent); user-select: none; }
.growth-details[open] .growth-summary { margin-bottom: 4px; }
@media (max-width: 760px) {
  .growth-compose .btn, .growth-ai .btn { min-height: 44px; }
}

/* ============ SPEC156 — video review (Frame.io-style) ============ */
/* library grid */
.review-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
.review-filters { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.review-fchip { padding: 5px 12px; border-radius: 999px; border: 1px solid var(--border); background: var(--panel);
  font-size: 12.5px; font-weight: var(--fw-semibold); cursor: pointer; color: var(--muted); }
.review-fchip:hover { background: var(--hover); }
.review-fchip.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.review-card { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; background: var(--panel);
  cursor: pointer; transition: transform .08s ease, box-shadow .12s ease; display: flex; flex-direction: column; }
.review-card:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,.12); }
.review-thumb { position: relative; aspect-ratio: 16/9; background: #11141c center/cover no-repeat;
  display: flex; align-items: center; justify-content: center; }
.review-thumb-ico { font-size: 38px; opacity: .65; }
.review-thumb-badge { position: absolute; left: 8px; bottom: 8px; font-size: var(--fs-micro); font-weight: var(--fw-bold); color: #fff;
  background: rgba(0,0,0,.6); padding: 2px 8px; border-radius: 999px; }
.review-card-body { padding: 12px; }
.review-card-title { font-weight: var(--fw-bold); font-size: var(--fs-body); line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* full-screen player overlay */
.review-overlay { position: fixed; inset: 0; z-index: 1000; display: flex; background: rgba(8,10,14,.92);
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }   /* SAFPOLISH 2026-08-25 D4 */
.review-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; position: relative; padding: 18px; gap: 12px; }
.review-close { position: absolute; top: 14px; right: 14px; z-index: 3; background: rgba(0,0,0,.5); color: #fff; border-color: transparent; }
.review-stage { flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; position: relative; }
.review-video { max-width: 100%; max-height: 100%; border-radius: 8px; background: #000; outline: none; }
.review-err { position: absolute; bottom: 12px; left: 12px; right: 12px; color: #fde68a; background: rgba(0,0,0,.7);
  padding: 10px 12px; border-radius: 8px; font-size: 12.5px; text-align: center; }
.review-transport { display: flex; align-items: center; gap: 10px; color: #e7e9ee; }
.review-play { min-width: 42px; font-size: var(--fs-body); }
.review-scrub-wrap { flex: 1 1 auto; min-width: 0; }
.review-scrub { position: relative; height: 16px; display: flex; align-items: center; cursor: pointer; touch-action: none; }
.review-scrub::before { content: ''; position: absolute; left: 0; right: 0; height: 5px; border-radius: 999px; background: rgba(255,255,255,.22); }
.review-scrub-fill { position: absolute; left: 0; height: 5px; border-radius: 999px; background: var(--accent); width: 0; }
.review-scrub-markers { position: absolute; left: 0; right: 0; top: 0; bottom: 0; }
.review-marker { position: absolute; top: 50%; transform: translate(-50%, -50%); width: 12px; height: 12px;
  border-radius: 50%; background: var(--warn); border: 2px solid #fff; cursor: pointer; padding: 0; }
.review-marker.resolved { background: var(--ok); opacity: .8; }
.review-marker:hover { transform: translate(-50%, -50%) scale(1.3); }
.review-tc-wrap { font-variant-numeric: tabular-nums; font-size: var(--fs-caption); white-space: nowrap; }
.review-tc { font-weight: var(--fw-bold); }
.review-tc.muted { color: rgba(255,255,255,.6); font-weight: var(--fw-medium); }

/* comments side panel */
.review-panel { flex: 0 0 360px; max-width: 40vw; background: var(--bg); border-left: 1px solid var(--border);
  display: flex; flex-direction: column; min-height: 0; }
.review-panel-head { padding: 16px; border-bottom: 1px solid var(--border); display: flex; gap: 10px; align-items: flex-start; justify-content: space-between; }
.review-title { font-weight: var(--fw-black); font-size: 15px; line-height: 1.3; overflow: hidden; text-overflow: ellipsis; }
.review-panel-sub { padding: 10px 16px; display: flex; align-items: center; gap: 8px; font-weight: var(--fw-bold); font-size: var(--fs-caption); border-bottom: 1px solid var(--border); }
.review-clist { flex: 1 1 auto; overflow-y: auto; padding: 8px 12px; }
.review-crow { padding: 10px; border-radius: var(--radius-sm); margin-bottom: 8px; background: var(--panel); border: 1px solid var(--border); }
.review-crow.resolved { opacity: .62; }
.review-crow.reply { margin: 6px 0 0 14px; background: var(--subtle); }
.review-crow-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; flex-wrap: wrap; }
.review-tcchip { font-variant-numeric: tabular-nums; font-weight: var(--fw-bold); font-size: var(--fs-meta); color: var(--accent);
  background: var(--accent-soft); border: 1px solid var(--accent); border-radius: 6px; padding: 1px 7px; cursor: pointer; }
.review-cby { font-weight: var(--fw-bold); font-size: 12.5px; }
.review-cago { font-size: 11.5px; }
.review-ctext { font-size: var(--fs-caption); line-height: 1.45; white-space: pre-wrap; word-break: break-word; }
.review-resolve { font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--muted); background: none; border: 1px solid var(--border);
  border-radius: 999px; padding: 2px 9px; cursor: pointer; }
.review-resolve.on { color: var(--ok); border-color: var(--ok); }
.review-crow-foot { margin-top: 6px; }
.review-replybtn { font-size: 11.5px; font-weight: var(--fw-semibold); color: var(--muted); background: none; border: none; cursor: pointer; padding: 0; }
.review-replyin { margin-top: 6px; }
.review-compose { padding: 12px 16px; border-top: 1px solid var(--border); }
.review-note { width: 100%; resize: vertical; }
.review-capture { font-variant-numeric: tabular-nums; font-weight: var(--fw-bold); font-size: var(--fs-meta); color: var(--accent);
  background: var(--accent-soft); border-radius: 6px; padding: 2px 8px; }

/* P2 — frame drawing */
.review-canvas { position: absolute; pointer-events: none; z-index: 2; touch-action: none; }   /* draw, don't scroll the page on touch */
.review-palette { position: absolute; top: 10px; left: 10px; z-index: 4; display: flex; flex-direction: column; gap: 6px;
  background: rgba(18,20,28,.92); border: 1px solid rgba(255,255,255,.15); border-radius: 10px; padding: 8px; }
.review-palette-row { display: flex; gap: 6px; }
.review-tool { width: 30px; height: 30px; border-radius: 7px; border: 1px solid rgba(255,255,255,.18); background: rgba(255,255,255,.06);
  color: #fff; font-size: var(--fs-body); cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; }
.review-tool.on { background: var(--accent); border-color: var(--accent); }
.review-swatch { width: 24px; height: 24px; border-radius: 50%; border: 2px solid rgba(255,255,255,.35); cursor: pointer; padding: 0; }
.review-swatch.on { border-color: #fff; box-shadow: 0 0 0 2px var(--accent); }
.review-drawtoggle.on { background: var(--accent); color: #fff; border-color: var(--accent); }
.review-hasdraw { font-size: var(--fs-meta); flex: 0 0 auto; }
/* P3 — versions */
.review-vers { display: flex; align-items: center; gap: 8px; }

/* ---- P5 client/internal split + visual polish ---- */
.review-marker { transition: transform .12s ease, background .15s ease; }
.review-marker.client { background: #ff7a3d; }
.review-marker.client.resolved { background: var(--ok); }   /* resolved wins over the client tint */
.review-scrub-fill { transition: width .06s linear; }
.review-play, .review-tcchip, .review-resolve, .review-tool, .review-swatch, .review-drawtoggle, .review-marker, .review-fchip { transition: background .15s ease, color .15s ease, transform .1s ease, box-shadow .15s ease; }
.review-tcchip:hover { transform: translateY(-1px); }
.review-resolve:hover { background: var(--hover); }
.review-crow { animation: reviewIn .22s cubic-bezier(.2,.7,.3,1) both; }
@keyframes reviewIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.review-card { animation: reviewIn .22s cubic-bezier(.2,.7,.3,1) both; }
.btn.pop { animation: reviewPop .24s ease; }
@keyframes reviewPop { 0%{transform:scale(1)} 40%{transform:scale(.93)} 100%{transform:scale(1)} }
.review-clientbadge { font-size: 10.5px; font-weight: var(--fw-black); color: #c2410c; background: rgba(255,122,61,.16);
  border: 1px solid rgba(255,122,61,.4); border-radius: 999px; padding: 1px 7px; flex: 0 0 auto; }
.review-crow.client { border-left: 3px solid #ff7a3d; }
.review-brandline { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--accent); margin-bottom: 4px; }
.review-empty-notes { text-align: center; padding: 28px 14px; }
.review-empty-ico { font-size: 30px; margin-bottom: 8px; opacity: .8; }

/* client mode: cleaner, brand-forward, bigger touch targets, calmer chrome */
.review-client .review-panel { background: var(--panel); }
.review-client .review-panel-head { padding: 18px 16px; }
.review-client .review-title { font-size: 17px; }
.review-client .review-note { min-height: 64px; font-size: var(--fs-body); }
.review-client .review-compose .btn-primary { padding: 9px 18px; font-weight: var(--fw-bold); font-size: 13.5px; }
.review-client .review-marker { width: 14px; height: 14px; }
.review-client .review-drawtoggle { font-size: 12.5px; }
.review-client .review-tcchip { font-size: 12.5px; padding: 2px 9px; }

@media (max-width: 860px) {
  .review-overlay { flex-direction: column; }
  /* STAGE1 2026-08-14 (design item 7 / G1, parity-frameio.md) — MEASURED DEFECT: at
     375×812 with a 9:16 (540×960) source, .review-main refused to shrink (705px of a
     812px column) and the panel was squeezed to 107px, collapsing the comments list to
     16px holding 1022px of content. Root cause is the classic flex trap: a column-flex
     item's default min-height is `auto` (= its content's intrinsic min size), and a
     tall vertical <video> pushes that intrinsic size past the space .review-panel's
     44vh cap actually leaves it — `flex:1 1 auto` alone can shrink BELOW content only
     once min-height:0 removes that floor. `.review-stage` already had it (line ~2324);
     `.review-main` — one level up the same chain — did not. Every deliverable in scope
     is 9:16 and agents review on phones, so this is the one G1 blocker. Two-part fix,
     both needed: min-height:0 lets main actually shrink to the space the panel's cap
     leaves it; the video's own max-height stops it from RE-forcing that same fight the
     next time content changes (belt + suspenders, not redundant — the min-height fix
     alone still lets a giant intrinsic size win a shrink/grow tug-of-war before layout
     settles on some runs). */
  .review-main { flex: 1 1 auto; padding: 10px; min-height: 0; }
  .review-video { max-height: 46vh; }
  /* SECOND defect, same root symptom, found live-testing the fix above (a real
     540×960 blob loaded into the player, not just measured statically): with main
     correctly shrinking now, .review-panel gets its full intended 357px (44vh @
     812px) — but panel-head + panel-sub + the comments list + the compose block
     (audience row, draw/attach/emoji controls, textarea) TOGETHER measured 484px,
     and `.review-panel` itself had no overflow rule (only `.review-clist` did), so
     the extra 128px spilled silently past the fixed, non-scrolling `.review-overlay`
     — the compose textarea and Send button sat off-screen and unreachable, same
     "composer sat below the fold" symptom the audit named, just no longer masked by
     the bigger main-shrinking bug. Making the panel itself the scroll container (the
     clist's own overflow-y:auto still applies inside it, redundant but harmless)
     guarantees every control stays reachable regardless of how tall the compose
     block gets on a narrow screen. */
  .review-panel { flex: 0 0 auto; max-width: none; max-height: 44vh; overflow-y: auto; border-left: none; border-top: 1px solid var(--border); }
  .review-transport .btn { min-height: 40px; }
  .review-tool { width: 40px; height: 40px; }     /* 44px-ish touch targets on phones */
  .review-swatch { width: 34px; height: 34px; }
}

/* ============ SPEC37 — Team Chat ============ */
.nav-badge {
  margin-left: auto; min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px;
  background: #475569; color: #fff; font-size: var(--fs-micro); font-weight: var(--fw-bold); line-height: 18px;
  text-align: center; flex: 0 0 auto;
}
.nav-badge.mention { background: var(--danger); }

.chat-layout { display: flex; gap: 16px; height: calc(100vh - 104px); height: calc(100dvh - 104px); min-height: 420px; }
.chat-rail {
  flex: 0 0 210px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px;
  border-right: 1px solid var(--border); padding-right: 8px;
}
.chat-rail-head {
  font-size: 10.5px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .6px;
  color: var(--faint); margin: 14px 8px 4px;
}
.chat-ch {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  padding: 7px 10px; border: none; background: transparent; border-radius: 7px;
  cursor: pointer; font: inherit; font-size: 13.5px; color: var(--text);
}
.chat-ch:hover { background: var(--hover); }
.chat-ch.active { background: var(--accent-soft); color: var(--accent); font-weight: var(--fw-semibold); }
/* VISUAL 07-30 — an unread channel now reads as unread from weight alone, not just the
   count pill (Slack's cue). Read channels sit back so the unread ones come forward. */
.chat-ch.has-unread .chat-ch-label { font-weight: var(--fw-bold); color: var(--text); }
.chat-ch-av { flex: 0 0 auto; }
.chat-ch svg { flex: 0 0 auto; opacity: .75; }
.chat-ch-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-ch-badge { background: var(--danger); color: var(--on-danger); font-size: 10.5px; font-weight: var(--fw-bold); border-radius: 999px; min-width: 17px; height: 17px; line-height: 17px; text-align: center; padding: 0 5px; }
.chat-add { color: var(--muted); }

.chat-main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.chat-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding-bottom: 10px; border-bottom: 1px solid var(--border); margin-bottom: 4px;
}
.chat-head-title { font-size: var(--fs-md); font-weight: var(--fw-bold); }
/* SLACK-M 2026-08-13 — base state is OFF, unscoped (desktop never sees this button,
   full stop — no media query means no chance of it). Turned on ONLY inside the
   ≤760px query below, and only for .m-convo (chat.js) — see that block. */
.chat-back-btn { display: none; }
.chat-status { font-size: 11.5px; font-weight: var(--fw-semibold); padding: 3px 9px; border-radius: 999px; white-space: nowrap; }
.chat-status.live { background: var(--ok-soft); color: var(--ok); }
/* CHATSTATUS-2026-08-10 — "sync healthy, realtime just isn't instant" is a GOOD state
   and must read as one: same green family as .live, distinguished by wording + tooltip
   (App.chatStatusSignal), not by a duller color that would look like a lesser status. */
.chat-status.ok { background: var(--ok-soft); color: var(--ok-ink); }
.chat-status.wait { background: var(--warn-soft); color: var(--warn); }
/* a REAL problem (erroring pushes, or too long since the last successful sync) —
   distinct from .wait's "in progress, nothing to worry about" amber. */
.chat-status.warn { background: var(--danger-soft); color: var(--danger-ink); }
.chat-status.off { background: var(--hover); color: var(--muted); }

.chat-list { flex: 1; overflow-y: auto; display: flex; flex-direction: column; padding: 10px 4px; gap: 2px; }
.chat-msg { display: flex; gap: 10px; padding: 3px 6px; border-radius: 8px; position: relative; }
.chat-msg:hover { background: var(--subtle); }
.chat-msg:hover .chat-msg-reply { opacity: 1; }
.chat-msg.mentions-me { background: var(--warn-soft); box-shadow: inset 3px 0 0 var(--warn); }
.chat-av {
  flex: 0 0 auto; width: 34px; height: 34px; border-radius: 50%; color: #fff;
  display: flex; align-items: center; justify-content: center; font-size: var(--fs-meta); font-weight: var(--fw-bold); margin-top: 2px;
}
.chat-av-spacer { flex: 0 0 34px; }
.chat-msg-body { flex: 1; min-width: 0; }
.chat-msg-meta { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.chat-author { font-weight: var(--fw-bold); font-size: 13.5px; }
.chat-role { font-size: 10.5px; color: var(--muted); background: var(--hover); padding: 0 6px; border-radius: 999px; }
.chat-time { font-size: var(--fs-micro); color: var(--faint); }
/* VISUAL 07-30 — the reply quote was a hairline + muted text and read as throwaway.
   Treated as a real quoted block (tinted ground, accent rule) the way Basecamp and
   Whop do, so a reply's context is legible at a glance instead of scanned for. */
.chat-quote {
  font-size: var(--fs-meta); color: var(--muted); line-height: var(--lh-snug);
  border-left: 3px solid color-mix(in srgb, var(--accent) 55%, var(--border));
  background: color-mix(in srgb, var(--accent) 7%, transparent);
  padding: 5px 10px; margin: 3px 0 5px; border-radius: 0 7px 7px 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-text { font-size: 13.5px; line-height: 1.45; word-wrap: break-word; overflow-wrap: anywhere; }
.chat-text a { color: var(--accent); }
.chat-mention { background: var(--accent-soft); color: var(--accent); font-weight: var(--fw-semibold); border-radius: 4px; padding: 0 3px; }
.chat-msg-reply { position: absolute; top: 4px; right: 6px; opacity: 0; border: none; background: var(--panel); box-shadow: var(--shadow); border-radius: 6px; cursor: pointer; font-size: var(--fs-caption); padding: 2px 7px; transition: opacity .1s; }

.chat-composer { border-top: 1px solid var(--border); padding-top: 10px; }
.chat-replybar { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: var(--fs-meta); padding: 6px 10px; background: var(--hover); border-radius: 7px; margin-bottom: 6px; }
.chat-reply-x { border: none; background: transparent; cursor: pointer; color: var(--muted); font-size: var(--fs-caption); }
.chat-composer-row { display: flex; gap: 8px; align-items: flex-end; }
.chat-input {
  flex: 1; resize: none; border: 1px solid var(--border-strong); border-radius: var(--radius-sm);
  padding: 10px 12px; font: inherit; font-size: var(--fs-body); max-height: 140px; min-height: 42px; outline: none;
}
.chat-input:focus { border-color: var(--accent); box-shadow: var(--focus-ring-soft); }
/* DESIGNA 2026-08-19 — TRAP: the base `.chat-input` rule above is (0,1,0), the SAME
   specificity as the SAFARI 07-30 anti-zoom list near the top of the ≤640 block (~:2150),
   and it sits LATER in the file — media queries add no specificity, so its 14px silently
   won on phones and iOS zoomed on every chat message again. Any ≤640 font-size for
   .chat-input must live BELOW the base rule (here), or the fix dies the same death. */
@media (max-width: 640px) { .chat-input { font-size: var(--fs-md); } }
.chat-send { flex: 0 0 auto; height: 42px; }

/* SLACK-M 2026-08-13 — mobile Chat becomes Slack's list-first pattern: LIST (the
   rail, full-width/full-height, vertically scrolling) or CONVO (chat-main), never
   both, never a horizontal strip. chat.js keeps exactly one of .m-list/.m-convo on
   .chat-layout at all times; EVERY rule below is scoped inside THIS media query so
   the classes are inert on desktop (≥761px) — the side-by-side rail+main is byte-
   identical to before, unchanged.
   REPLACES the old broken block: it flipped .chat-rail to flex-direction:row +
   overflow-x:auto (a horizontal strip) while `.chat-ch { width: 100% }` (the base
   rule above) still applied — so every chip rendered at full VIEWPORT width.
   Measured live: 7 chips at x = 14, 367, 720, 1073…, one visible, six off-screen,
   zero hint more existed. It also set `.chat-rail-head { display: none }` and
   `.chat-add { display: none }`, hiding the "Channels"/"Direct messages" section
   heads AND both "＋ New channel" and "＋ Browse channels" rows. Net effect
   (Vincent's exact report): mobile chat stuck on #general, no DMs, no switching.
   None of that hiding is needed anymore — deleting the override rules restores
   .chat-rail to its own BASE flex-direction:column layout above, which is exactly
   a vertical list; `.chat-ch { width: 100% }` (the very rule that broke the old
   strip) is exactly correct for a full-width list row. */
@media (max-width: 760px) {
  .chat-layout { height: calc(100vh - 150px); height: calc(100dvh - 150px); }

  /* the rail becomes the LIST screen: full width/height instead of a fixed 210px
     sidebar column. Its own internal layout (column, scrolling, section heads,
     rows) is untouched — this only changes .chat-rail's OWN size within the row
     .chat-layout still is. */
  .m-list .chat-rail { flex: 1 1 auto; border-right: none; padding-right: 0; }
  .m-list .chat-main { display: none; }
  .m-convo .chat-rail { display: none; }
  /* .chat-main already gets `display:flex; flex:1` from its own base rule once
     .m-list's display:none above no longer matches — no .m-convo override needed. */

  /* ≥44px touch target, full width — was fighting the row-strip parent before;
     now it IS the list. */
  .chat-ch { min-height: 44px; }

  /* back control — CONVO screen only, left of the header (chat.js prepends it as
     .chat-head's first child). D8 below (MOBILE HEAD BUDGET) gives the channel
     name flex:1 1 100% — its own full line — because an earlier attempt squeezing
     FOUR controls onto one line measured the title at 0px wide. This is a single
     small, fixed-width sibling ahead of it, not four, so sharing line 1 is safe;
     .m-convo's extra class beats D8's plain .chat-head-title on specificity
     regardless of which rule appears later in the file. */
  .m-convo .chat-back-btn {
    display: inline-flex; align-items: center; gap: 2px; flex: 0 0 auto;
    min-height: 44px; padding: 6px 6px 6px 0; margin-right: 2px;
    border: none; background: transparent; cursor: pointer; color: var(--accent);
    font: inherit; font-weight: var(--fw-semibold); font-size: var(--fs-body);
  }
  .m-convo .chat-head-title { flex: 1 1 auto; }

  /* DISCOVERY-C5a (2026-08-13) — the page above .chat-layout keeps ~76px of scroll
     slack at 375×812, so the CONVO header (and its “‹ Chats” back control) slid up
     UNDER the fixed #mobile-topbar (hit-test-proven: elementFromPoint over the back
     control returned mt-burger at scrollY≥52 — rects can't see occlusion, trap 11).
     Stick the header just below the topbar instead: 52px + safe-area matches
     #mobile-topbar's own height rule, background paints over messages scrolling
     beneath, z-index sits above chat content but far below the topbar (50 is the
     topbar's own layer; 5 is plenty here since they never overlap once stuck).
     THE LOAD-BEARING PAIR: sticky binds to the NEAREST scrollable ancestor, and
     #main (overflow-y:auto, its base rule) is one — but on a phone the 76px slack
     lives on the WINDOW (body scrollHeight > viewport), so a #main-bound sticky
     rides straight under the topbar with the page (measured live: headTop 32 at
     scrollY 76). Releasing #main's overflow on the mobile CHAT view only makes the
     window the nearest scrollport, which is the scroll that actually happens here;
     .chat-list keeps its own internal overflow-y:auto untouched, and every other
     view keeps #main exactly as it was. */
  body[data-view="chat"] #main { overflow-y: visible; }
  .m-convo .chat-head {
    position: sticky; top: calc(52px + env(safe-area-inset-top, 0px));
    z-index: 5; background: var(--bg);
  }
}

/* ---- SPEC37.A — chat attachments, reactions, emoji, composer tools ---- */
.chat-msg-actions { position: absolute; top: 2px; right: 6px; display: flex; gap: 2px; opacity: 0; transition: opacity .1s; }
.chat-msg:hover .chat-msg-actions { opacity: 1; }
.chat-msg-act { border: 1px solid var(--border); background: var(--panel); box-shadow: var(--shadow); border-radius: 6px; cursor: pointer; font-size: var(--fs-caption); padding: 2px 7px; }
.chat-msg-act:hover { background: var(--hover); }

.chat-jobcard {
  display: flex; align-items: center; gap: 10px; margin: 6px 0; padding: 9px 11px; max-width: 380px;
  border: 1px solid var(--border); border-left: 3px solid var(--accent); border-radius: var(--radius-sm);
  background: var(--subtle); cursor: pointer;
}
.chat-jobcard:hover { background: var(--accent-soft); }
.chat-jobcard-ico { font-size: var(--fs-md); }
.chat-jobcard-body { flex: 1; min-width: 0; }
.chat-jobcard-addr { font-weight: var(--fw-semibold); font-size: var(--fs-caption); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-jobcard-sub { font-size: 11.5px; color: var(--muted); }

.chat-imgs { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0; }
.chat-img { max-width: 240px; max-height: 200px; border-radius: 8px; border: 1px solid var(--border); cursor: pointer; object-fit: cover; }
.chat-file { display: inline-flex; align-items: center; gap: 6px; margin: 4px 6px 4px 0; padding: 6px 10px; border: 1px solid var(--border); border-radius: 7px; font-size: 12.5px; background: var(--subtle); }

.chat-reactions { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 5px; }
.chat-react { border: 1px solid var(--border); background: var(--panel); border-radius: 999px; padding: 1px 9px; font-size: 12.5px; cursor: pointer; }
.chat-react:hover { background: var(--hover); }
.chat-react.mine { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); font-weight: var(--fw-semibold); }

/* SPEC40 — private-channel member picker */
.chan-members { display: flex; flex-direction: column; gap: 4px; max-height: 240px; overflow-y: auto; margin-top: 8px; padding: 4px; border: 1px solid var(--border); border-radius: var(--radius-sm); }

.chat-tool { flex: 0 0 auto; border: 1px solid var(--border-strong); background: var(--panel); border-radius: var(--radius-sm); cursor: pointer; font-size: 17px; width: 42px; height: 42px; line-height: 1; }
.chat-tool:hover { background: var(--hover); }
.chat-pending { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: var(--fs-meta); padding: 6px 10px; background: var(--accent-soft); color: var(--accent); border-radius: 7px; margin-bottom: 6px; }

.emoji-pop {
  position: fixed; z-index: 300; display: grid; grid-template-columns: repeat(6, 1fr); gap: 2px;
  background: var(--panel); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow-lg);
  padding: 8px; width: 248px;
}
.emoji-btn { border: none; background: transparent; cursor: pointer; font-size: 19px; padding: 5px; border-radius: 6px; }
.emoji-btn:hover { background: var(--hover); }

@media (max-width: 640px) {
  .chat-msg-actions { opacity: 1; }
  .chat-tool { width: 44px; height: 44px; }
}

/* ---- SPEC37.B — file upload (pending tray + drag state) ---- */
.chat-pending { display: flex; flex-wrap: wrap; gap: 6px; }
.chat-pend-chip { display: inline-flex; align-items: center; gap: 6px; background: var(--accent-soft); color: var(--accent); font-size: var(--fs-meta); padding: 4px 6px 4px 10px; border-radius: 999px; }
.chat-pend-chip.uploading { background: var(--hover); color: var(--muted); }
.chat-main.chat-drag { outline: 2px dashed var(--accent); outline-offset: -6px; border-radius: var(--radius); background: var(--accent-soft); }

/* ---- SPEC44 — Slack-style threads ---- */
/* "N replies" pill under a root message in the main feed */
.chat-thread-link {
  display: inline-flex; align-items: center; gap: 8px; margin: 6px 0 2px;
  padding: 4px 12px 4px 6px; border: 1px solid var(--border); background: var(--panel);
  border-radius: 999px; cursor: pointer; font: inherit; color: var(--accent); font-weight: var(--fw-semibold); font-size: 12.5px;
}
.chat-thread-link:hover { background: var(--accent-soft); border-color: var(--accent); }
.chat-thread-avs { display: inline-flex; }
.chat-thread-avs .chat-av { width: 22px; height: 22px; font-size: 9px; margin-top: 0; margin-right: -7px; border: 2px solid var(--panel); }
.chat-thread-avs .chat-av:last-child { margin-right: 0; }
.chat-thread-count { white-space: nowrap; }
.chat-thread-last { color: var(--faint); font-weight: var(--fw-medium); }

/* the docked thread panel (3rd flex column inside .chat-layout) */
.chat-thread {
  flex: 0 0 360px; min-width: 0; display: flex; flex-direction: column;
  border-left: 1px solid var(--border); padding-left: 14px;
}
.chat-thread-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding-bottom: 10px; border-bottom: 1px solid var(--border); margin-bottom: 4px;
}
.chat-thread-title { display: flex; align-items: baseline; gap: 8px; }
.chat-thread-title strong { font-size: 15px; }
.chat-thread-sub { font-size: var(--fs-meta); color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-thread-list { flex: 1; overflow-y: auto; display: flex; flex-direction: column; padding: 10px 4px; gap: 2px; }
.chat-thread-divider {
  display: flex; align-items: center; gap: 10px; margin: 8px 2px 4px;
  font-size: 11.5px; font-weight: var(--fw-semibold); color: var(--faint); text-transform: uppercase; letter-spacing: .4px;
}
.chat-thread-divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.chat-thread-composer { margin-top: 4px; }
/* the root message sits visually apart at the top of the thread */
.chat-thread-list > .chat-msg:first-child { background: var(--subtle); border-radius: 8px; }

@media (max-width: 1100px) {
  /* Below ~1100px there isn't room for a 3rd docked column without crushing the
     message feed to a sliver (rail 210 + thread 360 + gaps + sidebar leaves <200px
     for .chat-main). So the thread becomes a full-screen overlay here, same as phones.
     z-index 90 sits above app chrome + the +FAB (60) but BELOW modals (100), toasts
     (200), command palette (250) and login (300) — so a job-card modal opened from
     inside a thread still paints on top instead of hiding behind the overlay. */
  .chat-thread {
    position: fixed; inset: 0; z-index: 90; flex: 1 1 auto;
    background: var(--panel); border-left: none; padding: 12px 14px 14px;
    box-shadow: var(--shadow-lg);
  }
}

/* ============ SPEC46 — shooter Field job sheet (phone-first) ============ */
.field-wrap { max-width: 640px; }

/* SPEC238 — Sun mode: a scoped high-contrast skin for shooting in bright sunlight. Forces
   a bright, max-contrast palette + bigger/bolder type + larger targets, regardless of the
   app's light/dark theme. Redefining the theme vars on the container cascades cleanly to
   every card/button/text inside without touching the rest of the app. */
.field-wrap.field-sun {
  --card: #ffffff; --panel: #ffffff; --bg: #ffffff;
  --text: #000000; --muted: #1f2937; --faint: #334155;
  --border: #475569; --hover: #f1f5f9;
  background: #ffffff; color: #000000; border-radius: 14px;
  padding: 12px 12px 28px; font-size: var(--fs-md); box-shadow: 0 0 0 2px #0f172a;
}
.field-wrap.field-sun .view-sub,
.field-wrap.field-sun .muted,
.field-wrap.field-sun .faint { color: #1f2937 !important; }
.field-wrap.field-sun .card,
.field-wrap.field-sun .field-card { border: 2px solid #475569; background: #ffffff; }
.field-wrap.field-sun .card-title { color: #000000; font-weight: var(--fw-black); }
.field-wrap.field-sun .field-addr { font-size: 25px; color: #000000; }
.field-wrap.field-sun .field-line,
.field-wrap.field-sun .field-meta { font-size: 14.5px; color: #111827; }
.field-wrap.field-sun .btn { min-height: 48px; font-size: 15px; font-weight: var(--fw-bold); border-width: 2px; }
.field-sun-btn { min-height: 44px; }   /* SPEC238 a11y — ≥44px touch target for the field toggle */
/* SPEC-A11Y — removed the `.field-wrap.field-sun .btn-sm.field-sun-btn { min-height: 0; }`
   override that used to collapse the toggle back below 44px the instant sun mode turned on
   (higher specificity than both the 44px rule above and the general 48px sun-mode .btn rule
   below). Now the toggle just falls through to `.field-wrap.field-sun .btn` like every other
   button in sun mode, so it grows to 48px instead of shrinking. */
.field-wrap.field-sun .btn-primary { box-shadow: 0 0 0 1px #1e1b4b; }
.field-wrap.field-sun .field-svc { border-top: 2px solid #475569; }
.field-wrap.field-sun .field-svc-name { font-size: 15px; font-weight: var(--fw-bold); color: #000000; }
.field-wrap.field-sun .select,
.field-wrap.field-sun .input,
.field-wrap.field-sun .textarea { border: 2px solid #475569; color: #000000; background: #ffffff; min-height: 44px; }
.field-wrap.field-sun .field-date-chip,
.field-wrap.field-sun .field-pick { border-color: #475569; }

/* SPEC239 — "Prep for field" pre-cache button */
.field-prep-wrap { margin: 0 0 12px; }
.field-prep-btn { width: 100%; justify-content: center; min-height: 42px; font-weight: var(--fw-bold); }
.field-wrap.field-sun .field-prep-btn { min-height: 48px; }
/* CHECKER FIX 2026-08-15 (LAW-A, §J.4 #24 completion) — `.field-prep-btn` above is
   (0,1,0), the SAME specificity as the phone `.btn { min-height:44px }` rule at
   ~:2119, and it sits LATER in the file, so it won the tiebreak and this button
   still measured 42px on a phone after #24 landed (getBoundingClientRect at
   375x812 on the Field screen: 347x42). Same class of miss #24's own follow-up
   already caught for `.toolbar .btn`. Phone-scoped so the desktop pill is
   unchanged; Sun mode's (0,3,0) 48px rule above still wins by specificity. */
@media (max-width: 640px) { .field-prep-btn { min-height: 44px; } }

.field-picker {
  display: flex; gap: 8px; overflow-x: auto; padding: 2px 2px 10px; margin-bottom: 4px;
  -webkit-overflow-scrolling: touch;
}
.field-pick {
  flex: 0 0 auto; display: flex; flex-direction: column; gap: 2px; align-items: flex-start;
  padding: 8px 12px; border: 1px solid var(--border); background: var(--panel);
  border-radius: var(--radius-sm); cursor: pointer; font: inherit; min-width: 120px; max-width: 200px;
}
.field-pick:hover { background: var(--hover); }
.field-pick.active { border-color: var(--accent); background: var(--accent-soft); }
.field-pick-date { font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--accent); text-transform: uppercase; letter-spacing: .4px; }
.field-pick.active .field-pick-date { color: var(--accent); }
.field-pick-addr { font-size: 12.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 176px; }

.field-sheet { display: flex; flex-direction: column; gap: 12px; }
.field-card { padding: 16px; }
.field-date-chip {
  display: inline-block; font-size: 11.5px; font-weight: var(--fw-bold); color: var(--accent);
  background: var(--accent-soft); border-radius: 999px; padding: 3px 10px; margin-bottom: 8px;
}
.field-addr { font-size: 21px; font-weight: var(--fw-black); line-height: 1.25; }
.field-meta { font-size: var(--fs-caption); color: var(--muted); margin-top: 6px; }
.field-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 4px; }
.field-actions .btn { min-height: 44px; }
.field-map { flex: 1; min-width: 160px; }
.field-line { font-size: var(--fs-caption); color: var(--text); margin-top: 8px; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.field-line.muted { color: var(--muted); }

.field-overall { font-size: 12.5px; font-weight: var(--fw-semibold); color: var(--muted); margin-bottom: 8px; }
.field-svc { border-top: 1px solid var(--border); padding: 10px 0; }
.field-svc:first-of-type { border-top: none; padding-top: 0; }
.field-svc-main { display: flex; align-items: center; gap: 10px; }
.field-svc-dot { flex: 0 0 auto; width: 12px; height: 12px; border-radius: 50%; background: var(--faint); }
.field-svc-name { flex: 1; min-width: 0; font-size: var(--fs-body); font-weight: var(--fw-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.field-svc-sel { flex: 0 0 auto; min-height: 38px; max-width: 150px; }
.field-svc-cmt {
  flex: 0 0 auto; border: 1px solid var(--border); background: var(--panel); border-radius: var(--radius-sm);
  cursor: pointer; font-size: var(--fs-caption); padding: 7px 10px; min-height: 38px; color: var(--muted);
}
.field-svc-cmt.has { color: var(--accent); border-color: var(--accent); background: var(--accent-soft); font-weight: var(--fw-semibold); }
.field-svc-cmt:hover { background: var(--hover); }
.field-cmt-panel { margin: 8px 0 2px; padding: 10px; background: var(--subtle); border-radius: var(--radius-sm); }
.field-cmt-compose { display: flex; gap: 8px; align-items: flex-end; margin-top: 8px; }
.field-cmt-compose .textarea { flex: 1; min-height: 40px; }
.field-cmt-compose .btn { flex: 0 0 auto; white-space: nowrap; min-height: 44px; }

.today-shoot-actions { margin-top: 10px; }
.today-shoot-actions .btn { min-height: 40px; }
/* CHECKER FIX 2026-08-15 (LAW-A, §J.4 #24 completion) — the rule above is (0,2,0)
   and so beats the phone `.btn { min-height:44px }` (0,1,0) at ~:2119 regardless of
   order, exactly like `.toolbar .btn` did. These are the actions on the Today
   shoot card — the row a shooter taps on the way out the door. Phone-scoped;
   desktop keeps its 40px. */
@media (max-width: 640px) { .today-shoot-actions .btn { min-height: 44px; } }

@media (max-width: 760px) {
  .field-addr { font-size: 19px; }
  .field-map { flex: 1 1 100%; }
  /* SPEC144 — field is a phone-in-the-sun tool: give the shooter controls real
     44px touch targets, and 16px on the <select> so iOS doesn't auto-zoom on focus. */
  .field-svc-sel { max-width: 140px; min-height: 44px; font-size: var(--fs-md); }
  .field-svc-cmt { min-height: 44px; }
  .field-pick { min-height: 44px; }
}
/* SPEC152 — on very narrow phones (<400px) stack the service row controls below the
   name so the dot + name + select + note button never squeeze or overflow. */
@media (max-width: 400px) {
  .field-svc-main { flex-wrap: wrap; }
  .field-svc-sel, .field-svc-cmt { flex: 1 1 calc(50% - 5px); max-width: none; }
}

/* ============ SPEC145 — Shoot Conditions (sun / weather / drone) ============ */
.cond-card { display: flex; flex-direction: column; gap: 4px; }
.cond-sec { padding: 14px 0; border-top: 1px solid var(--border); }
.cond-sec:first-child { padding-top: 2px; border-top: none; }
.cond-compass { margin: 6px 0 2px; }
.cond-readout { text-align: center; font-size: var(--fs-caption); padding: 8px 10px; background: var(--subtle); border-radius: var(--radius-sm); margin: 6px auto 0; max-width: 340px; line-height: var(--lh-normal); }
.cond-readout b { color: var(--text); }
.cond-slider { width: 100%; max-width: 340px; display: block; margin: 12px auto 4px; accent-color: var(--accent); height: 6px; cursor: pointer; }
.cond-pickrow { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; justify-content: center; }
.cond-chip { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; font-weight: var(--fw-bold); padding: 3px 9px; border-radius: 999px; background: var(--subtle); color: var(--muted); border: 1px solid var(--border); }
.cond-chip.gold { background: var(--warn-soft); color: var(--warn); border-color: var(--warn); }
.cond-rec { margin-top: 10px; padding: 10px 12px; background: var(--accent-soft); border-radius: var(--radius-sm); }
.cond-week { display: flex; gap: 6px; overflow-x: auto; padding: 4px 2px 8px; -webkit-overflow-scrolling: touch; }
.cond-day { flex: 0 0 auto; min-width: 56px; text-align: center; padding: 8px 4px; border-radius: var(--radius-sm); background: var(--subtle); border: 1px solid transparent; transition: transform .12s ease, box-shadow .12s ease; }
.cond-day.shoot { border-color: var(--accent); background: var(--accent-soft); box-shadow: var(--shadow); }
.cd-dow { font-size: var(--fs-micro); font-weight: var(--fw-black); color: var(--muted); }
.cd-emoji { font-size: var(--fs-h1); line-height: 1.3; }
.cd-hi { font-size: var(--fs-body); font-weight: var(--fw-black); }
.cd-lo { font-size: var(--fs-meta); }
.cd-rain { font-size: 10.5px; color: #0ea5e9; font-weight: var(--fw-bold); }
.cond-dayline { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline; margin-top: 8px; font-size: var(--fs-caption); }
.cond-dayline .muted { font-size: var(--fs-meta); }
.cond-tips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.cond-tip { font-size: var(--fs-meta); padding: 4px 9px; border-radius: var(--radius-sm); background: var(--subtle); border: 1px solid var(--border); }
.cond-fly { display: inline-flex; align-items: center; gap: 4px; font-size: 12.5px; font-weight: var(--fw-black); padding: 3px 10px; border-radius: 999px; }
.cond-fly-ok { background: var(--ok-soft); color: var(--ok); }
.cond-fly-caution { background: var(--warn-soft); color: var(--warn); }
.cond-fly-no { background: var(--danger-soft); color: var(--danger); }
/* LENS-S16 — the 4th drone level: wind/rain unknown. Deliberately NEUTRAL, never green —
   "we have no weather data" must not read as a go-fly. */
.cond-fly-unknown { background: var(--subtle); color: var(--muted); }
@media (prefers-reduced-motion: reduce) { .cond-day { transition: none; } }

/* ============ SPEC146 — premium micro-interactions (tasteful, token-based) ============ */
/* dense rows highlight on hover for scannability (JS-set inline hovers still win) */
.list-row { transition: background var(--t-fast) var(--ease); }
.list-row:hover { background: var(--hover); }
@media (prefers-reduced-motion: reduce) {
  .kanban-card, .card.is-clickable, .list-row { transition: none; }
  .kanban-card:hover, .card.is-clickable:hover { transform: none; }
}

/* ============ SPEC47 — notification bell + panel ============ */
/* count rides the top-right corner of the 🔔 glyph (its .help-q is the anchor),
   so it hugs the bell whether the row shows its label or collapses to an icon */
.notif-bell .help-q { position: relative; overflow: visible; }
.notif-bell-badge {
  position: absolute; top: -7px; right: -8px; left: auto;
  background: var(--danger); color: #fff; font-size: 9.5px; font-weight: var(--fw-bold);
  border-radius: 999px; min-width: 15px; height: 15px; line-height: 15px; text-align: center; padding: 0 4px;
  box-shadow: 0 0 0 2px var(--sidebar-bg);
}

.notif-list { display: flex; flex-direction: column; gap: 5px; max-height: 62vh; overflow-y: auto; }
.notif-row {
  display: flex; align-items: flex-start; gap: 10px; width: 100%; text-align: left;
  padding: 10px 12px; border: 1px solid var(--border); background: var(--panel);
  border-radius: var(--radius-sm); cursor: pointer; font: inherit;
}
.notif-row:hover { background: var(--hover); }
.notif-row.unread { border-color: var(--accent); background: var(--accent-soft); }
/* SPEC211 — "Needs you" standing-work rows: calm (no accent), muted icon. The accent
   highlight stays reserved for true unread events, so "new" and "to-do" read distinctly. */
.notif-subhead { font-size: var(--fs-micro); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .5px; color: var(--muted); padding: 12px 4px 4px; }
.notif-row.action { background: var(--subtle); }
.notif-row.action .notif-ico { color: var(--muted); }
/* inside the slide-over the panel body already scrolls — let the lists flow naturally */
.slideover-body .notif-list { max-height: none; overflow: visible; }
.notif-ico { flex: 0 0 auto; font-size: 17px; line-height: 1.4; }
.notif-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.notif-title { font-size: 13.5px; font-weight: var(--fw-semibold); color: var(--text); }
.notif-body { font-size: 12.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.notif-time { flex: 0 0 auto; font-size: var(--fs-micro); color: var(--faint); white-space: nowrap; margin-top: 1px; }

/* BELLDROP 2026-08-20 — per-row dismiss (× or swipe) + bulk clear. `.notif-row-x` is a
   MODIFIER on the existing row: it hands the padding to the inner .notif-go button so the
   whole text area stays tappable, and opens a 44px column for the ×. The plain .notif-row
   above is untouched, which is what keeps the "Needs you" rows (no ×) byte-identical. */
.notif-row-x { padding: 0; gap: 0; align-items: stretch; overflow: hidden; }
.notif-go {
  flex: 1 1 auto; min-width: 0; display: flex; align-items: flex-start; gap: 10px;
  padding: 10px 12px; text-align: left; background: none; border: 0; color: inherit;
  font: inherit; cursor: pointer;
}
.notif-x {
  flex: 0 0 44px; min-width: 44px; min-height: 44px; display: flex; align-items: center;
  justify-content: center; background: none; border: 0; border-left: 1px solid var(--border);
  color: var(--faint); cursor: pointer;
}
.notif-x:hover, .notif-x:focus-visible { background: var(--hover); color: var(--text); }
.notif-tools { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 2px 2px 8px; }
.notif-count { font-size: var(--fs-micro); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .5px; color: var(--muted); }
.notif-clear { min-height: 44px; }   /* §I.1 LAW 1 — every visible control clears 44px */
.notif-snoozed-note { font-size: 12.5px; color: var(--muted); padding: 6px 2px; }

/* ============ SPEC48 — Copy Library (snippets) ============ */
.snippet-toolbar { margin: 4px 0 10px; }
.snippet-search { width: 100%; }
.snippet-cats { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 14px; }
.chip-btn {
  flex: 0 0 auto; border: 1px solid var(--border); background: var(--panel); color: var(--muted);
  border-radius: 999px; padding: 5px 12px; font: inherit; font-size: 12.5px; font-weight: var(--fw-semibold); cursor: pointer;
}
.chip-btn:hover { background: var(--hover); }
.chip-btn.active { background: var(--accent); border-color: var(--accent); color: #fff; }
/* DESIGN 2026-08-11 — FRIDAY-panel citation chips only: a long address label may
   shrink + ellipsize instead of poking past the card edge at 375px. */
.chip-btn.fri-cite { flex: 0 1 auto; min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.snippet-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
.snippet-card { display: flex; flex-direction: column; gap: 8px; }
.snippet-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.snippet-title { font-weight: var(--fw-bold); font-size: 14.5px; line-height: 1.3; min-width: 0; }
.snippet-cat {
  flex: 0 0 auto; font-size: 10.5px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .3px;
  color: var(--accent); background: var(--accent-soft); border-radius: 999px; padding: 2px 8px; white-space: nowrap;
}
.snippet-body {
  font-size: var(--fs-caption); line-height: var(--lh-normal); color: var(--text); white-space: pre-wrap; word-break: break-word;
  background: var(--subtle); border: 1px solid var(--border); border-radius: var(--radius-sm);
  padding: 10px 12px; max-height: 168px; overflow-y: auto; flex: 1;
}
.snippet-actions { display: flex; gap: 8px; }

@media (max-width: 760px) {
  .snippet-grid { grid-template-columns: 1fr; }
  .snippet-cats { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; padding-bottom: 4px; }
}

/* ============ SPEC49 — Territory heat map ============ */
.table .num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
/* (SPEC126) removed dead .heat-grid/.heat-tile/.heat-city/.heat-val — replaced by the ranked top-list */

/* ============ SPEC51 — shared visual primitives ============ */
.avatar {
  display: inline-flex; align-items: center; justify-content: center; border-radius: 50%;
  color: #fff; font-weight: var(--fw-bold); flex: 0 0 auto; line-height: 1; letter-spacing: .2px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.12);
}
/* LAW-A 2026-08-15 (#6) → CHATEXTRA 2026-08-20 (THE REAL FIX, landed) → EXTRACLOSE
   2026-08-20 (D4, threshold corrected) — this used to be a hardcoded 3-hex
   attribute-selector stopgap for exactly Erika/Jeffrey/Vitaliy's fill colours
   (white-on-fill measured 2.21:1 / 1.90:1 / 2.26:1, all FAIL). App.avatar()
   (core.js) now sets ink inline from the fill's OWN measured luminance —
   `color: App.relLum(fill) > 0.179 ? '#000' : '#fff'` (0.3/'#0b0d13' let hire
   #8's #ef4444 through at 3.76:1 FAIL; see core.js's App.relLum comment for
   the full derivation) — which covers every past AND future roster/tag colour
   with no enumerable list to maintain here. The base `.avatar{color:#fff}`
   above is just the pre-JS-paint default now; App.avatar always overrides it
   inline. */
.avatar-stack { display: inline-flex; }
.avatar-stack .avatar { margin-right: -8px; border: 2px solid var(--panel); }
.avatar-stack .avatar:last-child { margin-right: 0; }
.spark { display: inline-block; vertical-align: middle; line-height: 0; }
.spark svg { display: block; }
.spark-empty { background: var(--subtle); border-radius: 4px; opacity: .5; }
.databar { display: inline-flex; align-items: center; gap: 8px; min-width: 80px; width: 100%; }
.databar-track { flex: 1; min-width: 28px; height: 8px; border-radius: 999px; background: var(--bg-2); overflow: hidden; }
.databar-fill { display: block; height: 100%; border-radius: 999px; min-width: 2px; transition: width .5s cubic-bezier(.22,1,.36,1); }
.databar-label { flex: 0 0 auto; font-variant-numeric: tabular-nums; font-weight: var(--fw-semibold); }
.gauge { display: inline-block; width: 48px; height: 7px; border-radius: 999px; background: var(--bg-2); overflow: hidden; vertical-align: middle; }
.gauge-fill { display: block; height: 100%; border-radius: 999px; transition: width .5s cubic-bezier(.22,1,.36,1); }

/* ============ SPEC51 — polish baseline (a11y, motion, feedback) ============ */
/* Visible keyboard focus everywhere (was nearly absent). Mouse users unaffected. */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.btn:focus-visible, .nav-item:focus-visible, .chat-ch:focus-visible, .help-btn:focus-visible, .modal-close:focus-visible { outline-offset: 1px; }

/* Respect reduced-motion: kill transitions/animations for users who ask for it. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; scroll-behavior: auto !important; }
}

/* Richer toasts: type color + icon (success/error), still one tidy pill. */
.toast { display: flex; align-items: center; gap: 8px; }
.toast-ico { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border-radius: 50%; font-size: var(--fs-micro); font-weight: var(--fw-black); }
.toast.error { box-shadow: inset 3px 0 0 var(--danger); }
.toast.error .toast-ico { background: var(--danger); color: var(--on-danger); }
.toast.success { box-shadow: inset 3px 0 0 var(--ok); }
.toast.success .toast-ico { background: var(--ok); color: #fff; }

/* ============ SPEC52 — status-at-a-glance ============ */
.due-overdue { color: var(--danger); font-weight: var(--fw-bold); }
.due-today { color: var(--warn); font-weight: var(--fw-bold); }
.due-soon { color: var(--warn); }
.age-badge { display: inline-flex; align-items: center; font-size: 10.5px; font-weight: var(--fw-bold); border-radius: 999px; padding: 1px 7px; margin-left: 6px; vertical-align: middle; }
.age-badge.age-warm { background: var(--warn-soft); color: var(--warn); }
.age-badge.age-hot { background: var(--danger-soft); color: var(--danger); }
/* status-group pipeline bar on tracker headers */
.statusgroup-bar { display: inline-flex; height: 6px; width: 90px; border-radius: 999px; overflow: hidden; margin-left: 10px; vertical-align: middle; background: var(--bg-2); }
.statusgroup-bar > span { display: block; height: 100%; }

/* ============ SPEC53 — delight (confetti) ============ */
.confetti-layer { position: fixed; inset: 0; pointer-events: none; z-index: 400; overflow: hidden; }
.confetti-piece {
  position: absolute; top: -14px; width: 9px; height: 14px; opacity: .95;
  animation-name: confetti-fall; animation-timing-function: cubic-bezier(.3,.5,.7,1); animation-fill-mode: forwards;
}
@keyframes confetti-fall {
  0% { transform: translateY(-14px) translateX(0) rotate(0); opacity: 1; }
  100% { transform: translateY(106vh) translateX(var(--drift,0)) rotate(var(--rot,360deg)); opacity: .9; }
}
@media (prefers-reduced-motion: reduce) { .confetti-layer { display: none; } }

/* ============ SPEC54 — best clients leaderboard ============ */
.rank-medal { font-size: 15px; line-height: 1; flex: 0 0 auto; }
.bestclient-card { margin-bottom: 14px; }
.bestclient-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; }
/* SPEC273 — Top Agents */
.ta-lenses { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 12px; margin-bottom: 14px; }
.ta-lens { border: 1px solid var(--border); border-radius: 12px; padding: 13px 14px; background: var(--card); }
.ta-lens-h { display: flex; align-items: center; gap: 7px; font-weight: var(--fw-bold); font-size: var(--fs-body); }
.ta-lens-ico { font-size: var(--fs-md); }
.ta-lens-n { margin-left: auto; background: var(--subtle); border-radius: 999px; padding: 1px 9px; font-size: var(--fs-meta); }
.ta-lens-blurb { font-size: var(--fs-meta); color: var(--muted); margin: 4px 0 8px; }
.ta-lens-list { display: flex; flex-direction: column; gap: 4px; }
.ta-lens-item { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; text-align: left; background: transparent; border: 0; border-radius: 7px; padding: 4px 6px; cursor: pointer; }
.ta-lens-item:hover { background: var(--subtle); }
.ta-lens-name { font-weight: var(--fw-semibold); font-size: var(--fs-caption); }
.ta-lens-meta { font-size: 11.5px; color: var(--muted); white-space: nowrap; }
.ta-lens-act { font-size: 11.5px; margin-top: 8px; }
.ta-rows { display: flex; flex-direction: column; }
.ta-row { display: grid; grid-template-columns: 30px 34px minmax(120px, 1.4fr) minmax(120px, 1fr) minmax(90px, 0.9fr) auto; align-items: center; gap: 10px; width: 100%; text-align: left; background: transparent; border: 0; border-bottom: 1px solid var(--border); padding: 9px 4px; cursor: pointer; }
.ta-row:last-child { border-bottom: 0; }
.ta-row:hover { background: var(--subtle); }
.ta-rank { font-size: 15px; font-weight: var(--fw-black); text-align: center; color: var(--muted); }
.ta-who { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.ta-name { font-weight: var(--fw-bold); font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ta-broker { font-size: 11.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ta-metrics { display: flex; flex-direction: column; gap: 1px; }
.ta-rev { font-weight: var(--fw-bold); font-size: 13.5px; }
.ta-sub { font-size: var(--fs-micro); color: var(--muted); }
.ta-scorewrap { display: flex; align-items: center; gap: 7px; }
.ta-scorebar { flex: 1; height: 7px; border-radius: 999px; background: var(--subtle); overflow: hidden; min-width: 40px; }
.ta-scorefill { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--accent, #2b608f), #22c55e); }
.ta-scoren { font-weight: var(--fw-black); font-size: var(--fs-caption); min-width: 22px; text-align: right; }
.ta-tail { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; justify-content: flex-end; }
.ta-recency { font-size: 10.5px; padding: 1px 7px; border-radius: 999px; white-space: nowrap; }
.ta-recency--hot { background: rgba(34,197,94,.16); color: #16a34a; }
.ta-recency--warm { background: rgba(253,171,61,.18); color: #c2740b; }
.ta-recency--cold { background: var(--subtle); color: var(--muted); }
.ta-flag { font-size: 10.5px; font-weight: var(--fw-bold); padding: 1px 7px; border-radius: 999px; white-space: nowrap; }
.ta-flag--lapse { background: rgba(239,68,68,.14); color: #dc2626; }
.ta-flag--ref { background: rgba(43,96,143,.14); color: #1e3f66; }
.ta-flag--rise { background: rgba(14,165,233,.16); color: #0284c7; }
.ta-broker-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 10px; margin-top: 4px; }
.ta-broker-card { border: 1px solid var(--border); border-radius: 11px; padding: 12px 13px; }
.ta-broker-top { display: flex; justify-content: space-between; gap: 8px; align-items: baseline; }
.ta-broker-name { font-weight: var(--fw-bold); font-size: var(--fs-body); }
.ta-broker-rev { font-weight: var(--fw-black); font-size: var(--fs-body); }
.ta-broker-sub { font-size: 11.5px; margin-top: 2px; }
.ta-broker-names { font-size: var(--fs-meta); margin-top: 6px; }
.ta-broker-why { font-size: 11.5px; margin-top: 7px; line-height: var(--lh-snug); }
.ta-note { font-size: 11.5px; margin-top: 14px; padding: 11px 13px; border-radius: 10px; background: var(--subtle); line-height: 1.4; }
@media (max-width: 640px) { .ta-row { grid-template-columns: 26px 30px 1fr auto; } .ta-row .ta-scorewrap, .ta-row .ta-metrics { display: none; } }
/* SPEC275 — Incoming review inbox */
.inc-row { padding: 11px 2px; border-bottom: 1px solid var(--border); }
.inc-row:last-child { border-bottom: 0; }
.inc-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.inc-vendor { font-weight: var(--fw-bold); font-size: 13.5px; text-transform: capitalize; }
.inc-what { font-size: 12.5px; color: var(--text); }
.inc-when { font-size: 11.5px; margin-left: auto; }
.inc-addr { font-size: var(--fs-meta); margin-top: 2px; }
.inc-actions { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; margin-top: 8px; }
.inc-actions .input { flex: 1 1 200px; min-width: 160px; }
/* SPEC-TONOMO-UPD — a parked Tonomo order-change proposal. Its OWN class rather than
   reusing .inc-row, so this stacked field layout can't be knocked sideways by an
   unrelated feature. (The leaderboard used to redeclare .inc-row with display:flex
   further down this file and win by source order; it is now .inc-lb-row.) */
.ou-row { padding: 12px 2px; border-bottom: 1px solid var(--border); }
.ou-row:last-child { border-bottom: 0; }
.ou-fields { margin: 8px 0 4px; display: flex; flex-direction: column; gap: 4px; }
.ou-field { display: flex; align-items: baseline; gap: 8px; font-size: 12.5px; flex-wrap: wrap; }
.ou-field input[type="checkbox"] { flex: 0 0 auto; }
.ou-field-label { flex: 0 0 92px; font-weight: var(--fw-semibold); }
.ou-vals { flex: 1 1 auto; }
.ou-from { color: var(--muted); text-decoration: line-through; }
.ou-arrow { color: var(--muted); }
.ou-to { font-weight: var(--fw-semibold); }
/* narrow: keep the tick + its field NAME together on one line, wrap only the
   old→new values underneath (indented past the checkbox) */
@media (max-width: 640px) {
  .ou-field-label { flex: 1 1 auto; }
  .ou-vals { flex-basis: 100%; padding-left: 24px; }
}
.bestclient-tile {
  display: flex; flex-direction: column; gap: 7px; align-items: flex-start; text-align: left;
  padding: 12px 14px; border: 1px solid var(--border); background: var(--subtle);
  border-radius: var(--radius-sm); cursor: pointer; font: inherit;
}
.bestclient-tile:hover { border-color: var(--accent); background: var(--accent-soft); }
.bestclient-label { font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--muted); text-transform: uppercase; letter-spacing: .4px; }
.bestclient-main { display: flex; align-items: center; gap: 10px; min-width: 0; width: 100%; }
.bestclient-text { display: flex; flex-direction: column; min-width: 0; }
.bestclient-name { font-weight: var(--fw-bold); font-size: var(--fs-body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bestclient-val { font-size: var(--fs-caption); color: var(--accent); font-weight: var(--fw-bold); }

/* ============ SPEC54 — client branding image previews ============ */
.brand-img-prev { margin-top: 6px; }
.brand-img-link { display: inline-block; line-height: 0; border-radius: 6px; }
.brand-img-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.brand-img { max-width: 130px; max-height: 72px; border-radius: 6px; border: 1px solid var(--border); cursor: pointer; object-fit: contain; background: var(--subtle); padding: 4px; }

/* ============ SPEC55 — client tiers + referrals ============ */
.tier-badge { display: inline-flex; align-items: center; gap: 4px; font-size: var(--fs-micro); font-weight: var(--fw-bold); color: #fff; border-radius: 999px; padding: 2px 9px; line-height: var(--lh-normal); }
.tier-badge-sm { padding: 1px 7px; }
/* SPEC270 (post-C #2) — Clients/Directory legend modal */
.legend-section { margin-top: 14px; }
.legend-section:first-child { margin-top: 4px; }
.legend-h { font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: .06em; text-transform: uppercase; color: var(--muted); margin-bottom: 6px; }
.legend-row { display: flex; align-items: flex-start; gap: 10px; padding: 5px 0; }
.legend-sample { flex: 0 0 92px; display: flex; align-items: center; min-height: 20px; }
.legend-text { display: flex; flex-direction: column; gap: 1px; }
.legend-label { font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--text); }
.legend-desc { font-size: var(--fs-meta); color: var(--muted); }
.reflink-row {
  display: flex; align-items: center; gap: 8px; width: 100%; text-align: left;
  padding: 7px 10px; border: 1px solid var(--border); background: var(--panel);
  border-radius: var(--radius-sm); cursor: pointer; font: inherit; font-size: var(--fs-caption); margin-bottom: 6px;
}
.reflink-row:hover { background: var(--hover); border-color: var(--accent); }

/* ============ SPEC56 — Ask / FAQ ============ */
.faq-ask { width: 100%; }
.faq-section-label { font-size: 11.5px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .5px; color: var(--muted); margin: 8px 2px 2px; }
.faq-card { border-left: 3px solid var(--ok); }
.faq-card.faq-open { border-left-color: var(--warn); }
.faq-q-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.faq-q { font-weight: var(--fw-bold); font-size: 15px; line-height: var(--lh-snug); }
.faq-cat { flex: 0 0 auto; font-size: 10.5px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .3px; color: var(--accent); background: var(--accent-soft); border-radius: 999px; padding: 2px 8px; white-space: nowrap; }
.faq-meta { font-size: 11.5px; color: var(--faint); margin-top: 3px; }
.faq-a { font-size: var(--fs-body); line-height: 1.55; white-space: pre-wrap; margin-top: 10px; padding: 10px 12px; background: var(--subtle); border-radius: var(--radius-sm); }
.faq-answered-by { color: var(--ok); font-weight: var(--fw-semibold); }
.faq-pending { font-size: var(--fs-caption); color: var(--warn); font-weight: var(--fw-semibold); margin-top: 10px; }
.faq-actions { display: flex; gap: 8px; margin-top: 10px; }

/* ============ SPEC57 — per-role QA accountability ============ */
/* AUDIT-2026-07-25 [16] — .qa-role-row/.qa-role-name deleted (zero emitters, the
   SPEC172 chain UI they belonged to is gone); .qa-role-who stays — live at tracker.js. */
.qa-role-who { font-size: 11.5px; color: var(--muted); background: var(--subtle); border-radius: 999px; padding: 1px 8px; }

/* ============ SPEC172 — role-based QC cards ============ */
.qa-rolecards { display: flex; flex-direction: column; gap: 10px; }
.qa-rolecard { border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; background: var(--panel); }
.qa-rolecard-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 2px; }
.qa-rolecard-title { display: flex; align-items: center; gap: 8px; font-size: 13.5px; }
.qa-rolecard-grade { display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto; }
.qa-chain-chip { display: inline-block; font-size: var(--fs-micro); font-weight: var(--fw-semibold); color: var(--muted); background: var(--subtle);
  border-radius: 999px; padding: 1px 9px; margin: 2px 0 8px; }
.qa-crit-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; padding: 3px 0; }
.qa-crit-name { flex: 1 1 180px; min-width: 0; font-size: 12.5px; color: var(--text); }
.qa-owner-audit { border: 1.5px solid var(--accent); border-radius: 12px; padding: 12px;
  background: color-mix(in srgb, var(--accent) 6%, var(--panel)); }
.qa-owner-audit-head { display: flex; flex-direction: column; gap: 2px; margin-bottom: 10px; }
.qa-owner-audit .qa-rolecard { background: var(--card, var(--panel)); }
@media (max-width: 640px) {
  .qa-crit-row { flex-direction: column; align-items: stretch; gap: 4px; }
  .qa-crit-row .qa-crit-name { flex-basis: auto; }   /* column axis: don't reserve 180px of height */
  .qa-crit-row .qa-score { align-self: flex-start; }
}

/* ============ SPEC58 — socials quick-links ============ */
.socials-row { display: flex; flex-wrap: wrap; gap: 8px; }
.social-link { text-decoration: none; }
.social-direct { border-color: var(--accent); color: var(--accent); font-weight: var(--fw-bold); }

/* ============ SPEC59 — Social Studio ============ */
.soc-grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-bottom: 14px; }
@media (max-width: 860px) { .soc-grid-2 { grid-template-columns: 1fr; } }

/* section heads inside cards + the post modal */
.soc-section-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.soc-section-head .faint { font-size: 11.5px; font-weight: var(--fw-medium); }
.soc-sub-head { font-size: var(--fs-micro); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .5px; color: var(--muted); margin: 12px 0 6px; }
.soc-modal-section { margin-top: 16px; border-top: 1px solid var(--border); padding-top: 12px; }
.soc-metric-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
@media (max-width: 560px) { .soc-metric-grid { grid-template-columns: repeat(2, 1fr); } }
.soc-assets { display: flex; flex-direction: column; gap: 8px; }
.soc-asset-row { display: grid; grid-template-columns: 1fr 1.4fr auto; gap: 8px; align-items: center; }

/* trends */
.soc-trend-row { display: flex; align-items: center; gap: 12px; margin: 8px 0; }
.soc-trend-label { width: 90px; font-size: 12.5px; font-weight: var(--fw-semibold); color: var(--muted); }
.soc-trend-now { margin-left: auto; font-weight: var(--fw-black); font-variant-numeric: tabular-nums; }
.soc-trend-months { display: flex; flex-wrap: wrap; gap: 6px 12px; margin-top: 8px; }
.soc-trend-month { font-size: var(--fs-micro); color: var(--faint); font-variant-numeric: tabular-nums; }

/* platform split */
.soc-plat-row { display: grid; grid-template-columns: 110px 1fr auto; align-items: center; gap: 10px; padding: 5px 0; }
.soc-plat-stat { font-size: 11.5px; color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }

/* top posts table */
.soc-top-table th.num, .soc-top-table td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.soc-top-row { cursor: pointer; }
.soc-top-row:hover { background: var(--hover); }
.soc-top-title { font-weight: var(--fw-semibold); }

/* pipeline rows */
.soc-stage-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.soc-stage-chip { font-size: var(--fs-meta); background: var(--subtle); border: 1px solid var(--border); border-radius: 999px; padding: 2px 10px; color: var(--muted); }
.soc-stage-chip b { color: var(--text); }
.soc-row { display: flex; align-items: center; gap: 8px; padding: 6px 6px; border-radius: 8px; cursor: pointer; }
.soc-row:hover { background: var(--hover); }
.soc-row-title { font-weight: var(--fw-semibold); font-size: var(--fs-caption); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.soc-row-when { margin-left: auto; font-size: 11.5px; color: var(--muted); white-space: nowrap; }
.soc-row-warn .soc-row-when { color: var(--warn); font-weight: var(--fw-bold); }

/* captions */
.soc-caption { border-top: 1px solid var(--border); padding: 8px 0; }
.soc-caption:first-of-type { border-top: 0; }
.soc-caption-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.soc-caption-title { font-weight: var(--fw-bold); font-size: var(--fs-caption); }
.soc-caption-body { font-size: 12.5px; color: var(--muted); margin-top: 4px; white-space: pre-wrap; }

/* AI brief */
.soc-brief { width: 100%; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--fs-meta); margin-top: 10px; }

/* ============ SPEC60 — Incentives & Recognition ============ */
/* your-standing hero */
.inc-hero { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin-bottom: 14px;
  background: linear-gradient(120deg, var(--accent-soft), var(--panel)); }
.inc-hero-main { flex: 1; min-width: 140px; }
.inc-hero-name { font-weight: var(--fw-black); font-size: var(--fs-md); display: flex; align-items: center; gap: 8px; }
.inc-hero-rank { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.inc-hero-right { text-align: right; }
.inc-hero-pts { font-size: 30px; font-weight: var(--fw-black); letter-spacing: -.5px; color: var(--accent); line-height: 1; }
.inc-hero-lbl { font-size: var(--fs-micro); color: var(--muted); text-transform: uppercase; letter-spacing: .5px; }
.inc-hero-badges { flex-basis: 100%; }

/* filter chips */
.inc-filter { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }

/* leaderboard rows */
.inc-list { display: flex; flex-direction: column; }
/* NOTE the -lb- : this is the LEADERBOARD row. Plain `.inc-row` belongs to the
   SPEC275 Incoming queue further up this file — the two features share the `inc-`
   prefix, and when this rule was also called `.inc-row` it won by source order and
   flex-laid-out (+ pointer-cursored) the incoming queue's stacked vendor rows. */
.inc-lb-row { display: flex; align-items: center; gap: 12px; padding: 9px 8px; border-radius: 10px; cursor: pointer; border: 1px solid transparent; }
.inc-lb-row:hover { background: var(--hover); }
.inc-lb-row-me { background: var(--accent-soft); border-color: var(--accent); }
.inc-lb-row-top .inc-rank { font-size: 20px; }
.inc-rank { width: 30px; text-align: center; font-weight: var(--fw-black); font-variant-numeric: tabular-nums; color: var(--muted); flex: 0 0 auto; }
.inc-name-wrap { flex: 1; min-width: 0; }
.inc-name { font-weight: var(--fw-bold); font-size: var(--fs-body); display: flex; align-items: center; gap: 6px; }
.inc-you { font-size: 10px; font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .5px; color: #fff; background: var(--accent); border-radius: 999px; padding: 1px 6px; }
.inc-sub { display: flex; align-items: center; gap: 6px; margin-top: 3px; flex-wrap: wrap; }
.inc-badge-mini { font-size: var(--fs-caption); }
.inc-pts-wrap { width: 130px; flex: 0 0 auto; text-align: right; }
.inc-pts { font-size: 19px; font-weight: var(--fw-black); font-variant-numeric: tabular-nums; letter-spacing: -.3px; }
.inc-pts-bar { margin-top: 3px; }
@media (max-width: 560px) { .inc-pts-wrap { width: 84px; } .inc-pts-bar .databar-label { display: none; } }

/* badges */
.inc-badge-row { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0; }
.inc-badge { font-size: var(--fs-meta); font-weight: var(--fw-bold); background: var(--subtle); border: 1px solid var(--border); border-radius: 999px; padding: 3px 10px; }

/* recent kudos feed */
.inc-kudo { display: flex; gap: 10px; padding: 8px 0; border-top: 1px solid var(--border); }
.inc-kudo:first-of-type { border-top: 0; }
.inc-kudo-body { flex: 1; font-size: var(--fs-caption); }
.inc-kudo-tag { font-size: 11.5px; background: var(--subtle); border-radius: 999px; padding: 1px 7px; }
.inc-kudo-pts { font-size: var(--fs-meta); font-weight: var(--fw-black); color: var(--ok); }
.inc-kudo-reason { color: var(--muted); font-style: italic; margin-top: 2px; }
.inc-kudo-date { font-size: var(--fs-micro); color: var(--faint); margin-top: 2px; }

/* legend */
.inc-legend-row { display: flex; align-items: center; gap: 10px; padding: 4px 0; font-size: var(--fs-caption); }
.inc-legend-ic { width: 22px; text-align: center; }
.inc-legend-what { flex: 1; }
.inc-legend-pts { font-weight: var(--fw-bold); color: var(--accent); font-size: 12.5px; white-space: nowrap; }

/* person modal */
.inc-person-head { display: flex; align-items: center; gap: 12px; margin-bottom: 12px; }
.inc-person-name { font-weight: var(--fw-black); font-size: 17px; display: flex; align-items: center; gap: 8px; }
.inc-breakdown { display: flex; flex-direction: column; gap: 6px; }
.inc-bd-row { display: grid; grid-template-columns: 92px 1fr 38px; align-items: center; gap: 10px; }
.inc-bd-label { font-size: 12.5px; font-weight: var(--fw-semibold); }
.inc-bd-val { text-align: right; font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; }
.inc-stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; margin-top: 16px; }
@media (max-width: 560px) { .inc-stat-grid { grid-template-columns: repeat(2, 1fr); } }
.inc-stat { background: var(--subtle); border-radius: 10px; padding: 10px; text-align: center; }
.inc-stat-val { font-size: var(--fs-lg); font-weight: var(--fw-black); }
.inc-stat-label { font-size: var(--fs-micro); color: var(--muted); margin-top: 2px; }

/* ============ SPEC61 — Customizable Pipelines ============ */
.pl-tabs { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.pl-tab { padding: 6px 12px; border-radius: 999px; border: 1px solid var(--border); background: var(--panel); cursor: pointer; font-weight: var(--fw-semibold); font-size: var(--fs-caption); }
.pl-tab:hover { background: var(--hover); }
.pl-tab.active { background: var(--accent-soft); border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); color: var(--accent-hover); }   /* SPEC175 — accent-soft pill; --accent-hover text clears AA on the soft fill in both themes */
.pl-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.pl-stats { display: flex; align-items: center; gap: 14px; font-size: var(--fs-caption); color: var(--muted); }
.pl-stat-val { font-weight: var(--fw-black); color: var(--text); }
.pl-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* board reuses .kanban; add a per-column value sum + add button + card extras */
.pl-board { align-items: flex-start; }
.pl-col-sum { font-size: var(--fs-meta); font-weight: var(--fw-black); color: var(--ok); margin: -4px 4px 8px; }
.pl-add-card { width: 100%; margin-top: 8px; opacity: .8; }
.pl-add-card:hover { opacity: 1; }
.pl-card .pl-value { font-weight: var(--fw-black); color: var(--ok); }
.pl-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 6px; }

/* section heads inside modals */
.pl-section-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  font-size: var(--fs-meta); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .4px; color: var(--muted);
  margin: 16px 0 8px; border-top: 1px solid var(--border); padding-top: 12px; }
.pl-custom { margin-top: 4px; }

/* stage + field editors */
.pl-edit-list { display: flex; flex-direction: column; gap: 8px; }
.pl-edit-row { display: flex; align-items: center; gap: 8px; }
.pl-edit-row .input { flex: 1; min-width: 0; }
.pl-color-sel { width: 92px; flex: 0 0 auto; }
.pl-field-row .select { flex: 0 0 auto; width: 110px; }

/* template picker */
.pl-templates { display: flex; flex-direction: column; gap: 10px; }
.pl-template { display: flex; align-items: center; gap: 14px; text-align: left; padding: 12px 14px; border-radius: 12px;
  border: 1px solid var(--border); background: var(--panel); cursor: pointer; }
.pl-template:hover { border-color: var(--accent); background: var(--hover); }
.pl-template-ico { font-size: 26px; flex: 0 0 auto; }
.pl-template-name { font-weight: var(--fw-bold); }
.pl-template-sub { font-size: var(--fs-meta); color: var(--muted); margin-top: 2px; }

/* ============ SPEC62 — Conversation Coaching ============ */
.cc-section { margin-top: 16px; border-top: 1px solid var(--border); padding-top: 12px; }
.cc-section-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-weight: var(--fw-bold); font-size: var(--fs-caption); margin-bottom: 8px; }
.cc-section-head .faint { font-weight: var(--fw-medium); font-size: 11.5px; }
.cc-row { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; }
.cc-transcript, .cc-prompt { width: 100%; }
.cc-prompt { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--fs-meta); }

/* coaching trend strip */
.cc-trend-row { display: flex; align-items: center; gap: 10px; padding: 5px 0; }
.cc-trend-name { font-weight: var(--fw-semibold); font-size: 13.5px; }
.cc-trend-n { font-size: 11.5px; color: var(--muted); }
.cc-trend-row .spark { margin-left: auto; }
.cc-trend-avg { font-weight: var(--fw-black); font-size: var(--fs-caption); font-variant-numeric: tabular-nums; }
.cc-trend-row .spark + .cc-trend-avg { margin-left: 8px; }
.cc-trend-row:not(:has(.spark)) .cc-trend-avg { margin-left: auto; }

/* session list + cards */
.cc-list { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; }
.cc-card-head { display: flex; align-items: center; gap: 10px; }
.cc-card-meta { flex: 1; min-width: 0; }
.cc-card-person { font-weight: var(--fw-bold); font-size: var(--fs-body); display: flex; align-items: center; gap: 8px; }
.cc-score { color: #fff; font-size: var(--fs-micro); font-weight: var(--fw-black); border-radius: 999px; padding: 1px 8px; }
.cc-card-sub { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 3px; font-size: var(--fs-meta); }
.cc-card-title { font-weight: var(--fw-semibold); margin: 8px 0 4px; }
.cc-analysis { font-size: var(--fs-caption); color: var(--text); white-space: pre-wrap; background: var(--subtle); border-radius: 10px; padding: 10px 12px; margin-top: 6px;
  max-height: 150px; overflow: auto; line-height: var(--lh-normal); }
.cc-card-actions { display: flex; gap: 8px; margin-top: 10px; }

/* ============ SPEC63 — Custom Dashboards ============ */
.dw-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; }
.dw-tile { background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 12px 14px; cursor: grab; transition: box-shadow .15s, border-color .15s; }
.dw-tile.dragging { opacity: .5; }
.dw-tile.dw-over { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
/* CUSTOM-1 — 12-column span grid (resizable widgets). Resting board is calm; the
   resize/reorder affordances only appear in Edit mode. Mobile collapses to 1 col. */
.dwx-grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: 14px; align-items: start; }
.dwx-tile { grid-column: span var(--w, 6); min-width: 0; position: relative; cursor: default; }
.dwx-editing .dwx-tile { cursor: grab; outline: 1px dashed var(--border-strong); outline-offset: 2px; }
.dwx-editing .dwx-tile.dragging { cursor: grabbing; }
.dwx-chips { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 10px; padding-top: 8px; border-top: 1px solid var(--border); }
.dwx-chip { font-size: var(--fs-micro); font-weight: var(--fw-semibold); padding: 2px 9px; border-radius: 99px; border: 1px solid var(--border); background: var(--subtle); color: var(--muted); cursor: pointer; line-height: 1.6; }
.dwx-chip:hover { border-color: var(--accent); color: var(--accent); }
.dwx-chip.on { background: var(--accent); color: #fff; border-color: var(--accent); }
.dwx-resize { position: absolute; right: 3px; bottom: 2px; width: 18px; height: 18px; display: flex; align-items: flex-end; justify-content: flex-end; color: var(--muted); font-size: var(--fs-micro); cursor: nwse-resize; opacity: .55; touch-action: none; user-select: none; }
.dwx-resize:hover { opacity: 1; color: var(--accent); }
@media (max-width: 700px) {
  .dwx-grid { grid-template-columns: 1fr; }
  .dwx-tile { grid-column: 1 / -1 !important; min-height: 0 !important; }
  .dwx-resize { display: none; }   /* mobile = chip-resize only, no corner-drag */
}
@media (prefers-reduced-motion: reduce) { .dwx-tile { transition: none; } }
/* CUSTOM-3/4 — configurable chart tile (bar = DOM, donut = SVG numbers only) */
.chart-empty { color: var(--muted); font-size: var(--fs-meta); padding: 18px 4px; text-align: center; }
.chart-plot { display: flex; align-items: flex-end; gap: 6px; position: relative; }
.chart-col { flex: 1 1 0; min-width: 0; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 2px; }
.chart-colval { font-size: 10px; color: var(--muted); font-weight: var(--fw-semibold); white-space: nowrap; }
.chart-colbar { width: 100%; min-height: 2px; border-radius: 4px 4px 0 0; transition: height .3s ease; }
.chart-goalline { position: absolute; left: 0; right: 0; border-top: 1.5px dashed var(--muted); opacity: .7; pointer-events: none; }
.chart-xlabels { display: flex; gap: 6px; margin-top: 5px; }
.chart-xlbl { flex: 1 1 0; min-width: 0; font-size: 10px; color: var(--muted); text-align: center; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chart-donut { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.chart-donut-svg { flex: 0 0 auto; line-height: 0; }
.chart-legend { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 auto; }
.chart-legrow { display: flex; align-items: center; gap: 6px; font-size: var(--fs-meta); min-width: 0; }
.chart-legdot { width: 10px; height: 10px; border-radius: 3px; flex: 0 0 auto; }
.chart-leglbl { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); }
.chart-legval { font-weight: var(--fw-bold); color: var(--text); flex: 0 0 auto; }
.chart-numwrap { padding: 10px 0 4px; }
.chart-number { font-size: 30px; font-weight: var(--fw-black); letter-spacing: -.5px; color: var(--text); }
@media (prefers-reduced-motion: reduce) { .chart-colbar { transition: none; } }
/* CUSTOM-8 — section shell (per-person collapse / reorder / hide on any view) */
.sec-shell-bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; flex-wrap: wrap; }
.sec-shell-title { font-weight: var(--fw-bold); font-size: 15px; }
.sec-block { margin-bottom: 14px; }
.sec-head { display: flex; align-items: center; gap: 6px; }
.sec-caret { background: none; border: 0; cursor: pointer; color: var(--muted); font-size: var(--fs-caption); padding: 2px 5px; line-height: 1; border-radius: 6px; flex: 0 0 auto; }
.sec-caret:hover { background: var(--hover); color: var(--text); }
.sec-title { font-weight: var(--fw-bold); font-size: var(--fs-caption); flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sec-ctrl { display: flex; gap: 2px; flex: 0 0 auto; }
.sec-body { margin-top: 6px; }
.sec-hidden-note { display: flex; align-items: center; gap: 10px; padding: 8px 2px; }
/* CUSTOM-11 — starter template picker */
.dw-tpl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; margin-top: 12px; }
.dw-tpl { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; padding: 14px; border: 1px solid var(--border); border-radius: 12px; background: var(--subtle); cursor: pointer; text-align: left; font: inherit; color: var(--text); transition: border-color .12s, box-shadow .12s; }
.dw-tpl:hover { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.dw-tpl-ico { font-size: var(--fs-h1); line-height: 1; }
.dw-tpl-name { font-weight: var(--fw-bold); font-size: 13.5px; }
.dw-tpl-sub { font-size: var(--fs-micro); }
.dw-tpl-blank { border-style: dashed; align-items: center; justify-content: center; text-align: center; color: var(--muted); }
.dw-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.dw-title { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--muted); text-transform: uppercase; letter-spacing: .4px; min-width: 0; }
.dw-title > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dw-title-ico { flex: 0 0 auto; color: var(--muted); }
/* SPEC210 — header drill button: reads as the plain title, gains a chevron + accent on hover/focus. */
.dw-title-go { display: inline-flex; align-items: center; gap: 5px; border: none; background: transparent; cursor: pointer;
  font: inherit; font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--muted); text-transform: uppercase; letter-spacing: .4px;
  padding: 0; border-radius: 6px; max-width: calc(100% - 28px); transition: color .12s; }
.dw-title-go > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dw-title-go:hover, .dw-title-go:focus-visible { color: var(--accent); outline: none; }
.dw-title-arrow { opacity: 0; transform: translateX(-2px); transition: opacity .12s, transform .12s; flex: 0 0 auto; }
.dw-title-go:hover .dw-title-arrow, .dw-title-go:focus-visible .dw-title-arrow { opacity: 1; transform: translateX(0); }
/* SPEC210 — any clickable widget row/stat: subtle hover + keyboard focus, generous tap target. */
.dw-go { cursor: pointer; border-radius: 7px; margin: 0 -6px; padding: 3px 6px; transition: background .12s; }
.dw-li.dw-go, .dw-rank.dw-go { padding: 4px 6px; }
.dw-go:hover { background: var(--hover); }
.dw-go:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; background: var(--hover); }
.dw-x { border: none; background: transparent; color: var(--faint); cursor: pointer; font-size: var(--fs-caption); padding: 2px 4px; border-radius: 6px; }
.dw-x:hover { background: var(--hover); color: var(--danger); }
.dw-body { min-height: 40px; }
.dw-stat { margin-bottom: 6px; }
.dw-big { font-size: 26px; font-weight: var(--fw-black); letter-spacing: -.5px; line-height: 1.1; }
.dw-stat-label { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.dw-list { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; }
.dw-li { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 12.5px; }
.dw-li-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dw-li-s { flex: 0 0 auto; color: var(--muted); font-variant-numeric: tabular-nums; font-weight: var(--fw-semibold); }
.dw-rank { display: flex; align-items: center; gap: 6px; font-size: 12.5px; }
.dw-rank .dw-li-t { flex: 1; font-weight: var(--fw-semibold); }
.dw-medal { width: 18px; text-align: center; }

/* add-widget catalog */
.dw-catalog { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
@media (max-width: 520px) { .dw-catalog { grid-template-columns: 1fr; } }
.dw-cat { display: flex; flex-direction: column; align-items: stretch; gap: 6px; text-align: left; padding: 10px 12px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--panel); cursor: pointer; }
.dw-cat:hover { border-color: var(--accent); background: var(--hover); }
.dw-cat-on { border-color: var(--accent); }
.dw-cat-ico { font-size: var(--fs-lg); }
.dw-cat-head { display: flex; align-items: center; gap: 8px; }
.dw-cat-label { flex: 1; font-weight: var(--fw-semibold); font-size: var(--fs-caption); display: inline-flex; align-items: center; gap: 4px; min-width: 0; }
/* CUSTOM-5 — clipped, non-interactive live preview of the widget in the catalog */
.dw-cat-preview { max-height: 92px; overflow: hidden; pointer-events: none; opacity: .82; border-top: 1px solid var(--border); padding-top: 6px; font-size: var(--fs-micro); -webkit-mask-image: linear-gradient(to bottom, #000 65%, transparent); mask-image: linear-gradient(to bottom, #000 65%, transparent); }
.dw-cat-preview .dw-big { font-size: 20px; }
.dw-cat-tag { font-size: 10px; font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .4px; color: var(--muted);
  background: var(--subtle); border-radius: 999px; padding: 1px 6px; }

/* ============ SPEC77 — live AI answer (FAQ) ============ */
.faq-ai-answer { margin-top: 12px; background: var(--accent-soft); border: 1px solid var(--accent); border-radius: 12px; padding: 12px 14px; }
.faq-ai-label { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .4px; color: var(--accent); margin-bottom: 6px; }
.faq-ai-text { font-size: var(--fs-body); line-height: 1.55; white-space: pre-wrap; }
/* SPEC79 — one-click AI draft box (App.aiButton result) */
.ai-gen-result { margin-top: 12px; }
.ai-gen-result:empty { display: none; }
.ai-gen-label { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .4px; color: var(--accent); margin-bottom: 6px; }
.ai-gen-text { font-size: var(--fs-body); line-height: 1.55; white-space: pre-wrap; background: var(--accent-soft); border: 1px solid var(--accent); border-radius: 12px; padding: 12px 14px; }
/* SPEC81 — reactive home "Pulse" strip */
.pulse-strip { display: flex; flex-wrap: wrap; gap: 8px; margin: 2px 0 14px; }
.pulse-pill { display: inline-flex; align-items: center; gap: 7px; padding: 7px 13px; border-radius: 999px; font-size: var(--fs-caption); font-weight: var(--fw-bold); cursor: pointer; border: 1px solid var(--border); background: var(--card); color: var(--text); transition: transform .08s ease, box-shadow .12s ease, background .12s ease; }
.pulse-pill:hover { transform: translateY(-1px); box-shadow: 0 3px 10px rgba(0,0,0,.10); }
.pulse-pill .pulse-ic { font-size: var(--fs-body); }
.pulse-pill.pulse-warn { border-color: var(--warn); background: var(--warn-soft); color: var(--warn); }
.pulse-pill.pulse-go { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.today-focus { margin: 0 0 12px; }
/* SPEC84 — tags / labels */
.tag-chips { display: inline-flex; flex-wrap: wrap; gap: 4px; vertical-align: middle; }
.tag-input-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.tag-input-chips:empty { display: none; }
.tag-chip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 8px; border-radius: 999px; font-size: var(--fs-meta); font-weight: var(--fw-bold); border: 1px solid transparent; }
.tag-chip .tag-x { border: none; background: transparent; color: inherit; cursor: pointer; font-size: var(--fs-micro); line-height: 1; padding: 0; opacity: .65; }
.tag-chip .tag-x:hover { opacity: 1; }
/* SPEC85 — bulk actions */
.bulk-cb { width: 16px; height: 16px; cursor: pointer; accent-color: var(--accent); }
tr.row-selected > td { background: var(--accent-soft) !important; }
.bulk-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 10px; padding: 8px 12px; border: 1px solid var(--accent); background: var(--accent-soft); border-radius: 10px; position: sticky; top: 6px; z-index: 5; }
.bulk-bar .bulk-count { font-weight: var(--fw-black); color: var(--accent); font-size: var(--fs-caption); }
.kanban-card .kc-sel { float: right; margin: 0 0 4px 6px; }
.kanban-card.card-selected { outline: 2px solid var(--accent); outline-offset: 1px; }
/* SPEC87 — saved / named views bar */
.views-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0 0 10px; }
.views-label { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .4px; color: var(--muted); margin-right: 2px; }
.view-chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 11px; border-radius: 999px; font-size: 12.5px; font-weight: var(--fw-bold); cursor: pointer; border: 1px solid var(--border); background: var(--card); color: var(--text); transition: border-color .12s ease, background .12s ease; }
.view-chip:hover { border-color: var(--accent); }
.view-chip.active { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.view-chip-x { font-size: 10px; opacity: .5; }
.view-chip-x:hover { opacity: 1; }
.view-chip-add { border-style: dashed; color: var(--muted); font-weight: var(--fw-semibold); }
/* SPEC90 — Books (Beancount reports) */
.books-section { margin-bottom: 16px; }
.books-sec-head { display: flex; justify-content: space-between; align-items: baseline; font-weight: var(--fw-black); font-size: var(--fs-body); padding: 6px 8px; border-bottom: 2px solid var(--border); }
.books-tree { padding: 3px 0; }
.books-row { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 4px 8px; font-size: var(--fs-caption); border-radius: 5px; }
.books-row:hover { background: var(--hover); }
.books-row.books-parent { font-weight: var(--fw-bold); }
.books-amt { font-variant-numeric: tabular-nums; white-space: nowrap; cursor: pointer; padding: 1px 4px; border-radius: 4px; }
.books-amt:hover { background: var(--accent-soft); color: var(--accent); text-decoration: underline; }
.books-grandtotal { display: flex; justify-content: space-between; align-items: baseline; margin-top: 14px; padding: 10px 8px; border-top: 2px solid var(--text); font-weight: var(--fw-black); font-size: 14.5px; }
.books-grandtotal.neg { color: var(--danger); }
.books-link { cursor: pointer; color: var(--accent); }
.books-link:hover { text-decoration: underline; }
.books-tb td, .books-drill td { font-size: 12.5px; }
.books-total td { font-weight: var(--fw-black); border-top: 2px solid var(--text); }

/* ---- SPEC100 Receivables ---- */
.field-label { display: block; font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--muted); margin: 0 0 4px; }
.ar-bar { display: flex; height: 16px; border-radius: 8px; overflow: hidden; background: var(--border); margin: 4px 0 10px; }
.ar-bar-seg { display: flex; align-items: center; justify-content: center; min-width: 2px; cursor: pointer; transition: opacity .15s; }
.ar-bar-seg.dim { opacity: .35; }
.ar-bar-seg:hover { filter: brightness(1.08); }
.ar-bar-lbl { font-size: 10px; font-weight: var(--fw-black); color: #fff; text-shadow: 0 1px 1px rgba(0,0,0,.25); }
.ar-legend { display: flex; flex-wrap: wrap; gap: 6px; }
.ar-chip { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--border); background: var(--panel); border-radius: 999px; padding: 4px 10px; font-size: var(--fs-meta); cursor: pointer; font-family: inherit; color: var(--text); }
.ar-chip.on { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.ar-chip strong { font-variant-numeric: tabular-nums; }
.ar-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; flex: none; }
.ar-age { display: inline-flex; align-items: center; gap: 6px; justify-content: flex-end; font-variant-numeric: tabular-nums; }
.ar-table td { font-size: var(--fs-caption); vertical-align: middle; }
.ar-table tr.ar-overdue td { background: color-mix(in srgb, var(--danger) 7%, transparent); }
.ar-actions { white-space: nowrap; text-align: right; }
.ar-actions .btn { margin-left: 4px; }

/* ---- SPEC104 Earnings + tip modal ---- */
.field { margin-bottom: 12px; }
.field:last-child { margin-bottom: 0; }
.earn-list { display: flex; flex-direction: column; }
.earn-row { display: flex; align-items: center; gap: 11px; padding: 9px 4px; border-bottom: 1px solid var(--border); }
.earn-row:last-child { border-bottom: none; }
.earn-dot { width: 26px; height: 26px; border-radius: 7px; display: inline-flex; align-items: center; justify-content: center; font-size: var(--fs-caption); flex: none; filter: saturate(.9); }
.earn-main { flex: 1 1 auto; min-width: 0; }
.earn-label { font-size: var(--fs-caption); font-weight: var(--fw-semibold); line-height: var(--lh-snug); }
.earn-note { font-size: 11.5px; line-height: 1.4; margin-top: 1px; }
.earn-date { font-size: var(--fs-meta); white-space: nowrap; }
.earn-amt { font-variant-numeric: tabular-nums; font-weight: var(--fw-black); white-space: nowrap; min-width: 64px; text-align: right; }

/* ---- SPEC105 Grow the Business ---- */
.grow-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 12px; }
.grow-play { margin: 0; display: flex; flex-direction: column; }
.grow-play-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; }
.grow-play-title { font-weight: var(--fw-black); font-size: 14.5px; letter-spacing: -.2px; }
.grow-earn { flex: none; font-size: var(--fs-micro); font-weight: var(--fw-black); color: var(--ok-ink); background: var(--ok-soft); border-radius: 999px; padding: 3px 9px; white-space: nowrap; }
.grow-what { font-size: 12.5px; line-height: var(--lh-normal); color: var(--muted); margin-top: 8px; }
.grow-pitch { font-size: var(--fs-caption); line-height: var(--lh-normal); margin-top: 10px; padding: 9px 11px; background: var(--hover); border-radius: 8px; border-left: 3px solid var(--accent); }
.grow-pitch-q { color: var(--accent); font-weight: var(--fw-black); }
.grow-earn-grid { display: flex; flex-wrap: wrap; gap: 7px; }
.grow-earn-chip { display: inline-flex; flex-direction: column; gap: 1px; border: 1px solid var(--border); background: var(--panel); border-radius: 9px; padding: 6px 10px; font-size: var(--fs-meta); }
.grow-earn-chip strong { font-size: 12.5px; }
.grow-earn-chip .muted { font-size: var(--fs-micro); }
.grow-job .grow-job-row { display: flex; align-items: center; gap: 8px; padding: 5px 0; border-bottom: 1px solid var(--border); }
.grow-job .grow-job-row:last-of-type { border-bottom: none; }

/* ---- SPEC106 ownership loop: goal bar, scoreboard, earned chip ---- */
.goal-bar { height: 9px; border-radius: 6px; background: var(--border); overflow: hidden; }
.goal-fill { height: 100%; border-radius: 6px; background: linear-gradient(90deg, var(--accent), #16a34a); transition: width .35s ease; min-width: 2px; }
.earn-chip { border: 1.5px solid var(--accent); background: var(--accent-soft); }
.earn-chip:hover { filter: brightness(1.02); }
.grow-score { display: flex; flex-direction: column; }
.grow-score-row { display: flex; align-items: center; gap: 10px; padding: 7px 2px; border-bottom: 1px solid var(--border); }
.grow-score-row:last-child { border-bottom: none; }
.grow-score-rank { width: 26px; text-align: center; font-weight: var(--fw-black); flex: none; }
.grow-score-name { font-weight: var(--fw-bold); font-size: var(--fs-caption); flex: 1 1 auto; }

/* ---- SPEC107 Production metrics ---- */
.cov-wrap { margin-top: 8px; }
.cov-bar { height: 5px; border-radius: 4px; background: var(--border); overflow: hidden; }
.cov-fill { height: 100%; background: var(--accent); border-radius: 4px; }
.cov-txt { font-size: 10.5px; color: var(--muted); margin-top: 3px; }
.cov-pill { font-size: 11.5px; font-weight: var(--fw-bold); color: var(--muted); background: var(--panel); border: 1px solid var(--border); border-radius: 999px; padding: 4px 11px; }
.metric-dualbar { display: flex; gap: 2px; align-items: flex-end; height: 100%; justify-content: center; }
.metric-dualbar .bar { width: 12px; }
.bar.bar-alt { background: var(--ok); }
.lg-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; vertical-align: middle; margin-right: 2px; }

/* ---- SPEC110 win moments (sparkle + pop) ---- */
.spark-layer { position: fixed; inset: 0; z-index: 300; pointer-events: none; overflow: hidden; }
.spark { position: fixed; transform: translate(-50%, -50%); will-change: transform, opacity; animation: spark-burst .7s var(--ease) forwards; line-height: 1; }
@keyframes spark-burst {
  0% { transform: translate(-50%, -50%) scale(.3); opacity: 0; }
  18% { opacity: 1; }
  100% { transform: translate(calc(-50% + var(--sx)), calc(-50% + var(--sy))) scale(1); opacity: 0; }
}
.win-pop { animation: win-pop .46s var(--ease-spring); }
@keyframes win-pop { 0% { transform: scale(1); } 38% { transform: scale(1.13); } 100% { transform: scale(1); } }

/* ---- SPEC111 Team Wins feed ---- */
.wins-feed { display: flex; flex-direction: column; }
.wins-empty { font-size: var(--fs-caption); padding: 8px 2px; line-height: var(--lh-normal); }
.win-row { display: flex; align-items: flex-start; gap: 10px; padding: 8px 2px; border-bottom: 1px solid var(--border); }
.win-row:last-child { border-bottom: none; }
.win-emoji { font-size: 19px; line-height: 1.3; flex: none; width: 24px; text-align: center; }
.win-mid { flex: 1 1 auto; min-width: 0; }
.win-text { font-size: var(--fs-caption); line-height: 1.4; }
.win-reacts { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 6px; position: relative; }
.win-react { font-size: 11.5px; font-weight: var(--fw-semibold); border: 1px solid var(--border); background: var(--panel); border-radius: 999px; padding: 2px 8px; cursor: pointer; font-family: inherit; color: var(--text); transition: background var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease); }
.win-react:hover { background: var(--hover); }
.win-react.on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.win-react-add { color: var(--muted); font-weight: var(--fw-black); padding: 2px 9px; }
.win-react-pop { position: absolute; bottom: calc(100% + 4px); left: 0; display: flex; gap: 2px; background: var(--panel); border: 1px solid var(--border-strong); border-radius: 999px; padding: 3px 5px; box-shadow: var(--shadow-lg); z-index: 5; }
.win-react-opt { font-size: var(--fs-md); line-height: 1; background: none; border: none; cursor: pointer; padding: 3px 4px; border-radius: 6px; transition: transform var(--t-fast) var(--ease); }
.win-react-opt:hover { transform: scale(1.25); }
.win-time { font-size: var(--fs-micro); white-space: nowrap; flex: none; padding-top: 2px; }
.milestone-banner { border: 1.5px solid var(--accent); background: var(--accent-soft); }
.milestone-line { font-size: 14.5px; font-weight: var(--fw-bold); padding: 3px 0; letter-spacing: -.1px; }

/* ============ SPEC76 — Integrations hub ============ */
.intg-row { border-top: 1px solid var(--border); padding: 12px 0; }
.intg-row:first-of-type { border-top: 0; }
.intg-head { display: flex; align-items: flex-start; gap: 10px; }
.intg-ico { font-size: 20px; flex: 0 0 auto; }
.intg-meta { flex: 1; min-width: 0; }
.intg-name { font-weight: var(--fw-bold); font-size: var(--fs-body); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.intg-blurb { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.intg-status { font-size: 10.5px; font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .4px; border-radius: 999px; padding: 2px 8px; white-space: nowrap; }
.intg-soon { background: var(--subtle); color: var(--muted); }
.intg-off { background: var(--warn-soft, rgba(220,104,3,.12)); color: var(--warn-ink); }
.intg-live { background: var(--ok-soft, rgba(7,148,85,.14)); color: var(--ok-ink); }

/* ============ SPEC73 — proactive nudges (stale deals) ============ */
.pl-idle { margin-top: 6px; font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--warn); background: var(--warn-soft, rgba(220,104,3,.12));
  border-radius: 6px; padding: 2px 7px; display: inline-flex; align-items: center; gap: 5px; }

/* SPEC244 — Reactive CRM card affordances: next-step line, "add a step" prompt, tiered rot */
.pl-next { display: block; width: 100%; text-align: left; margin-top: 6px; font-size: 11.5px; font-weight: var(--fw-bold);
  color: var(--accent-hover); background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
  border-radius: 6px; padding: 4px 8px; cursor: pointer; white-space: normal; line-height: var(--lh-snug); }
.pl-next.overdue { color: var(--danger); background: var(--danger-soft, rgba(239,68,68,.12)); border-color: color-mix(in srgb, var(--danger) 35%, transparent); }
.pl-needstep { display: inline-flex; align-items: center; margin-top: 6px; font-size: var(--fs-micro); font-weight: var(--fw-bold); cursor: pointer;
  color: var(--muted); background: var(--subtle); border: 1px dashed var(--border); border-radius: 6px; padding: 3px 8px; }
.pl-needstep:hover { color: var(--accent-hover); border-color: var(--accent); }
.pl-rot-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px; background: var(--warn); }
.pl-rot-cool .pl-rot-dot { background: #f59e0b; }
.pl-rot-warm .pl-rot-dot { background: #f97316; }
.pl-rot-hot { color: var(--danger); background: var(--danger-soft, rgba(239,68,68,.12)); }
.pl-rot-hot .pl-rot-dot { background: var(--danger); animation: pulse 1.4s infinite; }
.pl-nudge { margin-left: auto; font-size: 10.5px; font-weight: var(--fw-black); cursor: pointer; color: #fff; background: var(--accent);
  border: none; border-radius: 999px; padding: 2px 9px; }
.pl-nudge:hover { filter: brightness(1.06); }

/* ============ SPEC72 — auto Shoot Prep ============ */
.prep-facts { font-size: 13.5px; font-weight: var(--fw-bold); background: var(--subtle); border: 1px solid var(--border); border-radius: 8px; padding: 6px 10px; margin-bottom: 4px; }
.prep-head { font-size: 11.5px; font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .4px; color: var(--muted); margin: 12px 0 5px; }
.prep > .prep-head:first-child { margin-top: 0; }
.prep-svc { font-weight: var(--fw-bold); font-size: var(--fs-caption); margin: 8px 0 2px; }
.prep-list { margin: 0 0 4px; padding-left: 20px; }
.prep-list li { font-size: var(--fs-caption); line-height: var(--lh-normal); color: var(--text); margin-bottom: 2px; }
.prep-links { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 4px; }
.prep-links a { text-decoration: none; }

/* ============ SPEC71 — Activity Log ============ */
.act-day { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .5px; color: var(--muted); margin: 12px 0 4px; padding-top: 8px; border-top: 1px solid var(--border); }
.act-day:first-child { border-top: 0; padding-top: 0; margin-top: 0; }
.act-row { display: flex; align-items: flex-start; gap: 10px; padding: 6px 4px; border-radius: 8px; }
.act-clickable { cursor: pointer; }
.act-clickable:hover { background: var(--hover); }
.act-ico { font-size: 15px; width: 22px; text-align: center; flex: 0 0 auto; }
.act-body { flex: 1; min-width: 0; }
.act-text { font-size: var(--fs-caption); line-height: 1.45; }
.act-name { font-weight: var(--fw-semibold); }
.act-from { color: var(--muted); }
.act-to { color: var(--accent); font-weight: var(--fw-semibold); }
.act-when { font-size: var(--fs-micro); color: var(--faint); margin-top: 1px; }
.act-person-row { display: flex; align-items: center; gap: 10px; padding: 5px 0; }
.act-person-name { font-weight: var(--fw-semibold); font-size: var(--fs-caption); width: 110px; flex: 0 0 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.act-person-n { font-weight: var(--fw-black); font-variant-numeric: tabular-nums; width: 32px; text-align: right; flex: 0 0 auto; }
.act-history { display: flex; flex-direction: column; gap: 2px; max-height: 190px; overflow: auto; }

/* ============ SPEC69 — click-to-copy chip ============ */
.copyable { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; border-radius: 6px; padding: 0 4px; max-width: 100%; vertical-align: bottom; }
.copyable:hover { background: var(--hover); }
.copyable:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.copyable-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.copyable-ico { font-size: var(--fs-micro); opacity: 0; flex: 0 0 auto; color: var(--muted); transition: opacity .12s ease; }
.copyable:hover .copyable-ico, .copyable:focus-visible .copyable-ico { opacity: .7; }
.copyable.copied, .copyable.copied .copyable-ico { color: var(--ok); opacity: 1; }

/* ============ SPEC68 — get-started checklist + accent picker ============ */
.help-section-head { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: var(--fs-meta); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .4px; color: var(--muted);
  margin: 18px 0 8px; }
.setup-list { display: flex; flex-direction: column; gap: 6px; }
.setup-row { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--panel); cursor: pointer; }
.setup-row:hover { background: var(--hover); border-color: var(--accent); }
.setup-row.done { opacity: .7; cursor: default; }
.setup-row.done:hover { background: var(--panel); border-color: var(--border); }
.setup-check { width: 20px; height: 20px; flex: 0 0 auto; border-radius: 50%; border: 2px solid var(--border);
  display: inline-flex; align-items: center; justify-content: center; font-size: var(--fs-meta); font-weight: var(--fw-heavy); color: #fff; }
.setup-row.done .setup-check { background: var(--ok); border-color: var(--ok); }
.setup-label { flex: 1; font-weight: var(--fw-semibold); font-size: 13.5px; }
.setup-go { color: var(--accent); font-weight: var(--fw-black); }
.setup-done-tag { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .4px; color: var(--ok); }
.accent-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.accent-dot { width: 28px; height: 28px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; padding: 0;
  box-shadow: inset 0 0 0 2px var(--panel); }
.accent-dot.active { border-color: var(--text); }
.accent-reset { border: 1px solid var(--border); background: var(--panel); border-radius: 999px; padding: 4px 12px;
  font-size: var(--fs-meta); font-weight: var(--fw-bold); cursor: pointer; color: var(--muted); }
.accent-reset.active { border-color: var(--text); color: var(--text); }
.accent-reset:hover { background: var(--hover); }

/* ============ SPEC67 — interaction & motion polish ============ */
/* smooth transitions on interactive surfaces */
.btn, .chip-btn, .pl-tab, .dw-tile, .card, .input, .select, .textarea, .kanban-card, .pl-template,
.dw-cat, .inc-lb-row, .soc-top-row, .call-row, .cc-card, .snippet-card, .pl-card {
  transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease, transform .12s ease, color .15s ease;
}
/* tactile button press */
.btn:active, .chip-btn:active, .pl-tab:active, .dw-cat:active, .pl-template:active, .toast-btn:active { transform: translateY(1px); }
/* clear, modern keyboard focus rings (accessibility + polish) */
.btn:focus-visible, .chip-btn:focus-visible, .pl-tab:focus-visible, .inc-lb-row:focus-visible,
.dw-cat:focus-visible, a:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
/* DESIGNA 2026-08-19 — a duplicate `.input:focus, .select:focus, .textarea:focus` rule was
   deleted here: identical to :404's except it lacked background-color, so being later-in-file
   it added nothing and only invited the two rules to drift apart. :404 is the one source. */
/* clickable cards/tiles lift a touch */
.kanban-card:hover, .pl-card:hover, .pl-template:hover, .dw-cat:hover { transform: translateY(-1px); box-shadow: var(--shadow-lg); }
/* glassy backdrop behind modals + command palette */
.modal-overlay, .qs-overlay { backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); }
/* a soft fade-in for grids of cards/tiles (matches the count-up feel) */
@media (prefers-reduced-motion: no-preference) {
  .kpi-row > *, .dw-grid > *, .dwx-grid > *, .soc-grid-2 > *, .pl-templates > * { animation: tile-in .26s ease-out both; }
  /* SPEC175 — each view settles in on navigation (#view re-renders per route → fires
     naturally, no JS). A whisper of opacity + rise; reduced-motion disables it.
     SLACK-M checker1 2026-08-13 — fill `both` → `backwards`: with `both`, the finished
     animation kept APPLYING its (implicit-to) end state forever, which Chrome computes
     as transform matrix(1,0,0,1,0,0) — not `none` — so #view was permanently a fixed-
     position CONTAINING BLOCK. Every position:fixed element rendered inside #view
     (the ≤1100px .chat-thread full-screen overlay is the one that ships today) pinned
     to #view's box instead of the viewport — measured live on a 375×812 phone: the
     thread overlay sat at y=56 with its composer's Send button 59px BELOW the screen,
     unreachable. `backwards` is frame-identical (the implicit end state IS the base
     state) but stops applying once finished, so transform computes back to `none` and
     fixed children anchor to the real viewport — exactly what .chat-thread's own
     z-index comment ("above app chrome, below modals") always assumed. */
  #view { animation: view-enter var(--t-slow) var(--ease) backwards; }
  /* mobile: slide modals up from the bottom for a native-app feel */
  @media (max-width: 860px) { .modal, .modal.wide { animation: sheet-up .22s cubic-bezier(.22,1,.36,1); } }
}
@keyframes view-enter { from { opacity: 0; transform: translateY(4px); } }
@keyframes tile-in { from { opacity: 0; transform: translateY(6px); } }
@keyframes sheet-up { from { transform: translateY(100%); } }
/* refined desktop scrollbars */
@media (min-width: 861px) {
  .modal-body, .table-wrap, #view, .cc-analysis { scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
  .modal-body::-webkit-scrollbar, .table-wrap::-webkit-scrollbar, #view::-webkit-scrollbar, .cc-analysis::-webkit-scrollbar { width: 10px; height: 10px; }
  .modal-body::-webkit-scrollbar-thumb, .table-wrap::-webkit-scrollbar-thumb, #view::-webkit-scrollbar-thumb, .cc-analysis::-webkit-scrollbar-thumb { background: var(--border); border-radius: 999px; }
  .modal-body::-webkit-scrollbar-thumb:hover, .table-wrap::-webkit-scrollbar-thumb:hover { background: var(--muted); }
}

/* ============ SPEC64 — Call Tracking ============ */
.call-dir-row { display: grid; grid-template-columns: 110px 1fr auto; align-items: center; gap: 10px; padding: 5px 0; }
.call-dir-stat { font-size: var(--fs-meta); color: var(--muted); white-space: nowrap; font-variant-numeric: tabular-nums; }
.call-log-table th.num, .call-log-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
.call-row { cursor: pointer; }
.call-row:hover { background: var(--hover); }
.table th.num, .table td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* ---------- Schedule / crew dispatch (SPEC94) ---------- */
.sched-grid-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel); }
.sched-grid { border-collapse: collapse; width: 100%; min-width: 760px; }
.sched-grid th, .sched-grid td { border: 1px solid var(--border); vertical-align: top; }
.sched-grid thead th { position: sticky; top: 0; background: var(--panel); z-index: 1; padding: 6px 8px; font-size: var(--fs-meta); text-align: center; }
.sched-grid .sched-name-h { text-align: left; min-width: 110px; }
.sched-grid .sched-day-h.today { background: var(--accent-soft); color: var(--accent); }
.sched-cap-h { min-width: 130px; }
.sched-name { padding: 8px; font-weight: var(--fw-bold); white-space: nowrap; }
.sched-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; margin-right: 6px; vertical-align: middle; }
.sched-daycell { width: 13%; min-width: 92px; padding: 4px; }
.sched-daycell.drop-hot { background: var(--accent-soft); outline: 2px dashed var(--accent); outline-offset: -2px; }
.sched-block { border: 1px solid var(--border); border-left: 3px solid #94a3b8; border-radius: 6px; padding: 4px 6px; margin-bottom: 4px; background: var(--bg); font-size: var(--fs-meta); }
.sched-block.conflict { background: var(--danger-soft); border-color: var(--danger); }
.sched-block.soft { background: var(--warn-soft); border-color: var(--warn); }
.sched-block-top { display: flex; align-items: center; gap: 4px; }
.sched-time { border: none; background: transparent; font-size: 11.5px; font-weight: var(--fw-bold); color: var(--text); padding: 0; width: 84px; }
.sched-block-client { font-weight: var(--fw-semibold); cursor: pointer; margin-top: 2px; }
.sched-block-client:hover { color: var(--accent); }
.sched-block-addr { color: var(--muted); font-size: var(--fs-micro); cursor: pointer; }
.sched-cap { padding: 6px 8px; }
.sched-cap-row { display: flex; align-items: center; gap: 6px; margin: 2px 0; }
.sched-cap-row .databar { flex: 1; }
.sched-unassigned { display: flex; align-items: center; gap: 10px; padding: 8px; border-radius: 7px; border: 1px dashed var(--border); margin-bottom: 6px; cursor: grab; }
.sched-unassigned.dragging { opacity: .5; }
.sched-unassigned:hover { background: var(--hover); }
.sched-chiprow { display: flex; gap: 5px; flex-wrap: wrap; justify-content: flex-end; }
.sched-chip { font-size: 11.5px; padding: 3px 9px; border-radius: 999px; border: 1.5px solid var(--border); background: var(--panel); cursor: pointer; font-weight: var(--fw-semibold); }
.sched-chip:hover { background: var(--hover); }
.sched-myrow { display: flex; align-items: center; gap: 8px; padding: 6px 4px; border-radius: 6px; cursor: pointer; }
.sched-myrow:hover { background: var(--hover); }

/* ---------- Personal sidebar shortcuts (SPEC95) ---------- */
.nav-shortcuts { margin-bottom: 6px; }
.nav-sc-head { display: flex; align-items: center; justify-content: space-between; }
/* LAW-A 2026-08-15 (#22) — same bug as .nav-group-label above: var(--muted)/var(--faint)
   are PAGE inks, applied here on the permanently-dark sidebar rail. Measured on
   --sidebar-bg (light theme, the failing case): --muted 2.51:1 (FAIL) → --sidebar-text
   6.38:1 (PASS); --faint 3.15:1 (FAIL) → --sidebar-text 6.38:1 (PASS). Dark theme was
   already AA (6.46–6.97:1) and stays AA (7.01:1) — no regression. .nav-sc-cat wasn't in
   the original 3-site list but is the same rail, same bug, same fix — included for
   consistency (one ink, not three near-misses). */
.nav-sc-add { border: none; background: transparent; color: var(--sidebar-text); font-size: 15px; font-weight: var(--fw-bold); line-height: 1; cursor: pointer; padding: 0 4px; border-radius: 4px; }
.nav-sc-add:hover { background: var(--hover); color: var(--accent); }
.nav-sc-empty { font-size: 11.5px; color: var(--sidebar-text); padding: 4px 10px 8px; cursor: pointer; line-height: var(--lh-snug); }
.nav-sc-empty:hover { color: var(--accent); }
.nav-sc-cat { font-size: 10.5px; text-transform: uppercase; letter-spacing: var(--ls-label); color: var(--sidebar-text); padding: 4px 10px 2px; }
.nav-sc-item .nav-sc-lbl { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-align: left; }
.nav-sc-item .nav-sc-x { opacity: 0; color: var(--muted); font-size: var(--fs-micro); padding: 0 2px; border-radius: 4px; }
.nav-sc-item:hover .nav-sc-x { opacity: .7; }
.nav-sc-item .nav-sc-x:hover { opacity: 1; color: #ef4444; background: var(--hover); }
.datalist-host { height: 0; overflow: hidden; }

/* ---------- Snippet quick-insert (SPEC96) ---------- */
.snip-dd { z-index: 9000; background: var(--panel); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow-lg, 0 12px 32px rgba(0,0,0,.18)); max-height: 280px; overflow-y: auto; padding: 4px; }
.snip-opt { padding: 7px 9px; border-radius: 7px; cursor: pointer; }
.snip-opt.active, .snip-opt:hover { background: var(--accent-soft); }
.snip-opt-title { font-size: 12.5px; font-weight: var(--fw-bold); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.snip-opt-body { font-size: 11.5px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-top: 1px; }
.snip-dd-hint { font-size: 10.5px; color: var(--faint); padding: 5px 9px 3px; border-top: 1px solid var(--border); margin-top: 3px; }
/* SPEC267 — @-mention typeahead dropdown (mirrors .snip-dd) */
.mention-dd { z-index: 9000; background: var(--panel); border: 1px solid var(--border); border-radius: 10px; box-shadow: var(--shadow-lg, 0 12px 32px rgba(0,0,0,.18)); max-height: 260px; overflow-y: auto; padding: 4px; }
.mention-opt { display: flex; align-items: center; gap: 8px; padding: 6px 9px; border-radius: 7px; cursor: pointer; }
.mention-opt.active, .mention-opt:hover { background: var(--accent-soft); }
.mention-av { flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%; color: #fff; font-size: 10px; font-weight: var(--fw-bold); display: inline-flex; align-items: center; justify-content: center; }
.mention-opt-name { font-size: 12.5px; font-weight: var(--fw-bold); color: var(--text); }
.mention-opt-role { font-size: var(--fs-micro); color: var(--muted); margin-left: auto; }

/* ---------- Time tracking / timesheets (SPEC98) ---------- */
.ts-clock { border-left: 3px solid var(--accent); }
.ts-elapsed { font-variant-numeric: tabular-nums; }
.ts-live-dot { width: 10px; height: 10px; border-radius: 50%; background: #ef4444; display: inline-block; animation: tsPulse 1.4s infinite; }
@keyframes tsPulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } }
.ts-week { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.ts-day { border: 1px solid var(--border); border-radius: 8px; background: var(--bg); padding: 7px 4px; text-align: center; cursor: pointer; }
.ts-day:hover { background: var(--hover); }
.ts-day.has { background: var(--accent-soft); border-color: var(--accent); }
.ts-day.today { outline: 2px solid var(--accent); outline-offset: -2px; }
.ts-day-h { font-size: var(--fs-micro); font-weight: var(--fw-bold); }
.ts-day-d { font-size: 10.5px; }
.ts-day-hrs { font-size: var(--fs-body); font-weight: var(--fw-black); margin-top: 3px; font-variant-numeric: tabular-nums; }

/* ---------- Time off / PTO (SPEC99) ---------- */
.to-row { display: flex; align-items: center; gap: 8px; padding: 7px 0; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.to-row:last-child { border-bottom: none; }
.sched-off { font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--ok); background: var(--ok-soft); border: 1px dashed var(--ok); border-radius: 5px; padding: 2px 6px; margin-bottom: 4px; }

/* ---------- Calendar busy overlay in the scheduler (SPEC97) ---------- */
.sched-busy { font-size: 10.5px; color: var(--muted); background: repeating-linear-gradient(45deg, var(--hover), var(--hover) 5px, transparent 5px, transparent 10px); border: 1px dashed var(--border); border-radius: 5px; padding: 2px 5px; margin-bottom: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ============ SPEC112 v3 — client-facing "watch your numbers climb" report ============ */
.tss-report { max-width: 900px; margin: 0 auto; }
.tss-hero { background: linear-gradient(135deg, var(--accent), var(--accent-hover)); color: #fff; border-radius: var(--radius-lg); padding: 28px 24px; text-align: center; box-shadow: var(--shadow-lg); }
.tss-hero-kicker { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: 2px; opacity: .85; }
.tss-hero-title { font-size: var(--fs-display); font-weight: var(--fw-black); letter-spacing: -.5px; margin: 6px 0 4px; }
.tss-hero-sub { font-size: var(--fs-body); opacity: .92; }
.tss-stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-top: 16px; }
.tss-stat { background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 16px; text-align: center; box-shadow: var(--shadow-sm), var(--card-hi); }
.tss-stat-label { font-size: var(--fs-micro); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .5px; color: var(--muted); }
.tss-stat-val { font-size: 30px; font-weight: var(--fw-black); letter-spacing: -1px; margin: 4px 0 2px; font-variant-numeric: tabular-nums; }
.tss-stat-delta { font-size: var(--fs-meta); font-weight: var(--fw-bold); }
.tss-stat-delta.up { color: var(--ok); }
.tss-stat-delta.down { color: var(--danger); }
.tss-badges { display: flex; flex-wrap: wrap; gap: 8px; }
.tss-badge { display: inline-flex; align-items: center; gap: 8px; background: var(--accent-soft); color: var(--accent); border-radius: 999px; padding: 7px 14px; font-size: var(--fs-caption); font-weight: var(--fw-bold); }
.tss-badge-emoji { font-size: var(--fs-md); }
.tss-ba { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.tss-ba-col { flex: 1; min-width: 130px; text-align: center; font-size: var(--fs-caption); line-height: 1.7; }
.tss-ba-when { font-size: var(--fs-micro); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .5px; color: var(--muted); margin-bottom: 4px; }
.tss-ba-arrow { font-size: var(--fs-h1); color: var(--accent); font-weight: var(--fw-black); }
.tss-funnel > div { padding: 6px 0; border-bottom: 1px solid var(--bg-2); font-size: var(--fs-body); }
.tss-funnel > div:last-child { border-bottom: none; }
.tss-funnel strong { font-size: var(--fs-lg); }
.tss-close { text-align: center; font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--muted); padding: 14px; font-style: italic; }
@media (max-width: 560px) { .tss-hero-title { font-size: var(--fs-h1); } .tss-stat-val { font-size: 24px; } .tss-ba-arrow { transform: rotate(90deg); } .tss-ba-col { min-width: auto; flex-basis: calc(50% - 7px); } }

/* SPEC113 — Slack/IG-style chat day dividers */
.chat-day-divider { display: flex; align-items: center; gap: 12px; margin: 16px 4px 8px; }
.chat-day-divider::before, .chat-day-divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.chat-day-divider span { font-size: 11.5px; font-weight: var(--fw-bold); color: var(--muted); background: var(--card); padding: 2px 12px; border: 1px solid var(--border); border-radius: 999px; white-space: nowrap; }

/* SPEC116 — territory geo cluster map */
.geo-map-host { background: var(--subtle); border: 1px solid var(--border); border-radius: var(--radius); padding: 10px; }
/* responsive SVG charts/maps never force horizontal scroll on phones */
.geo-map-host svg { width: 100%; height: auto; max-width: 100%; display: block; }

/* ============================================================
   SPEC119 — premium + responsive pass (research-backed: Linear /
   Stripe / Notion / Vercel / Material-3 / Apple-HIG). Additive +
   appended last so equal-specificity overrides win cleanly.
   ============================================================ */

/* 44px touch-target utility for icon-only / tiny JS controls */
.tap { min-width: 44px; min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }

/* drag affordance — keep the dragged element legible instead of washed-out opacity
   (the Linear/Notion convention: a dashed accent outline, not a ghost) */
.kanban-card.dragging, .dw-tile.dragging, .sched-unassigned.dragging {
  opacity: .92; outline: 2px dashed var(--accent); outline-offset: 1px;
}

/* keyboard users can reach hover-revealed actions (no keyboard trap) */
.chat-msg-reply:focus-visible, .icon-btn:focus-visible, .th-x:focus-visible, .row-actions :focus-visible { opacity: 1 !important; }

/* smoother grid degradation: 3 → 2 → 1 (was 3 → 1 at 860). */
@media (min-width: 861px) and (max-width: 1140px) { .grid-3, .goal-grid { grid-template-columns: 1fr 1fr; } }

/* KPI value eases down on the smallest screens (auto-fit already wraps the cards) */
@media (max-width: 480px) { .kpi-value { font-size: var(--fs-h1); } }

/* search field never overflows a tiny phone */
@media (max-width: 380px) { .search-input { min-width: 0; width: 100%; } }

/* safe-area insets so content clears the notch / home-indicator (2-arg env fallback
   keeps non-notched browsers unaffected) */
@supports (padding: max(0px)) {
  #view { padding-left: max(30px, env(safe-area-inset-left, 0px)); padding-right: max(30px, env(safe-area-inset-right, 0px)); }
}
@media (max-width: 860px) {
  @supports (padding: max(0px)) {
    #view { padding-left: max(14px, env(safe-area-inset-left, 0px)); padding-right: max(14px, env(safe-area-inset-right, 0px)); }
    #sidebar { padding-top: max(12px, env(safe-area-inset-top, 0px)); }
  }
}

/* dense tables + cards breathe a little less on phones so more fits before scroll */
@media (max-width: 560px) {
  .table th, .table td { padding: 8px 10px; }
  .table { font-size: 12.5px; }
  .card-pad { padding: 14px; }
}

/* SPEC164 — client status portal (preview + future client page). Branded, money-free. */
/* SPEC233 — Client Hub "Presented by [agent]" foregrounds the agent brand at the top of the unified hub */
.ch-presented { font-size: var(--fs-meta); font-weight: var(--fw-bold); letter-spacing: .05em; text-transform: uppercase; color: var(--accent); margin-bottom: 4px; }
.cstatus { max-width: 560px; margin: 0 auto; }
.cstatus-brand { font-weight: var(--fw-black); letter-spacing: .02em; color: var(--accent); font-size: var(--fs-caption); text-transform: uppercase; }
.cstatus-title { margin: 4px 0 2px; font-size: 20px; line-height: var(--lh-tight); }
.cstatus-hi { color: var(--muted); font-size: var(--fs-caption); margin-bottom: 14px; }
.cstatus-prog-label { font-weight: var(--fw-bold); font-size: var(--fs-caption); margin: 8px 0 6px; }
.cstatus-track { height: 10px; border-radius: 999px; background: var(--bg-2); overflow: hidden; }
.cstatus-fill { height: 100%; background: var(--ok); border-radius: 999px; transition: width .35s ease; }
.cstatus-services { margin: 14px 0; display: flex; flex-direction: column; gap: 8px; }
.cstatus-svc { display: flex; align-items: center; gap: 10px; padding: 11px 13px; border: 1px solid var(--border); border-radius: 12px; background: var(--card-bg, var(--bg)); }
.cstatus-svc-main { display: flex; align-items: center; gap: 8px; flex: 1 1 auto; flex-wrap: wrap; min-width: 0; }
.cstatus-svc-name { font-weight: var(--fw-bold); font-size: var(--fs-body); }
.cstatus-chip { color: #fff; font-size: var(--fs-micro); font-weight: var(--fw-bold); padding: 2px 9px; border-radius: 999px; white-space: nowrap; }
.cstatus-link { flex: 0 0 auto; font-weight: var(--fw-bold); font-size: var(--fs-caption); color: var(--accent); text-decoration: none; padding: 6px 10px; border-radius: 8px; background: var(--accent-soft); }
.cstatus-allfiles { display: inline-block; margin-top: 4px; font-weight: var(--fw-bold); font-size: var(--fs-caption); color: var(--accent); text-decoration: none; }
.cstatus-empty { color: var(--muted); font-size: var(--fs-caption); padding: 12px 0; }
.cstatus-rate { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border); }
.cstatus-rate-q { font-weight: var(--fw-bold); font-size: 13.5px; margin-bottom: 6px; }
/* SPEC271 (post-C #3) — client-facing Impact proof strip */
.cstatus-impact { margin-top: 22px; padding: 18px 18px 6px; border-radius: 14px; background: color-mix(in srgb, var(--cover-accent, #2b608f) 8%, var(--card, #fff)); border: 1px solid color-mix(in srgb, var(--cover-accent, #2b608f) 20%, transparent); }
.cstatus-impact-head { text-align: center; margin-bottom: 4px; }
.cstatus-impact-title { font-family: var(--serif, Georgia, serif); font-size: 19px; font-weight: var(--fw-semibold); letter-spacing: -.01em; }
.cstatus-impact-since { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.cstatus-impact-stats { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 26px; padding: 12px 0 14px; }
.cstatus-impact-stat { text-align: center; min-width: 64px; }
.cstatus-impact-n { font-size: 26px; font-weight: var(--fw-black); line-height: 1; letter-spacing: var(--ls-tight); color: var(--cover-accent, #2b608f); }
.cstatus-impact-l { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .06em; color: var(--muted); margin-top: 4px; }
.cstatus-stars { display: flex; gap: 4px; }
.cstatus-star { background: none; border: 0; cursor: pointer; font-size: 26px; line-height: 1; color: var(--warn); padding: 9px; min-width: 44px; min-height: 44px; }   /* SPEC280 wave 1 — real touch targets */
/* SPEC280 wave 1 — the invoice as a quiet text link below the gallery, never a hero CTA */
.cstatus-paylink { text-align: center; padding: 14px 0 4px; }
.cstatus-paylink a { font-size: 13.5px; font-weight: var(--fw-semibold); color: var(--muted); text-decoration: underline; text-underline-offset: 3px; }
.cstatus-paylink a:hover { color: var(--text); }
.cstatus-req { margin-top: 16px; }

/* SPEC165 — branded delivery page extras */
.cstatus-facts { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 4px; }
.cstatus-fact { font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--text-soft); background: var(--bg-2); border-radius: 999px; padding: 3px 10px; }
.cstatus-dlall { display: inline-block; margin-top: 12px; }

/* SPEC206 — "what happens next" journey stepper (client status page) */
.cstatus-steps { display: flex; align-items: flex-start; gap: 2px; margin: 4px 0 18px; }
.cstatus-step { flex: 1 1 0; min-width: 0; position: relative; display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px; }
/* connector line between dots (drawn to the left of each step except the first) */
.cstatus-step::before { content: ''; position: absolute; top: 14px; right: 50%; width: 100%; height: 2px; background: var(--border); z-index: 0; }
.cstatus-step:first-child::before { display: none; }
.cstatus-step--done::before, .cstatus-step--now::before { background: color-mix(in srgb, var(--cover-accent, var(--accent)) 60%, var(--border)); }
.cstatus-step-dot { position: relative; z-index: 1; width: 28px; height: 28px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-caption); line-height: 1; background: var(--bg-2); border: 2px solid var(--border); color: var(--text-soft); transition: transform .25s var(--ease-spring); }
.cstatus-step--done .cstatus-step-dot { background: var(--cover-accent, var(--accent)); border-color: transparent; color: #15181c; font-weight: var(--fw-black); }
.cstatus-step--now .cstatus-step-dot { background: color-mix(in srgb, var(--cover-accent, var(--accent)) 18%, var(--panel)); border-color: var(--cover-accent, var(--accent)); color: var(--text); transform: scale(1.12);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--cover-accent, var(--accent)) 18%, transparent); }
.cstatus-step-label { font-size: 10.5px; font-weight: var(--fw-bold); color: var(--text-soft); line-height: var(--lh-tight); }
.cstatus-step--now .cstatus-step-label { color: var(--text); }

/* SPEC206 — location block (delivery page) */
.cstatus-loc { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; margin: 12px 0 4px; padding: 11px 13px; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-2); }
.cstatus-loc-ic { font-size: var(--fs-md); line-height: 1; }
.cstatus-loc-addr { flex: 1 1 auto; min-width: 120px; font-size: var(--fs-caption); font-weight: var(--fw-bold); color: var(--text); }
.cstatus-loc-link { font-size: 12.5px; font-weight: var(--fw-black); color: var(--cover-accent, var(--accent)); white-space: nowrap; }

/* SPEC206 — referral ask (delivery happy-path) */
.cstatus-refer { margin-top: 6px; }

/* SPEC166 — delivery gallery grid + lightbox (the "see everything at a glance" view) */
.cstatus-gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 6px; margin: 12px 0 4px; }
.cstatus-thumb { position: relative; padding: 0; border: 0; border-radius: 10px; overflow: hidden; cursor: pointer; aspect-ratio: 1 / 1; background: var(--bg-2); display: block; }
.cstatus-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .25s ease; }
.cstatus-thumb:hover img { transform: scale(1.06); }
.cstatus-thumb-video { display: flex; align-items: center; justify-content: center; text-decoration: none; }
.cstatus-play { width: 34px; height: 34px; border-radius: 999px; background: rgba(0,0,0,.55); color: #fff; display: flex; align-items: center; justify-content: center; font-size: var(--fs-body); }
.cstatus-lightbox { position: fixed; inset: 0; z-index: 4000; background: rgba(8,10,16,.92); display: flex; align-items: center; justify-content: center; }
.cstatus-lightbox img { max-width: 92vw; max-height: 86vh; border-radius: 8px; box-shadow: 0 20px 60px rgba(0,0,0,.5); }
/* SPEC268 (Bundle C item 6) — before/after "Reveal" slider */
.cstatus-lb-reveal { position: relative; width: min(92vw, 1400px); aspect-ratio: 3 / 2; max-height: 86vh; border-radius: 8px; overflow: hidden; box-shadow: 0 20px 60px rgba(0,0,0,.5); user-select: none; touch-action: pan-y; }
.cstatus-lb-rev-before, .cstatus-lb-rev-after { position: absolute; inset: 0; background-size: cover; background-position: center; }
.cstatus-lb-rev-after { will-change: clip-path; }
.cstatus-lb-rev-range { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; opacity: 0; cursor: ew-resize; -webkit-appearance: none; appearance: none; background: transparent; }
.cstatus-lb-rev-range::-webkit-slider-thumb { -webkit-appearance: none; width: 46px; height: 100%; cursor: ew-resize; }
.cstatus-lb-rev-range::-moz-range-thumb { width: 46px; height: 100%; border: 0; background: transparent; cursor: ew-resize; }
.cstatus-lb-rev-handle { position: absolute; top: 0; bottom: 0; left: 50%; width: 2px; margin-left: -1px; background: rgba(255,255,255,.9); box-shadow: 0 0 0 1px rgba(0,0,0,.28); pointer-events: none; }
.cstatus-lb-rev-knob { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 40px; height: 40px; border-radius: 999px; background: rgba(255,255,255,.94); color: #14181f; font-size: var(--fs-caption); letter-spacing: -.03em; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 12px rgba(0,0,0,.45); }
.cstatus-lb-rev-tag { position: absolute; top: 12px; padding: 4px 10px; border-radius: 999px; font-size: var(--fs-micro); letter-spacing: .07em; text-transform: uppercase; background: rgba(10,12,18,.58); color: #fff; backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); pointer-events: none; }
.cstatus-lb-rev-tag--after { left: 12px; }
.cstatus-lb-rev-tag--before { right: 12px; }
.cstatus-lb-rev-label { position: absolute; left: 12px; bottom: 12px; padding: 5px 11px; border-radius: 6px; font-size: var(--fs-meta); font-weight: var(--fw-semibold); background: rgba(10,12,18,.66); color: #fff; backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); pointer-events: none; }
.cstatus-lightbox.chrome-hidden .cstatus-lb-rev-tag { opacity: 0; transition: opacity .3s var(--ease); }
.cstatus-lb-x { position: absolute; top: 16px; right: 18px; background: rgba(255,255,255,.12); color: #fff; border: 0; width: 40px; height: 40px; border-radius: 999px; font-size: var(--fs-lg); cursor: pointer; }
.cstatus-lb-nav { position: absolute; top: 50%; transform: translateY(-50%); background: rgba(255,255,255,.12); color: #fff; border: 0; width: 46px; height: 46px; border-radius: 999px; font-size: 26px; line-height: 1; cursor: pointer; }
.cstatus-lb-prev { left: 14px; } .cstatus-lb-next { right: 14px; }
.cstatus-lb-cap { position: absolute; bottom: 16px; left: 0; right: 0; text-align: center; color: rgba(255,255,255,.85); font-size: var(--fs-caption); font-weight: var(--fw-bold); }

/* ============================================================
   SPEC167 — Marketing Studio: template cards (.tpl-*) + studio UI (.mkt-*).
   Cards use container units (cqw = 1% of card width) so type scales at any size.
   ============================================================ */
.tpl-card { container-type: inline-size; position: relative; overflow: hidden; border-radius: 14px;
  font-family: var(--tpl-font, sans-serif); color: #fff; background: var(--tpl-primary, #0e7c5a);
  display: flex; flex-direction: column; box-shadow: 0 6px 22px rgba(0,0,0,.18); }
.tpl-square { aspect-ratio: 1 / 1; }
.tpl-story  { aspect-ratio: 9 / 16; }
.tpl-hero { flex: 1 1 auto; min-height: 0; background-size: cover; background-position: center; background-color: #1b2433; }
.tpl-hero--empty { background-image: linear-gradient(150deg, var(--tpl-primary), rgba(0,0,0,.5)); }
.tpl-band { background: var(--tpl-primary); padding: 5.5cqw 6cqw 6cqw; display: flex; flex-direction: column; gap: 1.6cqw; flex: 0 0 auto; }
.tpl-badge { align-self: flex-start; background: var(--tpl-accent); color: #15181c; font-weight: var(--fw-black);
  letter-spacing: .14em; font-size: 3cqw; padding: 1.2cqw 2.8cqw; border-radius: 999px; text-transform: uppercase; }
.tpl-badge--accent { background: var(--tpl-accent); color: #15181c; }
.tpl-headline { font-size: 7cqw; font-weight: var(--fw-black); line-height: 1.04; }
.tpl-headline--center { text-align: center; font-size: 6.4cqw; }
.tpl-tagline { font-size: 3.1cqw; opacity: .85; }
.tpl-tagline--center { text-align: center; }
.tpl-when { font-size: 4.6cqw; font-weight: var(--fw-black); color: var(--tpl-accent); }
.tpl-price { font-size: 6cqw; font-weight: var(--fw-black); color: var(--tpl-accent); }
.tpl-price--center { text-align: center; }
.tpl-facts { font-size: 3.1cqw; font-weight: var(--fw-bold); letter-spacing: .03em; opacity: .92; }
.tpl-agent { display: flex; align-items: center; gap: 2.2cqw; margin-top: 1.6cqw; padding-top: 2.4cqw; border-top: 1px solid rgba(255,255,255,.25); }
.tpl-agent-pic { width: 9cqw; height: 9cqw; border-radius: 999px; background-size: cover; background-position: center; flex: 0 0 auto; }
.tpl-agent-text { display: flex; flex-direction: column; min-width: 0; }
.tpl-agent-name { font-size: 3.4cqw; font-weight: var(--fw-black); }
.tpl-agent-sub { font-size: 2.6cqw; opacity: .8; }
/* Just Sold — centered over a scrimmed hero */
.tpl-justsold .tpl-hero { position: absolute; inset: 0; }
.tpl-scrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(0,0,0,.34), rgba(0,0,0,.66)); }
.tpl-center { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 9cqw; gap: 2cqw; }
.tpl-foot { position: absolute; left: 0; right: 0; bottom: 0; padding: 5cqw 6cqw; background: linear-gradient(0deg, rgba(0,0,0,.6), transparent); }
.tpl-foot .tpl-agent { border-top: 0; padding-top: 0; margin-top: 0; justify-content: center; }
/* Agent Brand — text-only, gradient bg (PNG-exportable) */
.tpl-ab-bg { position: absolute; inset: 0; background: linear-gradient(155deg, var(--tpl-primary), rgba(0,0,0,.6)); }
.tpl-ab-inner { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 9cqw; gap: 2.2cqw; }
.tpl-ab-pic { width: 26cqw; height: 26cqw; border-radius: 999px; background-size: cover; background-position: center; border: .8cqw solid var(--tpl-accent); }
.tpl-ab-name { font-size: 8cqw; font-weight: var(--fw-black); line-height: 1.05; }
.tpl-ab-title { font-size: 3.4cqw; opacity: .85; letter-spacing: .05em; }
.tpl-ab-quote { font-size: 4.2cqw; font-style: italic; color: var(--tpl-accent); max-width: 84%; }
.tpl-ab-cta { font-size: 3.6cqw; font-weight: var(--fw-black); background: var(--tpl-accent); color: #15181c; padding: 1.6cqw 4cqw; border-radius: 999px; }
.tpl-ab-contact { font-size: 2.8cqw; opacity: .82; }

/* studio + editor */
.mkt-templates { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 14px; }
.mkt-tile { padding: 0; border: 1px solid var(--border); border-radius: 14px; overflow: hidden; cursor: pointer; background: var(--card-bg, var(--bg)); display: flex; flex-direction: column; transition: transform .18s ease, box-shadow .18s ease; }
.mkt-tile:hover { transform: translateY(-2px); box-shadow: 0 10px 26px rgba(0,0,0,.14); }
.mkt-mini { padding: 12px; background: var(--bg-2); }
.mkt-mini .tpl-card { width: 100%; }
.mkt-tile-name { padding: 10px 12px; font-weight: var(--fw-bold); font-size: var(--fs-caption); }
.mkt-editor { display: flex; gap: 18px; flex-wrap: wrap; align-items: flex-start; }
.mkt-stage { flex: 0 0 auto; }
.mkt-stage .tpl-card { width: min(420px, 62vw); }
.mkt-ctrl { flex: 1 1 240px; min-width: 220px; display: flex; flex-direction: column; gap: 11px; }
.mkt-field { display: flex; flex-direction: column; gap: 4px; }
.mkt-field--row { flex-direction: row; align-items: center; gap: 8px; }
.mkt-flabel { font-size: 11.5px; font-weight: var(--fw-bold); color: var(--text-soft); text-transform: uppercase; letter-spacing: var(--ls-label); }
.mkt-full { position: fixed; inset: 0; z-index: 4000; background: rgba(8,10,16,.94); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 20px; }
.mkt-full .tpl-card.tpl-square { width: min(86vmin, 560px); }
.mkt-full .tpl-card.tpl-story { height: min(84vh, 820px); width: auto; }
.mkt-full-bar { display: flex; gap: 10px; align-items: center; color: #fff; flex-wrap: wrap; justify-content: center; }
.mkt-full-hint { font-size: var(--fs-caption); opacity: .85; }
@media (max-width: 560px) { .mkt-stage .tpl-card { width: min(420px, 86vw); } }

/* SPEC168 — world-class (Pixieset-style) delivery gallery */
.cstatus--delivery { max-width: 860px; }
.cstatus-cover { position: relative; width: 100%; aspect-ratio: 16 / 9; max-height: 380px; border-radius: 16px; overflow: hidden;
  background-size: cover; background-position: center; background-color: #1b2433; display: flex; align-items: flex-end; }
.cstatus-cover-scrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(0,0,0,.12) 30%, rgba(0,0,0,.72)); }
.cstatus-cover-text { position: relative; padding: 22px 24px; color: #fff; }
.cstatus-cover-brand { font-weight: var(--fw-black); letter-spacing: .12em; text-transform: uppercase; font-size: var(--fs-meta); opacity: .9; }
/* SPEC268 — agent-forward cover credit (agent leads, studio demoted) */
.cstatus-cover-presented { display: flex; flex-direction: column; gap: 1px; text-transform: none; }
.cstatus-cover-eyebrow { font-size: 10.5px; letter-spacing: .18em; text-transform: uppercase; opacity: .82; }
.cstatus-cover-agent { font-size: 15px; letter-spacing: .03em; font-weight: var(--fw-bold); }
.cstatus-cover-mediaby { font-size: 10px; letter-spacing: .1em; opacity: .6; margin-top: 2px; }
.cstatus-cover-title { font-size: clamp(22px, 4vw, 34px); font-weight: var(--fw-black); line-height: 1.1; margin-top: 2px; text-shadow: 0 2px 16px rgba(0,0,0,.4); }
.cstatus-cover-sub { font-size: var(--fs-body); opacity: .92; margin-top: 4px; }
.cstatus-gal { display: flex; flex-wrap: wrap; gap: 5px; margin: 14px 0 6px; }
.cstatus-gal::after { content: ''; flex-grow: 999; }  /* keep the last row from stretching wide */
.cstatus-gal-item { position: relative; height: 250px; flex-grow: 1; flex-basis: 280px; padding: 0; border: 0; border-radius: 6px; overflow: hidden; cursor: pointer; background: color-mix(in srgb, var(--gal-acc, #2b608f) 13%, #1b2433); }
.cstatus-gal-item img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .5s cubic-bezier(.2,.7,.2,1); }
.cstatus-gal-item:hover img { transform: scale(1.045); }
.cstatus-gal-video { display: flex; align-items: center; justify-content: center; text-decoration: none; }
@media (max-width: 620px) { .cstatus-gal-item { height: 180px; } .cstatus-cover { max-height: 260px; } }
/* premium lightbox additions */
.cstatus-lightbox img { opacity: 0; transition: opacity .25s ease; }
.cstatus-lightbox img.in { opacity: 1; }
.cstatus-lb-dl { position: absolute; top: 16px; right: 70px; background: rgba(255,255,255,.12); color: #fff; width: 40px; height: 40px; border-radius: 999px; display: flex; align-items: center; justify-content: center; text-decoration: none; font-size: var(--fs-md); }
.cstatus-lb-dl:hover, .cstatus-lb-x:hover, .cstatus-lb-nav:hover { background: rgba(255,255,255,.22); }

/* SPEC169 — delivery downloads (top bar + per-photo) */
.cstatus-dlbar { margin: 12px 0 4px; }
.cstatus-gal-open { position: absolute; inset: 0; padding: 0; border: 0; background: none; cursor: pointer; display: block; }
.cstatus-gal-dl { position: absolute; top: 7px; right: 7px; z-index: 2; width: 30px; height: 30px; border-radius: 999px; background: rgba(0,0,0,.55); color: #fff; display: flex; align-items: center; justify-content: center; text-decoration: none; font-size: var(--fs-caption); opacity: 0; transition: opacity .18s ease; }
.cstatus-gal-item:hover .cstatus-gal-dl, .cstatus-gal-dl:focus { opacity: 1; }
.cstatus-gal-dl:hover { background: rgba(0,0,0,.8); }
/* SPEC251 — one-tap Share, just left of the download */
.cstatus-gal-share { position: absolute; top: 7px; right: 43px; z-index: 2; width: 30px; height: 30px; border-radius: 999px; border: 0; cursor: pointer; background: rgba(0,0,0,.55); color: #fff; display: flex; align-items: center; justify-content: center; font-size: var(--fs-body); line-height: 1; opacity: 0; transition: opacity .18s ease; }
.cstatus-gal-item:hover .cstatus-gal-share, .cstatus-gal-share:focus { opacity: 1; }
.cstatus-gal-share:hover { background: rgba(0,0,0,.8); }
@media (hover: none) { .cstatus-gal-share, .cstatus-gal-dl { opacity: 1; } }
.cstatus-lb-mls { right: auto; left: 70px; width: auto; padding: 0 12px; font-size: var(--fs-meta); font-weight: var(--fw-black); letter-spacing: .06em; }
/* SPEC267 — plain-language download-size hint in the lightbox */
.cstatus-lb-sizehint { position: absolute; bottom: 52px; left: 50%; transform: translateX(-50%); color: rgba(255,255,255,.9); font-size: 11.5px; letter-spacing: .02em; background: rgba(0,0,0,.4); padding: 4px 13px; border-radius: 999px; pointer-events: none; white-space: nowrap; max-width: 92vw; overflow: hidden; text-overflow: ellipsis; }

/* SPEC170 — single-property website (.site-*) + its editor */
.site-page { font-family: var(--site-font, 'Fraunces', Georgia, serif); color: var(--text); max-width: 920px; margin: 0 auto; }
.site-hero { position: relative; width: 100%; aspect-ratio: 16/9; max-height: 460px; border-radius: 14px; overflow: hidden; background-size: cover; background-position: center; background-color: #1b2433; display: flex; align-items: flex-end; }
.site-hero--empty { background-image: linear-gradient(150deg, var(--site-primary), rgba(0,0,0,.55)); }
.site-hero-scrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(0,0,0,.08) 35%, rgba(0,0,0,.74)); }
.site-hero-text { position: relative; padding: 26px 28px; color: #fff; }
.site-hero-brand { font-weight: var(--fw-bold); letter-spacing: .18em; text-transform: uppercase; font-size: var(--fs-meta); opacity: .9; font-family: var(--font); }
.site-hero-title { font-size: clamp(26px, 5vw, 44px); font-weight: var(--fw-black); line-height: 1.05; margin: 4px 0 0; text-shadow: 0 2px 18px rgba(0,0,0,.45); }
.site-hero-sub { font-size: var(--fs-md); opacity: .94; margin-top: 6px; }
.site-facts { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin: 18px 0; }
.site-fact { flex: 1 1 90px; max-width: 140px; text-align: center; padding: 14px 8px; border: 1px solid var(--border); border-radius: 12px; }
.site-fact-n { font-size: 24px; font-weight: var(--fw-black); color: var(--site-primary); line-height: 1; }
.site-fact-l { font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: .08em; text-transform: uppercase; color: var(--text-soft); margin-top: 5px; }
.site-section { margin: 30px 0; }
.site-section--agent { border-top: 1px solid var(--border); padding-top: 24px; }
.site-h2 { font-size: var(--fs-caption); font-weight: var(--fw-black); letter-spacing: .14em; text-transform: uppercase; color: var(--site-primary); margin: 0 0 14px; font-family: var(--font); }
.site-detail { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 0 28px; }
.site-detail-row { display: flex; justify-content: space-between; gap: 12px; padding: 11px 0; border-bottom: 1px solid var(--border); }
.site-detail-k { color: var(--text-soft); font-size: 13.5px; }
.site-detail-v { font-weight: var(--fw-bold); font-size: 13.5px; text-align: right; }
.site-desc { font-size: var(--fs-md); line-height: 1.7; max-width: 680px; white-space: pre-wrap; }
.site-highlights { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 8px 18px; }
.site-hl { display: flex; align-items: flex-start; gap: 8px; font-size: 14.5px; }
.site-hl-check { color: var(--site-accent); font-weight: var(--fw-heavy); }
.site-map { width: 100%; aspect-ratio: 16/9; max-height: 380px; border: 0; border-radius: 14px; }
/* SPEC220 — enrichment sections: video/3D embeds, floor plans, schedule-a-showing CTA */
.site-embed { position: relative; width: 100%; aspect-ratio: 16/9; border-radius: 14px; overflow: hidden; background: #000; }
.site-embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.site-video { width: 100%; max-height: 540px; border-radius: 14px; background: #000; display: block; }
.site-floorplans { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 14px; }
.site-floorplan { width: 100%; border-radius: 12px; border: 1px solid var(--border); background: #fff; }
.site-cta { text-align: center; background: var(--site-primary, #0e7c5a); color: var(--site-on-primary, #fff); border-radius: 18px; padding: 30px 22px; }
.site-cta .site-h2 { color: var(--site-on-primary, #fff); }
.site-cta-sub { font-size: 15px; line-height: 1.6; max-width: 520px; margin: 6px auto 16px; color: var(--site-on-primary, #fff); }
.site-cta-row { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
/* SPEC220 — QR modal */
.qr-wrap { display: flex; flex-direction: column; gap: 12px; }
.qr-box { display: flex; align-items: center; justify-content: center; min-height: 220px; background: #fff; border: 1px solid var(--border); border-radius: 14px; padding: 14px; }
.qr-box svg { width: 220px; height: 220px; max-width: 100%; }
.qr-note { font-size: var(--fs-meta); }
.site-agent { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; }
.site-agent-pic { width: 92px; height: 92px; border-radius: 999px; background-size: cover; background-position: center; flex: 0 0 auto; border: 3px solid var(--site-accent); }
.site-agent-name { font-size: 21px; font-weight: var(--fw-black); }
.site-agent-sub { color: var(--text-soft); font-size: var(--fs-body); margin-top: 2px; }
.site-agent-lic { color: var(--text-soft); font-size: var(--fs-meta); margin-top: 2px; }
.site-agent-cta { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.site-footer { text-align: center; color: var(--text-soft); font-size: 12.5px; padding: 26px 0 6px; margin-top: 18px; border-top: 1px solid var(--border); font-family: var(--font); }

/* ============================================================
   SPEC221 — luxury property-site TEMPLATES + stat-hero. Base uses the template's
   display/body font vars; each .site-tpl--{id} re-skins palette/spacing/type for a
   distinct boutique feel. Money-safe (stat-hero shows only public price/status). */
.site-page { font-family: var(--site-body-font, var(--site-font, 'Fraunces', Georgia, serif)); }
.site-page .site-hero-title, .site-page .sh-price, .site-page .sh-street { font-family: var(--site-display-font, var(--site-font, 'Fraunces', Georgia, serif)); }
.site-hero-brand { font-family: var(--site-body-font, var(--font)); }
/* stat-hero — the "what everyone checks first" block */
.site-stathero { text-align: center; }
.sh-top { display: flex; gap: 10px; justify-content: center; align-items: center; margin-bottom: 12px; flex-wrap: wrap; }
.sh-status { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .1em; text-transform: uppercase; padding: 5px 12px; border-radius: 999px; }
.sh-status--ok { background: rgba(22,163,74,.14); color: #15803d; }
.sh-status--warn { background: rgba(217,119,6,.16); color: #b45309; }
.sh-status--danger { background: rgba(220,38,38,.14); color: #b91c1c; }
.sh-status--muted { background: var(--bg-2); color: var(--text-soft); }
.sh-status--info { background: rgba(37,99,235,.12); color: #1d4ed8; }
.sh-dom { font-size: var(--fs-meta); color: var(--text-soft); }
.sh-addr { margin-bottom: 6px; }
.sh-street { font-size: clamp(20px,3.4vw,28px); font-weight: var(--fw-bold); line-height: 1.15; }
.sh-city { font-size: var(--fs-caption); letter-spacing: var(--ls-label); color: var(--text-soft); margin-top: 3px; }
.sh-price { font-size: clamp(28px,5vw,40px); font-weight: var(--fw-black); color: var(--text); margin: 8px 0 20px; letter-spacing: -.01em; }
.sh-stats { display: flex; justify-content: center; flex-wrap: wrap; }
.sh-cell { display: flex; flex-direction: column; align-items: center; gap: 5px; padding: 6px 22px; position: relative; }
.sh-cell + .sh-cell::before { content: ''; position: absolute; left: 0; top: 16%; height: 68%; width: 1px; background: var(--border); }
.sh-ic { color: var(--site-primary); display: inline-flex; }
.sh-n { font-size: 19px; font-weight: var(--fw-black); line-height: 1; }
.sh-l { font-size: 10.5px; font-weight: var(--fw-bold); letter-spacing: .08em; text-transform: uppercase; color: var(--text-soft); }
.site-agent-eyebrow { font-size: 10.5px; font-weight: var(--fw-bold); letter-spacing: .16em; text-transform: uppercase; color: var(--site-primary); margin-bottom: 4px; }
/* EDITORIAL — magazine, drop-cap, hairline section kickers */
.site-tpl--editorial .site-h2 { color: var(--text-soft); }
.site-tpl--editorial .site-section { border-top: 1px solid var(--border); padding-top: 26px; }
.site-tpl--editorial .site-section--agent { border-top: 1px solid var(--border); }
.site-tpl--editorial .site-desc::first-letter { font-family: var(--site-display-font); font-size: 3em; line-height: .82; float: left; padding: 4px 10px 0 0; color: var(--site-primary); font-weight: var(--fw-bold); }
/* BOUTIQUE — maximum whitespace, minimal, centered */
.site-tpl--boutique .site-section { margin: 68px 0; }
.site-tpl--boutique .site-h2 { text-align: center; color: var(--text-soft); letter-spacing: .22em; }
.site-tpl--boutique .site-desc { margin: 0 auto; text-align: center; }
.site-tpl--boutique .site-hero { aspect-ratio: 3/4; max-height: 600px; }
/* ESTATE — dark, dramatic, gold accent (the trophy template) */
/* SPEC221 — estate is a FIXED dark surface (stays dark in the app's light mode), so scope a
   dark palette on the container: every inherited token (--text-soft/--muted/--border/--bg-2)
   becomes dark-correct in one place — fixes the muted status pill, agent hairline, and all
   secondary-text contrast (WCAG AA) without per-element patches. */
.site-tpl--estate { background: #0d0d0f; color: #f3f1ec; padding: 0 22px 12px; border-radius: 16px;
  --text: #f3f1ec; --text-soft: #b8b2a6; --muted: #b8b2a6; --border: rgba(255,255,255,.14); --bg-2: #1a1a1d; }
/* colored status pills are hardcoded for a light page — relight them for the dark estate (AA on #0d0d0f) */
.site-tpl--estate .sh-status--ok { background: rgba(22,163,74,.22); color: #4ade80; }
.site-tpl--estate .sh-status--warn { background: rgba(217,119,6,.22); color: #fbbf24; }
.site-tpl--estate .sh-status--danger { background: rgba(220,38,38,.22); color: #f87171; }
.site-tpl--estate .sh-status--info { background: rgba(37,99,235,.22); color: #93c5fd; }
.site-tpl--estate .site-h2 { color: var(--site-accent, #d4af37); }
.site-tpl--estate .sh-price { color: #fff; }
.site-tpl--estate .sh-price::after { content: ''; display: block; width: 56px; height: 2px; background: var(--site-accent, #d4af37); margin: 14px auto 0; }
.site-tpl--estate .sh-n, .site-tpl--estate .sh-street { color: #fff; }
.site-tpl--estate .sh-ic { color: var(--site-accent, #d4af37); }
.site-tpl--estate .sh-l, .site-tpl--estate .sh-city, .site-tpl--estate .sh-dom, .site-tpl--estate .site-hero-sub { color: #b8b2a6; }
.site-tpl--estate .site-detail-row { border-color: rgba(255,255,255,.12); }
.site-tpl--estate .site-detail-k { color: #b8b2a6; }
.site-tpl--estate .site-desc { color: #e7e3da; }
.site-tpl--estate .site-footer { color: #8a857c; border-color: rgba(255,255,255,.12); }
.site-tpl--estate .sh-cell + .sh-cell::before { background: rgba(255,255,255,.18); }
.site-tpl--estate .site-agent-eyebrow { color: var(--site-accent, #d4af37); }
/* LIFESTYLE — warm, rounded, soft, pill highlights */
.site-tpl--lifestyle .site-hero { border-radius: 18px; }
.site-tpl--lifestyle .site-desc { line-height: 1.8; }
.site-tpl--lifestyle .site-h2 { letter-spacing: .1em; }
.site-tpl--lifestyle .site-highlights { display: flex; flex-wrap: wrap; gap: 8px; grid-template-columns: none; }
.site-tpl--lifestyle .site-hl { background: var(--bg-2); border-radius: 999px; padding: 8px 15px; align-items: center; }
/* MODERN — gallery-white, swiss grid, left-aligned, tabular price */
.site-tpl--modern .site-h2 { color: var(--text); letter-spacing: .18em; }
.site-tpl--modern .sh-price { font-variant-numeric: tabular-nums; font-family: var(--site-body-font); letter-spacing: var(--ls-body); }
.site-tpl--modern .site-section { border-top: 1.5px solid var(--text); padding-top: 16px; }
.site-tpl--modern .site-stathero, .site-tpl--modern .sh-top, .site-tpl--modern .sh-stats { text-align: left; justify-content: flex-start; }
.site-tpl--modern .sh-cell:first-child { padding-left: 0; }
/* SPEC221 — template picker (in the listing-site editor) */
.site-tplpick { display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 8px; margin: 6px 0 2px; }
.site-tplcard { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; text-align: left; padding: 9px 10px; border: 1px solid var(--border); border-radius: 11px; background: var(--panel); cursor: pointer; transition: border-color .12s, box-shadow .12s; }
.site-tplcard:hover { border-color: var(--accent); }
.site-tplcard.is-active { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft, rgba(14,124,90,.16)); }
.site-tplcard-sw { width: 100%; height: 26px; border-radius: 6px; border: 1px solid rgba(0,0,0,.06); }
.site-tplcard-n { font-size: var(--fs-caption); font-weight: var(--fw-bold); color: var(--text); }
.site-tplcard-b { font-size: var(--fs-micro); color: var(--muted); line-height: 1.3; }
.site-tplsw--editorial { background: linear-gradient(120deg, #FAF9F6 60%, #c2410c); }
.site-tplsw--boutique { background: linear-gradient(120deg, #EDEAE0 60%, #C9C0A8); }
.site-tplsw--estate { background: linear-gradient(120deg, #141414 60%, #d4af37); }
.site-tplsw--lifestyle { background: linear-gradient(120deg, #FAF0E6 58%, #9CAF88); }
.site-tplsw--modern { background: linear-gradient(120deg, #ffffff 60%, #0e2a47); }
/* SPEC221 Phase B — compliance footer + sticky agent contact bar */
.site-foot-agent { font-weight: var(--fw-semibold); color: var(--text); }
.site-foot-eho { font-size: var(--fs-micro); margin-top: 4px; opacity: .82; }
.site-foot-credit { margin-top: 7px; }
.site-stickybar { position: sticky; bottom: 14px; z-index: 6; display: flex; align-items: center; justify-content: space-between; gap: 12px; max-width: 640px; margin: 20px auto 8px; padding: 9px 11px 9px 14px; background: var(--panel); border: 1px solid var(--border); border-radius: 999px; box-shadow: 0 12px 34px rgba(0,0,0,.18); }
@supports ((backdrop-filter: blur(6px)) or (-webkit-backdrop-filter: blur(6px))) { .site-stickybar { background: color-mix(in srgb, var(--panel) 88%, transparent); backdrop-filter: saturate(1.3) blur(8px); -webkit-backdrop-filter: saturate(1.3) blur(8px); } }   /* SAFPOLISH 2026-08-25 D4 — gate widened to accept the -webkit- only form (older Safari), property paired inside */
.site-stickybar-l { display: flex; align-items: center; gap: 10px; min-width: 0; }
.site-stickybar-pic { width: 36px; height: 36px; border-radius: 999px; background-size: cover; background-position: center; flex: 0 0 auto; }
.site-stickybar-txt { display: flex; flex-direction: column; min-width: 0; }
.site-stickybar-name { font-weight: var(--fw-bold); font-size: 13.5px; line-height: var(--lh-tight); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.site-stickybar-sub { font-size: 11.5px; color: var(--text-soft); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.site-stickybar-r { display: flex; gap: 8px; flex: 0 0 auto; }
.site-tpl--estate .site-stickybar { background: rgba(20,20,22,.92); border-color: rgba(255,255,255,.16); }
.site-tpl--estate .site-stickybar-name { color: #fff; }
.site-tpl--estate .site-stickybar-sub { color: #b8b2a6; }
@media (max-width: 520px) { .site-stickybar { bottom: 8px; padding: 8px 9px 8px 11px; } .site-stickybar-sub { display: none; } .site-stickybar-calllbl { display: none; } }
/* SPEC221 Phase C — area research: walk badge, nearby chips, schools (amenity/lifestyle only) */
.site-walk { display: inline-flex; align-items: baseline; gap: 8px; margin-bottom: 12px; }
.site-walk-n { font-size: 26px; font-weight: var(--fw-black); color: var(--site-primary); line-height: 1; }
.site-walk-l { font-size: var(--fs-meta); font-weight: var(--fw-bold); letter-spacing: var(--ls-label); color: var(--text-soft); text-transform: uppercase; }
.site-nearby { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.site-nearby-chip { display: inline-flex; align-items: center; gap: 6px; padding: 7px 13px; border: 1px solid var(--border); border-radius: 999px; font-size: var(--fs-caption); }
.site-nearby-chip .icon { color: var(--site-primary); }
.site-subh { font-size: var(--fs-meta); font-weight: var(--fw-bold); letter-spacing: .1em; text-transform: uppercase; color: var(--text-soft); margin: 18px 0 8px; }
.site-schools { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 6px 18px; }
.site-school { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--border); }
.site-school-n { font-weight: var(--fw-semibold); font-size: var(--fs-body); }
.site-school-m { color: var(--text-soft); font-size: 12.5px; white-space: nowrap; }
.site-tpl--estate .site-nearby-chip { border-color: rgba(255,255,255,.16); }
.site-tpl--estate .site-school { border-color: rgba(255,255,255,.12); }
.site-tpl--estate .site-walk-n { color: var(--site-accent, #d4af37); }
/* SPEC298 — "Walkability" is an estimate, labelled as such (honesty + no Walk Score trademark) */
.site-walk { flex-wrap: wrap; }
.site-walk-est { flex-basis: 100%; font-size: var(--fs-micro); color: var(--text-soft); font-style: italic; margin-top: 2px; }
/* SPEC298 — the branded, money-free "Request a private showing" inquiry form (agent accent) */
.site-inquiry { max-width: 620px; }
.site-inquiry-sub { font-size: 15px; line-height: 1.6; color: var(--text-soft); margin: 4px 0 16px; }
.site-inquiry-form { display: flex; flex-direction: column; gap: 12px; }
.site-inquiry-form .mkt-field { display: flex; flex-direction: column; gap: 5px; }
.site-inquiry-form .input { width: 100%; }
.site-hp { position: absolute !important; left: -9999px !important; width: 1px; height: 1px; opacity: 0; }
.site-inquiry-actions { margin-top: 4px; }
.site-inquiry-send { background: var(--site-primary); color: var(--site-on-primary, #fff); border: 0; }
.site-inquiry-note { font-size: var(--fs-caption); margin-top: 8px; min-height: 1em; }
.site-inquiry-note.is-ok { color: var(--site-primary); }
.site-inquiry-note.is-err { color: var(--danger, #dc2626); }
/* SPEC298 — human-verify: "Auto-filled ✓ confirm" chip in the editor + the review panel */
.site-verify-chip { background: #fef3c7; color: #92400e; border: 1px solid #fcd34d; font-size: var(--fs-micro); padding: 3px 8px; border-radius: 999px; cursor: pointer; white-space: nowrap; }
.site-verify-chip:hover { background: #fde68a; }
.site-gate { display: none; margin-top: 10px; padding: 10px 12px; border: 1px solid #fcd34d; background: #fffbeb; border-radius: 10px; }
.site-gate.is-open { display: block; }
.site-gate-h { font-size: var(--fs-caption); font-weight: var(--fw-bold); color: #92400e; display: flex; align-items: center; gap: 4px; }
.site-gate-l { font-size: var(--fs-meta); color: #92400e; margin-top: 4px; }
.site-gate-l--soft { color: #a16207; }
/* SPEC298 — live-state pill in the editor footer */
.site-livepill { font-size: var(--fs-meta); font-weight: var(--fw-bold); padding: 4px 10px; border-radius: 999px; margin-right: auto; }
.site-livepill.is-live { background: #dcfce7; color: #166534; }
.site-livepill.is-draft { background: var(--bg-2, #f1f5f9); color: var(--text-soft, #64748b); }
.site-editor { display: flex; gap: 18px; flex-wrap: wrap; align-items: flex-start; }
/* SPEC222 — Mind Map: a free-form spatial board (positioned nodes + an SVG link layer) */
.mm-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.mm-hint { font-size: var(--fs-meta); color: var(--muted); }
.mm-wrap { position: relative; margin-top: 14px; height: 70vh; min-height: 420px; overflow: auto; border: 1px solid var(--border); border-radius: 14px; background: radial-gradient(circle, var(--border) 1px, transparent 1px) 0 0 / 26px 26px, var(--bg-2); -webkit-overflow-scrolling: touch; }
/* CONSOL 2026-07-12 — Canvas camera model: fixed viewport + one transformed world layer */
.mm-board { position: relative; margin-top: 14px; height: 72vh; min-height: 440px; overflow: hidden; touch-action: none; border: 1px solid var(--border); border-radius: 14px; background: radial-gradient(circle, var(--border) 1px, transparent 1px) 0 0 / 26px 26px, var(--bg-2); cursor: default; }
.mm-board.mm-space { cursor: grab; }
.mm-board.mm-panning { cursor: grabbing; }
.mm-world { position: absolute; top: 0; left: 0; transform-origin: 0 0; will-change: transform; }
.mm-links { position: absolute; top: 0; left: 0; width: 1px; height: 1px; overflow: visible; pointer-events: none; }
.mm-link { stroke: var(--muted); stroke-width: 2; fill: none; pointer-events: none; }
.mm-arrowhead { fill: var(--muted); }
.mm-temp { stroke: var(--accent); stroke-width: 2; fill: none; stroke-dasharray: 5 4; pointer-events: none; }
.mm-zbtn { min-width: 30px; font-weight: var(--fw-bold); }
.mm-zlabel { min-width: 52px; font-variant-numeric: tabular-nums; }
.mm-tools-gap { flex: 1 1 auto; }
.mm-color { width: 15px; height: 15px; border-radius: 50%; border: 1px solid var(--border); background: var(--mm-accent, var(--accent)); cursor: pointer; padding: 0; flex: 0 0 auto; }
.mm-node--drop { box-shadow: 0 0 0 3px var(--accent) !important; }
/* CONSOL — Canvas media nodes (photo / video-embed) + a SE resize grip */
.mm-node--image, .mm-node--embed { overflow: hidden; }
.mm-img { width: 100%; display: block; border-radius: 0 0 9px 9px; }
.mm-embed { position: relative; width: 100%; aspect-ratio: 16 / 9; background: #000; border-radius: 0 0 9px 9px; overflow: hidden; }
.mm-embed iframe { width: 100%; height: 100%; border: 0; display: block; }
.mm-video { width: 100%; display: block; border-radius: 0 0 9px 9px; background: #000; max-height: 60vh; }

/* CONSOL-11/12 — deliverable guide (How-To lens) + QC checklist */
.dg-card { padding: 0; overflow: hidden; }
.dg-head { width: 100%; display: flex; align-items: center; gap: 8px; padding: 12px 14px; background: none; border: 0; cursor: pointer; text-align: left; font: inherit; color: inherit; }
.dg-head:hover { background: var(--bg-2); }
.dg-caret { color: var(--muted); font-size: var(--fs-meta); width: 12px; flex: none; }
.dg-title { font-weight: var(--fw-bold); font-size: var(--fs-body); }
.dg-badge { font-size: 10.5px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .03em; color: var(--accent); background: var(--accent-soft); padding: 2px 7px; border-radius: 999px; flex: none; }
.dg-count { font-size: 11.5px; margin-left: auto; flex: none; }
.dg-detail { padding: 2px 16px 16px; border-top: 1px solid var(--border); }
.dg-sec-h { font-weight: var(--fw-black); font-size: var(--fs-meta); text-transform: uppercase; letter-spacing: var(--ls-label); color: var(--muted); margin: 12px 0 6px; }
.dg-howto { margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 7px; }
.dg-howto li { font-size: var(--fs-caption); line-height: var(--lh-normal); }
.dg-qc { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 5px; }
.dg-qc li { font-size: var(--fs-caption); line-height: 1.45; padding-left: 22px; position: relative; }
.dg-qc li::before { content: '✓'; position: absolute; left: 0; top: 0; color: var(--accent); font-weight: var(--fw-black); }
.dg-watch { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 5px; }
.dg-watch li { font-size: 12.5px; line-height: 1.45; padding-left: 22px; position: relative; color: var(--text-2, inherit); }
.dg-watch li::before { content: '⚠'; position: absolute; left: 0; top: 0; }

/* SOPQC-4 — the "📐 Compare against the standard" example-triad strip. Shared by
   deliverableDetail() (Learn → By Deliverable) and the ⚡ QC gate header (qc.js) — a
   quiet --bg-2 reference panel, same family as .qc-brief, deliberately NOT the
   .qc-gate gradient/animation treatment since it's reference material, not a payoff. */
.dg-examples { background: var(--bg-2); border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; margin: 10px 0; display: flex; flex-direction: column; gap: 7px; }
.dg-examples-head { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .03em; color: var(--muted); }
.dg-examples-row { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-size: 12.5px; line-height: 1.45; }
.dg-examples-link { font-weight: var(--fw-semibold); color: var(--accent); }
.dg-examples-why { color: var(--muted); font-style: italic; }

/* SOPQC-8 — "🎯 The standard" header block: the optional one-page style-guide summary
   (purpose, runtime, hook, music, required moments) that sits ABOVE the how-to steps
   when a deliverable carries a `standard`. An accent-left callout — this IS the
   headline of the card, unlike the quiet --bg-2 .dg-examples reference strip below it. */
.dg-standard { background: var(--accent-soft); border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border)); border-left: 3px solid var(--accent); border-radius: 10px; padding: 10px 12px; margin-bottom: 14px; display: flex; flex-direction: column; gap: 7px; }
.dg-standard-head { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .03em; color: var(--accent); }
.dg-standard-purpose { font-size: 13.5px; line-height: var(--lh-normal); font-weight: var(--fw-semibold); }
.dg-standard-facts { display: flex; flex-direction: column; gap: 3px; }
.dg-standard-fact { font-size: 12.5px; line-height: 1.45; }
.dg-standard-fact-label { font-weight: var(--fw-bold); }
.dg-standard-moments-head { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .03em; color: var(--muted); margin-top: 2px; }
.dg-standard-moments { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 3px; }
.dg-standard-moments li { font-size: 12.5px; line-height: 1.45; }

.qc-check { display: flex; gap: 9px; align-items: flex-start; padding: 5px 2px; font-size: var(--fs-caption); line-height: 1.45; cursor: pointer; }
.qc-check input { margin-top: 2px; flex: none; width: 16px; height: 16px; accent-color: var(--accent); }

/* QCGAME — gamified, kinetic quality control (Persona-5 "movement", Deep Harbor palette) */
.qc-strip { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin: 10px 0 8px; }
.qc-strip-title { font-family: var(--font-serif); font-size: var(--fs-lg); font-weight: var(--fw-semibold); }
.qc-strip-r { display: flex; align-items: center; gap: 12px; }
.qc-ring-wrap { position: relative; width: 52px; height: 52px; flex: none; }
.qc-ring { width: 52px; height: 52px; display: block; }
.qc-ring-track { fill: none; stroke: var(--bg-2); stroke-width: 4; }
.qc-ring-bar { fill: none; stroke: var(--accent); stroke-width: 4; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 24px 24px; transition: stroke-dashoffset .5s var(--ease-spring), stroke .3s var(--ease); }
.qc-ring-label { position: absolute; inset: 0; display: grid; place-items: center; font-size: var(--fs-meta); font-weight: var(--fw-black); font-variant-numeric: tabular-nums; color: var(--text); }
.qc-streak { display: inline-flex; align-items: center; gap: 3px; border: 1px solid var(--border); background: var(--panel); border-radius: 999px; padding: 4px 10px 4px 8px; cursor: pointer; font: inherit; line-height: 1; filter: grayscale(1) opacity(.55); transition: filter .2s var(--ease), transform .2s var(--ease-spring); }
.qc-streak.on { filter: none; border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); background: var(--warn-soft); }
.qc-streak:hover { transform: translateY(-1px); }
.qc-streak-n { font-weight: var(--fw-black); font-variant-numeric: tabular-nums; }
.qc-sound { border: 1px solid var(--border); background: var(--panel); border-radius: 999px; width: 30px; height: 30px; padding: 0; cursor: pointer; font-size: var(--fs-body); line-height: 1; opacity: .8; transition: opacity .15s var(--ease), transform .15s var(--ease-spring); }
.qc-sound:hover { opacity: 1; transform: translateY(-1px); }
.qc-sound[aria-pressed="true"] { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); background: var(--accent-soft); }
.qc-meter { display: flex; gap: 4px; margin-bottom: 10px; }
.qc-seg { flex: 1; height: 8px; border-radius: 999px; background: var(--bg-2); overflow: hidden; }
.qc-seg > i { display: block; height: 100%; width: 0; border-radius: 999px; background: var(--accent); transition: width .45s var(--ease-spring); }
.qc-seg.done > i { background: linear-gradient(90deg, var(--accent), var(--ok)); }
.qc-list { display: block; }
.qc-sec-h { display: flex; align-items: center; gap: 8px; margin-top: 12px; transition: color .2s var(--ease); }
.qc-sec-h.is-cleared { color: var(--ok-ink); }
.qc-sec-cleared { font-size: 10.5px; font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .03em; color: var(--ok-ink); background: var(--ok-soft); padding: 2px 8px; border-radius: 999px; }
/* SOPQC-1 — severity: "N must-fix · N judgment" open-count chip (section header)
   + a small ● dot marking a RED must-fix row. Additive-only classes — absent from
   every checklist that never sets it.sev. */
.qc-sec-sev { font-size: 10.5px; font-weight: var(--fw-bold); color: var(--muted); background: var(--bg-2); padding: 2px 8px; border-radius: 999px; white-space: nowrap; }
.clp-sev-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; background: var(--danger); margin-top: 6px; box-shadow: 0 0 0 2px var(--danger-soft); }
.qc-row { opacity: 0; transform: translateX(-10px) translateY(6px); animation: qcRowIn .34s var(--ease-spring) both; animation-delay: calc(min(var(--i, 0), 8) * 42ms); border-radius: 8px; }
@keyframes qcRowIn { to { opacity: 1; transform: none; } }
.qc-row--just { animation: qcFlash .5s var(--ease) forwards; }
@keyframes qcFlash { 0% { background: color-mix(in srgb, var(--accent) 22%, transparent); } 100% { background: transparent; } }
.qc-check input:checked ~ span { text-decoration: line-through; color: var(--muted); opacity: .7; transition: color .18s var(--ease), opacity .18s var(--ease); }
/* rich checklist rows (hint subtitle + jump-to action) */
.qc-row--rich { display: flex; align-items: flex-start; gap: 8px; }
.clp-textwrap { display: flex; flex-direction: column; }
.clp-hint { font-size: 11.5px; color: var(--muted); margin-top: 1px; line-height: 1.4; }
.qc-row--rich.is-done .clp-label { text-decoration: line-through; color: var(--muted); opacity: .7; }
.clp-action { flex: none; margin-top: 1px; }
.clp-topper { margin-bottom: 12px; }
/* SOPQC-3 — the shooter's structured brief atop the QC gate (job.brief; App.jobBriefFields).
   A quiet reference card, not a gate — no animation, no gradient, so it never reads like a
   payoff state. Absent entirely when the job has no brief. */
.qc-brief { background: var(--bg-2); border: 1px solid var(--border); border-radius: 12px; padding: 10px 12px; margin-bottom: 12px; }
.qc-brief-head { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .03em; color: var(--muted); margin-bottom: 5px; }
.qc-brief-row { font-size: 12.5px; line-height: 1.45; }
.qc-brief-label { font-weight: var(--fw-bold); color: var(--text); }
.qc-brief-link { display: inline-block; margin-top: 5px; font-size: var(--fs-meta); font-weight: var(--fw-semibold); color: var(--accent); }
/* SOPQC-6 — the escalate row: a quiet release valve, not a gate action, so it sits
   ghost-styled below the brief/examples rather than competing with the checklist. */
.qc-escalate-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 2px 0 12px; }
.qc-verdict { transform: translateY(12px); opacity: 0; animation: qcUp .3s var(--ease-spring) forwards; border-radius: 12px; padding: 11px 14px; margin: 8px 0; font-size: var(--fs-caption); font-weight: var(--fw-semibold); }
@keyframes qcUp { to { transform: none; opacity: 1; } }
.qc-verdict--ok { background: var(--ok-soft); color: var(--ok-ink); box-shadow: inset 3px 0 0 var(--ok); }
.qc-verdict--warn { background: var(--warn-soft); color: var(--warn-ink); box-shadow: inset 3px 0 0 var(--warn); }
.qc-verdict--stop { background: var(--danger-soft); color: var(--danger-ink); box-shadow: inset 3px 0 0 var(--danger); }
.qc-gate { margin-top: 12px; padding: 20px 18px; text-align: center; border-radius: 16px; background: linear-gradient(160deg, var(--accent-soft), var(--panel)); border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border)); animation: qcGateIn .28s var(--ease-spring) both; }
@keyframes qcGateIn { from { transform: scale(.92); opacity: 0; } to { transform: none; opacity: 1; } }
/* SOPQC-1 — the PARTIAL gate (every must-fix clear, judgment items still open).
   Deliberately its OWN class, not a `.qc-gate` modifier: several tests (and any
   future code) treat `.qc-gate` presence as "the full cleared payoff fired", and
   this is a real but distinct, quieter state — reads amber, not the full-clear
   green/accent gradient, so it never looks identical to "fully done" either. */
.qc-gate-partial { margin-top: 12px; padding: 20px 18px; text-align: center; border-radius: 16px; background: linear-gradient(160deg, var(--warn-soft), var(--panel)); border: 1px solid color-mix(in srgb, var(--warn) 30%, var(--border)); animation: qcGateIn .28s var(--ease-spring) both; }
.qc-gate-partial .qc-score { color: var(--warn); }
.qc-score { position: relative; display: inline-block; font-family: var(--font-serif); font-weight: var(--fw-bold); font-size: 54px; line-height: 1; font-variant-numeric: tabular-nums; color: var(--accent); transform: skewX(-3deg); overflow: hidden; }
.qc-score::after { content: ''; position: absolute; inset: 0; background: linear-gradient(115deg, transparent 42%, rgba(255,255,255,.55) 50%, transparent 58%); transform: translateX(-120%); animation: qcShine .8s var(--ease) .15s; }
@keyframes qcShine { to { transform: translateX(120%); } }
.qc-gate-h { font-family: var(--font-serif); font-size: 20px; font-weight: var(--fw-semibold); margin: 4px 0 2px; }
.qc-stat-trio { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; }
.qc-stat { flex: 1 1 90px; max-width: 150px; padding: 10px 8px; border-radius: 12px; background: var(--panel); border: 1px solid var(--border); }
.qc-stat.ok { border-color: color-mix(in srgb, var(--ok) 40%, var(--border)); }
.qc-stat.accent { border-color: color-mix(in srgb, var(--accent) 40%, var(--border)); }
.qc-stat.warn { border-color: color-mix(in srgb, var(--warn) 40%, var(--border)); }
.qc-stat-n { font-size: 20px; font-weight: var(--fw-black); font-variant-numeric: tabular-nums; }
.qc-stat-l { font-size: var(--fs-micro); color: var(--muted); margin-top: 2px; }
.qc-week { display: flex; gap: 6px; }
.qc-dot { width: 22px; height: 22px; border-radius: 50%; background: var(--bg-2); border: 1px solid var(--border); }
.qc-dot.on { background: var(--warn); border-color: var(--warn); box-shadow: 0 0 0 3px var(--warn-soft); }
.qc-ai { margin-top: 14px; border-top: 1px solid var(--border); padding-top: 8px; }
.qc-ai > summary { cursor: pointer; font-size: 12.5px; font-weight: var(--fw-bold); color: var(--muted); list-style: none; padding: 4px 0; }
.qc-ai > summary::-webkit-details-marker { display: none; }
.qc-ai > summary::before { content: '▸ '; }
.qc-ai[open] > summary::before { content: '▾ '; }
/* RELGATE-W3a — the example-strip toggle: collapsed by default for a
   certified viewer (compact gate), open by default for a novice
   (App.reviewTierInfo(viewer).certified === false — see qc.js openQcPass). */
.qc-examples-toggle { margin: 10px 0; }
.qc-examples-toggle > summary { cursor: pointer; font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .03em; color: var(--muted); list-style: none; padding: 2px 0; }
.qc-examples-toggle > summary::-webkit-details-marker { display: none; }
.qc-examples-toggle > summary::before { content: '▸ '; }
.qc-examples-toggle[open] > summary::before { content: '▾ '; }
/* the inner .dg-examples-head stays IN THE DOM (unchanged node, unchanged
   text — a test walks it) but is visually redundant once its text is
   already the <summary> label above it. */
.qc-examples-toggle .dg-examples-head { display: none; }
/* RELGATE-W3c — the gate header's work link (the thing a reviewer must
   actually open before a red row's "open the work first" hint clears). */
.qc-gate-worklink { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; font-weight: var(--fw-bold); color: var(--accent); text-decoration: none; }
.qc-gate-worklink:hover { text-decoration: underline; }
/* QA score → teaching-moment callout (fires on a low grade) */
.qa-teach-cta { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-meta); font-weight: var(--fw-bold); text-decoration: none; color: var(--warn); background: var(--warn-soft); border: 1px solid color-mix(in srgb, var(--warn) 35%, var(--border)); border-radius: 8px; padding: 5px 10px; margin-top: 2px; transition: transform .15s var(--ease-spring); }
.qa-teach-cta:hover { transform: translateX(2px); }
.mm-embed-poster { position: absolute; inset: 0; width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; border: 0; background: linear-gradient(135deg, #1a2634, #0f1722); color: #fff; cursor: pointer; font-size: var(--fs-meta); }
.mm-embed-poster:hover { background: linear-gradient(135deg, #22384f, #16202e); }
.mm-linkchip { display: inline-flex; align-items: center; gap: 6px; margin: 10px; padding: 6px 10px; border: 1px solid var(--border); border-radius: 999px; background: var(--panel); color: var(--accent); font-size: 12.5px; text-decoration: none; }
.mm-linkchip:hover { border-color: var(--accent); background: var(--accent-soft); }
.mm-media-fail { display: flex; align-items: center; gap: 6px; padding: 14px; color: var(--muted); font-size: 12.5px; text-decoration: none; }
.mm-resize { position: absolute; right: 1px; bottom: 1px; width: 16px; height: 16px; cursor: nwse-resize; z-index: 3; touch-action: none; opacity: 0; background: linear-gradient(135deg, transparent 45%, var(--accent) 45%); border-radius: 0 0 9px 0; transition: opacity .12s; }
.mm-node:hover .mm-resize { opacity: .85; }
.mm-link-del { position: absolute; transform: translate(-50%, -50%); z-index: 2; width: 22px; height: 22px; padding: 0; border-radius: 50%; border: 1px solid var(--border); background: var(--surface, var(--panel)); color: var(--muted); font-size: var(--fs-body); line-height: 1; display: grid; place-items: center; cursor: pointer; opacity: 0; transition: opacity .12s, color .12s, border-color .12s; }
.mm-board:hover .mm-link-del, .mm-link-del:hover, .mm-link-del:focus-visible { opacity: 1; }
.mm-link-del:hover, .mm-link-del:focus-visible { color: var(--danger, #dc2626); border-color: var(--danger, #dc2626); }

/* SPEC225 — sortable table header as an accessible (keyboard) button that inherits the th look */
.th-sort { background: none; border: 0; padding: 0; margin: 0; font: inherit; color: inherit; font-weight: inherit; letter-spacing: inherit; text-transform: inherit; cursor: pointer; white-space: nowrap; }
.th-sort:hover { color: var(--text); }
.th-sort:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }
.mm-node { position: absolute; width: 200px; background: var(--panel); border: 1px solid var(--border); border-left: 3px solid var(--mm-accent, var(--accent)); border-radius: 10px; box-shadow: 0 6px 18px rgba(0,0,0,.08); }
.mm-node--linking { box-shadow: 0 0 0 2px var(--accent); }
.mm-node--task { --mm-accent: #2563eb; } .mm-node--job { --mm-accent: #0e7c5a; } .mm-node--client { --mm-accent: #b45309; } .mm-node--note { --mm-accent: #5f6b78; }
.mm-node-head { display: flex; align-items: center; gap: 6px; padding: 5px 6px 5px 8px; cursor: grab; border-bottom: 1px solid var(--border); touch-action: none; }
.mm-node.dragging { opacity: .94; box-shadow: 0 14px 30px rgba(0,0,0,.18); }
.mm-node.dragging .mm-node-head { cursor: grabbing; }
.mm-grip { color: var(--faint); display: inline-flex; }
.mm-kind { font-size: 10px; font-weight: var(--fw-bold); letter-spacing: .06em; text-transform: uppercase; color: var(--muted); flex: 1 1 auto; }
.mm-connect { width: 16px; height: 16px; border-radius: 999px; border: 2px solid var(--mm-accent, var(--accent)); background: transparent; cursor: pointer; padding: 0; flex: 0 0 auto; }
.mm-connect:hover { background: var(--mm-accent, var(--accent)); }
.mm-del { border: 0; background: transparent; color: var(--muted); font-size: 17px; line-height: 1; cursor: pointer; padding: 0 2px; }
.mm-del:hover { color: var(--danger, #dc2626); }
.mm-node-body { width: 100%; box-sizing: border-box; padding: 9px 11px; font-size: var(--fs-caption); line-height: 1.45; color: var(--text); min-height: 38px; }
.mm-node-body[contenteditable] { outline: none; cursor: text; white-space: pre-wrap; word-break: break-word; }
.mm-node-body[contenteditable]:empty::before { content: 'Type your idea…'; color: var(--faint); }
.mm-node-body--rec { text-align: left; background: transparent; border: 0; cursor: pointer; font: inherit; font-size: var(--fs-caption); }
.mm-node-body--rec:hover { color: var(--accent); }
.mm-empty { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); text-align: center; color: var(--muted); max-width: 320px; pointer-events: none; }
.mm-pick-wrap { display: flex; flex-direction: column; gap: 8px; }
.mm-pick-results { max-height: 320px; overflow: auto; display: flex; flex-direction: column; gap: 2px; }
.mm-pick-row { text-align: left; padding: 9px 11px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); cursor: pointer; font-size: var(--fs-caption); }
.mm-pick-row:hover { border-color: var(--accent); }
/* SPEC223 — view-mode switcher + Tasks Cards grid + Calendar */
.seg-viewmode button { display: inline-flex; align-items: center; gap: 5px; }
@media (max-width: 700px) { .seg-viewmode button > span:not(.icon) { display: none; } }
.task-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(244px, 1fr)); gap: 12px; align-items: start; }
.cal-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.cal-title { font-weight: var(--fw-black); font-size: 15px; min-width: 150px; text-align: center; }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; }
.cal-dow { font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--muted); text-align: center; padding: 2px 0; }
.cal-cell { min-height: 92px; border: 1px solid var(--border); border-radius: 8px; padding: 5px; background: var(--panel); display: flex; flex-direction: column; gap: 3px; }
.cal-cell--pad { border: 0; background: transparent; min-height: 0; }
.cal-cell--today { border-color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.cal-day { font-size: 11.5px; font-weight: var(--fw-bold); color: var(--muted); }
.cal-cell--today .cal-day { color: var(--accent); }
.cal-task { display: flex; align-items: center; gap: 5px; width: 100%; text-align: left; border: 0; background: var(--bg-2); border-radius: 5px; padding: 3px 6px; font-size: 11.5px; cursor: pointer; color: var(--text); overflow: hidden; }
.cal-task:hover { background: var(--hover); }
.cal-task-dot { width: 7px; height: 7px; border-radius: 999px; flex: 0 0 auto; background: var(--accent); }
.cal-task-t { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cal-task--done .cal-task-t { text-decoration: line-through; opacity: .65; }
.cal-task--over { background: rgba(220,38,38,.1); }
.cal-more { font-size: 10.5px; color: var(--muted); padding: 1px 2px; border: 0; background: transparent; cursor: pointer; text-align: left; font-weight: var(--fw-semibold); font-family: inherit; border-radius: 4px; }
.cal-more:hover { color: var(--accent); background: var(--hover); }
.cal-more-list { display: flex; flex-direction: column; gap: 4px; }
.cal-more-row { display: flex; align-items: center; gap: 8px; text-align: left; border: 1px solid var(--border); border-radius: 8px; padding: 9px 11px; background: var(--panel); cursor: pointer; font-size: var(--fs-caption); font-family: inherit; color: var(--text); }
.cal-more-row:hover { border-color: var(--accent); }
.cal-nodate { margin-top: 14px; border-top: 1px solid var(--border); padding-top: 12px; }
.cal-nodate-h { font-size: var(--fs-meta); font-weight: var(--fw-bold); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--muted); margin-bottom: 8px; }
.cal-nodate .cal-task { display: inline-flex; width: auto; max-width: 220px; margin: 0 6px 6px 0; }
@media (max-width: 560px) { .cal-cell { min-height: 64px; } .cal-task-t { font-size: 10.5px; } }

/* SPEC230 — Timeline / Gantt view */
.tl-wrap { margin-top: 14px; }
.tl-scroll { overflow-x: auto; border: 1px solid var(--border); border-radius: 12px; background: var(--panel); -webkit-overflow-scrolling: touch; }
.tl-axis, .tl-row { display: grid; grid-template-columns: 150px 1fr; align-items: stretch; }
.tl-axis { position: sticky; top: 0; z-index: 2; background: var(--bg-2); border-bottom: 1px solid var(--border); }
.tl-axis-label { padding: 6px 10px; }
.tl-axis-days { display: grid; }
.tl-axis-day { text-align: center; font-size: 10.5px; color: var(--muted); padding: 6px 0; border-left: 1px solid var(--border); }
.tl-axis-day.tl-wknd { background: color-mix(in srgb, var(--bg-2) 70%, transparent); }
.tl-axis-day.tl-today { color: var(--accent); font-weight: var(--fw-black); }
.tl-row { border-bottom: 1px solid var(--border); min-height: 38px; }
.tl-row:last-child { border-bottom: 0; }
.tl-row-label { padding: 8px 10px; font-size: 12.5px; font-weight: var(--fw-semibold); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border-right: 1px solid var(--border); display: flex; align-items: center; }
.tl-track { position: relative; display: grid; }
.tl-cellline { border-left: 1px solid color-mix(in srgb, var(--border) 50%, transparent); }
.tl-cellline.tl-wknd { background: color-mix(in srgb, var(--bg-2) 55%, transparent); }
.tl-cellline.tl-today { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.tl-bar { position: absolute; top: 6px; bottom: 6px; min-width: 12px; border: 0; border-radius: 6px; background: var(--tl-bar, var(--accent)); color: #fff; font-size: 11.5px; font-weight: var(--fw-bold); padding: 0 8px; display: flex; align-items: center; cursor: pointer; overflow: hidden; box-shadow: 0 1px 3px rgba(0,0,0,.14); font-family: inherit; }
.tl-bar-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tl-bar:hover { filter: brightness(1.07); }
.tl-bar:focus-visible { outline: 2px solid var(--text); outline-offset: 1px; }
.tl-bar--done { opacity: .5; text-decoration: line-through; }
.tl-bar--over { box-shadow: 0 0 0 2px var(--danger), 0 1px 3px rgba(0,0,0,.14); }
.tl-clipL { border-top-left-radius: 0; border-bottom-left-radius: 0; }
.tl-clipR { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.tl-empty { padding: 24px; text-align: center; }
@media (max-width: 640px) { .tl-axis, .tl-row { grid-template-columns: 96px 1fr; } .tl-row-label { font-size: 11.5px; padding: 6px 8px; } }

/* SPEC234 — Your First Week onboarding */
.firstweek-card { margin-bottom: 14px; border: 1px solid var(--border); background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 10%, var(--panel)), var(--panel)); }
.fw-welcome { font-weight: var(--fw-black); font-size: 14.5px; display: inline-flex; align-items: center; gap: 4px; }
.firstweek-hero { margin-bottom: 12px; }
/* AUDIT-2026-07-25 [16] — the pre-checklistPlay first-week markup (.firstweek-phase,
   .fw-phase-*, .fw-step*, .fw-check*, .firstweek-done + its @media rule) deleted here:
   firstweek.js was migrated to the shared App.checklistPlay engine and now emits only
   .firstweek-card/.fw-welcome/.firstweek-hero (kept above); proven zero JS/HTML
   emitters repo-wide before deletion. Regenerated order.css/portal.css/site.css —
   three of these rules had leaked into the client-facing slices. */

/* SPEC223 — Clients / Leads Cards layout */
.client-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(258px, 1fr)); gap: 12px; align-items: start; }
.cl-card { background: var(--panel); border: 1px solid var(--border); border-radius: 12px; padding: 14px; cursor: pointer; transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }
.cl-card:hover { border-color: var(--accent); box-shadow: 0 6px 18px rgba(0,0,0,.08); }
.cl-card-top { display: flex; align-items: flex-start; gap: 10px; }
.cl-card-id { flex: 1 1 auto; min-width: 0; }
.cl-card-name { display: flex; align-items: center; gap: 6px; font-weight: var(--fw-bold); flex-wrap: wrap; }
.cl-card-co { font-size: var(--fs-meta); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cl-card-stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px 10px; margin-top: 12px; }
.cl-stat-v { font-weight: var(--fw-black); font-size: 15px; }
.cl-stat-l { font-size: 10.5px; font-weight: var(--fw-bold); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--muted); margin-top: 1px; }
.cl-card-foot { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border); }
.cl-card-contact { font-size: 11.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.site-stage { flex: 1 1 360px; min-width: 300px; max-height: 70vh; overflow: auto; border: 1px solid var(--border); border-radius: 14px; padding: 14px; background: var(--bg-2); }
.site-stage .site-page { max-width: 100%; }
.site-stage .site-hero { max-height: 220px; }
.site-ctrl { flex: 1 1 250px; min-width: 230px; max-height: 70vh; overflow: auto; display: flex; flex-direction: column; gap: 9px; }

/* SPEC171 — gallery favorites / selects (delivery proofing) */
.cstatus-galbar { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 12px 0 2px; flex-wrap: wrap; }
.cstatus-galbar-n { font-size: 12.5px; font-weight: var(--fw-bold); color: var(--text-soft); }
.cstatus-gal-fav { position: absolute; top: 7px; left: 7px; z-index: 2; width: 30px; height: 30px; border-radius: 999px; border: 0; cursor: pointer; background: rgba(0,0,0,.5); color: #fff; font-size: var(--fs-body); line-height: 1; display: flex; align-items: center; justify-content: center; opacity: 0; transition: opacity .18s ease, transform .15s ease; }
.cstatus-gal-item:hover .cstatus-gal-fav, .cstatus-gal-fav.on { opacity: 1; }
.cstatus-gal-fav.on { color: #ff4d6d; background: rgba(255,255,255,.92); }
.cstatus-gal-fav:active { transform: scale(1.25); }

/* ============================================================
   SPEC173 — shared premium client-surface layer (delivery + status + property site).
   One reveal helper + one cinematic image treatment + an editorial type/accent pass
   lift all three surfaces. Pure CSS, dark-mode + reduced-motion safe.
   ============================================================ */
/* reveal-on-scroll (driven by App.revealOnScroll) */
.reveal { opacity: 0; transform: translateY(13px); transition: opacity .6s var(--ease), transform .6s var(--ease-spring); }
.reveal.in { opacity: 1; transform: none; }

/* cinematic Ken Burns photo layer (cover + hero) — image pans slowly under a still scrim */
.cstatus-cover-img, .site-hero-img { position: absolute; inset: -2.5%; background-size: cover; background-position: var(--cover-pos, center);
  background-color: #1b2433; transform-origin: 50% 42%; animation: vvtKenBurns 26s var(--ease) both alternate infinite; will-change: transform; }
/* SPEC268 — a studio-set cover focal holds the pan still so the chosen framing stays exact */
.cstatus-cover-img--focal { animation: none; inset: 0; }
@keyframes vvtKenBurns { from { transform: scale(1.05); } to { transform: scale(1.16) translate(-1.6%, -1.4%); } }
.cstatus-cover, .site-hero { isolation: isolate; border-top: 3px solid var(--cover-accent, var(--accent)); }
/* taller, more cinematic delivery cover that opens the page */
.cstatus--delivery .cstatus-cover { aspect-ratio: 16 / 10; max-height: min(64vh, 600px); }
/* branded-gradient empty cover (no photo yet / image blocked) — still looks designed */
.cstatus-cover--empty { background-image: linear-gradient(140deg, var(--cover-primary, var(--accent)), rgba(10,12,20,.88)); }
.cstatus-cover--empty .cstatus-cover-img { display: none; }
/* upgraded two-stop bottom-weighted scrims (text always legible) */
.cstatus-cover-scrim { background: linear-gradient(180deg, transparent 42%, rgba(10,12,20,.5) 76%, rgba(10,12,20,.84)); }
.site-hero-scrim { background: linear-gradient(180deg, transparent 40%, rgba(10,12,20,.48) 74%, rgba(10,12,20,.8)); }
/* editorial serif cover title */
.cstatus-cover-title { font-family: var(--font-serif); letter-spacing: -.012em; line-height: 1.04; }
.cstatus-cover-brand { color: #fff; }
.cstatus-cover-brand, .site-hero-brand { text-shadow: 0 1px 10px rgba(0,0,0,.4); }

/* blur-up gallery tiles (sharpen on load; keep hover-zoom transition intact) */
.cstatus-gal-item img { opacity: 0; filter: blur(14px); transition: opacity .5s var(--ease), filter .65s var(--ease), transform .5s cubic-bezier(.2,.7,.2,1); }
.cstatus-gal-item img.loaded { opacity: 1; filter: none; }
.cstatus-gal-item--err { background: linear-gradient(150deg, var(--bg-2), var(--hover)); }
.cstatus-gal-item--err::after { content: '🖼'; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 26px; opacity: .35; }

/* brand-tinted category rail + consistent line-icon */
.cstatus-svc { border-left: 3px solid var(--stage, var(--border-strong)); transition: box-shadow .18s var(--ease), transform .18s var(--ease); }
.cstatus-svc:hover { box-shadow: var(--shadow); transform: translateY(-1px); }
.cstatus-svc-name { display: inline-flex; align-items: center; gap: 9px; }
.cstatus-svc-ic { display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; border-radius: 9px; flex: 0 0 auto;
  color: var(--stage, var(--accent)); background: color-mix(in srgb, var(--stage, var(--accent)) 13%, transparent); }

@media (prefers-reduced-motion: reduce) {
  .cstatus-cover-img, .site-hero-img { animation: none; }
  .reveal { transition: none; }
}

/* ============================================================
   SPEC173 — Marketing Studio: photo-forward templates, vibes, presets.
   ============================================================ */
.tpl-landscape { aspect-ratio: 1.91 / 1; }
/* photo-forward layouts: hero fills the frame, text over a legibility scrim */
.tpl-comingsoon .tpl-hero, .tpl-pricedrop .tpl-hero, .tpl-feature .tpl-hero,
.tpl-undercontract .tpl-hero, .tpl-carousel .tpl-hero { position: absolute; inset: 0; }
.tpl-overlay { position: absolute; inset: 0; background: linear-gradient(0deg, rgba(0,0,0,.85), rgba(0,0,0,.30) 56%, transparent 74%); }
.tpl-pf-body { position: absolute; left: 0; right: 0; bottom: 0; padding: 6cqw 6cqw 6.5cqw; display: flex; flex-direction: column; gap: 1.7cqw; }
.tpl-pf-body .tpl-headline, .tpl-pf-body .tpl-when, .tpl-pf-body .tpl-tagline, .tpl-pf-body .tpl-facts,
.tpl-pf-body .tpl-eyebrow, .tpl-pf-body .tpl-newprice, .tpl-pf-body .tpl-oldprice, .tpl-pf-body .tpl-bignum,
.tpl-center .tpl-headline, .tpl-center .tpl-price { text-shadow: 0 2px 16px rgba(0,0,0,.55); }
.tpl-pf-body .tpl-agent { border-top: 0; padding-top: .5cqw; margin-top: .5cqw; }
/* eyebrow kicker (editorial alt to the pill badge) */
.tpl-eyebrow { font-size: 2.7cqw; font-weight: var(--fw-bold); letter-spacing: .22em; text-transform: uppercase; color: var(--tpl-accent); }
/* price improvement */
.tpl-pricewrap { display: flex; align-items: baseline; gap: 3cqw; flex-wrap: wrap; }
.tpl-oldprice { font-size: 4.4cqw; font-weight: var(--fw-bold); opacity: .72; text-decoration: line-through; text-decoration-thickness: .35cqw; }
.tpl-newprice { font-size: 7cqw; font-weight: var(--fw-black); color: var(--tpl-accent); }
/* by the numbers */
.tpl-stats { display: flex; gap: 5.5cqw; margin: 1cqw 0; }
.tpl-stat-n { font-size: 8.4cqw; font-weight: var(--fw-black); line-height: 1; color: var(--tpl-accent); }
.tpl-stat-l { font-size: 2.5cqw; font-weight: var(--fw-bold); letter-spacing: .12em; text-transform: uppercase; opacity: .92; margin-top: .6cqw; }
/* testimonial (text-only, serif) */
.tpl-quote-inner { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 9cqw; gap: 2.6cqw; }
.tpl-quote-stars { font-size: 5cqw; color: var(--tpl-accent); letter-spacing: .4cqw; }
.tpl-quote { font-family: var(--font-serif); font-size: 5.4cqw; font-style: italic; line-height: 1.32; max-width: 92%; }
.tpl-quote-by { font-size: 3.4cqw; font-weight: var(--fw-black); opacity: .92; }
.tpl-testimonial .tpl-agent { border-top: 0; justify-content: center; margin-top: 1cqw; }
/* under contract (diagonal ribbon) */
.tpl-ribbon { position: absolute; top: 7cqw; right: -13cqw; transform: rotate(45deg); background: var(--tpl-accent); color: #15181c;
  font-weight: var(--fw-black); font-size: 3cqw; letter-spacing: .12em; padding: 1.4cqw 13cqw; text-transform: uppercase; box-shadow: 0 1.6cqw 4cqw rgba(0,0,0,.3); }
/* carousel cover */
.tpl-bignum { font-size: 19cqw; font-weight: var(--fw-black); line-height: .85; color: var(--tpl-accent); }
.tpl-swipe { font-size: 3.2cqw; font-weight: var(--fw-black); letter-spacing: .1em; opacity: .92; margin-top: .8cqw; }
/* VIBES — restyle the whole card, not just the font */
.tpl--serif .tpl-headline, .tpl--serif .tpl-ab-name, .tpl--serif .tpl-bignum, .tpl--serif .tpl-stat-n {
  font-family: var(--font-serif); letter-spacing: -.01em; }
.tpl--serif .tpl-badge { border-radius: 0; letter-spacing: .2em; background: transparent; color: var(--tpl-accent); border: 1px solid var(--tpl-accent); }
.tpl--condensed .tpl-headline, .tpl--condensed .tpl-ab-name { text-transform: uppercase; letter-spacing: .005em; }
.tpl--condensed .tpl-eyebrow { letter-spacing: .3em; }
/* editor: preset swatches + segmented size */
.mkt-swatches { display: flex; flex-wrap: wrap; gap: 7px; }
.mkt-swatch { width: 30px; height: 30px; border-radius: 8px; border: 1px solid var(--border-strong); cursor: pointer; padding: 0;
  transition: transform .12s var(--ease), box-shadow .12s var(--ease); }
.mkt-swatch:hover { transform: translateY(-1px) scale(1.07); box-shadow: var(--shadow); }
.mkt-seg { display: inline-flex; border: 1px solid var(--border-strong); border-radius: 9px; overflow: hidden; width: 100%; max-width: 320px; }
.mkt-seg-btn { flex: 1; padding: 8px 10px; font: inherit; font-size: 12.5px; font-weight: var(--fw-bold); border: 0; background: var(--panel); color: var(--muted); cursor: pointer; border-right: 1px solid var(--border); }
.mkt-seg-btn:last-child { border-right: 0; }
.mkt-seg-btn.on { background: var(--accent); color: #fff; }
.mkt-full .tpl-card.tpl-landscape { width: min(92vw, 760px); height: auto; }

/* ============================================================
   SPEC173 — Pixieset polish: status hero, glass download, lightbox, site mobile.
   ============================================================ */
/* client-status branded header card + animated % progress */
.cstatus-hero { position: relative; border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 20px 20px 18px; margin-bottom: 16px;
  background: linear-gradient(135deg, color-mix(in srgb, var(--cover-accent, var(--accent)) 14%, var(--panel)), var(--panel) 62%); overflow: hidden; }
.cstatus-hero::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px; background: var(--cover-accent, var(--accent)); }
.cstatus-hero .cstatus-title { margin-top: 2px; }
.cstatus-progwrap { margin-top: 15px; }
.cstatus-prog-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 7px; }
.cstatus-pct { font-size: 26px; font-weight: var(--fw-black); line-height: 1; color: var(--cover-accent, var(--accent)); }
.cstatus-hero .cstatus-track { height: 13px; box-shadow: inset 0 1px 2px rgba(0,0,0,.12); }
.cstatus-fill { background: linear-gradient(90deg, var(--ok), color-mix(in srgb, var(--ok) 58%, var(--cover-accent, var(--accent)))); transition: width 1s var(--ease-spring); position: relative; overflow: hidden; }
.cstatus-fill::after { content: ''; position: absolute; inset: 0; background: linear-gradient(90deg, transparent, rgba(255,255,255,.4), transparent); transform: translateX(-100%); animation: cstatusShimmer 2.6s ease-in-out infinite; }
@keyframes cstatusShimmer { to { transform: translateX(240%); } }

/* frosted-glass "download all" on the delivery cover (top-right, clear of the
   bottom-left title that can wrap to two lines) */
.cstatus-cover-dl { position: absolute; right: 18px; top: 18px; z-index: 3; display: flex; flex-direction: column; gap: 1px;
  padding: 10px 16px; border-radius: var(--radius-lg); text-decoration: none; color: #fff;
  background: rgba(255,255,255,.16); backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px); border: 1px solid rgba(255,255,255,.28);
  box-shadow: 0 6px 20px rgba(0,0,0,.28); transition: transform .15s var(--ease), background .15s var(--ease); }
.cstatus-cover-dl:hover { transform: translateY(-2px); background: rgba(255,255,255,.27); }
.cstatus-cover-dl-main { font-weight: var(--fw-black); font-size: var(--fs-body); }
.cstatus-cover-dl-sub { font-size: var(--fs-micro); opacity: .85; }

/* lightbox: blurred backdrop + auto-hiding chrome */
.cstatus-lightbox { background: rgba(8,10,16,.95); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); }
.cstatus-lightbox .cstatus-lb-nav, .cstatus-lightbox .cstatus-lb-x, .cstatus-lightbox .cstatus-lb-dl, .cstatus-lightbox .cstatus-lb-cap, .cstatus-lightbox .cstatus-lb-sizehint { transition: opacity .3s var(--ease); }
.cstatus-lightbox.chrome-hidden .cstatus-lb-nav, .cstatus-lightbox.chrome-hidden .cstatus-lb-x,
.cstatus-lightbox.chrome-hidden .cstatus-lb-dl, .cstatus-lightbox.chrome-hidden .cstatus-lb-cap, .cstatus-lightbox.chrome-hidden .cstatus-lb-sizehint { opacity: 0; pointer-events: none; }

/* property site — seamless hairline-divided fact bar (one considered unit) */
.site-facts { gap: 0; border: 1px solid var(--border); border-radius: 14px; overflow: hidden; background: var(--bg-2); justify-content: stretch; }
.site-fact { flex: 1; max-width: none; border: 0; border-left: 1px solid var(--border); border-radius: 0; padding: 18px 10px; }
.site-fact:first-child { border-left: 0; }

/* property site — the previously-missing mobile layer */
@media (max-width: 640px) {
  .site-hero { aspect-ratio: 4 / 5; max-height: none; }
  .site-hero-text { padding: 18px 16px; }
  .site-hero-title { font-size: clamp(24px, 8vw, 34px); }
  .site-section { margin: 24px 0; }
  .site-detail { grid-template-columns: 1fr; }
  .site-agent { flex-direction: column; text-align: center; align-items: center; }
  .site-agent-cta { justify-content: center; }
  .site-map { max-height: 280px; }
  .cstatus-cover-dl { right: 12px; top: 12px; padding: 8px 12px; }
  .cstatus-cover-dl-sub { display: none; }
}

/* ============================================================
   SPEC174 — Pixieset cover landing + unbranded client preview.
   ============================================================ */
.cstatus--delivery .cstatus-cover--landing { aspect-ratio: auto; min-height: min(70vh, 640px); max-height: none; align-items: center; justify-content: center; text-align: center; }
.cstatus-cover--landing .cstatus-cover-scrim { background: linear-gradient(180deg, rgba(8,10,16,.34), rgba(8,10,16,.5)); }
.cstatus-cover--landing .cstatus-cover-text { padding: 30px 24px; max-width: 720px; }
.cstatus-cover--landing .cstatus-cover-title { font-size: clamp(28px, 5.2vw, 46px); }
.cstatus-cover--landing .cstatus-cover-brand { letter-spacing: .16em; }
.cstatus-cover-actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-top: 22px; }
.cstatus-cta { display: inline-flex; align-items: center; gap: 6px; padding: 11px 20px; border-radius: 999px; font: inherit; font-weight: var(--fw-bold); font-size: var(--fs-body); cursor: pointer; text-decoration: none;
  color: #fff; background: rgba(255,255,255,.15); backdrop-filter: blur(7px); -webkit-backdrop-filter: blur(7px); border: 1px solid rgba(255,255,255,.34);
  transition: transform .15s var(--ease), background .15s var(--ease); }
.cstatus-cta:hover { transform: translateY(-2px); background: rgba(255,255,255,.26); }
.cstatus-cta--primary { background: var(--cover-accent, var(--accent)); border-color: transparent; color: #15181c; }
.cstatus-cta--primary:hover { filter: brightness(1.08); }
/* unbranded preview: a subtle "PREVIEW" ribbon so the team never confuses it with the live page */
.cstatus--preview .cstatus-cover-title { font-family: var(--font-serif); }
@media (max-width: 620px) {
  .cstatus--delivery .cstatus-cover--landing { min-height: min(64vh, 520px); }
  .cstatus-cover-actions { gap: 8px; }
  .cstatus-cta { padding: 10px 16px; font-size: var(--fs-caption); }
}

/* ============================================================
   SPEC176 — gallery hover captions, tile lift, prominent video, designed empty state.
   ============================================================ */
.cstatus-gal-cap { position: absolute; left: 0; right: 0; bottom: 0; padding: 18px 11px 8px; z-index: 1;
  font-size: 11.5px; font-weight: var(--fw-bold); color: #fff; letter-spacing: .02em; text-shadow: 0 1px 6px rgba(0,0,0,.5);
  background: linear-gradient(0deg, rgba(0,0,0,.5), transparent); pointer-events: none;
  opacity: 0; transform: translateY(5px); transition: opacity .2s var(--ease), transform .2s var(--ease); }
.cstatus-gal-item:hover .cstatus-gal-cap, .cstatus-gal-item:focus-within .cstatus-gal-cap { opacity: 1; transform: none; }
.cstatus-gal-item:hover { z-index: 2; box-shadow: 0 12px 28px -8px rgba(0,0,0,.5); }
.cstatus-gal-cap--video { opacity: 1; transform: none; text-align: center; }
/* a more confident video play affordance */
.cstatus-gal-video .cstatus-play { width: 56px; height: 56px; font-size: 21px; box-shadow: 0 6px 20px rgba(0,0,0,.4);
  transition: transform .18s var(--ease), background .18s var(--ease); }
.cstatus-gal-video:hover .cstatus-play { transform: scale(1.08); background: var(--cover-accent, var(--accent)); }
/* designed empty / video-only delivery state */
.cstatus-gal-empty { text-align: center; padding: 46px 20px; margin: 14px 0 6px; border: 1px dashed var(--border-strong); border-radius: 16px;
  background: linear-gradient(160deg, color-mix(in srgb, var(--cover-accent, var(--accent)) 6%, var(--bg-2)), var(--bg-2)); }
.cstatus-gal-empty-ic { font-size: var(--fs-hero); opacity: .55; }
.cstatus-gal-empty-h { font-weight: var(--fw-black); font-size: var(--fs-md); margin-top: 8px; }
.cstatus-gal-empty-p { color: var(--muted); font-size: var(--fs-caption); margin-top: 4px; }
@media (prefers-reduced-motion: reduce) { .cstatus-gal-cap { transition: none; } }

/* ============================================================
   SPEC178 — Feature Guide (searchable "how to use everything").
   ============================================================ */
.guide-intro { font-size: 13.5px; color: var(--muted); margin: 0 0 14px; }
.guide-toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.guide-search { flex: 1 1 240px; min-width: 180px; }
.guide-rolefilter { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.guide-rf-btn { font: inherit; font-size: var(--fs-meta); font-weight: var(--fw-semibold); padding: 6px 11px; border-radius: 999px; border: 1px solid var(--border);
  background: var(--panel); color: var(--muted); cursor: pointer; transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease); }
.guide-rf-btn:hover { background: var(--hover); color: var(--text); }
.guide-rf-btn.on { background: var(--accent-soft); color: var(--accent-hover); border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }
.guide-count-row { margin: 8px 0 14px; }
.guide-count { font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--faint); text-transform: uppercase; letter-spacing: .06em; }
.guide-list { display: flex; flex-direction: column; gap: 12px; }
/* SPEC178 — each category is ONE clean tap-to-open card (12 areas, not 98 rows) */
.guide-cat { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--panel); box-shadow: var(--shadow-sm); overflow: hidden; transition: box-shadow var(--t-fast) var(--ease); }
.guide-cat[open] { box-shadow: var(--shadow); }
.guide-cat-head { display: flex; align-items: center; gap: 12px; padding: 14px 16px; cursor: pointer; list-style: none; }
.guide-cat-head::-webkit-details-marker { display: none; }
.guide-cat-head:hover { background: var(--subtle); }
.guide-cat-ic { font-size: 19px; width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; border-radius: 12px; background: var(--accent-soft); flex: 0 0 auto; }
.guide-cat-meta { flex: 1; min-width: 0; }
.guide-cat-title { font-family: var(--font-serif); font-size: var(--fs-lg); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); line-height: var(--lh-tight); }
.guide-cat-blurb { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.guide-cat-n { font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--muted); background: var(--subtle); border: 1px solid var(--border); border-radius: 999px; padding: 2px 9px; flex: 0 0 auto; }
.guide-cat-chev { color: var(--faint); font-size: 15px; transition: transform var(--t-fast) var(--ease); flex: 0 0 auto; }
.guide-cat[open] .guide-cat-chev { transform: rotate(180deg); }
.guide-cat-body { padding: 2px 14px 8px; border-top: 1px solid var(--border); }
/* features inside a category — flat rows with hairline dividers, not nested cards */
.guide-feat { border: 0; border-bottom: 1px solid var(--border); border-radius: 0; background: transparent; box-shadow: none; overflow: hidden; }
.guide-cat-body .guide-feat:last-child { border-bottom: 0; }
/* coverage banner (admin) — keeps the guide honest as the app grows */
.guide-coverage { font-size: 12.5px; border-radius: var(--radius); padding: 10px 13px; margin-bottom: 14px; }
.guide-coverage--ok { background: var(--ok-soft); color: var(--ok-ink); font-weight: var(--fw-semibold); }
.guide-coverage--gap { background: var(--warn-soft); border: 1px solid color-mix(in srgb, var(--warn) 30%, transparent); }
.guide-coverage-sum { cursor: pointer; font-weight: var(--fw-bold); color: var(--warn); list-style: none; }
.guide-coverage-sum::-webkit-details-marker { display: none; }
.guide-coverage-list { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 9px; }
.guide-coverage-chip { font-size: var(--fs-micro); font-weight: var(--fw-semibold); background: var(--panel); border: 1px solid var(--border); border-radius: 999px; padding: 2px 9px; }

/* ============================================================
   SPEC179 — Coverage Center (nothing falls through the cracks).
   ============================================================ */
.cov { display: flex; flex-direction: column; gap: 12px; }
.cov-headline { display: flex; align-items: center; gap: 16px; padding: 16px 18px; border-radius: var(--radius-lg); border: 1px solid var(--border); }
.cov-headline--ok { background: var(--ok-soft); border-color: color-mix(in srgb, var(--ok) 30%, transparent); }
.cov-headline--gap { background: var(--warn-soft); border-color: color-mix(in srgb, var(--warn) 30%, transparent); }
.cov-head-pct { font-family: var(--font-serif); font-size: var(--fs-hero); font-weight: var(--fw-bold); line-height: 1; flex: 0 0 auto; }
.cov-headline--ok .cov-head-pct { color: var(--ok); }
.cov-headline--gap .cov-head-pct { color: var(--warn); }
.cov-head-title { font-weight: var(--fw-black); font-size: 15px; }
.cov-head-sub { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
.cov-dim { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--panel); box-shadow: var(--shadow-sm); padding: 14px 16px; }
.cov-dim-head { display: flex; align-items: center; gap: 12px; }
.cov-dim-ic { font-size: var(--fs-lg); width: 38px; height: 38px; display: flex; align-items: center; justify-content: center; border-radius: 11px; background: var(--accent-soft); flex: 0 0 auto; }
.cov-dim-meta { flex: 1; min-width: 0; }
.cov-dim-label { font-weight: var(--fw-bold); font-size: var(--fs-body); }
.cov-dim-count { font-size: var(--fs-meta); color: var(--muted); margin-top: 1px; }
.cov-dim-pct { font-weight: var(--fw-black); font-size: 15px; color: var(--warn-ink); flex: 0 0 auto; }
.cov-dim-pct--ok { color: var(--ok-ink); }
.cov-bar { height: 8px; border-radius: 999px; background: var(--bg-2); overflow: hidden; margin: 10px 0 0; }
.cov-bar-fill { height: 100%; border-radius: 999px; background: var(--warn); transition: width .5s var(--ease-spring); }
.cov-bar-fill--ok { background: var(--ok); }
.cov-gaps { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 11px; }
.cov-gap-chip { font-size: 11.5px; font-weight: var(--fw-semibold); background: var(--subtle); border: 1px solid var(--border); border-radius: 999px; padding: 3px 10px; }
.cov-fix-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 11px; flex-wrap: wrap; }
.cov-fix-hint { font-size: var(--fs-meta); color: var(--muted); }
.cov-dim-allok { font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--ok); margin-top: 9px; }

/* ============================================================
   SPEC180 — client notes log (accumulating, expandable entries).
   ============================================================ */
.cnotes-bar { display: flex; justify-content: flex-end; margin-bottom: 6px; }
.cnotes-list { display: flex; flex-direction: column; gap: 6px; }
.cnotes-item { border: 1px solid var(--border); border-radius: var(--radius-sm); background: var(--panel); overflow: hidden; }
.cnotes-item[open] { box-shadow: var(--shadow-sm); border-color: var(--border-strong); }
.cnotes-sum { display: flex; align-items: baseline; gap: 10px; padding: 9px 12px; cursor: pointer; list-style: none; }
.cnotes-sum::-webkit-details-marker { display: none; }
.cnotes-sum:hover { background: var(--subtle); }
.cnotes-preview { flex: 1; min-width: 0; font-size: var(--fs-caption); font-weight: var(--fw-semibold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cnotes-meta { flex: 0 0 auto; font-size: var(--fs-micro); color: var(--faint); }
.cnotes-body { padding: 2px 12px 11px; }
.cnotes-text { font-size: var(--fs-caption); line-height: 1.55; white-space: pre-wrap; }
.cnotes-del { margin-top: 8px; color: var(--danger); }
.cnotes-empty { font-size: 12.5px; color: var(--muted); padding: 8px 2px; }
.cnotes-compose { margin-top: 10px; }

/* ============================================================
   SPEC182 — retainer consult script (first-meeting sales playbook).
   ============================================================ */
.cscript-cta { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border)); background: var(--accent-soft);
  border-radius: var(--radius-lg); padding: 12px 16px; margin: 10px 0 16px; }
.cscript { display: flex; flex-direction: column; gap: 10px; }
.cscript-philosophy { font-size: var(--fs-caption); line-height: 1.6; color: var(--text); background: var(--subtle); border-left: 3px solid var(--accent); border-radius: var(--radius-sm); padding: 11px 14px; }
.cscript-phase { border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--panel); box-shadow: var(--shadow-sm); overflow: hidden; }
.cscript-phase[open] { box-shadow: var(--shadow); border-color: var(--border-strong); }
.cscript-extra { background: color-mix(in srgb, var(--accent) 4%, var(--panel)); }
.cscript-sum { display: flex; align-items: center; gap: 12px; padding: 13px 15px; cursor: pointer; list-style: none; }
.cscript-sum::-webkit-details-marker { display: none; }
.cscript-sum:hover { background: var(--subtle); }
.cscript-num { flex: 0 0 auto; width: 28px; height: 28px; border-radius: 999px; display: flex; align-items: center; justify-content: center; font-weight: var(--fw-black); font-size: var(--fs-caption); color: #fff; background: var(--accent); }
.cscript-num--alt { background: var(--accent-soft); color: var(--accent-hover); }
.cscript-meta { flex: 1; min-width: 0; }
.cscript-name { font-family: var(--font-serif); font-weight: var(--fw-semibold); font-size: var(--fs-md); letter-spacing: var(--ls-tight); }
.cscript-goal { font-size: var(--fs-meta); color: var(--muted); margin-top: 1px; }
.cscript-chev { color: var(--faint); font-size: 15px; transition: transform var(--t-fast) var(--ease); flex: 0 0 auto; }
.cscript-phase[open] .cscript-chev { transform: rotate(180deg); }
.cscript-body { padding: 2px 15px 14px; }
.cscript-label { font-size: var(--fs-micro); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .06em; color: var(--faint); margin: 12px 0 6px; }
.cscript-lines { display: flex; flex-direction: column; gap: 6px; }
.cscript-line { display: flex; align-items: flex-start; gap: 8px; background: var(--subtle); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 9px 11px; }
.cscript-line-t { flex: 1; min-width: 0; font-size: var(--fs-caption); line-height: 1.55; }
.cscript-copy { flex: 0 0 auto; padding: 2px 7px; }
.cscript-listen { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 4px; }
.cscript-listen li { font-size: 12.5px; line-height: var(--lh-normal); color: var(--muted); }
.cscript-tip { font-size: 12.5px; line-height: 1.55; margin-top: 12px; background: var(--warn-soft); border-radius: var(--radius-sm); padding: 9px 11px; }
.cscript-obj { padding: 9px 0; border-bottom: 1px solid var(--border); }
.cscript-obj:last-child { border-bottom: 0; }
.cscript-obj-q { font-weight: var(--fw-bold); font-size: var(--fs-caption); }
.cscript-obj-a { font-size: var(--fs-caption); line-height: 1.55; color: var(--text); margin-top: 3px; }
.guide-feat-sum { display: flex; align-items: flex-start; gap: 11px; padding: 12px 14px; cursor: pointer; list-style: none; }
.guide-feat-sum::-webkit-details-marker { display: none; }
.guide-feat-sum:hover { background: var(--subtle); }
.guide-feat-ic { font-size: var(--fs-lg); flex: 0 0 auto; line-height: 1.45; }
.guide-feat-main { flex: 1; min-width: 0; }
.guide-feat-name { font-weight: var(--fw-bold); font-size: var(--fs-body); }
.guide-feat-what { font-size: 12.5px; color: var(--muted); margin-top: 2px; line-height: var(--lh-normal); }
.guide-feat-chev { color: var(--faint); font-size: 15px; transition: transform var(--t-fast) var(--ease); flex: 0 0 auto; }
.guide-feat[open] .guide-feat-chev { transform: rotate(180deg); }
.guide-feat-body { padding: 0 14px 14px 47px; }
.guide-feat-where { font-size: 11.5px; font-weight: var(--fw-bold); color: var(--accent-hover); margin-bottom: 8px; }
.guide-feat-how { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 5px; }
.guide-feat-how li { font-size: var(--fs-caption); line-height: 1.55; }
.guide-feat-roles { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 11px; }
.guide-role-chip { font-size: 10.5px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: var(--ls-label); padding: 2px 8px; border-radius: 999px;
  background: var(--subtle); color: var(--muted); box-shadow: inset 0 0 0 1px var(--border); }
.guide-role-client { background: var(--accent-soft); color: var(--accent-hover); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 25%, transparent); }
.guide-empty { padding: 34px 12px; text-align: center; color: var(--muted); font-size: 13.5px; }
@media (max-width: 640px) { .guide-feat-body { padding-left: 14px; } }

/* SPEC190 — live consult capture + Diagnose & Close */
.ccap-phase { border-bottom: 1px solid var(--border); }
.ccap-phase > summary { list-style: none; }
.ccap-phase > summary::-webkit-details-marker { display: none; }
.ccap-phase[open] > summary { color: var(--accent-hover); }
.ccap-input { width: 100%; box-sizing: border-box; }
.ccap-pill { transition: opacity .2s; }
.cscript-diagnose-card { border-left: 4px solid var(--accent); }

/* SPEC191 — Marketing Studio layout VARIANTS (pure-CSS repositions of the same zones) */
.tpl-card.tpl-var-framed::after { content: ''; position: absolute; inset: 3.4cqw; border: 0.7cqw solid rgba(255,255,255,.9); border-radius: 5px; pointer-events: none; z-index: 6; }
.tpl-card.tpl-var-top { flex-direction: column-reverse; }
.tpl-card.tpl-var-center .tpl-pf-body { top: 0; bottom: 0; justify-content: center; align-items: center; text-align: center; }
.tpl-card.tpl-var-center .tpl-overlay { background: linear-gradient(0deg, rgba(0,0,0,.6), rgba(0,0,0,.4)); }
.tpl-card.tpl-var-center .tpl-stats { justify-content: center; }
.tpl-card.tpl-var-center .tpl-agent { justify-content: center; }
/* a segmented control that wraps when it has several options (Layout) */
.mkt-seg--wrap { flex-wrap: wrap; }

/* SPEC192 — Studio stickers: a corner layer on the card + the editor picker */
.tpl-stickers { position: absolute; z-index: 7; display: flex; flex-wrap: wrap; gap: 2cqw; max-width: 42%; pointer-events: none; }
.tpl-stickers--tr { top: 4cqw; right: 4cqw; justify-content: flex-end; }
.tpl-stickers--tl { top: 4cqw; left: 4cqw; }
.tpl-stickers--br { bottom: 4cqw; right: 4cqw; justify-content: flex-end; }
.tpl-stickers--bl { bottom: 4cqw; left: 4cqw; }
.tpl-sticker { display: inline-flex; }
.tpl-sticker--emoji { font-size: 11cqw; line-height: 1; filter: drop-shadow(0 1px 2px rgba(0,0,0,.35)); }
.tpl-sticker--svg svg { width: 11cqw; height: 11cqw; filter: drop-shadow(0 1px 2px rgba(0,0,0,.35)); }
.mkt-stickers-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(40px, 1fr)); gap: 6px; margin-top: 6px; }
.mkt-sticker-btn { display: inline-flex; align-items: center; justify-content: center; height: 40px; border: 1px solid var(--border); border-radius: 8px; background: var(--panel); cursor: pointer; font-size: 20px; color: var(--text); padding: 0; }
.mkt-sticker-btn:hover { border-color: var(--accent); }
.mkt-sticker-btn.on { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-hover); box-shadow: inset 0 0 0 1px var(--accent); }
.mkt-sticker-ic { display: inline-flex; }

/* SPEC193 — Studio photo picker (swap the hero from the listing's gallery) */
.mkt-photo-strip { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.mkt-photo-thumb { width: 52px; height: 40px; border-radius: 7px; border: 1px solid var(--border); background: var(--hover) center/cover no-repeat; cursor: pointer; padding: 0; color: var(--muted); font-size: var(--fs-md); display: inline-flex; align-items: center; justify-content: center; }
.mkt-photo-thumb:hover { border-color: var(--accent); }
.mkt-photo-thumb.on { box-shadow: 0 0 0 2px var(--accent); border-color: var(--accent); }
.mkt-photo-thumb--none { background: var(--panel); }

/* SPEC195 — the $0 reel (Ken-Burns slideshow you screen-record) */
.reel-ov { position: fixed; inset: 0; z-index: 1000; background: rgba(8,10,16,.93); display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 14px; padding: 16px; }
.reel-empty { text-align: center; color: #e7eaf2; max-width: 320px; }
.reel-stage { position: relative; width: min(46vh, 92vw); aspect-ratio: 9 / 16; border-radius: 16px; overflow: hidden; background: #0c0f16; box-shadow: 0 24px 70px rgba(0,0,0,.55); }
.reel-slide { position: absolute; inset: 0; opacity: 0; transition: opacity .8s ease; background-size: cover; background-position: center; }
.reel-slide.on { opacity: 1; }
.reel-photo.on { animation: vvtKenBurns 5s ease both; }
.reel-end { display: flex; align-items: center; justify-content: center; text-align: center; background: linear-gradient(140deg, var(--reel-primary, #2b608f), rgba(10,12,20,.96)); }
.reel-end-inner { color: #fff; padding: 9%; }
.reel-end-title { font-size: 7vmin; font-weight: var(--fw-black); line-height: 1.12; }
.reel-end-sub { margin-top: 2.2vmin; font-size: 3.4vmin; opacity: .92; }
.reel-end-brand { margin-top: 4.5vmin; font-size: 2.8vmin; letter-spacing: .12em; text-transform: uppercase; opacity: .85; }
.reel-bar { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: center; max-width: min(46vh, 92vw); transition: opacity .4s ease; }
.reel-hint { color: #cdd3df; font-size: var(--fs-meta); width: 100%; text-align: center; margin-bottom: 2px; }
.reel-dots { display: flex; gap: 6px; align-items: center; justify-content: center; flex-wrap: wrap; max-width: min(46vh, 92vw); transition: opacity .4s ease; }
.reel-dot { width: 6px; height: 6px; border-radius: 999px; background: rgba(255,255,255,.28); transition: background .2s ease, transform .2s ease; }
.reel-dot.on { background: var(--reel-primary, #2b608f); transform: scale(1.35); }
.reel-ov.reel-hidden .reel-bar, .reel-ov.reel-hidden .reel-dots { opacity: 0; }

/* SPEC268 (Bundle C) — cinematic slideshow (landscape, agent-branded, music) */
.ss-ov { position: fixed; inset: 0; z-index: 1000; background: #05070c; display: flex; flex-direction: column; align-items: center; justify-content: center; }
.ss-empty { text-align: center; color: #e7eaf2; max-width: 340px; }
.ss-stage { position: relative; width: 100vw; height: 100vh; overflow: hidden; background: #05070c; }
.ss-slide, .ss-card { position: absolute; inset: 0; opacity: 0; transition: opacity 1.2s ease; }
.ss-slide { background-size: cover; background-position: center; }
.ss-slide.on, .ss-card.on { opacity: 1; }
.ss-slide.on { animation: vvtKenBurns 9s var(--ease) both; }
.ss-card { display: flex; align-items: center; justify-content: center; text-align: center; background: radial-gradient(120% 120% at 50% 30%, color-mix(in srgb, var(--ss-accent, #2b608f) 34%, #05070c), #05070c 72%); }
.ss-card-inner { color: #fff; padding: 6vmin; max-width: 88%; }
.ss-eyebrow { font-size: 2.1vmin; letter-spacing: .22em; text-transform: uppercase; opacity: .78; margin-bottom: 2.4vmin; }
.ss-headline { font-family: var(--serif, Georgia, 'Times New Roman', serif); font-size: 7vmin; font-weight: var(--fw-semibold); line-height: 1.1; letter-spacing: -.01em; }
.ss-sub { margin-top: 2.6vmin; font-size: 3vmin; opacity: .92; }
.ss-brand { margin-top: 5vmin; font-size: 2.2vmin; letter-spacing: .16em; text-transform: uppercase; opacity: .8; }
.ss-bar { position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%); display: flex; gap: 8px; align-items: center; padding: 8px 12px; border-radius: 999px; background: rgba(14,17,25,.72); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); box-shadow: 0 10px 34px rgba(0,0,0,.5); transition: opacity .4s ease; }   /* SAFPOLISH 2026-08-25 D4 */
.ss-ov.ss-hidden .ss-bar { opacity: 0; pointer-events: none; }
.ss-btn { min-width: 38px; height: 38px; padding: 0 10px; border: 0; border-radius: 999px; background: rgba(255,255,255,.08); color: #eef1f7; font-size: var(--fs-md); line-height: 1; cursor: pointer; display: inline-flex; align-items: center; justify-content: center; transition: background .16s ease, transform .16s ease; }
.ss-btn:hover { background: rgba(255,255,255,.18); }
.ss-btn:active { transform: scale(.94); }
.ss-btn.on { background: var(--ss-accent, #2b608f); color: #fff; }
.ss-btn-txt { font-size: var(--fs-caption); font-weight: var(--fw-bold); letter-spacing: .02em; }
.ss-btn-close { background: rgba(255,255,255,.05); }
.ss-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .ss-slide, .ss-card { transition: opacity .4s ease; }
  .ss-slide.on { animation: none; }
  .reel-photo.on { animation: none; }   /* SPEC280 wave 1 — the reel's Ken-Burns was the one vestibular trigger left */
}

/* SPEC197 — free-form text boxes on a card */
.tpl-ctext { position: absolute; z-index: 8; display: flex; flex-direction: column; gap: 1.5cqw; max-width: 84%; pointer-events: none; }
.tpl-ctext--tl { top: 5cqw; left: 5cqw; align-items: flex-start; text-align: left; }
.tpl-ctext--tr { top: 5cqw; right: 5cqw; align-items: flex-end; text-align: right; }
.tpl-ctext--bl { bottom: 5cqw; left: 5cqw; align-items: flex-start; text-align: left; }
.tpl-ctext--br { bottom: 5cqw; right: 5cqw; align-items: flex-end; text-align: right; }
.tpl-ctext--center { top: 50%; left: 50%; transform: translate(-50%, -50%); align-items: center; text-align: center; max-width: 80%; }
.tpl-ctext-box { font-family: var(--tpl-font); font-weight: var(--fw-black); line-height: 1.1; letter-spacing: -0.01em; text-shadow: 0 2px 10px rgba(0,0,0,.45); word-break: break-word; }
.tpl-ctext-s-s { font-size: 4cqw; }
.tpl-ctext-s-m { font-size: 6.5cqw; }
.tpl-ctext-s-l { font-size: 10cqw; }
.tpl-ctext-c-light { color: #fff; }
.tpl-ctext-c-dark { color: #14181f; text-shadow: 0 1px 4px rgba(255,255,255,.35); }
.tpl-ctext-c-accent { color: var(--tpl-accent); }
/* editor rows */
.mkt-ctext-list { display: flex; flex-direction: column; gap: 8px; }
.mkt-ctext-row { display: flex; flex-direction: column; gap: 6px; border: 1px solid var(--border); border-radius: 8px; padding: 8px; background: var(--panel); }
.mkt-ctext-controls { display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
.mkt-ctext-sel { flex: 1 1 auto; min-width: 0; }

/* SPEC202 — touch targets: small icon-only buttons get a 44px invisible hit-area on
   phones (visual size unchanged), matching the app's touch-first standard.
   SPEC-A11Y — added .pp-act (Post-Production Pipeline card icons, 27×24px, no
   mobile accommodation before this). */
@media (max-width: 640px) {
  .btn-icon, .icon-btn, .chip-x, .view-chip-x, .tag-x, .win-react-add, .pp-act { position: relative; }
  .btn-icon::after, .icon-btn::after, .chip-x::after, .view-chip-x::after, .tag-x::after, .win-react-add::after, .pp-act::after {
    content: ''; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
    min-width: 44px; min-height: 44px; width: 100%; height: 100%;
  }
}

/* ============ SPEC245 — Standup / TV board + benchmark badges ============ */
.standup { position: fixed; inset: 0; z-index: 99999; background: radial-gradient(1200px 800px at 50% -10%, #1b2030, #0b0e16 70%);
  color: #f1f5f9; display: flex; flex-direction: column; font-family: inherit; -webkit-font-smoothing: antialiased; animation: suIn .25s ease; }
@keyframes suIn { from { opacity: 0; } to { opacity: 1; } }
.su-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 18px 26px; }
.su-live { display: flex; align-items: center; gap: 8px; font-size: var(--fs-caption); font-weight: var(--fw-black); letter-spacing: .12em; text-transform: uppercase; color: #cbd5e1; }
.su-live-dot { width: 9px; height: 9px; border-radius: 50%; background: #22c55e; box-shadow: 0 0 0 4px rgba(34,197,94,.18); animation: pulse 1.6s infinite; }
.su-clock { font-size: 17px; font-weight: var(--fw-black); color: #e2e8f0; font-variant-numeric: tabular-nums; }
.su-exit { background: rgba(255,255,255,.08); color: #e2e8f0; border: 1px solid rgba(255,255,255,.16); border-radius: 999px; padding: 7px 16px; font-weight: var(--fw-bold); font-size: var(--fs-caption); cursor: pointer; min-height: 40px; }
.su-exit:hover { background: rgba(255,255,255,.16); }
.su-stage { flex: 1 1 auto; display: flex; align-items: center; justify-content: center; padding: 12px 32px; transition: background .4s ease; }
.su-stage.su-good { background: radial-gradient(900px 600px at 50% 40%, rgba(34,197,94,.12), transparent 70%); }
.su-stage.su-warn { background: radial-gradient(900px 600px at 50% 40%, rgba(245,158,11,.12), transparent 70%); }
.su-stage.su-bad  { background: radial-gradient(900px 600px at 50% 40%, rgba(239,68,68,.14), transparent 70%); }
.su-card { max-width: 1100px; width: 100%; text-align: center; animation: suCard .4s ease; }
@keyframes suCard { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
.su-kicker { font-size: clamp(15px, 2.4vw, 26px); font-weight: var(--fw-black); letter-spacing: .02em; color: #94a3b8; margin-bottom: 10px; }
.su-big { font-size: clamp(64px, 17vw, 220px); font-weight: var(--fw-heavy); line-height: .95; letter-spacing: var(--ls-tight);
  background: linear-gradient(180deg, #ffffff, #c7d2fe); -webkit-background-clip: text; background-clip: text; color: transparent; }
.su-stage.su-good .su-big { background: linear-gradient(180deg, #fff, #86efac); -webkit-background-clip: text; background-clip: text; }
.su-stage.su-bad .su-big  { background: linear-gradient(180deg, #fff, #fca5a5); -webkit-background-clip: text; background-clip: text; }
.su-bar { max-width: 640px; margin: 18px auto 0; height: 14px; border-radius: 999px; background: rgba(255,255,255,.1); overflow: hidden; }
.su-bar-fill { height: 100%; border-radius: 999px; background: var(--accent); transition: width .6s ease; }
.su-sub { font-size: clamp(16px, 2.6vw, 30px); font-weight: var(--fw-bold); color: #e2e8f0; margin-top: 18px; }
.su-bench { display: inline-block; margin-top: 14px; font-size: clamp(13px, 1.8vw, 19px); font-weight: var(--fw-black); padding: 5px 16px; border-radius: 999px; }
.su-bench-up { color: #86efac; background: rgba(34,197,94,.14); }
.su-bench-down { color: #fca5a5; background: rgba(239,68,68,.14); }
.su-bench-flat { color: #cbd5e1; background: rgba(255,255,255,.08); }
.su-chips { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-top: 20px; }
.su-chip { font-size: clamp(14px, 1.8vw, 20px); font-weight: var(--fw-bold); color: #e2e8f0; background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.14); border-radius: 999px; padding: 7px 18px; }
.su-list { list-style: none; margin: 18px auto 0; padding: 0; max-width: 760px; text-align: left; }
.su-list li { font-size: clamp(15px, 2vw, 22px); font-weight: var(--fw-semibold); color: #e2e8f0; padding: 9px 4px; border-bottom: 1px solid rgba(255,255,255,.08); }
.su-list li::before { content: '→ '; color: var(--accent); font-weight: var(--fw-black); }
.su-prog { height: 4px; background: var(--accent, #2b608f); width: 0%; transition: width .12s linear; }
.su-dots { display: flex; gap: 9px; justify-content: center; padding: 16px; }
.su-dot { width: 9px; height: 9px; border-radius: 50%; background: rgba(255,255,255,.22); }
.su-dot.on { background: #fff; transform: scale(1.25); }
.su-hint { text-align: center; font-size: var(--fs-meta); color: #64748b; padding-bottom: 16px; letter-spacing: var(--ls-label); }
.su-paused .su-prog { opacity: .35; }
.su-paused .su-live-dot { animation: none; background: #f59e0b; }
/* reusable self-benchmark badge (KPI cards) */
.bm-badge { display: inline-flex; align-items: center; font-size: 10.5px; font-weight: var(--fw-black); padding: 1px 7px; border-radius: 999px; margin-left: 6px; white-space: nowrap; }
.bm-up { color: var(--ok, #16a34a); background: var(--ok-soft, rgba(22,163,74,.12)); }
.bm-down { color: var(--danger, #ef4444); background: var(--danger-soft, rgba(239,68,68,.12)); }
.bm-flat { color: var(--muted); background: var(--subtle); }

/* ============ SPEC246 — SOP sign-off (read-receipt) ============ */
.sop-signoff { margin-top: 18px; padding: 14px 16px; border: 1px solid var(--border); border-radius: 12px; background: var(--subtle); }
.sop-signoff-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.sop-signoff-title { display: inline-flex; align-items: center; gap: 5px; font-weight: var(--fw-black); font-size: 13.5px; }
.sop-signoff-me { font-size: var(--fs-caption); font-weight: var(--fw-bold); }
.sop-signoff-me.done { color: var(--ok); }

/* ============ SPEC247 — bank reconciliation (Books) ============ */
.rec-result { margin-top: 12px; }
.rec-line { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 7px 0; border-bottom: 1px dashed var(--border); font-size: var(--fs-body); }
.rec-line strong { font-variant-numeric: tabular-nums; font-size: var(--fs-md); }
.rec-verdict { margin-top: 12px; padding: 10px 14px; border-radius: 10px; font-weight: var(--fw-black); font-size: var(--fs-body); }
.rec-verdict.ok { color: var(--ok); background: var(--ok-soft, rgba(22,163,74,.12)); border: 1px solid color-mix(in srgb, var(--ok) 30%, transparent); }
.rec-verdict.off { color: var(--danger); background: var(--danger-soft, rgba(239,68,68,.12)); border: 1px solid color-mix(in srgb, var(--danger) 30%, transparent); }
.rec-txns { margin-top: 12px; }
.rec-hist { font-size: var(--fs-meta); font-weight: var(--fw-semibold); color: var(--muted); padding: 4px 0; border-bottom: 1px solid var(--border); }

/* ============ SPEC248 — pre-handoff photo-proof gate ============ */
.proof-list { display: flex; flex-direction: column; gap: 6px; }
.proof-row { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border: 1px solid var(--border); border-radius: 10px; cursor: pointer; font-weight: var(--fw-semibold); font-size: var(--fs-body); min-height: 44px; }
.proof-row input { width: 20px; height: 20px; flex: 0 0 20px; }
.proof-row.got { background: var(--ok-soft, rgba(22,163,74,.1)); border-color: color-mix(in srgb, var(--ok) 28%, transparent); }
.proof-row.got span { color: var(--ok); }
.proof-warn { margin-top: 8px; padding: 9px 13px; border-radius: 10px; font-size: 12.5px; font-weight: var(--fw-bold); color: var(--danger); background: var(--danger-soft, rgba(239,68,68,.1)); border: 1px solid color-mix(in srgb, var(--danger) 28%, transparent); }

/* ============ SPEC249 — Client Studio Snapshot (sell-ready one-pager) ============ */
.snap { max-width: 640px; }
.snap-head { display: flex; align-items: center; gap: 14px; padding-bottom: 14px; border-bottom: 2px solid var(--accent); margin-bottom: 16px; }
.snap-logo { width: 56px; height: 56px; border-radius: 12px; background: #fff center/cover no-repeat; flex: 0 0 56px; box-shadow: 0 0 0 1px var(--border); }
.snap-for { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.snap-agent { font-size: 20px; font-weight: var(--fw-black); line-height: 1.1; }
.snap-broker { font-size: var(--fs-caption); color: var(--muted); font-weight: var(--fw-semibold); }
.snap-title { font-size: var(--fs-h1); font-weight: var(--fw-black); margin: 0 0 4px; }
.snap-sub { font-size: 13.5px; color: var(--muted); margin: 0 0 16px; line-height: var(--lh-normal); }
.snap-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 12px; }
.snap-stat { background: var(--subtle); border: 1px solid var(--border); border-radius: 14px; padding: 16px 12px; text-align: center; }
.snap-big { font-size: var(--fs-hero); font-weight: var(--fw-heavy); line-height: 1; color: var(--accent-hover); letter-spacing: var(--ls-tight); }
.snap-label { font-size: 12.5px; font-weight: var(--fw-bold); margin-top: 6px; }
.snap-stat-sub { font-size: var(--fs-micro); color: var(--muted); margin-top: 2px; }
.snap-recent { margin-top: 18px; }
.snap-recent-head { font-size: var(--fs-meta); font-weight: var(--fw-black); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--muted); margin-bottom: 6px; }
.snap-recent-row { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; border-bottom: 1px solid var(--border); font-size: 13.5px; }
.snap-recent-addr { font-weight: var(--fw-semibold); }
.snap-recent-date { color: var(--muted); white-space: nowrap; }
.snap-close { margin-top: 18px; font-size: var(--fs-body); font-weight: var(--fw-bold); text-align: center; color: var(--text); }

/* ============================================================
   SPEC256 — Output Matrix slide-over (wave-2 Bundle A). Reuses the Marketing-Kit
   visual language: bg cards, hairline borders, muted uppercase section heads.
   ============================================================ */
.omx-sub { margin-bottom: 14px; }
.omx-addr { font-weight: var(--fw-black); font-size: 15px; color: var(--text); }
.omx-hint { font-size: 12.5px; color: var(--muted); margin-top: 3px; line-height: var(--lh-normal); }
.omx-count { font-size: 11.5px; font-weight: var(--fw-bold); color: var(--accent); margin-top: 6px; letter-spacing: .01em; }
.mkit-omx { margin-top: 9px; }
.omx-section-h { font-weight: var(--fw-bold); font-size: 11.5px; letter-spacing: .03em; text-transform: uppercase; color: var(--muted); margin: 4px 0 9px; }

.omx-list { display: flex; flex-direction: column; gap: 9px; }
.omx-row { background: var(--bg); border: 1px solid var(--border); border-radius: 12px; padding: 11px 12px 12px; transition: border-color .14s ease, box-shadow .14s ease; }
.omx-row:hover { border-color: color-mix(in oklch, var(--accent) 45%, var(--border)); }
.omx-row--muted { opacity: .72; }
.omx-row-h { display: flex; align-items: flex-start; gap: 10px; }
.omx-ico { flex: 0 0 auto; color: var(--accent); display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; margin-top: 1px; }
.omx-row-main { flex: 1 1 auto; min-width: 0; }
.omx-name { font-weight: var(--fw-bold); font-size: 13.5px; color: var(--text); }
.omx-from { font-size: var(--fs-micro); color: var(--muted); margin-top: 2px; }
.omx-status { flex: 0 0 auto; font-size: 10.5px; font-weight: var(--fw-black); letter-spacing: .02em; text-transform: uppercase; padding: 3px 8px; border-radius: 999px; white-space: nowrap; }
.omx-status--ready { background: var(--ok-soft); color: var(--ok); }
.omx-status--delivered { background: var(--ok-soft); color: var(--ok); }
.omx-status--building { background: var(--warn-soft); color: var(--warn); }
.omx-status--capture { background: var(--bg); color: var(--muted); border: 1px solid var(--border); }
.omx-row-hint { font-size: var(--fs-meta); color: var(--muted); line-height: var(--lh-normal); margin: 7px 0 9px; }
.omx-row-acts { display: flex; flex-wrap: wrap; gap: 7px; }

.omx-qr { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border); }
.omx-qr-grid { display: flex; gap: 12px; align-items: stretch; }
.omx-qr-box { flex: 0 0 116px; width: 116px; height: 116px; background: #fff; border: 1px solid var(--border); border-radius: 10px; display: flex; align-items: center; justify-content: center; overflow: hidden; padding: 5px; }
.omx-qr-box svg { width: 100%; height: 100%; display: block; }
.omx-qr-side { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; justify-content: center; gap: 9px; }
.omx-qr-cap { font-size: var(--fs-meta); color: var(--muted); line-height: var(--lh-normal); }
.omx-qr-btns { display: flex; flex-wrap: wrap; gap: 7px; }

.omx-stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-top: 14px; }
.omx-stat { background: var(--bg); border: 1px solid var(--border); border-radius: 10px; padding: 9px 6px; text-align: center; }
.omx-stat-n { font-weight: var(--fw-black); font-size: var(--fs-md); color: var(--text); line-height: 1.1; }
.omx-stat--last .omx-stat-n { font-size: 11.5px; font-weight: var(--fw-bold); color: var(--muted); }
.omx-stat-l { font-size: 9.5px; color: var(--muted); margin-top: 3px; letter-spacing: .01em; }
.omx-note { font-size: var(--fs-micro); color: var(--muted); line-height: var(--lh-normal); margin-top: 11px; }

@media (max-width: 520px) {
  .omx-qr-grid { flex-direction: column; align-items: center; }
  .omx-qr-side { text-align: center; }
  .omx-qr-btns { justify-content: center; }
  .omx-stats { grid-template-columns: repeat(2, 1fr); }
}

/* SPEC256 review fixes — 'Set up' status (invites go-live setup, not "Not captured")
   + field-grade tap targets for the in-panel actions on phones. */
.omx-status--setup { background: color-mix(in oklch, var(--accent) 16%, var(--card)); color: var(--accent); }
@media (max-width: 640px) {
  .omx-row-acts .btn, .omx-qr-btns .btn { min-height: 40px; }
}

/* SPEC257 — Automation Outbox (wave-2 Bundle B). Queued message drafts awaiting review. */
.ob-card .ob-badge { display: inline-flex; min-width: 20px; height: 20px; padding: 0 6px; align-items: center; justify-content: center; border-radius: 999px; background: var(--accent); color: #fff; font-size: var(--fs-micro); font-weight: var(--fw-black); vertical-align: middle; }
.ob-row { display: flex; gap: 12px; align-items: flex-start; padding: 11px 0; border-bottom: 1px solid var(--border); }
.ob-row:last-child { border-bottom: 0; }
.ob-main { flex: 1 1 auto; min-width: 0; }
.ob-head { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.ob-who { font-weight: var(--fw-bold); font-size: var(--fs-caption); color: var(--text); }
.ob-kind { font-size: var(--fs-micro); color: var(--muted); background: var(--bg); border: 1px solid var(--border); border-radius: 999px; padding: 1px 8px; }
.ob-prev { font-size: var(--fs-meta); color: var(--muted); margin-top: 4px; line-height: var(--lh-normal); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.ob-acts { flex: 0 0 auto; display: flex; flex-direction: column; gap: 6px; }
@media (max-width: 560px) { .ob-row { flex-direction: column; } .ob-acts { flex-direction: row; } }

/* SPEC257 review fix — field-grade tap targets for the Outbox actions on phones */
@media (max-width: 640px) { .ob-acts .btn { min-height: 40px; } }

/* SPEC258 — Studio Packs settings card (wave-2 Bundle C) */
.pack-incl { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.pack-chip { font-size: var(--fs-micro); color: var(--muted); background: var(--bg); border: 1px solid var(--border); border-radius: 999px; padding: 3px 9px; }
.pack-safe { font-size: 11.5px; color: var(--muted); margin: 10px 0 0; display: flex; align-items: center; gap: 4px; }

/* SPEC259 — Guided Studio Setup Wizard (wave-2 Bundle C) */
.sw-progress { display: flex; align-items: center; gap: 10px; margin: 12px 0; }
.sw-bar { flex: 1 1 auto; height: 8px; background: var(--bg); border: 1px solid var(--border); border-radius: 999px; overflow: hidden; }
.sw-bar-fill { height: 100%; background: var(--accent); border-radius: 999px; transition: width .3s ease; }
.sw-pct { font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--muted); white-space: nowrap; }
.sw-fast { display: flex; gap: 12px; align-items: center; justify-content: space-between; padding: 12px 14px; border: 1px solid color-mix(in oklch, var(--accent) 40%, var(--border)); background: color-mix(in oklch, var(--accent) 7%, var(--card)); border-radius: 12px; margin-top: 6px; }
.sw-fast-main { min-width: 0; }
.sw-fast-t { font-weight: var(--fw-bold); font-size: var(--fs-caption); color: var(--text); }
.sw-fast-h { font-size: var(--fs-meta); color: var(--muted); margin-top: 3px; line-height: var(--lh-normal); }
.sw-row { align-items: flex-start; }
.sw-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.sw-row-hint { font-size: var(--fs-meta); color: var(--muted); margin-top: 2px; line-height: var(--lh-normal); }
.sw-opt { font-size: 10.5px; color: var(--muted); font-weight: var(--fw-semibold); }
.sw-card-h { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.sw-card-x { border: 0; background: transparent; color: var(--muted); cursor: pointer; font-size: var(--fs-body); line-height: 1; padding: 4px 6px; border-radius: 6px; }
.sw-card-x:hover { background: var(--bg); color: var(--text); }
.sw-card-sub { font-size: 12.5px; color: var(--muted); margin: 8px 0 10px; }

/* SPEC260 — Studio HQ (owner cockpit, wave-2 Bundle C) */
.hq-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 14px; }
.hq-card { border: 1px solid var(--border); border-radius: 12px; padding: 13px 14px; background: var(--bg); display: flex; flex-direction: column; }
.hq-card-h { display: flex; gap: 10px; align-items: flex-start; }
.hq-ico { font-size: var(--fs-lg); line-height: var(--lh-tight); flex: 0 0 auto; }
.hq-card-tt { min-width: 0; }
.hq-card-t { font-weight: var(--fw-bold); font-size: 13.5px; color: var(--text); }
.hq-card-s { font-size: 11.5px; color: var(--accent); font-weight: var(--fw-bold); margin-top: 1px; }
.hq-card-hint { font-size: var(--fs-meta); color: var(--muted); line-height: var(--lh-normal); margin: 8px 0 10px; flex: 1 1 auto; }
.hq-card-acts { display: flex; flex-wrap: wrap; gap: 7px; }
@media (max-width: 560px) { .hq-grid { grid-template-columns: 1fr; } }

/* SPEC261 — Referral flywheel card (wave-2 Bundle D) */
.refw-head { display: flex; gap: 22px; margin: 10px 0 2px; }
.refw-n { font-weight: var(--fw-black); font-size: 20px; color: var(--text); line-height: 1.1; }
.refw-l { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.refw-section-h { font-weight: var(--fw-bold); font-size: var(--fs-micro); letter-spacing: .03em; text-transform: uppercase; color: var(--muted); margin: 14px 0 7px; }
.refw-list { display: flex; flex-direction: column; gap: 2px; }
.refw-row { display: flex; align-items: center; gap: 9px; width: 100%; text-align: left; background: transparent; border: 0; border-radius: 8px; padding: 7px 8px; cursor: pointer; color: var(--text); font: inherit; }
.refw-row:hover { background: var(--bg); }
.refw-ask { cursor: default; }
.refw-name { flex: 1 1 auto; min-width: 0; font-weight: var(--fw-semibold); font-size: var(--fs-caption); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.refw-sub { font-weight: 400; color: var(--muted); font-size: var(--fs-meta); }
.refw-badge { font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--accent); background: var(--accent-soft); border-radius: 999px; padding: 2px 8px; white-space: nowrap; }
.refw-val { font-size: var(--fs-meta); font-weight: var(--fw-bold); color: var(--muted); white-space: nowrap; }

/* SPEC262 — Studio Index scorecard (wave-2 Bundle D) */
.si-overall { display: flex; align-items: center; gap: 16px; margin: 14px 0; padding: 14px; border: 1px solid var(--border); border-radius: 12px; background: var(--bg); }
.si-grade { width: 54px; height: 54px; border-radius: 14px; display: flex; align-items: center; justify-content: center; font-weight: var(--fw-black); font-size: 26px; color: #fff; background: var(--muted); flex: 0 0 auto; }
.si-grade--a { background: #00a86b; }
.si-grade--b { background: #4a9d2f; }
.si-grade--c { background: #cab641; color: #3a2f06; }
.si-grade--d { background: #e0773b; }
.si-grade--na { background: var(--muted); font-size: 20px; }
.si-index { font-weight: var(--fw-black); font-size: var(--fs-lg); color: var(--text); }
.si-index-l { font-size: var(--fs-meta); margin-top: 2px; }
.si-list { display: flex; flex-direction: column; }
.si-row { display: flex; align-items: center; gap: 12px; padding: 10px 2px; border-bottom: 1px solid var(--border); }
.si-row:last-child { border-bottom: 0; }
.si-row-main { flex: 1 1 auto; min-width: 0; }
.si-label { font-weight: var(--fw-semibold); font-size: var(--fs-caption); color: var(--text); }
.si-hint { font-size: 11.5px; color: var(--muted); margin-top: 1px; }
.si-val { font-weight: var(--fw-black); font-size: 15px; color: var(--text); white-space: nowrap; }
.si-band { font-size: 10.5px; font-weight: var(--fw-black); letter-spacing: .02em; text-transform: uppercase; padding: 3px 9px; border-radius: 999px; white-space: nowrap; flex: 0 0 auto; }
.si-band--great { background: var(--ok-soft); color: var(--ok); }
.si-band--good { background: var(--ok-soft); color: var(--ok); }
.si-band--typical { background: var(--warn-soft); color: var(--warn); }
.si-band--work { background: var(--danger-soft); color: var(--danger); }
.si-band--na { background: var(--bg); color: var(--muted); border: 1px solid var(--border); }

/* SPEC278 — the in-Hub Book a Shoot view: the public order page embedded full-height */
.bookshoot-frame { width: 100%; height: calc(100vh - 150px); min-height: 480px; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--bg); box-shadow: var(--shadow-sm); display: block; }
.bookshoot-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

/* ============================================================
   SPEC278b — “Book a Shoot” (order.html): the Tonomo-mechanics ×
   Pixieset-skin editorial layer (RESEARCH-TONOMO-VISUAL-2026-07-01.md).
   Real VVT photography on every step · paper/ink chapter bands ·
   Fraunces display serif (self-hosted, OFL) · price styled as a quiet
   caption and never before the package step. Accent stays scoped to
   .order; --order-on-accent is the auto-contrast ink from order.js.
   ============================================================ */
@font-face {
  font-family: 'Fraunces';
  src: url('assets/fraunces-var.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}
.order {
  --order-accent: var(--accent);
  --order-on-accent: #ffffff;
  --order-serif: 'Fraunces', Georgia, 'Times New Roman', serif;
  /* chapter tone (paper by default) */
  --o-bg: var(--bg);
  --o-panel: var(--panel);
  --o-text: var(--text);
  --o-muted: var(--muted);
  --o-faint: var(--faint);
  --o-line: var(--border);
  --o-line-strong: var(--border-strong);
  min-height: 100svh;
  background: var(--o-bg);
  color: var(--o-text);
  transition: background .5s var(--ease);
  padding-bottom: calc(84px + env(safe-area-inset-bottom));
}
.order[data-tone="ink"] {
  --o-bg: #101013;
  --o-panel: #17171b;
  --o-text: #f4f2ee;
  --o-muted: rgba(255, 255, 255, .64);
  --o-faint: rgba(255, 255, 255, .55);
  --o-line: rgba(255, 255, 255, .13);
  --o-line-strong: rgba(255, 255, 255, .24);
}
html[data-theme="dark"] .order { --o-bg: #141416; --o-panel: #1a1a1d; }
html[data-theme="dark"] .order[data-tone="ink"] { --o-bg: #1c1c1f; --o-panel: #232327; }
.order button { font-family: var(--font); }
.order img { filter: saturate(.92) contrast(1.04); }
/* SPEC293 — Portal Studio font packs. order.js sets [data-fontpack] on .order;
   each pack overrides the display serif (--order-serif) only. The text face
   stays Inter (the body --font). All faces are self-hosted or system-safe —
   NO CDN. 'editorial' is the shipped default and needs no rule (the base
   --order-serif above already carries Fraunces). */
.order[data-fontpack="classic"] { --order-serif: Georgia, 'Times New Roman', 'Iowan Old Style', serif; }
.order[data-fontpack="modern"]  { --order-serif: 'Inter var', Inter, system-ui, -apple-system, 'Segoe UI', sans-serif; }
.order[data-fontpack="grotesk"] { --order-serif: 'Inter var', Inter, ui-sans-serif, system-ui, sans-serif; }

/* content rhythm: a centered column; media may run wider */
.order-col { max-width: 720px; margin-inline: auto; padding-inline: clamp(20px, 5vw, 32px); }
.order-wide { max-width: 1080px; margin-inline: auto; padding-inline: clamp(20px, 4vw, 32px); }
.order-step { padding-block: clamp(56px, 9vh, 110px) 24px; min-height: calc(100svh - 190px); animation: order-in .56s cubic-bezier(.16, 1, .3, 1) both; }
@keyframes order-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* ---- masthead ---- */
.order-mast { display: flex; align-items: center; justify-content: space-between; gap: 12px; max-width: 1080px; margin-inline: auto; padding: 18px clamp(20px, 4vw, 32px) 6px; }
.order-mast-left { display: flex; align-items: center; gap: 10px; min-width: 0; }
.order-mast-headshot { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; border: 2px solid var(--order-accent); }
.order-mast-logo { height: 30px; max-width: 140px; object-fit: contain; }
.order-mast-name { font-family: var(--order-serif); font-size: var(--fs-md); letter-spacing: .1px; color: var(--o-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.order-mast-credit { font-size: 10.5px; font-weight: var(--fw-bold); letter-spacing: .18em; text-transform: uppercase; color: var(--o-muted); white-space: nowrap; }

/* ---- progress rail ---- */
.order-rail { max-width: 720px; margin-inline: auto; padding: 8px clamp(20px, 5vw, 32px) 0; }
.order-rail.hide { display: none; }
.order-rail-meta { font-family: var(--order-serif); font-size: 12.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--o-muted); margin-bottom: 8px; }
.order-rail-track { position: relative; height: 1px; background: var(--o-line); overflow: visible; }
.order-rail-fill { height: 1px; background: var(--order-accent); transition: width .5s var(--ease); }
.order-rail-nodes { display: flex; justify-content: space-between; margin-top: -4px; position: relative; }
.order-rail-node { width: 7px; height: 7px; border-radius: 50%; border: 1px solid var(--o-line-strong); background: var(--o-bg); padding: 0; cursor: default; transition: all var(--t-base) var(--ease); position: relative; }
.order-rail-node::after { content: ''; position: absolute; inset: -10px; }
.order-rail-node.done { border-color: var(--order-accent); background: var(--order-accent); cursor: pointer; }
.order-rail-node.cur { border-color: var(--order-accent); background: var(--o-bg); transform: scale(1.35); }

/* ---- editorial step head: eyebrow · ghost numeral · serif title ---- */
.order-eyebrow { font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: .22em; text-transform: uppercase; color: var(--order-accent); margin-bottom: 14px; }
.order-eyebrow.onink, .order[data-tone="ink"] .order-eyebrow { color: var(--o-muted); }
.order-title-row { position: relative; }
.order-ghost-no { position: absolute; right: -8px; top: 50%; transform: translateY(-58%); font-family: var(--order-serif); font-weight: 300; font-size: clamp(80px, 15vw, 150px); line-height: 1; color: transparent; -webkit-text-stroke: 1px var(--o-line-strong); pointer-events: none; user-select: none; }
.order[data-tone="ink"] .order-ghost-no { -webkit-text-stroke: 0; color: rgba(255, 255, 255, .07); }
.order-step-title { font-family: var(--order-serif); font-weight: 420; font-size: clamp(32px, 6vw, 54px); letter-spacing: -.7px; line-height: 1.08; margin: 0 0 12px; color: var(--o-text); outline: none; text-wrap: balance; position: relative; }
.order-step-sub { color: var(--o-muted); font-size: 15.5px; line-height: 1.6; margin: 0 0 clamp(28px, 4vh, 44px); max-width: 54ch; }
.order-step-head { margin-bottom: 6px; }
.order-optional { font-weight: var(--fw-medium); font-size: var(--fs-micro); letter-spacing: .05em; text-transform: uppercase; color: var(--o-muted); }

/* ---- the 21:9 chapter image ---- */
.order-chapter { margin: 0 0 clamp(28px, 5vh, 48px); border-radius: 14px; overflow: hidden; box-shadow: var(--shadow); }
.order-chapter-img { display: block; width: 100%; aspect-ratio: 21 / 9; object-fit: cover; }

/* ---- fields ---- */
.order-field { margin-bottom: 26px; position: relative; }
.order-label { display: block; font-size: 11.5px; font-weight: var(--fw-bold); letter-spacing: .08em; text-transform: uppercase; color: var(--o-muted); margin-bottom: 9px; }
.order-input { width: 100%; box-sizing: border-box; font: inherit; font-size: var(--fs-md); color: var(--o-text); background: var(--o-panel); border: 1px solid var(--o-line-strong); border-radius: 12px; padding: 14px 15px; transition: border-color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease); }
.order-input::placeholder { color: var(--o-faint); }
.order-input:focus { outline: none; border-color: var(--order-accent); box-shadow: var(--focus-ring-soft); }
.order-input.area { min-height: 84px; resize: vertical; }
.order-input.sqft-lg { max-width: 230px; font-family: var(--order-serif); font-size: 26px; font-variant-numeric: tabular-nums; letter-spacing: -.3px; }
.order-input.mini { width: 86px; text-align: center; font-variant-numeric: tabular-nums; }
.order-sqft-row, .order-bb-row { display: flex; align-items: center; gap: 10px; }
.order-sqft-unit { color: var(--o-muted); font-size: var(--fs-caption); }
.order-err { color: #b45309; font-size: var(--fs-caption); font-weight: var(--fw-semibold); margin-top: 7px; display: none; }
html[data-theme="dark"] .order .order-err, .order[data-tone="ink"] .order-err { color: var(--warn); }
.order-err.show { display: block; }
.order-concierge { margin-top: 10px; font-family: var(--order-serif); font-size: 15.5px; color: var(--o-muted); }
.order-prefill { font-size: 12.5px; color: var(--o-muted); margin-top: 7px; }
.order-prefill:empty { display: none; }

/* address suggestions (Photon) */
.order-sugg { position: absolute; left: 0; right: 0; top: calc(100% - 22px); z-index: 30; display: none; flex-direction: column; background: var(--o-panel); border: 1px solid var(--o-line-strong); border-radius: 12px; overflow: hidden; box-shadow: var(--shadow-lg); }
.order-field.addr .order-sugg { top: auto; }
.order-sugg.show { display: flex; }
.order-sugg-item { font: inherit; font-size: 14.5px; text-align: left; padding: 12px 15px; background: none; border: 0; border-bottom: 1px solid var(--o-line); color: var(--o-text); cursor: pointer; }
.order-sugg-item:last-child { border-bottom: 0; }
.order-sugg-item:hover, .order-sugg-item:focus-visible { background: color-mix(in srgb, var(--order-accent) 8%, var(--o-panel)); }
.order-attrib { font-size: var(--fs-micro); color: var(--o-muted); margin-top: 6px; }
.order-attrib a { color: var(--o-muted); text-decoration: underline; }

/* ---- chips ---- */
.order-chiprow { display: flex; flex-wrap: wrap; gap: 8px; }
.order-chip { font: inherit; font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--o-text); background: var(--o-panel); border: 1px solid var(--o-line-strong); border-radius: 999px; padding: 10px 16px; min-height: 44px; cursor: pointer; transition: border-color var(--t-base) var(--ease), background var(--t-base) var(--ease), color var(--t-base) var(--ease); }
.order-chip:hover { border-color: var(--order-accent); }
.order-chip.on { background: var(--order-accent); border-color: var(--order-accent); color: var(--order-on-accent); }

/* ---- landing hero (ink chapter, real twilight) ---- */
.order-hero { position: relative; overflow: hidden; min-height: min(78svh, 760px); display: flex; align-items: flex-end; }
.order-hero-media { position: absolute; inset: 0; }
.order-hero-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.order-hero-img.kenburns { animation: order-kb 1.4s var(--ease) both; }
@keyframes order-kb { from { transform: scale(1.06); } to { transform: scale(1); } }
.order-hero-scrim { position: absolute; inset: 0; background:
  linear-gradient(to top, rgba(10, 10, 12, .82) 0%, rgba(10, 10, 12, .38) 40%, transparent 70%),
  linear-gradient(to bottom, rgba(10, 10, 12, .38), transparent 26%); }
.order-hero-body { position: relative; width: 100%; max-width: 1080px; margin-inline: auto; padding: clamp(48px, 10vh, 110px) clamp(20px, 4vw, 32px) clamp(40px, 7vh, 72px); color: #fff; }
.order-hero-title { font-family: var(--order-serif); font-weight: 400; font-size: clamp(42px, 8.2vw, 82px); line-height: 1.05; letter-spacing: -1px; margin: 0 0 16px; color: #fff; text-shadow: 0 1px 24px rgba(0, 0, 0, .25); outline: none; text-wrap: balance; max-width: 16ch; }
.order-hero-sub { color: rgba(255, 255, 255, .82); font-size: clamp(15px, 2vw, 17px); line-height: 1.6; max-width: 46ch; margin: 0 0 30px; }
.order-resume { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 18px; }
.order-fine { font-size: 12.5px; color: var(--o-muted); margin-top: 18px; line-height: 1.6; }
.order-fine.center { text-align: center; }
.order-fine.onink { color: rgba(255, 255, 255, .55); }
.order-logos-kicker { font-size: 10.5px; font-weight: var(--fw-bold); letter-spacing: .2em; text-transform: uppercase; color: var(--o-faint); text-align: center; margin: clamp(32px, 6vh, 56px) 0 18px; }
.order-logos { display: flex; align-items: center; justify-content: center; gap: clamp(18px, 4vw, 40px); flex-wrap: wrap; padding-bottom: 12px; }
/* the harvested logos mix light and dark art — neutral press-strip chips read consistently on any tone */
.order-logo-img { height: 34px; width: auto; max-width: 120px; object-fit: contain; background: #fff; padding: 5px 12px; border-radius: 6px; box-sizing: border-box; filter: grayscale(1); opacity: .82; }

/* ---- buttons ---- */
.order-btn { font: inherit; font-size: 15px; font-weight: var(--fw-bold); border-radius: 999px; padding: 14px 26px; min-height: 48px; cursor: pointer; border: 1px solid transparent; transition: transform var(--t-fast) var(--ease-spring), box-shadow var(--t-base) var(--ease), background var(--t-base) var(--ease); }
.order-btn.primary { background: var(--order-accent); color: var(--order-on-accent); box-shadow: var(--shadow); }
.order-btn.primary:hover { transform: translateY(-1px); box-shadow: var(--shadow-lg); }
.order-btn.primary:active { transform: none; }
.order-btn.primary:disabled { opacity: .6; cursor: default; transform: none; }
.order-btn.ghost { background: transparent; border-color: var(--o-line-strong); color: var(--o-text); }
.order-btn.ghost:hover { border-color: var(--order-accent); }
.order-btn.xl { font-size: var(--fs-md); padding: 17px 32px; min-height: 56px; }
.order-cta-arrow { display: inline-block; transition: transform var(--t-base) var(--ease); }
.order-btn:hover .order-cta-arrow { transform: translateX(3px); }
.order-back { background: none; border: 0; padding: 6px 0; font: inherit; font-size: 12.5px; font-weight: var(--fw-bold); letter-spacing: .1em; text-transform: uppercase; color: var(--o-muted); cursor: pointer; border-bottom: 1px solid var(--o-line-strong); }
.order-back:hover { color: var(--o-text); border-color: var(--o-text); }
.order-link { background: none; border: 0; padding: 4px 0; font: inherit; font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--order-accent); cursor: pointer; }
.order-hero .order-link { color: #fff; text-decoration: underline; text-underline-offset: 3px; }
.order-link:hover { text-decoration: underline; }
.order-link.quiet { color: var(--o-muted); font-weight: var(--fw-medium); }
.order-hero .order-link.quiet { color: rgba(255, 255, 255, .6); }
.order-nav { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-top: clamp(28px, 5vh, 44px); }
.order-nav.confirm { margin-top: 24px; }

/* ---- vision cards ---- */
.order-vision-grid { display: grid; gap: 12px; }
.order-vision-card { text-align: left; background: var(--o-panel); border: 1px solid var(--o-line); border-radius: 14px; padding: 22px 24px; cursor: pointer; box-shadow: var(--shadow-sm); display: flex; flex-direction: column; gap: 6px; transition: border-color var(--t-base) var(--ease), transform var(--t-fast) var(--ease-spring), box-shadow var(--t-base) var(--ease); }
.order-vision-card:hover { border-color: var(--order-accent); transform: translateY(-2px); box-shadow: var(--shadow); }
.order-vision-card.sel { border: 1.5px solid var(--order-accent); }
.order-vision-title { font-family: var(--order-serif); font-size: 21px; color: var(--o-text); }
.order-vision-sub { color: var(--o-muted); font-size: 13.5px; line-height: var(--lh-normal); }

/* SPEC315 — the welcome-back bar (returning agent memory link) */
.order-wb { max-width: 1080px; margin: 0 auto; padding-inline: clamp(20px, 4vw, 32px); }
.order-wb-card { display: flex; align-items: center; justify-content: space-between; gap: 18px; flex-wrap: wrap;
  background: var(--o-panel); border: 1px solid color-mix(in srgb, var(--order-accent) 35%, var(--o-line)); border-radius: 14px;
  padding: 18px 22px; box-shadow: var(--shadow); margin-bottom: 26px; }
.order-wb-hi { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.order-wb-name { font-family: var(--order-serif); font-size: clamp(19px, 2.4vw, 24px); letter-spacing: -.2px; color: var(--o-text); }
.order-wb-sub { font-size: var(--fs-caption); color: var(--o-muted); }
.order-wb-row { display: flex; gap: 10px; flex-wrap: wrap; }

/* ---- package ladder (ink chapter — the photos glow) ---- */
.order-pkg-grid { display: grid; gap: 28px; grid-template-columns: 1fr; max-width: 1160px; margin: 0 auto; padding-inline: clamp(20px, 4vw, 32px); }
/* Vincent 2026-07-08 — the two-up grid is RETIRED: every package is a grand
   full-width band, read top-down from the Signature anchor. The desktop
   sideways-band rules live BELOW the base .order-pkg rules (cascade). */
.order-pkg { text-align: left; background: var(--o-panel); border: 1px solid var(--o-line); border-radius: 14px; padding: 0 0 18px; cursor: pointer; overflow: hidden; display: flex; flex-direction: column; gap: 12px; transition: border-color var(--t-base) var(--ease), transform var(--t-fast) var(--ease-spring), box-shadow var(--t-base) var(--ease); }
.order-pkg:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); }
.order-pkg:hover .order-pkg-img { transform: scale(1.03); }
.order-pkg.sel { border: 1.5px solid var(--order-accent); box-shadow: var(--shadow-lg); }
.order-pkg-media { position: relative; aspect-ratio: 3 / 2; overflow: hidden; }
.order-pkg-img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .7s var(--ease); }
.order-pkg-scrim { position: absolute; inset: 0; background: linear-gradient(to top, rgba(10, 10, 12, .78) 0%, rgba(10, 10, 12, .35) 38%, transparent 68%); }
.order-play { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -62%); width: 54px; height: 54px; border-radius: 50%; border: 1px solid rgba(255, 255, 255, .85); color: #fff; font-size: var(--fs-md); display: flex; align-items: center; justify-content: center; padding-left: 4px; background: rgba(10, 10, 12, .25); backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); }   /* SAFPOLISH 2026-08-25 D4 */
.order-pkg-onimg { position: absolute; left: 20px; right: 20px; bottom: 16px; color: #fff; display: flex; flex-direction: column; gap: 4px; }
.order-pkg-badge { font-size: 10.5px; font-weight: var(--fw-black); letter-spacing: .16em; text-transform: uppercase; color: #fff; border-bottom: 1px solid var(--order-accent); padding-bottom: 3px; align-self: flex-start; text-shadow: 0 1px 12px rgba(0, 0, 0, .4); }
.order-pkg-name { font-family: var(--order-serif); font-size: clamp(24px, 3vw, 30px); letter-spacing: -.3px; text-shadow: 0 1px 20px rgba(0, 0, 0, .35); }
.order-pkg-tag { color: var(--o-muted); font-size: 13.5px; line-height: 1.55; padding: 2px 20px 0; max-width: 56ch; }
.order-pkg-inc { display: flex; flex-direction: column; padding: 4px 20px 0; flex: 1 1 auto; }   /* SPEC289 — absorb the slack so prices align at the bottom across equal-height cards */
.order-pkg-inc-row { font-size: var(--fs-meta); font-weight: var(--fw-semibold); letter-spacing: .05em; text-transform: uppercase; color: var(--o-muted); padding: 7px 0; border-top: 1px solid var(--o-line); }
.order-pkg-inc-row:first-child { border-top: 0; }
.order-pkg-pricefoot { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 10px 20px 0; border-top: 1px solid var(--o-line); margin: 8px 20px 0; padding-inline: 0; }
.order-pkg-selmark { font-family: var(--order-serif); font-size: var(--fs-body); letter-spacing: var(--ls-label); color: var(--o-text); }
.order-pkg-price { display: flex; flex-direction: column; align-items: flex-end; font-family: var(--order-serif); font-variant-numeric: tabular-nums; font-size: 27px; letter-spacing: -.4px; color: var(--o-text); }
.order-price-from { font-family: var(--font); font-size: 10.5px; font-weight: var(--fw-semibold); letter-spacing: .14em; text-transform: uppercase; color: var(--o-muted); }
/* Vincent 2026-07-08 — desktop turns each package band sideways: a tall photo
   on the left, the sell (tagline, best-for, the full include list in two
   columns, price) on the right. Mobile keeps the stacked flex column above. */
@media (min-width: 860px) {
  /* SPEC308 W3 — the fact line (row 3) pushes the include grid to row 4, which is
     the minmax(0,1fr) slack row so prices still settle at the bottom of the band */
  .order-pkg { display: grid; grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr); grid-template-rows: auto auto auto minmax(0, 1fr) auto auto auto; column-gap: 30px; padding: 0 0 26px; }
  .order-pkg-media { grid-area: 1 / 1 / -1 / 2; aspect-ratio: auto; min-height: 480px; height: 100%; }
  .order-pkg-tag, .order-pkg-bestfor, .order-pkg-facts, .order-pkg-inc, .order-proofchip, .order-pkg-pricefoot, .order-pkg-delta, .order-pkg-actions { grid-column: 2; }
  .order-pkg-facts { padding: 4px 30px 0 0; }
  .order-pkg .order-proofchip { padding: 6px 30px 0 0; }
  .order-pkg-actions { padding: 16px 30px 0 0; }
  .order-pkg-tag { font-size: 15.5px; padding: 28px 30px 0 0; max-width: none; }
  .order-pkg-bestfor { padding: 0 30px 0 0; }
  .order-pkg-inc { display: grid; grid-template-columns: 1fr 1fr; column-gap: 24px; align-content: start; padding: 10px 30px 0 0; }
  .order-pkg-inc-row:nth-child(2) { border-top: 0; }   /* the 2nd column's first row loses its hairline too */
  .order-pkg-pricefoot { margin: 10px 30px 0 0; }
  .order-pkg-delta { padding-right: 30px; }
  .order-pkg-name { font-size: clamp(28px, 3vw, 38px); }
}

/* ---- add-ons: shop-the-story rows ---- */
.order-addon-grid { display: grid; gap: 14px; margin-bottom: 20px; }
.order-addon { display: flex; align-items: center; gap: 16px; background: var(--o-panel); border: 1px solid var(--o-line); border-radius: 14px; padding: 14px 16px; box-shadow: var(--shadow-sm); cursor: pointer; transition: border-color var(--t-base) var(--ease), box-shadow var(--t-base) var(--ease); }   /* whole row opens the details sheet (Vincent 2026-07-08 round 2) */
.order-addon:hover { border-color: var(--o-line-strong); box-shadow: var(--shadow); }
.order-addon.on { border-color: var(--order-accent); }
.order-addon-thumb { position: relative; flex: 0 0 116px; aspect-ratio: 4 / 3; border: 0; padding: 0; border-radius: 10px; overflow: hidden; cursor: zoom-in; background: var(--o-bg); }
.order-addon-thumbimg { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .7s var(--ease); }
.order-addon-thumb:hover .order-addon-thumbimg { transform: scale(1.05); }
.order-addon-see { position: absolute; left: 0; right: 0; bottom: 0; font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: .08em; text-transform: uppercase; color: #fff; background: linear-gradient(to top, rgba(10, 10, 12, .72), transparent); padding: 14px 6px 6px; text-align: center; }
.order-addon-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; flex: 1 1 auto; }
.order-addon-name { font-family: var(--order-serif); font-size: var(--fs-lg); color: var(--o-text); }
.order-addon-why { color: var(--o-muted); font-size: var(--fs-caption); line-height: var(--lh-normal); max-width: 44ch; }
.order-addon-price { font-family: var(--order-serif); font-variant-numeric: tabular-nums; font-size: 17px; color: var(--o-text); margin-top: 4px; }
.order-addon-price-fine { font-family: var(--font); font-size: 11.5px; color: var(--o-faint); }
.order-add-btn { flex: 0 0 auto; font: inherit; font-size: var(--fs-body); font-weight: var(--fw-bold); min-width: 92px; min-height: 44px; border-radius: 999px; border: 1px solid var(--o-line-strong); background: var(--o-panel); color: var(--o-text); cursor: pointer; transition: background var(--t-base) var(--ease), color var(--t-base) var(--ease), border-color var(--t-base) var(--ease), transform var(--t-fast) var(--ease-spring); }
.order-add-btn:hover { border-color: var(--order-accent); }
.order-add-btn.on { background: var(--order-accent); border-color: var(--order-accent); color: var(--order-on-accent); }
.order-add-btn.sm { min-width: 76px; min-height: 38px; font-size: var(--fs-caption); }
.order-covered { color: var(--o-muted); font-size: 14.5px; line-height: 1.6; background: var(--o-panel); border: 1px solid var(--o-line); border-radius: 14px; padding: 18px 20px; }

/* staging qty + tier controls */
.order-staging-controls { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin-top: 8px; }
.order-qty { display: inline-flex; align-items: center; gap: 2px; border: 1px solid var(--o-line-strong); border-radius: 999px; overflow: hidden; }
.order-qty-btn { width: 40px; height: 40px; border: 0; background: var(--o-panel); font-size: var(--fs-lg); font-weight: var(--fw-bold); color: var(--o-text); cursor: pointer; }
.order-qty-btn:hover { background: color-mix(in srgb, var(--order-accent) 8%, var(--o-panel)); }
.order-qty-val { min-width: 26px; text-align: center; font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; }
.order-qty-unit { color: var(--o-muted); font-size: var(--fs-caption); }
.order-seg-row { display: inline-flex; border: 1px solid var(--o-line-strong); border-radius: 999px; overflow: hidden; }
.order-seg { font: inherit; font-size: 12.5px; font-weight: var(--fw-bold); padding: 9px 14px; border: 0; background: var(--o-panel); color: var(--o-muted); cursor: pointer; }
.order-seg.on { background: var(--order-accent); color: var(--order-on-accent); }

/* included + full collection */
.order-included { margin: 22px 0; }
.order-included-label { font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: .16em; text-transform: uppercase; color: var(--o-muted); margin-bottom: 8px; }
.order-included-rows { display: flex; flex-wrap: wrap; gap: 6px 18px; }
.order-included-item { font-size: 12.5px; font-weight: var(--fw-semibold); color: var(--o-muted); }
.order-more { border-top: 1px solid var(--o-line); padding-top: 14px; }
.order-more-sum { cursor: pointer; font-weight: var(--fw-bold); font-size: var(--fs-caption); letter-spacing: .08em; text-transform: uppercase; color: var(--o-muted); list-style: none; padding: 8px 0; }
.order-more-sum:hover { color: var(--o-text); }
.order-more-sum::-webkit-details-marker { display: none; }
.order-more-sum::after { content: ' ⌄'; }
.order-more[open] .order-more-sum::after { content: ' ⌃'; }
.order-more-list { display: flex; flex-direction: column; }
.order-more-row { display: flex; align-items: center; gap: 14px; padding: 12px 2px; border-bottom: 1px solid var(--o-line); }
.order-more-row:last-child { border-bottom: 0; }
.order-more-thumb { flex: 0 0 64px; aspect-ratio: 4 / 3; border: 0; padding: 0; border-radius: 8px; overflow: hidden; cursor: zoom-in; background: var(--o-bg); }
.order-more-thumbimg { width: 100%; height: 100%; object-fit: cover; display: block; }
.order-more-name { flex: 1 1 auto; font-size: 14.5px; font-weight: var(--fw-semibold); color: var(--o-text); }
.order-more-price { font-variant-numeric: tabular-nums; font-size: var(--fs-body); color: var(--o-muted); }

/* bundle-beat nudge — generosity, not pressure */
.order-nudge { display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px; background: color-mix(in srgb, var(--order-accent) 7%, var(--o-panel)); border: 1px solid color-mix(in srgb, var(--order-accent) 30%, var(--o-line)); border-radius: 14px; padding: 14px 18px; font-size: 13.5px; line-height: 1.55; color: var(--o-text); margin-bottom: 18px; }

/* ---- contact + the print-mount receipt ---- */
.order-contact-grid { display: grid; gap: 4px; }
.order-hp { position: absolute; left: -9999px; top: -9999px; height: 1px; width: 1px; opacity: 0; pointer-events: none; }
.order-receipt { background: var(--o-panel); border: 1px solid var(--o-line); border-radius: 4px; box-shadow: var(--shadow-lg); padding: 12px 12px 20px; margin-top: 28px; }
.order-receipt-img { display: block; width: 100%; aspect-ratio: 21 / 9; object-fit: cover; margin-bottom: 20px; }
.order-receipt-kicker { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .18em; text-transform: uppercase; color: var(--o-muted); margin: 0 12px 6px; }
.order-receipt-addr { font-family: var(--order-serif); font-size: var(--fs-h1); color: var(--o-text); line-height: 1.25; margin: 0 12px; }
.order-receipt-meta { font-size: 12.5px; color: var(--o-faint); margin: 4px 12px 16px; }
.order-receipt-line { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; padding: 9px 12px; border-bottom: 1px solid var(--o-line); font-size: var(--fs-body); color: var(--o-text); }
.order-receipt-addontag { font-size: 10px; font-weight: var(--fw-bold); letter-spacing: .08em; text-transform: uppercase; color: var(--o-faint); margin-left: 8px; }
.order-receipt-amt { font-variant-numeric: tabular-nums; font-weight: var(--fw-semibold); white-space: nowrap; }
.order-receipt-total { display: flex; justify-content: space-between; align-items: baseline; gap: 14px; padding: 16px 12px 4px; font-weight: var(--fw-bold); font-size: 15px; color: var(--o-text); }
.order-receipt-totalnum { font-family: var(--order-serif); font-variant-numeric: tabular-nums; font-size: 31px; letter-spacing: -.4px; }
.order-receipt.done { margin: 26px auto 0; text-align: left; max-width: 480px; }

/* ---- frosted running-total ribbon (steps 3–6 only) ---- */
.order-ribbon { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; display: flex; align-items: center; justify-content: space-between; gap: 16px; max-width: 760px; margin: 0 auto; background: rgba(255, 255, 255, .82); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); border-top: 1px solid var(--border); padding: 12px 22px calc(12px + env(safe-area-inset-bottom)); }
.order[data-tone="ink"] .order-ribbon, html[data-theme="dark"] .order .order-ribbon { background: rgba(20, 20, 22, .78); border-top-color: rgba(255, 255, 255, .13); }
.order-ribbon.hide { display: none; }
.order-ribbon-left { display: flex; flex-direction: column; }
.order-ribbon-label { font-size: 10.5px; font-weight: var(--fw-black); letter-spacing: .14em; text-transform: uppercase; color: var(--o-muted); }
.order-ribbon-note { font-size: 11.5px; color: var(--o-muted); }
.order-ribbon-total { font-family: var(--order-serif); font-variant-numeric: tabular-nums; font-size: 27px; letter-spacing: -.4px; color: var(--o-text); }

/* one-line affirmations (aria-live) */
.order-affirm { position: fixed; left: 50%; transform: translateX(-50%); bottom: calc(72px + env(safe-area-inset-bottom)); width: max-content; max-width: 92vw; text-align: center; font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--accent-hover); background: var(--panel); border: 1px solid var(--border); border-radius: 999px; padding: 8px 18px; box-shadow: var(--shadow); pointer-events: none; z-index: 39; }
.order-affirm:empty { display: none; }

/* ---- lightbox (native dialog) ---- */
.order-lightbox { border: 0; border-radius: 14px; padding: 0; max-width: min(920px, 92vw); width: 100%; background: var(--panel); color: var(--text); box-shadow: var(--shadow-lg); }
.order-lightbox::backdrop { background: rgba(10, 10, 12, .72); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }   /* SAFPOLISH 2026-08-25 D4 — ::backdrop pseudo, paired for parity, harmless (unpaired anywhere ratchets to 0) */
.order-lightbox-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 16px 20px 10px; }
.order-lightbox-title { font-family: var(--order-serif); font-size: 21px; }
.order-lightbox-close { font: inherit; border: 0; background: none; font-size: var(--fs-md); cursor: pointer; color: var(--muted); padding: 6px 10px; }
.order-lightbox-body { display: flex; flex-direction: column; gap: 12px; padding: 0 20px 20px; max-height: 76vh; overflow: auto; }
.order-lb-img { width: 100%; border-radius: 10px; display: block; }
.order-lb-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.order-lb-fig { margin: 0; }
.order-lb-fig figcaption { font-size: 11.5px; font-weight: var(--fw-semibold); letter-spacing: .06em; text-transform: uppercase; color: var(--muted); margin-top: 6px; }
.order-lb-tour { width: 100%; aspect-ratio: 16 / 10; border: 0; border-radius: 10px; }
.order-lb-cap { font-size: 12.5px; color: var(--muted); margin: 0; }

/* ---- SPEC291 · benefit sheet (progressive disclosure inside "see the work")
   media column + honest benefit aside; side-by-side on wide, stacked on mobile.
   The stat is the ONE rationed accent (tabular-nums, brief); the source tag word
   carries the meaning — the tint is redundant reinforcement (WCAG 1.4.1). ---- */
.order-lightbox-body:has(.order-benefit) { display: grid; grid-template-columns: 1fr; align-items: start; }
@media (min-width: 720px) {
  .order-lightbox-body:has(.order-benefit) { grid-template-columns: minmax(0, 62fr) minmax(240px, 38fr); gap: 20px; }
}
.order-lb-media { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.order-benefit { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.order-benefit-hook { font-family: var(--order-serif); font-size: 18.5px; line-height: 1.4; color: var(--text); margin: 0; }
.order-benefit-why { font-size: 13.5px; line-height: 1.6; color: var(--muted); margin: 0; }
.order-benefit-stat { display: flex; flex-direction: column; gap: 5px; padding: 13px 15px; border-radius: 12px;
  background: color-mix(in srgb, var(--order-accent) 7%, var(--panel)); border: 1px solid color-mix(in srgb, var(--order-accent) 22%, var(--o-line, var(--line))); }
.order-benefit-num { font-size: 13.5px; line-height: var(--lh-normal); font-weight: var(--fw-bold); color: var(--text); font-variant-numeric: tabular-nums; }
.order-benefit-src { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; font-size: var(--fs-meta); line-height: 1.4; color: var(--muted); }
.order-benefit-tag { font-size: 10.5px; font-weight: var(--fw-black); letter-spacing: .1em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px; border: 1px solid currentColor; white-space: nowrap; }
.order-benefit-srcname { font-weight: var(--fw-semibold); }
/* redundant color reinforcement only — the WORD above already states the tier */
.order-benefit-independent .order-benefit-tag { color: color-mix(in srgb, var(--order-accent) 88%, var(--text)); }
.order-benefit-industry .order-benefit-tag,
.order-benefit-vendor .order-benefit-tag { color: var(--muted); }

/* ---- confirmation (ink curtain call) ---- */
.order-step.done { text-align: center; padding-top: clamp(48px, 10vh, 96px); }
.order-step.done .order-hero-title { color: var(--o-text); max-width: none; text-shadow: none; margin-inline: auto; }
.order-step.done .order-hero-sub { color: var(--o-muted); margin-inline: auto; }
.order-done-mark { width: 74px; height: 74px; border-radius: 50%; background: var(--order-accent); color: var(--order-on-accent); font-size: var(--fs-hero); font-weight: var(--fw-black); display: flex; align-items: center; justify-content: center; margin: 0 auto 24px; box-shadow: var(--shadow-lg); animation: order-pop .55s var(--ease-spring) both; }
@keyframes order-pop { from { transform: scale(.5); opacity: 0; } to { transform: scale(1); opacity: 1; } }
.order-payment-note { color: var(--o-muted); font-size: 13.5px; line-height: 1.6; max-width: 44ch; margin: 20px auto 0; }
.order-step.done .order-btn.primary.xl { display: inline-block; margin-top: 22px; text-decoration: none; }
.order-step.done .order-receipt.done { background: var(--panel); color: var(--text); }
.order-step.done .order-receipt.done .order-receipt-addr, .order-step.done .order-receipt.done .order-receipt-line, .order-step.done .order-receipt.done .order-receipt-total { color: var(--text); }

/* ---- desktop refinements + reduced motion ---- */
@media (min-width: 720px) {
  .order-vision-grid { grid-template-columns: repeat(3, 1fr); }
  .order-contact-grid { grid-template-columns: 1fr 1fr; column-gap: 16px; }
  .order-contact-grid .order-field:nth-child(4) { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .order-addon { flex-wrap: wrap; }
  .order-addon-thumb { flex-basis: 96px; }
  /* text sits higher on the tall mobile hero — deepen the scrim so it always clears */
  .order-hero-scrim { background:
    linear-gradient(to top, rgba(10, 10, 12, .9) 0%, rgba(10, 10, 12, .58) 52%, rgba(10, 10, 12, .22) 82%),
    linear-gradient(to bottom, rgba(10, 10, 12, .38), transparent 26%); }
}
@media (prefers-reduced-motion: reduce) {
  .order-step, .order-done-mark, .order-hero-img.kenburns { animation: none; }
  .order-pkg-img, .order-addon-thumbimg, .order-cta-arrow, .order-rail-fill, .order-rail-node, .order { transition: none; }
  .order-btn.primary:hover, .order-pkg:hover, .order-vision-card:hover { transform: none; }
}
/* programmatic focus lands on titles for screen readers — no ring needed */
.order-step-title:focus, .order-step-title:focus-visible, .order-hero-title:focus, .order-hero-title:focus-visible { outline: none; box-shadow: none; }

/* SPEC278c — world-class pass additions (identity, policy, timeline, deltas, marks) */
.order-identity { border-top: 1px solid var(--o-line); margin-top: clamp(28px, 5vh, 44px); padding-top: 14px; font-size: var(--fs-meta); color: var(--o-muted); line-height: 1.8; text-align: center; }
.order-identity a { color: var(--o-muted); text-decoration: underline; text-underline-offset: 2px; }
.order-identity-privacy { font-size: 11.5px; color: var(--o-muted); opacity: .85; }
.order-policy { display: flex; flex-direction: column; gap: 4px; margin: 18px 0 4px; padding: 14px 18px; border: 1px solid var(--o-line); border-radius: 12px; background: var(--o-panel); font-size: 12.5px; color: var(--o-muted); line-height: 1.55; }
.order-cred { font-size: var(--fs-micro); color: var(--o-muted); margin-top: 4px; }
.order-change { background: none; border: 0; padding: 0 10px 0 0; font: inherit; font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: .06em; text-transform: uppercase; color: var(--o-muted); opacity: .7; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
.order-change:hover { opacity: 1; color: var(--o-text); }
.order-receipt-actions { display: inline-flex; align-items: baseline; gap: 2px; white-space: nowrap; }
.order-pkg-delta { font-size: var(--fs-meta); font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; color: var(--o-muted); padding: 6px 20px 0; align-self: flex-end; }
.order-okmark { display: none; color: var(--ok); font-weight: var(--fw-black); }
.order-okmark.show { display: inline; }
.order-fries { font-family: var(--order-serif); font-size: 15.5px; color: var(--o-muted); margin: -14px 0 22px; }
.order-fine.tight { margin-top: 6px; }
.order-done-email { color: var(--o-muted); font-size: var(--fs-body); line-height: 1.6; max-width: 52ch; margin: 6px auto 0; }
.order-timeline { list-style: none; padding: 0; margin: 26px auto 0; max-width: 460px; text-align: left; display: flex; flex-direction: column; gap: 0; }
.order-timeline-node { position: relative; padding: 0 0 18px 26px; font-size: 13.5px; color: var(--o-muted); line-height: var(--lh-normal); }
.order-timeline-node::before { content: ''; position: absolute; left: 7px; top: 16px; bottom: 0; width: 1px; background: var(--o-line); }
.order-timeline-node:last-child::before { display: none; }
.order-timeline-dot { position: absolute; left: 2px; top: 4px; width: 11px; height: 11px; border-radius: 50%; border: 1px solid var(--o-line-strong); background: var(--o-bg); }
.order-timeline-node.lit { color: var(--o-text); }
.order-timeline-node.lit .order-timeline-dot { background: var(--order-accent); border-color: var(--order-accent); }
.order-done-offer { max-width: 480px; margin: 18px auto 0; padding: 14px 18px; border: 1px solid var(--o-line); border-radius: 12px; background: var(--o-panel); font-size: var(--fs-caption); color: var(--o-muted); line-height: 1.6; text-align: left; }
.order-done-offer-name { font-family: var(--order-serif); font-size: 15px; color: var(--o-text); }

/* SPEC279 — live slot booking on the schedule step */
.order-cal.hide, .order-request.hide { display: none; }
.order-photog-row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }
.order-photog { font: inherit; font-size: var(--fs-body); font-weight: var(--fw-semibold); color: var(--o-text); background: var(--o-panel); border: 1px solid var(--o-line-strong); border-radius: 999px; padding: 9px 16px; min-height: 44px; cursor: pointer; transition: border-color var(--t-base) var(--ease), background var(--t-base) var(--ease), color var(--t-base) var(--ease); }
.order-photog:hover { border-color: var(--order-accent); }
.order-photog.on { background: var(--order-accent); border-color: var(--order-accent); color: var(--order-on-accent); }
.order-photog-inner { display: inline-flex; align-items: center; gap: 8px; }
.order-photog-initial { width: 22px; height: 22px; border-radius: 50%; border: 1px solid currentColor; display: inline-flex; align-items: center; justify-content: center; font-family: var(--order-serif); font-size: var(--fs-meta); }
.order-cal-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 10px; }
.order-cal-title { font-size: 11.5px; font-weight: var(--fw-bold); letter-spacing: .08em; text-transform: uppercase; color: var(--o-muted); }
.order-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px; margin-bottom: 16px; }
.order-cal-pad { min-height: 1px; }
.order-cal-day { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 8px 2px 7px; background: var(--o-panel); border: 1px solid var(--o-line); border-radius: 10px; cursor: pointer; transition: border-color var(--t-base) var(--ease), transform var(--t-fast) var(--ease-spring); }
.order-cal-day:hover:not(.off) { border-color: var(--order-accent); transform: translateY(-1px); }
.order-cal-day.sel { border: 1.5px solid var(--order-accent); }
.order-cal-day.off { opacity: .38; cursor: default; }
.order-cal-dow { font-size: 9.5px; font-weight: var(--fw-bold); letter-spacing: .08em; text-transform: uppercase; color: var(--o-muted); }
.order-cal-num { font-family: var(--order-serif); font-size: 17px; font-variant-numeric: tabular-nums; color: var(--o-text); }
.order-cal-dot { width: 5px; height: 5px; border-radius: 50%; background: transparent; }
.order-cal-dot.has { background: var(--order-accent); }
.order-slotgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 8px; margin-bottom: 12px; }
.order-slot { font: inherit; font-size: 13.5px; font-weight: var(--fw-semibold); font-variant-numeric: tabular-nums; color: var(--o-text); background: var(--o-panel); border: 1px solid var(--o-line-strong); border-radius: 10px; padding: 11px 6px; min-height: 44px; cursor: pointer; transition: border-color var(--t-base) var(--ease), background var(--t-base) var(--ease), color var(--t-base) var(--ease); }
.order-slot:hover { border-color: var(--order-accent); }
.order-slot.sel { background: var(--order-accent); border-color: var(--order-accent); color: var(--order-on-accent); }
.order-slot-summary { font-size: var(--fs-body); color: var(--o-text); margin: 6px 0 4px; min-height: 20px; }
.order-slot-summary-check { color: var(--ok); font-weight: var(--fw-black); }
.order-escape { margin: 10px 0 18px; }

/* ============================================================
   SPEC287 — the goal→package selling engine (RESEARCH-PORTAL-SELL)
   Goal-aware package step: recommended ribbon, benefit + best-for copy,
   per-package "See the work", the always-on upgrade nudge, guided path.
   ============================================================ */
/* each package now sits in a cell so its "See the work" control can live
   OUTSIDE the card <button> (valid HTML — no button-in-button) */
.order-pkg-cell { display: flex; flex-direction: column; gap: 8px; }
.order-pkg-cell .order-pkg { width: 100%; flex: 1 1 auto; }   /* SPEC289 — card fills the cell (minus the See-the-work row) so cards match height */
/* the dynamic "Recommended for {goal}" ribbon — a quiet accent lift */
.order-pkg-badge.rec { border-bottom-color: var(--order-accent); color: #fff; }
.order-pkg.rec { border-color: color-mix(in srgb, var(--order-accent) 45%, var(--o-line)); }
.order-pkg.rec.sel { border-color: var(--order-accent); }
/* the plain self-select line */
.order-pkg-bestfor { font-size: var(--fs-meta); font-weight: var(--fw-semibold); letter-spacing: .02em; color: var(--o-muted); padding: 0 20px; opacity: .85; }
/* quiet until hover/focus — restraint per the luxury brief */
/* Vincent 2026-07-08 round 2 — BOTH actions live INSIDE the card as big
   equal pills: Choose (selects) + See everything you get (depth sheet).
   Nothing important in fine print, ever. */
.order-pkg-actions { display: flex; flex-wrap: wrap; gap: 10px; padding: 16px 20px 0; }
.order-pkg-actions .order-btn { flex: 1 1 auto; min-height: 50px; white-space: nowrap; }
.order-pkg-choose.sel { border-color: var(--order-accent); color: var(--order-accent); }

/* the "Help me choose" entry — a quiet link right under the step header */
.order-help-row { margin: 10px auto 0; max-width: 1080px; padding-inline: clamp(20px, 4vw, 32px); display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; }   /* SPEC289 helpers — now real pills (Vincent 2026-07-08 round 2) */
.order-addon-details { align-self: flex-start; margin-top: 6px; }

/* the always-on upgrade nudge — one quiet strip, never a nag */
.order-upgrade { max-width: 1080px; margin: 0 auto; padding: 15px 20px; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px 18px; background: color-mix(in srgb, var(--order-accent) 6%, var(--o-panel)); border: 1px solid color-mix(in srgb, var(--order-accent) 26%, var(--o-line)); border-radius: 14px; }
.order-upgrade-body { display: flex; flex-direction: column; gap: 3px; min-width: 220px; flex: 1 1 340px; }
.order-upgrade-kick { font-size: 10.5px; font-weight: var(--fw-black); letter-spacing: .14em; text-transform: uppercase; color: var(--order-accent); }
.order-upgrade-line { font-size: 13.5px; line-height: var(--lh-normal); color: var(--o-text); }
/* SPEC291 — one honest, independent proof line under the upgrade nudge */
.order-upgrade-proof { font-size: 12.5px; line-height: var(--lh-normal); color: var(--o-muted); font-variant-numeric: tabular-nums; margin-top: 2px; }
.order-upgrade-proofsrc { font-size: var(--fs-micro); font-weight: var(--fw-bold); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--o-muted); }   /* nowrap removed — it forced 525px on a 375px phone (horizontal page scroll) */
.order-btn.sm { font-size: 13.5px; padding: 10px 18px; min-height: 40px; white-space: nowrap; }

/* the guided "Help me choose" dialog (reuses the .order-lightbox shell) */
.order-guide { max-width: min(560px, 92vw); }
.order-guide-body { gap: 16px; padding-top: 6px; }
.order-guide-dots { display: flex; gap: 7px; }
.order-guide-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--o-line-strong); opacity: .5; }
.order-guide-dot.on { background: var(--order-accent); opacity: 1; }
.order-guide-q { font-family: var(--order-serif); font-size: 20px; line-height: var(--lh-snug); color: var(--o-text); margin: 0; }
.order-guide-opts { display: flex; flex-direction: column; gap: 10px; }
.order-guide-opt { text-align: left; font: inherit; font-size: 15px; font-weight: var(--fw-semibold); color: var(--o-text); background: var(--o-panel); border: 1px solid var(--o-line-strong); border-radius: 12px; padding: 14px 18px; min-height: 48px; cursor: pointer; transition: border-color var(--t-base) var(--ease), background var(--t-base) var(--ease); }
.order-guide-opt:hover { border-color: var(--order-accent); }
.order-guide-opt.on { border-color: var(--order-accent); background: color-mix(in srgb, var(--order-accent) 8%, var(--o-panel)); }
.order-guide-nav { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.order-guide-reco-kick { font-size: 10.5px; font-weight: var(--fw-black); letter-spacing: .14em; text-transform: uppercase; color: var(--order-accent); margin: 0; }
.order-guide-reco-name { font-family: var(--order-serif); font-size: var(--fs-display); letter-spacing: -.3px; color: var(--o-text); margin: 2px 0 0; }
.order-guide-reco-why { font-size: 14.5px; line-height: 1.6; color: var(--o-text); margin: 0; }
.order-guide-reco-alt { font-size: var(--fs-caption); line-height: 1.55; color: var(--o-muted); margin: 0; }
.order-guide-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 4px; }

/* SPEC288 (§2.3) — the honest side-by-side "Compare all four" (opens in the
   lightbox shell). Each column is one tier's own includes, priced live; the
   row scrolls inside its own container so the page body never scrolls sideways. */
.order-compare-dlg { max-width: min(1000px, 96vw); }
.order-compare-sub { margin: 0 0 14px; }
.order-compare { display: flex; gap: 12px; overflow-x: auto; padding-bottom: 8px; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; }
.order-compare-col { flex: 0 0 clamp(210px, 44vw, 236px); scroll-snap-align: start; display: flex; flex-direction: column; gap: 7px; padding: 16px 16px 18px; border: 1px solid var(--o-line); border-radius: 14px; background: var(--o-panel); }
.order-compare-col.sel { border-color: var(--order-accent); }
.order-compare-col.rec { border-color: color-mix(in srgb, var(--order-accent) 45%, var(--o-line)); }
.order-compare-rec { min-height: 14px; font-size: 10px; font-weight: var(--fw-black); letter-spacing: .14em; text-transform: uppercase; color: var(--order-accent); }
.order-compare-name { font-family: var(--order-serif); font-size: 21px; letter-spacing: -.2px; color: var(--o-text); }
.order-compare-price { font-size: 17px; font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; color: var(--o-text); }
.order-compare-best { font-size: var(--fs-meta); font-weight: var(--fw-semibold); color: var(--o-muted); opacity: .9; }
.order-compare-inc { list-style: none; margin: 6px 0 4px; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.order-compare-inc li { position: relative; padding-left: 20px; font-size: var(--fs-caption); line-height: 1.4; color: var(--o-text); }
.order-compare-inc li::before { content: "✓"; position: absolute; left: 0; top: 0; color: var(--order-accent); font-weight: var(--fw-bold); }
.order-compare-choose { margin-top: auto; width: 100%; justify-content: center; }
@media (max-width: 560px) { .order-compare-col { flex-basis: 78vw; } }

/* ============================================================
   SPEC290 — the "Your Brand" Mini Branding card + the money-free
   Signature Standard peak-end panel. One card, a pick-one reel-count
   tier picker; a two-column honest ladder (what every tier includes vs
   what the Signature Standard adds). Matches the SPEC287/288 order-layer
   tokens; the equal-height package grid (SPEC289) is untouched. */
.order-brandcard { background: var(--o-panel); border: 1px solid var(--o-line); border-radius: 16px; padding: 18px; margin-bottom: 20px; box-shadow: var(--shadow-sm); display: flex; gap: 18px; align-items: stretch; transition: border-color var(--t-base) var(--ease); }
.order-brandcard.on { border-color: var(--order-accent); }
.order-brandcard.lead { border-color: color-mix(in srgb, var(--order-accent) 42%, var(--o-line)); box-shadow: var(--shadow); }
.order-brandcard-thumb { position: relative; flex: 0 0 148px; align-self: flex-start; aspect-ratio: 4 / 3; border: 0; padding: 0; border-radius: 12px; overflow: hidden; cursor: zoom-in; background: var(--o-bg); }
.order-brandcard-thumbimg { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .7s var(--ease); }
.order-brandcard-thumb:hover .order-brandcard-thumbimg { transform: scale(1.05); }
.order-brandcard-body { display: flex; flex-direction: column; gap: 10px; min-width: 0; flex: 1 1 auto; }
.order-brandcard-eyebrow { font-size: 10.5px; font-weight: var(--fw-black); letter-spacing: .18em; text-transform: uppercase; color: var(--order-accent); }
.order-brandcard-title { font-family: var(--order-serif); font-weight: 440; font-size: 24px; letter-spacing: -.3px; line-height: 1.12; color: var(--o-text); margin: 0; }
.order-brandcard-lede { color: var(--o-muted); font-size: 13.5px; line-height: 1.55; margin: 0; max-width: 58ch; }
.order-brandtier-row { display: flex; flex-wrap: wrap; gap: 10px; margin: 2px 0 4px; }
.order-brandtier { position: relative; flex: 1 1 130px; min-height: 62px; display: flex; flex-direction: column; align-items: flex-start; justify-content: center; gap: 2px; font: inherit; text-align: left; padding: 10px 14px; border-radius: 12px; border: 1px solid var(--o-line-strong); background: var(--o-panel); color: var(--o-text); cursor: pointer; transition: border-color var(--t-base) var(--ease), background var(--t-base) var(--ease); }
.order-brandtier:hover { border-color: var(--order-accent); }
.order-brandtier.on { border-color: var(--order-accent); background: color-mix(in srgb, var(--order-accent) 8%, var(--o-panel)); }
.order-brandtier-reels { font-size: var(--fs-meta); font-weight: var(--fw-bold); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--o-muted); }
.order-brandtier-price { font-family: var(--order-serif); font-variant-numeric: tabular-nums; font-size: var(--fs-h1); color: var(--o-text); }
.order-brandtier-mark { position: absolute; top: 8px; right: 10px; font-size: var(--fs-meta); font-weight: var(--fw-black); color: var(--order-accent); }
.order-brandcard-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; margin-top: 4px; }
.order-brandcard-collabel { font-size: 10.5px; font-weight: var(--fw-black); letter-spacing: .1em; text-transform: uppercase; color: var(--o-muted); margin-bottom: 6px; }
.order-brandcard-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
.order-brandcard-list li { position: relative; padding-left: 19px; font-size: 12.5px; line-height: 1.45; color: var(--o-text); }
.order-brandcard-list.yes li::before { content: "✓"; position: absolute; left: 0; top: 0; color: var(--order-accent); font-weight: var(--fw-bold); }
.order-brandcard-list.add li { color: var(--o-muted); }
.order-brandcard-list.add li::before { content: "+"; position: absolute; left: 0; top: 0; color: var(--o-faint); font-weight: var(--fw-bold); }
.order-brandcard-scent { font-family: var(--order-serif); font-size: var(--fs-body); line-height: var(--lh-normal); color: var(--o-muted); margin: 4px 0 0; }
@media (max-width: 640px) {
  .order-brandcard { flex-direction: column; }
  .order-brandcard-thumb { flex-basis: auto; width: 100%; align-self: stretch; aspect-ratio: 16 / 9; }
  .order-brandcard-cols { grid-template-columns: 1fr; }
}

/* the peak-end Signature Standard learn-more (money-free — NO retainer price) */
.order-ss-panel { max-width: 480px; margin: 26px auto 0; text-align: left; background: color-mix(in srgb, var(--order-accent) 6%, var(--o-panel)); border: 1px solid color-mix(in srgb, var(--order-accent) 28%, var(--o-line)); border-radius: 16px; padding: 20px 22px; }
/* on the ink-toned confirmation, mirror the receipt: a light panel with the
   app's real dark text/muted so nothing goes faint on the dark background. */
.order-step.done .order-ss-panel { background: color-mix(in srgb, var(--order-accent) 7%, var(--panel)); border-color: color-mix(in srgb, var(--order-accent) 26%, var(--border)); }
.order-ss-eyebrow { font-size: 10.5px; font-weight: var(--fw-black); letter-spacing: .18em; text-transform: uppercase; color: var(--order-accent); }
.order-ss-title { font-family: var(--order-serif); font-weight: 440; font-size: 21px; letter-spacing: -.2px; line-height: 1.15; color: var(--o-text); margin: 6px 0 8px; }
.order-step.done .order-ss-title { color: var(--text); }
.order-ss-body { font-size: 13.5px; line-height: 1.55; color: var(--o-muted); margin: 0 0 14px; }
.order-step.done .order-ss-body { color: var(--muted); }
.order-ss-panel .order-btn.ghost { display: inline-block; text-decoration: none; }
.order-step.done .order-ss-panel .order-btn.ghost { color: var(--text); border-color: var(--border-strong); }
.order-step.done .order-ss-panel .order-btn.ghost:hover { border-color: var(--order-accent); }

/* SPEC312 — order → portal handoff card (confirmation step; mirrors the ss-panel light treatment) */
.order-portal-card { max-width: 480px; margin: 26px auto 0; text-align: left; background: color-mix(in srgb, var(--order-accent) 7%, var(--panel)); border: 1px solid color-mix(in srgb, var(--order-accent) 26%, var(--border)); border-radius: 16px; padding: 20px 22px; }
.order-portal-body { font-size: 13.5px; line-height: 1.55; color: var(--muted); margin: 6px 0 14px; }
.order-portal-card .order-btn.ghost { display: inline-block; text-decoration: none; color: var(--text); border-color: var(--border-strong); }
.order-portal-card .order-btn.ghost:hover { border-color: var(--order-accent); }

/* ── SPEC297 Coaching KB (Playbook cards) ── */
.coaching-kb .kb-card { display: flex; flex-direction: column; }
.coaching-kb .kb-card-title { font-weight: var(--fw-bold); font-size: 14.5px; margin-bottom: 4px; }
.coaching-kb .kb-hook { font-weight: var(--fw-semibold); font-size: 13.5px; margin-bottom: 6px; }
.coaching-kb .kb-why { font-size: var(--fs-caption); line-height: var(--lh-normal); margin-bottom: 8px; }
.coaching-kb .kb-stat { font-size: var(--fs-caption); font-weight: var(--fw-semibold); padding: 8px 10px; border-radius: 8px;
  background: var(--hover); border-left: 3px solid var(--accent); }
.coaching-kb .kb-source { font-size: var(--fs-meta); margin-top: 5px; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.coaching-kb .kb-say { font-size: var(--fs-caption); font-style: italic; margin: 6px 0; color: var(--text); }
.coaching-kb .kb-star { color: #f59e0b; }
.coaching-kb .kb-fulltool code { font-size: var(--fs-meta); padding: 1px 5px; border-radius: 4px; background: var(--hover); }

/* ============================================================
   SPEC306 — streamed-boot loading skeleton (quiet, token-based;
   shows only for the ~1s a navigated-to module is still loading).
   Brief-compliant: skeleton (never a spinner), motion is a soft
   opacity pulse, disabled under prefers-reduced-motion.
   ============================================================ */
.stream-skel { max-width: 720px; margin: 32px auto; padding: 0 16px; display: flex; flex-direction: column; gap: 16px; }
.stream-skel-bar { height: 14px; border-radius: 7px; background: var(--hover); animation: skelPulse 1.4s ease-in-out infinite; }
.stream-skel-bar.w40 { width: 40%; height: 22px; border-radius: 8px; }
.stream-skel-bar.w70 { width: 70%; }
.stream-skel-bar.w55 { width: 55%; }
.stream-skel-card { height: 120px; border-radius: var(--radius-lg, 12px); background: var(--hover); border: 1px solid var(--border); animation: skelPulse 1.4s ease-in-out infinite; }
@keyframes skelPulse { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) { .stream-skel-bar, .stream-skel-card { animation: none; } }

/* ============================================================
   SPEC307 — client portal default accent: warm bronze, not the
   ops-app indigo (DESIGN-BRIEF §3 Delivery: "warm accent"). The
   agent's brand color still wins — screenReport sets --accent
   inline on the report wrap, which outranks this. Dark theme gets
   the lighter bronze for contrast. Hub UI is unaffected —
   #portal-root exists only on portal.html.
   ============================================================ */
#portal-root { --accent: #8a6134; --accent-hover: #74501f; --accent-soft: #f6efe4; }
[data-theme="dark"] #portal-root { --accent: #c9a061; --accent-hover: #d9b077; --accent-soft: #2a2318; }

/* ============================================================
   SPEC308 — order AOV (RESEARCH-ORDER-AOV-2026-07-08, wave 1)
   Landing package ladder · rail-as-argument · encouragement
   lines · post-confirm add window. Order-page only (all classes
   live under .order on order.html); uses the --o-* tone vars.
   After editing here: node tools/extract-order-css.js
   ============================================================ */

/* — item 1B · the landing package ladder (package-first front door) — */
.order-lpkgs { margin-top: clamp(30px, 5vh, 52px); }
.order-lpkgs-sub { text-align: center; color: var(--o-muted); font-size: var(--fs-caption); line-height: var(--lh-normal); margin: -6px auto 20px; max-width: 52ch; }
.order-lpkg-grid { display: grid; gap: 14px; grid-template-columns: 1fr; }
@media (min-width: 640px) { .order-lpkg-grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1080px) { .order-lpkg-grid { grid-template-columns: repeat(4, 1fr); } }
.order-lpkg { text-align: left; font: inherit; background: var(--o-panel); border: 1px solid var(--o-line); border-radius: 14px; padding: 0 0 16px; cursor: pointer; overflow: hidden; display: flex; flex-direction: column; gap: 7px; box-shadow: var(--shadow-sm); transition: border-color var(--t-base) var(--ease), transform var(--t-fast) var(--ease-spring), box-shadow var(--t-base) var(--ease); }
.order-lpkg:hover { transform: translateY(-3px); box-shadow: var(--shadow-lg); border-color: var(--order-accent); }
.order-lpkg:hover .order-lpkg-img { transform: scale(1.04); }
/* the Best-Seller card reads architectural: tinted panel + hairline accent border */
.order-lpkg.bestseller { background: color-mix(in srgb, var(--order-accent) 6%, var(--o-panel)); border-color: color-mix(in srgb, var(--order-accent) 45%, var(--o-line)); }
.order-lpkg-media { position: relative; display: block; aspect-ratio: 3 / 2; overflow: hidden; background: var(--o-bg); }
.order-lpkg-img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .7s var(--ease); }
.order-lpkg-badge { position: absolute; left: 12px; bottom: 10px; font-size: 10px; font-weight: var(--fw-black); letter-spacing: .16em; text-transform: uppercase; color: #fff; border-bottom: 1px solid var(--order-accent); padding-bottom: 2px; text-shadow: 0 1px 12px rgba(0, 0, 0, .45); }
.order-lpkg-name { font-family: var(--order-serif); font-size: 21px; letter-spacing: -.2px; color: var(--o-text); padding: 5px 16px 0; }
.order-lpkg-best { color: var(--o-muted); font-size: 12.5px; line-height: var(--lh-normal); padding: 0 16px; flex: 1 1 auto; }
.order-lpkg-price { font-family: var(--order-serif); font-variant-numeric: tabular-nums; font-size: 19px; color: var(--o-text); padding: 0 16px; }
.order-lpkg-cta { font-size: var(--fs-meta); font-weight: var(--fw-bold); letter-spacing: .06em; text-transform: uppercase; color: var(--order-accent); padding: 2px 16px 0; }

/* — item 7 · the fact-anchored encouragement line in the step head — */
.order-affirm-note { font-family: var(--order-serif); font-size: 15.5px; font-style: italic; color: var(--o-muted); margin: 0 0 10px; }

/* — X2 · the "matches your goal" chip on the goal's lead package card — */
.order-pkg-goalchip { font-size: 10px; font-weight: var(--fw-black); letter-spacing: .14em; text-transform: uppercase; color: #fff; align-self: flex-start; background: rgba(10, 10, 12, .38); border: 1px solid rgba(255, 255, 255, .55); border-radius: 999px; padding: 3px 10px; backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px); text-shadow: 0 1px 8px rgba(0, 0, 0, .4); }   /* SAFPOLISH 2026-08-25 D4 */

/* — item 4 · the ribbon argues quietly: piece count + promise + honest "ahead" — */
.order-ribbon-ahead { font-size: 11.5px; font-weight: var(--fw-bold); color: var(--order-accent); }
.order-ribbon-ahead:empty { display: none; }

/* — item 4 · receipt benefit echoes + the three trust ticks under the total — */
.order-receipt-echo { display: block; font-size: var(--fs-meta); font-weight: 400; color: var(--o-faint); line-height: 1.45; margin-top: 2px; max-width: 46ch; }
.order-trust-ticks { display: flex; flex-wrap: wrap; gap: 4px 16px; padding: 6px 12px 2px; }
.order-trust-tick { font-size: var(--fs-meta); font-weight: var(--fw-semibold); color: var(--o-muted); }

/* — item 8 · the post-confirm add-window CTA — */
.order-done-offer-cta { display: inline-block; margin-top: 8px; font-weight: var(--fw-bold); }

/* ============================================================
   SPEC308 — order AOV, wave 2 (education + add-on moments).
   Depth sheets · before/after reveal · own-before-offer chips ·
   quiet contextual moments · equal-dignity skip. Order-page only;
   after editing here: node tools/extract-order-css.js
   ============================================================ */

/* — item 2 · the service depth sheet (inside the existing lightbox) — */
.order-sheet { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.order-sheet-hook { font-family: var(--order-serif); font-size: var(--fs-h1); line-height: 1.3; letter-spacing: -.2px; color: var(--o-text); margin: 2px 0 0; }
.order-sheet-why { color: var(--o-muted); font-size: var(--fs-body); line-height: 1.65; margin: 0; max-width: 62ch; }
.order-sheet-media { display: grid; gap: 10px; }
.order-sheet-img { width: 100%; border-radius: 10px; display: block; }
.order-sheet-foot { position: sticky; bottom: 0; display: flex; align-items: center; justify-content: flex-end; gap: 10px; padding: 12px 0 2px; margin-top: 2px; background: var(--panel); border-top: 1px solid var(--o-line); }
.order-sheet-in { font-size: var(--fs-caption); font-weight: var(--fw-bold); color: var(--o-text); margin-right: auto; }

/* — package sheet walkthrough (Vincent 2026-07-08): every include, taught — */
.order-sheet-walkhead { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .18em; text-transform: uppercase; color: var(--o-muted); margin: 16px 0 0; }
.order-sheet-walk { display: flex; flex-direction: column; }
.order-walk-row { display: flex; gap: 16px; align-items: flex-start; padding: 14px 0; border-bottom: 1px solid var(--o-line); }
.order-walk-row:last-child { border-bottom: 0; }
.order-walk-media { flex: 0 0 128px; aspect-ratio: 4 / 3; border-radius: 8px; overflow: hidden; background: var(--o-bg); }
.order-walk-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.order-walk-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.order-walk-name { font-family: var(--order-serif); font-size: 17px; color: var(--o-text); }
.order-walk-hook { font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--o-text); }
.order-walk-why { font-size: 12.5px; line-height: 1.55; color: var(--o-muted); margin: 0; max-width: 60ch; }
@media (max-width: 560px) { .order-walk-media { flex-basis: 96px; } }

/* — item 2 (D2) · the before/after reveal — twilight + staging sheets only.
   Two stacked images; the AFTER layer is clipped by an invisible full-cover
   range input (keyboard + touch for free), a hairline handle rides the value. */
.order-ba { position: relative; aspect-ratio: 3 / 2; border-radius: 10px; overflow: hidden; user-select: none; touch-action: pan-y; background: var(--o-bg); }
.order-ba-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.order-ba-top { will-change: clip-path; }
.order-ba-range { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; opacity: 0; cursor: ew-resize; -webkit-appearance: none; appearance: none; background: transparent; z-index: 2; }
.order-ba-range::-webkit-slider-thumb { -webkit-appearance: none; width: 44px; height: 100%; cursor: ew-resize; }
.order-ba-range::-moz-range-thumb { width: 44px; height: 100%; border: 0; background: transparent; cursor: ew-resize; }
.order-ba-handle { position: absolute; top: 0; bottom: 0; left: 50%; width: 2px; margin-left: -1px; background: rgba(255, 255, 255, .92); box-shadow: 0 0 0 1px rgba(0, 0, 0, .25); pointer-events: none; }
.order-ba-tag { position: absolute; top: 10px; padding: 3px 9px; border-radius: 999px; font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; background: rgba(10, 12, 18, .6); color: #fff; pointer-events: none; }
.order-ba-tag.before { right: 10px; }
.order-ba-tag.after { left: 10px; }
.order-ba-room { position: absolute; left: 10px; bottom: 10px; padding: 4px 10px; border-radius: 6px; font-size: 11.5px; font-weight: var(--fw-semibold); background: rgba(10, 12, 18, .62); color: #fff; pointer-events: none; }

/* — item 2 · the quiet learn-more paired with Add on every add-on card — */
.order-addon-details { align-self: flex-start; font-size: 12.5px; padding: 0; }

/* — item 3a · own-before-offer: the "In your {package}" chip strip — */
.order-own { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; margin: 0 0 18px; }
.order-own-label { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .12em; text-transform: uppercase; color: var(--o-muted); margin-right: 2px; }
.order-own-chip { font: inherit; font-size: 12.5px; color: var(--o-text); background: var(--o-panel); border: 1px solid var(--o-line); border-radius: 999px; padding: 5px 12px; }
button.order-own-chip { cursor: pointer; transition: border-color var(--t-base) var(--ease); }
button.order-own-chip:hover { border-color: var(--order-accent); }

/* — items 3b/3c · the quiet contextual moment (golden hour / sqft) — */
.order-moment { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; border: 1px solid var(--o-line); border-left: 3px solid var(--order-accent); border-radius: 10px; padding: 12px 14px; background: var(--o-panel); margin: 12px 0 0; }
.order-moment.head { margin: 4px 0 14px; }
.order-moment-line { flex: 1 1 260px; font-size: 13.5px; line-height: 1.55; color: var(--o-text); }
.order-moment-actions { display: flex; gap: 8px; }
.order-moment-btn { font: inherit; font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--o-text); background: transparent; border: 1px solid var(--o-line); border-radius: 999px; padding: 7px 16px; min-height: 36px; cursor: pointer; transition: border-color var(--t-base) var(--ease); }
.order-moment-btn:hover { border-color: var(--order-accent); }

/* — item 10 · the equal-dignity skip under the add-on grid — */
.order-skip { text-align: center; margin: 14px 0 0; }

/* ============================================================
   SPEC308 — order AOV, wave 3 (RESEARCH-ORDER-AOV-2026-07-08 §2 B2/B3/B4/C5/E/F,
   §5 items 5/6/9/11/12). Cumulative includes · one-door comparison matrix ·
   data-true proof chips · package fact lines · honest availability · adjacency
   narration · mobile one-thumb pass. Order-page only; after editing here:
   node tools/extract-order-css.js
   ============================================================ */

/* — item 5 · the "Everything in {below}, plus —" header inside the include grid — */
.order-pkg-inc-plus { grid-column: 1 / -1; font-size: var(--fs-meta); font-weight: var(--fw-bold); letter-spacing: var(--ls-label); color: var(--o-text); padding: 2px 0 5px; }
.order-pkg-inc-plus + .order-pkg-inc-row { border-top: 0; }   /* first row never doubles a hairline under the header */
@media (min-width: 860px) { .order-pkg-inc-plus ~ .order-pkg-inc-row:nth-child(3) { border-top: 0; } }   /* the 2nd column's first row too */

/* — B4 · the per-package fact line (real catalog + duration numbers) — */
.order-pkg-facts { font-size: 11.5px; font-weight: var(--fw-semibold); letter-spacing: .02em; color: var(--o-muted); padding: 0 20px; font-variant-numeric: tabular-nums; }

/* — item 6 · data-true social-proof chip (packages + surfaced add-ons) — */
.order-proofchip { font-size: 11.5px; font-weight: var(--fw-semibold); color: var(--o-muted); }
.order-pkg .order-proofchip { display: block; padding: 6px 20px 0; }
.order-addon .order-proofchip { display: inline-block; }

/* — item 5 · one quiet door to the ✓ / — comparison matrix — */
.order-cmp-linkwrap { text-align: center; margin-top: 14px; }
.order-cmp-link { font-size: var(--fs-caption); }
/* NB: this table lives inside the lightbox <dialog>, which mounts OUTSIDE the
   .order shell — so it uses ROOT theme vars (--text/--muted/--faint/--border,
   light-or-dark correct) for colour; only --order-accent/--order-serif are carried
   in from the shell by openCompareMatrix (see order.js). */
.order-cmp-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.order-cmp-table { border-collapse: collapse; width: 100%; min-width: 520px; font-variant-numeric: tabular-nums; }
.order-cmp-table th, .order-cmp-table td { padding: 10px 12px; text-align: center; border-bottom: 1px solid var(--border); }
.order-cmp-rowhead { text-align: left; font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--text); white-space: nowrap; }
.order-cmp-col { vertical-align: bottom; }
.order-cmp-colname { display: block; font-family: var(--order-serif); font-size: var(--fs-md); color: var(--text); }
.order-cmp-colprice { display: block; font-size: var(--fs-caption); font-weight: var(--fw-bold); color: var(--text); }
.order-cmp-colrec { display: block; font-size: 9.5px; font-weight: var(--fw-black); letter-spacing: .12em; text-transform: uppercase; color: var(--order-accent); margin-top: 2px; }
.order-cmp-col.rec, .order-cmp-cell.rec { background: color-mix(in srgb, var(--order-accent) 8%, transparent); }
.order-cmp-yes { color: var(--order-accent); font-weight: var(--fw-black); }
.order-cmp-dash { color: var(--faint); }
.order-cmp-teaser td { border-bottom: 0; }
.order-cmp-teasercell { text-align: center; font-size: 12.5px; color: var(--muted); padding-top: 14px; }

/* — item 11 · honest availability caption under the slot grid (fact, not alarm) — */
.order-slots-left { font-size: 12.5px; color: var(--o-muted); margin: 10px 0 0; }

/* — item 12 · included-vs-adjacent narration in the browse rows — */
.order-more-namecol { flex: 1 1 auto; display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.order-more-namecol .order-more-name { flex: 0 0 auto; }
.order-adjacent { font-size: 11.5px; line-height: 1.45; color: var(--o-muted); }

/* — item 9 · mobile one-thumb: the ribbon docks as a total + CTA bottom bar — */
.order-ribbon-right { display: flex; align-items: center; gap: 14px; min-width: 0; }
.order-ribbon-cta { display: none; }
@keyframes order-sheet-up { from { transform: translateY(100%); } to { transform: translateY(0); } }
@media (max-width: 640px) {
  .order-ribbon { gap: 12px; padding: 10px 16px calc(10px + env(safe-area-inset-bottom)); }
  .order-ribbon-note { display: none; }   /* the "every price shown" promise lives in the flow copy; the bar stays total + action */
  .order-ribbon-total { font-size: var(--fs-h1); }
  .order-ribbon-cta:not(.empty) { display: inline-flex; align-items: center; justify-content: center; font: inherit; font-size: var(--fs-body); font-weight: var(--fw-bold); min-height: 44px; padding: 0 18px; border: 0; border-radius: 999px; background: var(--order-accent); color: var(--order-on-accent); cursor: pointer; white-space: nowrap; }
  .order-host { padding-bottom: calc(78px + env(safe-area-inset-bottom)); }   /* keep the in-flow Back/Continue reachable above the fixed bar */
  /* depth sheets + comparison matrix dock as slide-up bottom sheets */
  .order-lightbox { max-width: 100vw; width: 100vw; margin: 0; position: fixed; left: 0; right: 0; bottom: 0; top: auto; border-radius: 16px 16px 0 0; max-height: 92vh; animation: order-sheet-up .28s var(--ease); }
  .order-lightbox-body { max-height: 78vh; }
}
@media (prefers-reduced-motion: reduce) { .order-lightbox { animation: none; } }

/* SPEC308 landing-reorder (Vincent 2026-07-08) — the package ladder shares the
   first viewport: compact hero (no button), cards pull UP over the hero's bottom
   edge (art-directed overlap; solid --o-panel cards), the guided path demoted to
   a quiet link under the ladder. Landing tone is ink, so the kicker/sub that sit
   on the photo edge get a whisper of shadow for legibility. */
.order-hero.compact { min-height: min(58svh, 560px); }
.order-hero.compact .order-hero-title { font-size: clamp(34px, 6vw, 62px); margin-bottom: 12px; }
.order-hero.compact .order-hero-sub { margin-bottom: 8px; }
.order-hero.compact .order-hero-body { padding-bottom: clamp(72px, 11vh, 118px); }
.order-lpkgs.overlap { margin-top: clamp(-84px, -7vh, -44px); position: relative; z-index: 2; }
.order-lpkgs.overlap .order-logos-kicker, .order-lpkgs.overlap .order-lpkgs-sub { text-shadow: 0 1px 18px rgba(0, 0, 0, .45); }
.order-undecided { display: flex; flex-direction: column; align-items: center; gap: 2px; margin: 26px auto 0; padding-inline: 20px; text-align: center; }
.order-undecided .order-link { color: var(--o-muted); font-weight: var(--fw-medium); text-decoration: underline; text-underline-offset: 3px; min-height: 44px; }
.order-undecided .order-link:hover { color: var(--o-text, inherit); }
.order-undecided .order-fine { margin-top: 4px; text-align: center; }
.order-logos-band { margin-top: clamp(26px, 4.5vh, 44px); }
@media (max-width: 640px) {
  .order-hero.compact { min-height: min(46svh, 430px); }
  .order-hero.compact .order-hero-body { padding-bottom: 64px; }
  .order-lpkgs.overlap { margin-top: -34px; }
}

/* SPEC308 intimacy pass (Vincent 2026-07-08) — less scrolling, always-reachable
   Continue, the agent-brand spotlight leads the add-ons, preview-slots tag. */
/* 1 · property step de-scroll: slim chapter banner + 2-col optional-details grid */
.order-chapter.slim .order-chapter-img { aspect-ratio: auto; height: clamp(88px, 13vh, 140px); }
.order-detgrid { display: grid; gap: 0 22px; }
@media (min-width: 640px) { .order-detgrid { grid-template-columns: 1fr 1fr; } }
/* 2 · the Continue mirror in the fixed ribbon now lives on EVERY viewport —
   the next page is always one tap away at the bottom edge, no scrolling. */
.order-ribbon-cta:not(.empty) { display: inline-flex; align-items: center; justify-content: center; font: inherit; font-size: var(--fs-body); font-weight: var(--fw-bold); min-height: 44px; padding: 0 20px; border: 0; border-radius: 999px; background: var(--order-accent); color: var(--order-on-accent); cursor: pointer; white-space: nowrap; transition: transform var(--t-fast) var(--ease-spring), box-shadow var(--t-base) var(--ease); }
.order-ribbon-cta:not(.empty):hover { transform: translateY(-1px); box-shadow: var(--shadow); }
.order-ribbon-cta:disabled { opacity: .55; cursor: default; transform: none; box-shadow: none; }
/* 3 · the Your-Brand SPOTLIGHT — an editorial ink moment that leads the offers,
   visually distinct from the utility add-on cards below it */
.order-brandcard.spotlight { background: linear-gradient(135deg, #17181d, #232630 82%); color: #f4f1ea; border: 1px solid rgba(255, 255, 255, .14); border-radius: 18px; box-shadow: var(--shadow-lg); }
.order-brandcard.spotlight .order-brandcard-eyebrow { color: color-mix(in srgb, var(--order-accent) 34%, #fff); letter-spacing: .18em; }
.order-brandcard.spotlight .order-brandcard-title { font-family: var(--order-serif); font-weight: 400; font-size: clamp(24px, 3.4vw, 34px); color: #fff; }
.order-brandcard.spotlight .order-brandcard-lede { color: rgba(255, 255, 255, .78); }
.order-brandcard.spotlight .order-brandcard-collabel { color: rgba(255, 255, 255, .55); }
.order-brandcard.spotlight .order-brandcard-list { color: rgba(255, 255, 255, .82); }
.order-brandcard.spotlight .order-brandcard-scent { color: rgba(255, 255, 255, .62); }
.order-brandcard.spotlight .order-link { color: color-mix(in srgb, var(--order-accent) 30%, #fff); }
.order-brandcard.spotlight .order-brandtier { background: rgba(255, 255, 255, .06); border: 1px solid rgba(255, 255, 255, .22); color: #f4f1ea; }
.order-brandcard.spotlight .order-brandtier:hover { border-color: rgba(255, 255, 255, .5); }
.order-brandcard.spotlight .order-brandtier.on { background: var(--order-accent); border-color: var(--order-accent); color: var(--order-on-accent); }
.order-brandcard.spotlight .order-brandtier-price { color: inherit; opacity: .82; }
.order-logos-kicker.home-addons { margin: 30px auto 14px; }
/* 4 · preview-slots — honest, unmistakable sample-data tag */
.order-preview-tag { background: #fef3c7; color: #92400e; border: 1px solid #f3d489; border-radius: 10px; padding: 9px 14px; font-size: 12.5px; line-height: var(--lh-normal); margin: 0 0 14px; }
html[data-theme="dark"] .order-preview-tag { background: #2c2413; color: #f5d489; border-color: #57431c; }

/* SPEC308 identity (Vincent 2026-07-08) — "Ordering for" internal picker, agent
   welcome line. The picker reuses the address .order-sugg dropdown for results. */
.order-forwhom { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 0 0 20px; padding: 12px 16px; background: var(--o-panel); border: 1px solid var(--o-line); border-radius: 12px; box-shadow: var(--shadow-sm); }
.order-forwhom-label { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .14em; text-transform: uppercase; color: var(--o-muted); white-space: nowrap; }
.order-forwhom-search { position: relative; flex: 1 1 240px; min-width: 200px; }
.order-forwhom-search .order-sugg { top: calc(100% + 4px); }
.order-forwhom-set { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.order-forwhom-chip { display: inline-flex; align-items: baseline; gap: 8px; padding: 5px 12px; border-radius: 999px; background: color-mix(in srgb, var(--order-accent) 10%, var(--o-panel)); border: 1px solid color-mix(in srgb, var(--order-accent) 32%, var(--o-line)); }
.order-forwhom-name { font-weight: 650; color: var(--o-text); }
.order-forwhom-sub { font-size: 12.5px; color: var(--o-muted); }
.order-forwhom-new { font-weight: 650; color: var(--order-accent); border-top: 1px solid var(--o-line); }
.order-hero-greet { color: rgba(255, 255, 255, .92); font-size: clamp(15px, 2vw, 18px); line-height: 1.55; margin: 0 0 10px; font-weight: 550; text-shadow: 0 1px 14px rgba(0, 0, 0, .35); max-width: 46ch; }

/* SPEC309 — "Team on this job" chips (one-tap crew attachment in the job modal) */
.job-team-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 8px; }
.job-team-chip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 6px 3px 10px; border-radius: 999px; background: var(--accent-soft, color-mix(in srgb, var(--accent) 12%, var(--card))); border: 1px solid color-mix(in srgb, var(--accent) 28%, var(--border)); font-size: 12.5px; font-weight: var(--fw-semibold); color: var(--text); }
.job-team-x { display: inline-grid; place-items: center; width: 18px; height: 18px; border: 0; border-radius: 50%; background: transparent; color: var(--muted); font-size: 15px; line-height: 1; cursor: pointer; }
.job-team-x:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); color: var(--text); }
.role-select:disabled { opacity: .7; cursor: default; }

/* ============================================================
   SPEC312 — locked (view-only) delivery: watermark + lock notice
   ============================================================ */
/* the repeating diagonal brand watermark (bg image set inline per-brand) */
.cstatus-wm { position: absolute; inset: 0; pointer-events: none; background-repeat: repeat; z-index: 3; }
/* on the cinematic cover the mark sits over the PHOTO but under the scrim + title/CTAs */
.cstatus-cover .cstatus-wm { z-index: 0; }
.cstatus-gal--locked .cstatus-gal-open, .cstatus-gal--locked .cstatus-gal-item { -webkit-user-select: none; user-select: none; }
.cstatus-gal--locked img { -webkit-user-drag: none; }
.cstatus-gal-item { position: relative; }
.cstatus-gal-open { position: relative; }
/* quiet luxury lock notice under the cover */
.cstatus-locknote { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 14px 18px 0; padding: 12px 16px; border: 1px solid color-mix(in srgb, var(--cover-accent, #d4af37) 35%, var(--border)); border-radius: 12px; background: color-mix(in srgb, var(--cover-accent, #d4af37) 7%, var(--card)); font-size: 13.5px; }
.cstatus-locknote-ic { display: inline-grid; place-items: center; color: color-mix(in srgb, var(--cover-accent, #d4af37) 80%, var(--text)); }
.cstatus-locknote-txt { flex: 1 1 240px; }
.cstatus-locknote .btn { margin-left: auto; }
/* lightbox: watermark stage wrapper (img keeps its own transitions) */
.cstatus-lb-stage { position: relative; display: grid; place-items: center; max-width: 100%; max-height: 100%; }
.cstatus-lb-stage img { display: block; }
.cstatus-lb-stage .cstatus-wm { z-index: 4; }
/* locked video overlay */
.cstatus-lb--video .cstatus-lb-vidwrap { position: relative; width: min(1100px, 94vw); max-height: 86vh; }
.cstatus-lb--video video { width: 100%; max-height: 86vh; display: block; border-radius: 10px; background: #000; }
.cstatus-lb--video .cstatus-wm { border-radius: 10px; }

/* ============================================================
   SPEC314 — Signature Pulse (retainer at-a-glance board)
   ============================================================ */
.tss-pulse { display: flex; flex-direction: column; }
.tss-pulse-row { display: grid; grid-template-columns: 26px minmax(140px, 1.4fr) minmax(150px, 1.3fr) 82px minmax(90px, .9fr) minmax(90px, .9fr) minmax(80px, .8fr); gap: 10px; align-items: center; padding: 9px 8px; border-radius: 8px; cursor: pointer; font-size: var(--fs-caption); }
.tss-pulse-row:not(.tss-pulse-head):hover { background: var(--bg-2); }
.tss-pulse-head { cursor: default; font-size: 10.5px; font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .05em; color: var(--muted); border-bottom: 1px solid var(--border); border-radius: 0; padding-bottom: 6px; }
.tss-pulse-rag { text-align: center; font-size: var(--fs-meta); }
.tss-pulse-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tss-pulse-cell { display: inline-flex; align-items: center; gap: 6px; min-width: 0; white-space: nowrap; }
.tss-pulse-cell.overdue { color: var(--danger); font-weight: var(--fw-bold); }
.tss-pulse-quota { position: relative; display: inline-block; width: 74px; height: 16px; border-radius: 8px; background: var(--bg-2); overflow: hidden; }
.tss-pulse-quota-fill { position: absolute; inset: 0 auto 0 0; background: color-mix(in srgb, var(--info) 55%, transparent); border-radius: 8px; }
.tss-pulse-quota-fill.done { background: color-mix(in srgb, var(--ok) 60%, transparent); }
.tss-pulse-quota-n { position: relative; display: block; text-align: center; font-size: 10.5px; font-weight: var(--fw-black); line-height: 16px; }
@media (max-width: 860px) { .tss-pulse-row { grid-template-columns: 22px minmax(120px, 1.5fr) minmax(130px, 1.2fr) 70px; } .tss-pulse-row > :nth-child(n+5) { display: none; } }

/* SPEC316 — Jarvis Search jump-to-message flash */
.chat-msg--flash { animation: vvt-msg-flash 2.4s ease-out; border-radius: 8px; }
@keyframes vvt-msg-flash { 0% { background: color-mix(in srgb, var(--accent) 22%, transparent); } 100% { background: transparent; } }

/* SPEC317 — Ask VVT (Jarvis) answer card in the palette */
.qs-askhost:empty { display: none; }
.qs-ask { margin: 10px 14px 4px; padding: 12px 14px; border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--border)); border-radius: 12px; background: color-mix(in srgb, var(--accent) 6%, var(--panel)); }
.qs-ask-h { font-weight: var(--fw-black); font-size: 13.5px; margin-bottom: 6px; }
.qs-ask-a { font-size: 13.5px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; }
.qs-ask-p { font-size: var(--fs-caption); color: var(--muted); margin-bottom: 8px; }
.qs-ask-src { font-size: 10.5px; font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .05em; color: var(--muted); margin: 10px 0 2px; }

/* SPEC318 — "how the sun hits this home" impact lines */
.cond-impact { display: flex; flex-direction: column; gap: 5px; margin-top: 10px; }
.cond-impact-line { font-size: var(--fs-caption); line-height: var(--lh-normal); }
.cond-impact-line.strong { font-weight: var(--fw-bold); }

/* ============================================================
   SPEC319 — Post Production pipeline board (Timeliner-style)
   ============================================================ */
.pp-batches { display: flex; gap: 10px; overflow-x: auto; padding: 2px 2px 10px; margin-bottom: 6px; }
/* GOLIVE wave2 pick1 — wraps a batch pill + its optional "Deliver the shoot" shortcut */
.pp-batch-wrap { display: flex; flex-direction: column; gap: 5px; flex: 0 0 auto; }
.pp-batch-deliver { border: 1px solid color-mix(in srgb, var(--ok) 45%, var(--border)); background: color-mix(in srgb, var(--ok) 12%, transparent); color: var(--ok); border-radius: 8px; padding: 4px 9px; font-size: var(--fs-micro); font-weight: var(--fw-bold); cursor: pointer; white-space: nowrap; transition: transform .12s, box-shadow .12s; }
.pp-batch-deliver:hover { transform: translateY(-1px); box-shadow: var(--shadow-lg); }
.pp-batch { display: flex; align-items: center; gap: 9px; flex: 0 0 auto; border: 1px solid var(--border); border-radius: 12px; background: var(--panel); padding: 8px 12px; cursor: pointer; transition: transform .12s, box-shadow .12s, border-color .12s; }
.pp-batch:hover { transform: translateY(-1px); box-shadow: var(--shadow-lg); }
.pp-batch.active { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent); }
.pp-batch-ring { display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; flex: 0 0 auto; }
.pp-batch-ring-n { display: grid; place-items: center; width: 30px; height: 30px; border-radius: 50%; background: var(--panel); font-size: 10.5px; font-weight: var(--fw-black); }
.pp-batch-txt { display: flex; flex-direction: column; text-align: left; min-width: 0; }
.pp-batch-addr { font-weight: var(--fw-bold); font-size: 12.5px; white-space: nowrap; max-width: 150px; overflow: hidden; text-overflow: ellipsis; }
.pp-batch-date { font-size: var(--fs-micro); color: var(--muted); }
.pp-board { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(215px, 1fr); gap: 10px; overflow-x: auto; align-items: start; padding-bottom: 8px; }
.pp-col { background: var(--bg-2); border-radius: 12px; padding: 8px; min-height: 120px; }
.pp-col-head { display: flex; align-items: center; gap: 6px; font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .05em; color: var(--muted); padding: 4px 4px 8px; border-bottom: 2px solid; margin-bottom: 8px; }
.pp-col-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.pp-col-n { margin-left: auto; background: var(--panel); border-radius: 999px; padding: 1px 7px; font-size: 10.5px; }
.pp-col-empty { text-align: center; color: var(--faint); padding: 14px 0; }
.pp-card { background: var(--panel); border: 1px solid var(--border); border-radius: 10px; margin-bottom: 8px; overflow: hidden; cursor: pointer; transition: transform .12s, box-shadow .12s; }
.pp-card:hover { transform: translateY(-1px); box-shadow: var(--shadow-lg); }
.pp-thumb { height: 74px; background-size: cover; background-position: center; background-color: var(--bg-2); }
.pp-card-body { padding: 9px 11px 10px; }
.pp-card-title { font-weight: var(--fw-bold); font-size: 12.5px; line-height: 1.3; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pp-card-svc { font-size: 11.5px; color: var(--accent); font-weight: var(--fw-semibold); margin-top: 1px; }
.pp-card-meta { font-size: var(--fs-micro); color: var(--muted); margin-top: 4px; }
/* SOPQC-3 — the shooter's brief preview line (job.brief; App.jobBriefFields). Absent
   when the job has no brief, same as .pp-card-meta above it. */
.pp-card-brief { font-size: var(--fs-micro); color: var(--accent); margin-top: 3px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pp-acts { display: flex; gap: 4px; margin-top: 7px; }
.pp-act { border: 1px solid var(--border); background: var(--bg); border-radius: 7px; width: 27px; height: 24px; display: grid; place-items: center; font-size: var(--fs-meta); cursor: pointer; }
.pp-act:hover { border-color: var(--accent); }
.pp-act--ok { color: var(--ok); font-weight: var(--fw-black); }
.pp-act--warn { color: var(--warn); }

/* SPEC321 — review player: general notes + attachments + circle tool */
.review-generaltoggle.on { background: var(--accent-soft); color: var(--accent); border-color: var(--accent); }
.review-tcchip--general { cursor: default; opacity: .85; }
.review-filesrow { display: flex; gap: 6px; flex-wrap: wrap; margin: 4px 0 6px; }
.review-filesrow:empty { display: none; }
.review-filechip { display: inline-flex; align-items: center; gap: 4px; border: 1px solid var(--border); border-radius: 999px; background: var(--bg); padding: 2px 10px; font-size: 11.5px; font-weight: var(--fw-semibold); color: var(--text); text-decoration: none; max-width: 220px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.review-filechip:hover { border-color: var(--accent); }
.review-filechip-x { border: 0; background: none; cursor: pointer; font-size: var(--fs-caption); color: var(--muted); padding: 0 0 0 2px; }

/* SPEC322 — Training Machine: skill matrix + 40-day arc */
.tm-matrix { display: grid; gap: 3px; align-items: center; min-width: 560px; }
.tm-h { font-size: 10px; font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: var(--ls-label); color: var(--muted); text-align: center; }
.tm-h--skill { writing-mode: vertical-rl; transform: rotate(180deg); max-height: 96px; overflow: hidden; text-overflow: ellipsis; justify-self: center; }
.tm-who { font-size: 12.5px; font-weight: var(--fw-bold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-right: 6px; }
.tm-who.me { color: var(--accent); }
.tm-cell { border: 1px solid var(--border); background: var(--bg); border-radius: 8px; height: 30px; display: grid; place-items: center; cursor: pointer; transition: border-color .12s, transform .12s; }
.tm-cell:hover { border-color: var(--accent); transform: scale(1.08); }
.tm-dot { width: 13px; height: 13px; border-radius: 50%; display: inline-block; flex: 0 0 auto; }
.tm-arc { padding: 10px 0; border-bottom: 1px solid var(--border); }
.tm-arc:last-of-type { border-bottom: 0; }
.tm-arc-bar { height: 8px; border-radius: 999px; background: var(--bg-2); overflow: hidden; margin-top: 6px; }
.tm-arc-fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, #579bfc, #00c875); transition: width .3s; }

/* SPEC323 — Jarvis Daily Brief. D6 — retired the bespoke gradient background + animated
   orb; the card now conforms to .insight (accent border) like every other insight card,
   and the FRIDAY brand mark is the sparkles line icon in the card-title, same as elsewhere. */
.jarvis-brief { margin-bottom: 14px; background: var(--panel); border: 1px solid var(--border); }
.jarvis-brief-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.jarvis-brief-chips { display: flex; flex-wrap: wrap; gap: 7px; }
.jarvis-chip { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--border); background: var(--bg); border-radius: 999px; padding: 6px 13px 6px 9px; font-size: 12.5px; font-weight: var(--fw-semibold); color: var(--text); cursor: pointer; transition: border-color .12s, transform .12s; max-width: 100%; }
.jarvis-chip:hover { border-color: var(--accent); transform: translateY(-1px); }
.jarvis-chip-ico { font-size: var(--fs-body); }
/* INTEGRATOR 07-30: raw hex → semantic tokens, so both borders re-tint in dark
   mode like every other chip. Computed light-mode result is unchanged. */
.jarvis-chip--warn { border-color: color-mix(in srgb, var(--warn) 45%, var(--border)); }
.jarvis-chip--red { border-color: color-mix(in srgb, var(--danger) 55%, var(--border)); }

/* SPEC324 — B-roll library */
.broll-form { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.broll-form .btn { grid-column: 1 / -1; justify-self: start; }
@media (max-width: 640px) { .broll-form { grid-template-columns: 1fr; } }
.broll-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 10px 0 12px; }
.broll-chips .chip { cursor: pointer; border: 0; background: var(--bg-2); color: var(--muted); }
.broll-chips .chip--on { background: var(--accent-soft, var(--bg-2)); color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent); }
.broll-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 10px; }
.broll-card { border: 1px solid var(--border); border-radius: 12px; padding: 12px 13px; background: var(--panel); }
.broll-card-title { font-weight: var(--fw-bold); font-size: 13.5px; line-height: var(--lh-snug); }
.broll-card-tags { display: flex; flex-wrap: wrap; gap: 4px; margin: 6px 0 5px; }
.broll-tag { font-size: 10.5px; font-weight: var(--fw-bold); color: var(--accent); background: var(--accent-soft, var(--bg-2)); border-radius: 999px; padding: 2px 8px; }

/* SPEC326 — Trend Radar */
.trend--scripted { opacity: .78; }

/* SPEC327 — portal brand-intake wizard */
.pt-intake-invite { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; border: 1px solid var(--border); border-radius: 14px; padding: 14px 16px; margin: 4px 0 18px; background: var(--panel); }
.pt-intake-dots { display: flex; gap: 6px; margin: 6px 0 12px; }
.pt-intake-dot { width: 26px; height: 5px; border-radius: 999px; background: var(--border); }
.pt-intake-dot.on { background: var(--accent); }
.pt-intake-dot.done { background: var(--accent); opacity: .45; }
.pt-intake-card { border: 1px solid var(--border); border-radius: 14px; padding: 18px; background: var(--panel); }
.pt-intake-card .input { width: 100%; box-sizing: border-box; margin-bottom: 8px; }

/* SPEC328 — live-call FAB: its own slot LEFT of the ＋ (was stacked exactly on top of it) */
.call-fab {
  position: fixed; right: 84px; bottom: 22px; z-index: 60;
  width: 52px; height: 52px; border-radius: 50%; border: 0; cursor: pointer;
  background: var(--accent); color: #fff; font-size: var(--fs-h1); line-height: 1;
  display: flex; align-items: center; justify-content: center;
  box-shadow: 0 6px 18px -3px rgba(var(--ring-rgb), .5), 0 2px 6px rgba(16, 24, 40, .2);
  transition: transform .12s ease, background .12s ease;
}
.call-fab:hover { background: var(--accent-hover); transform: translateY(-2px) scale(1.03); }
.call-fab:active { transform: scale(.96); }
@media (max-width: 640px) { .call-fab { right: 84px; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); width: 56px; height: 56px; } }
@media (prefers-reduced-motion: reduce) { .call-fab { transition: none; } }

/* SPEC333 — Lead Setting queue */
.ls-sect { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .05em; color: var(--muted); margin: 12px 0 2px; }

/* SPEC334 — Feature Spotlight chip */
.jarvis-chip--spot { border-style: dashed; border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); max-width: 100%; white-space: normal; text-align: left; }
.jarvis-chip-x { margin-left: 4px; color: var(--muted); font-size: var(--fs-meta); padding: 0 2px; }
.jarvis-chip-x:hover { color: var(--text); }

/* ============ SPEC336 — chat glow-up (Mobbin: Slack/ClickUp patterns) ============ */
/* avatars: rounded-square (Slack), a touch bigger presence */
.chat-av { border-radius: 9px; }
/* message rows: calmer hover, more air between groups */
.chat-msg { padding: 4px 8px; }
.chat-msg:not(.grouped) { margin-top: 2px; }
/* the floating hover toolbar (was: two flat buttons) */
.chat-msg-actions {
  top: -14px; right: 12px; gap: 0; opacity: 0; transform: translateY(2px);
  border: 1px solid var(--border); border-radius: 9px; background: var(--panel);
  box-shadow: 0 6px 18px -6px rgba(16, 24, 40, .28); overflow: hidden;
  transition: opacity .12s, transform .12s;
}
.chat-msg:hover .chat-msg-actions, .chat-msg:focus-within .chat-msg-actions { opacity: 1; transform: translateY(0); }
.chat-msg-act { border: 0; box-shadow: none; border-radius: 0; padding: 5px 10px; background: var(--panel); }
.chat-msg-act + .chat-msg-act { border-left: 1px solid var(--border); }
/* grouped gutter time — appears on row hover */
.chat-av-spacer { display: flex; align-items: center; justify-content: flex-end; }
.chat-gutter-time { font-size: 10px; color: var(--faint); opacity: 0; padding-right: 2px; }
.chat-msg:hover .chat-gutter-time { opacity: 1; }
/* day divider: floating pill on a hairline (Slack) */
.chat-day-divider { display: flex; align-items: center; margin: 14px 0 6px; }
.chat-day-divider::before, .chat-day-divider::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.chat-day-divider span {
  font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--muted); background: var(--panel);
  border: 1px solid var(--border); border-radius: 999px; padding: 3px 12px; margin: 0 8px;
  box-shadow: 0 1px 3px rgba(16, 24, 40, .06);
}
/* the red New line (Slack unread rule) */
.chat-new-divider { display: flex; align-items: center; margin: 10px 0 4px; }
.chat-new-divider::before, .chat-new-divider::after { content: ''; flex: 1; height: 1px; background: #e2445c; opacity: .5; }
.chat-new-divider span { font-size: 10px; font-weight: var(--fw-black); letter-spacing: .08em; text-transform: uppercase; color: #e2445c; padding: 0 10px; }
/* bot/system cards: one quiet collapsed line, not a fake teammate */
.chat-bot-card { margin: 6px 0 6px 44px; border: 1px solid var(--border); border-radius: 12px; background: var(--subtle); overflow: hidden; max-width: 620px; flex-shrink: 0; }
/* ^ flex-shrink:0 (COHESION closer 2026-08-11): .chat-list is a column-flex scroller and
   overflow:hidden gives this card an automatic min-size of 0, so it absorbed ALL flex
   shrink and rendered 2px tall whenever the list overflowed (i.e. always on a phone
   with real history). Verified live at 375x812: 2px before, 42px after. */
.chat-bot-head {
  display: flex; align-items: center; gap: 8px; width: 100%; padding: 8px 12px;
  border: 0; background: none; cursor: pointer; font: inherit; text-align: left; color: var(--text);
}
.chat-bot-head:hover { background: var(--hover); }
.chat-bot-av { width: 24px; height: 24px; border-radius: 7px; background: var(--bg-2); display: grid; place-items: center; font-size: var(--fs-caption); flex: 0 0 auto; }
.chat-bot-title { font-weight: var(--fw-bold); font-size: var(--fs-meta); color: var(--muted); flex: 0 0 auto; }
.chat-bot-sum { font-size: 12.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; min-width: 0; }
.chat-bot-caret { color: var(--faint); font-size: var(--fs-micro); flex: 0 0 auto; }
.chat-bot-body { display: none; padding: 4px 14px 12px 44px; font-size: var(--fs-caption); line-height: var(--lh-normal); }
.chat-bot-card.open .chat-bot-body { display: block; }
/* composer: a framed, focusable surface with a send that lights up */
.chat-composer { border-top: 0; padding-top: 8px; }
.chat-composer-row {
  border: 1px solid var(--border-strong); border-radius: 14px; background: var(--panel);
  padding: 6px 8px; align-items: flex-end; transition: border-color .12s, box-shadow .12s;
}
.chat-composer-row:focus-within { border-color: var(--accent); box-shadow: var(--focus-ring-soft); }
.chat-composer-row .chat-input { border: 0; box-shadow: none; min-height: 36px; padding: 8px 6px; background: transparent; }
.chat-composer-row .chat-input:focus { border: 0; box-shadow: none; }
.chat-send { height: 36px; border-radius: 10px; }
/* thread pill: hover lift + accent count */
.chat-thread-link { border-radius: 9px; transition: background .12s, border-color .12s; }
.chat-thread-link:hover { border-color: var(--accent); background: var(--accent-soft); }
@media (prefers-reduced-motion: reduce) { .chat-msg-actions, .chat-thread-link, .chat-composer-row { transition: none; } }

/* SPEC336 — on the chat view the FAB cluster lifts ABOVE the composer (floating
   buttons never sit on an input — the SPEC328 rule). The composer has its own
   inline mic, so the voice FAB hides there entirely. */
body[data-view="chat"] .quick-add-fab { bottom: 140px; }
body[data-view="chat"] .call-fab { bottom: 140px; }
body[data-view="chat"] .voice-fab { display: none; }
body[data-view="chat"] .bug-fab { bottom: 206px; }
@media (max-width: 640px) {
  body[data-view="chat"] .quick-add-fab, body[data-view="chat"] .call-fab { bottom: calc(140px + env(safe-area-inset-bottom, 0px)); }
  body[data-view="chat"] .bug-fab { bottom: calc(206px + env(safe-area-inset-bottom, 0px)); }
}

/* SPEC336 reviewer fix — touch devices have no hover: actions stay visible and in-row
   (the floating lift left an INVISIBLE tappable toolbar over the message above) */
@media (max-width: 640px), (hover: none) {
  /* reviewer fixes (SPEC337): the toolbar FLOWS after the message instead of overlaying
     the author/timestamp (6 buttons now), and the composer wraps so the input keeps
     full width instead of collapsing to a 12px sliver next to 5 tool buttons */
  .chat-msg-actions { opacity: 1; transform: none; position: static; justify-content: flex-end; box-shadow: none; border: 0; background: transparent; margin-top: 3px; }
  .chat-msg-act { border: 1px solid var(--border); border-radius: 6px; background: var(--panel); }
  .chat-msg-act + .chat-msg-act { border-left: 1px solid var(--border); margin-left: 2px; }
  .chat-composer-row { flex-wrap: wrap; }
  .chat-composer-row .chat-input { flex: 1 1 100%; order: -1; }
}

/* SPEC337 — quick reactions + prominent threads */
.chat-msg-act--emoji { font-size: 15px; padding: 5px 8px; }
.chat-msg-act--reply { font-weight: var(--fw-bold); font-size: var(--fs-meta); color: var(--accent); white-space: nowrap; }
.chat-msg-act--reply:hover { background: var(--accent-soft); }
.chat-thread-ghost {
  display: none; align-items: center; gap: 5px; margin-top: 4px;
  border: 1px dashed var(--border-strong); border-radius: 9px; background: none;
  padding: 4px 12px; font-size: var(--fs-meta); font-weight: var(--fw-semibold); color: var(--accent); cursor: pointer;
}
.chat-msg:hover .chat-thread-ghost, .chat-msg:focus-within .chat-thread-ghost { display: inline-flex; }   /* keyboard path: focusing the row (tabindex 0) reveals it */
.chat-msg:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 8px; }
.chat-thread-ghost:hover { background: var(--accent-soft); border-color: var(--accent); border-style: solid; }
@media (max-width: 640px), (hover: none) { .chat-thread-ghost { display: inline-flex; } }
.emoji-pop-edit {
  display: block; width: 100%; margin-top: 4px; padding: 5px 8px; border: 0; border-top: 1px solid var(--border);
  background: none; cursor: pointer; font: inherit; font-size: 11.5px; font-weight: var(--fw-semibold); color: var(--muted); text-align: center;
}
.emoji-pop-edit:hover { color: var(--accent); }

/* SPEC338 — GIF picker */
.chat-tool--gif { font-size: 10.5px; font-weight: var(--fw-black); letter-spacing: var(--ls-label); color: var(--accent); }
.gif-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 6px; max-height: 380px; overflow-y: auto; }
.gif-cell { border: 1px solid var(--border); border-radius: 10px; padding: 0; overflow: hidden; cursor: pointer; background: var(--bg-2); aspect-ratio: 4 / 3; transition: transform .12s, border-color .12s; }
.gif-cell:hover { transform: scale(1.03); border-color: var(--accent); }
.gif-cell img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (prefers-reduced-motion: reduce) { .gif-cell { transition: none; } }

/* SPEC339 — voice messages + screen recordings */
.chat-voice { display: inline-flex; align-items: center; gap: 8px; margin: 5px 0; padding: 6px 12px 6px 10px; border: 1px solid var(--border); border-radius: 999px; background: var(--subtle); }
.chat-voice-ico { font-size: 15px; }
.chat-voice audio { height: 36px; max-width: min(320px, 60vw); }
.chat-screenrec { display: block; margin: 6px 0; max-width: min(420px, 100%); border-radius: 10px; border: 1px solid var(--border); background: #000; }
.chat-rec-pill {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: 96px; z-index: 950;
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  border: 1px solid var(--border); border-radius: 999px; background: var(--panel);
  box-shadow: 0 10px 30px -6px rgba(16, 24, 40, .35); font-size: var(--fs-caption); font-weight: var(--fw-semibold);
}
.chat-rec-dot { width: 10px; height: 10px; border-radius: 50%; background: #e2445c; animation: recPulse 1.2s ease-in-out infinite; }
@keyframes recPulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
@media (prefers-reduced-motion: reduce) { .chat-rec-dot { animation: none; } }
.chat-rec-timer { font-variant-numeric: tabular-nums; color: var(--muted); }

/* SPEC340 — ghost row (quick reacts + reply pill), ＋ composer menu, add-cut act */
.chat-ghost-row { display: none; align-items: center; gap: 4px; margin-top: 4px; flex-wrap: wrap; }
.chat-msg:hover .chat-ghost-row, .chat-msg:focus-within .chat-ghost-row { display: inline-flex; }
@media (max-width: 640px), (hover: none) { .chat-ghost-row { display: inline-flex; } }
.chat-ghost-react { border: 1px solid var(--border); border-radius: 999px; background: var(--panel); padding: 3px 9px; font-size: var(--fs-caption); cursor: pointer; line-height: 1; }
.chat-ghost-react:hover { border-color: var(--accent); background: var(--accent-soft); transform: scale(1.1); }

/* CONSOL-5 — reusable anchored popover + the service dropdown + per-service notes thread.
   All tokens (var(--panel/--border/--accent/--hover)) so it inherits the brand restyle. */
.popover { position: fixed; z-index: 3000; background: var(--panel); border: 1px solid var(--border); border-radius: 12px; box-shadow: 0 12px 36px -8px rgba(16, 24, 40, .32); padding: 6px; min-width: 210px; max-width: min(340px, 92vw); max-height: 62vh; overflow: auto; }
/* subtle ghost button (no bordered-chip outline — Vincent: "weird outline, looks really bad") */
.svc-menu-trigger { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; max-width: 100%; border: 0; background: transparent; color: var(--text); font: inherit; font-size: 12.5px; font-weight: var(--fw-medium); padding: 3px 7px; border-radius: 8px; white-space: nowrap; }
.svc-menu-trigger:hover, .svc-menu-trigger[aria-expanded="true"] { background: var(--hover); }
.svc-menu-trigger:focus-visible { background: var(--hover); }
/* CONSOL-3 — Big-density expanded services: each service as its own small chip */
.svc-exp { display: flex; flex-wrap: wrap; gap: 5px; }
.svc-exp-chip { display: inline-flex; align-items: center; gap: 5px; border: 1px solid var(--border); background: var(--panel); border-radius: 999px; padding: 3px 10px; font-size: 12.5px; cursor: pointer; color: var(--text); }
.svc-exp-chip:hover, .svc-exp-chip:focus-visible { border-color: var(--accent); background: var(--accent-soft); }
.svc-exp-n { font-size: var(--fs-micro); color: var(--muted); }
.svc-menu-dots { display: inline-flex; align-items: center; }
.svc-menu-dots .chip-dot { margin-right: -4px; box-shadow: 0 0 0 1.5px var(--panel); }
.svc-menu-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svc-menu-caret { opacity: .55; font-size: 10px; }
.svc-menu-list { display: flex; flex-direction: column; gap: 2px; }
.svc-menu-row { display: flex; align-items: center; gap: 4px; }
.svc-menu-pick { flex: 1 1 auto; display: flex; align-items: center; gap: 8px; text-align: left; background: transparent; border: 0; border-radius: 8px; padding: 7px 9px; cursor: pointer; font-size: var(--fs-caption); color: var(--text); min-width: 0; }
.svc-menu-pick:hover, .svc-menu-pick:focus-visible { background: var(--hover); }
.svc-menu-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.svc-menu-thread { flex: 0 0 auto; display: inline-flex; align-items: center; gap: 3px; background: transparent; border: 0; border-radius: 8px; padding: 6px 8px; cursor: pointer; color: var(--muted); font-size: var(--fs-meta); }
.svc-menu-thread:hover, .svc-menu-thread:focus-visible { background: var(--hover); color: var(--text); }
.svc-menu-thread.has-notes { color: var(--accent); }
.svc-menu-count { font-weight: var(--fw-bold); }
.svc-thread-list { display: flex; flex-direction: column; gap: 8px; max-height: 46vh; overflow: auto; }
.svc-thread-row { position: relative; border: 1px solid var(--border); border-radius: 10px; padding: 8px 10px; }
.svc-thread-meta { display: flex; justify-content: space-between; gap: 8px; font-size: 11.5px; margin-bottom: 3px; }
.svc-thread-text { font-size: var(--fs-caption); line-height: 1.45; white-space: pre-wrap; word-break: break-word; }
.svc-thread-del { position: absolute; top: 4px; right: 4px; }
.chat-tool--plus { font-size: 20px; font-weight: var(--fw-bold); color: var(--accent); }
.chat-plus-menu {
  position: fixed; z-index: 960; min-width: 250px; padding: 6px;
  border: 1px solid var(--border); border-radius: 14px; background: var(--panel);
  box-shadow: 0 14px 40px -8px rgba(16, 24, 40, .35);
}
.chat-plus-item { display: flex; align-items: center; gap: 11px; width: 100%; padding: 9px 10px; border: 0; border-radius: 9px; background: none; cursor: pointer; font: inherit; text-align: left; color: var(--text); }
.chat-plus-item:hover { background: var(--accent-soft); }
.chat-plus-ico { font-size: 17px; width: 24px; text-align: center; flex: 0 0 auto; }
.chat-plus-txt { display: flex; flex-direction: column; min-width: 0; }
.chat-plus-txt > span:first-child { font-weight: var(--fw-bold); font-size: var(--fs-caption); }
.chat-plus-sub { font-size: var(--fs-micro); color: var(--muted); }
.pp-act--add { width: auto; padding: 0 9px; font-size: var(--fs-micro); font-weight: var(--fw-black); color: var(--accent); white-space: nowrap; }

/* SPEC341 — focus layer */
.focus-nudge { display: flex; align-items: center; justify-content: space-between; gap: 10px; border: 1px solid var(--border); border-left: 3px solid var(--accent); border-radius: 10px; background: var(--subtle); padding: 8px 12px; margin-bottom: 12px; }
.focus-bar { height: 10px; border-radius: 999px; background: var(--bg-2); overflow: hidden; }
.focus-bar-fill { height: 100%; border-radius: 999px; background: var(--accent); transition: width .4s; }
.focus-bar-fill.over { background: linear-gradient(90deg, var(--accent), #00c875); }
.focus-stats { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 8px; }
.focus-stat-v { font-size: 20px; font-weight: var(--fw-black); font-variant-numeric: tabular-nums; }
.focus-stat-l { font-size: var(--fs-micro); color: var(--muted); text-transform: uppercase; letter-spacing: var(--ls-label); font-weight: var(--fw-bold); }
.focus-stat-s { font-size: var(--fs-micro); color: var(--faint); }
@media (prefers-reduced-motion: reduce) { .focus-bar-fill { transition: none; } }

/* SPEC342 — My Day timeline */
.myday-tl { position: relative; margin-left: 52px; }
.myday-hour { position: absolute; left: -52px; right: 0; border-top: 1px solid var(--border); font-size: 10px; color: var(--faint); }
.myday-hour span { position: relative; top: -7px; background: var(--panel); padding-right: 6px; }
.myday-busy {
  position: absolute; left: 0; right: 46%; overflow: hidden;
  background: var(--bg-2); border: 1px solid var(--border); border-radius: 8px;
  padding: 3px 8px; font-size: var(--fs-micro); color: var(--muted); white-space: nowrap; text-overflow: ellipsis;
}
.myday-block {
  position: absolute; left: 55%; right: 0; overflow: hidden; cursor: pointer;
  background: var(--accent-soft, var(--bg-2)); border: 1px solid var(--accent); border-left-width: 3px; border-radius: 8px;
  padding: 3px 8px; transition: transform .1s;
}
.myday-block:hover { transform: scale(1.01); }
.myday-block.done { opacity: .55; border-color: var(--ok, #00c875); text-decoration: line-through; }
.myday-block.pinned { border-style: solid; box-shadow: 0 2px 8px -2px rgba(16,24,40,.25); }
.myday-block-t { font-size: 11.5px; font-weight: var(--fw-bold); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.myday-block-r { font-size: 10px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.myday-now { position: absolute; left: -52px; right: 0; height: 2px; background: #e2445c; z-index: 5; }
.myday-now::before { content: ''; position: absolute; left: 0; top: -3px; width: 8px; height: 8px; border-radius: 50%; background: #e2445c; }
@media (prefers-reduced-motion: reduce) { .myday-block { transition: none; } }

/* SPEC344 — hit/miss + insights */
.myday-block.missed { opacity: .6; border-color: #e2445c; background: color-mix(in srgb, #e2445c 8%, var(--panel)); }
.myday-hitring { font-size: 11.5px; font-weight: var(--fw-bold); color: var(--muted); border: 1px solid var(--border); border-radius: 999px; padding: 3px 11px; }
.myday-hitring.good { color: var(--ok, #00c875); border-color: color-mix(in srgb, #00c875 40%, var(--border)); }
.myday-fun { margin: 8px 0 2px; padding: 8px 12px; border-radius: 10px; background: var(--accent-soft, var(--bg-2)); font-size: var(--fs-caption); }
.myday-tip { display: flex; align-items: flex-start; gap: 9px; padding: 7px 2px; border-bottom: 1px solid var(--border); }
.myday-tip:last-child { border-bottom: 0; }
.myday-tip-ico { font-size: 15px; flex: 0 0 auto; }

/* SPEC346 — pay statement */
.pay-statement { margin: 10px 0 0; padding: 12px 14px; border: 1px solid var(--border); border-radius: 10px; background: var(--subtle); font-size: 12.5px; line-height: 1.6; white-space: pre-wrap; font-variant-numeric: tabular-nums; }

/* SPEC347 — skills & knowledge importer */
.skills-drop { display: block; width: 100%; padding: 22px 14px; margin: 8px 0; border: 2px dashed var(--border-strong); border-radius: 12px; background: var(--subtle); cursor: pointer; font: inherit; font-size: var(--fs-caption); font-weight: var(--fw-semibold); color: var(--muted); text-align: center; transition: border-color .12s, color .12s; }
.skills-drop:hover, .skills-drop.on { border-color: var(--accent); color: var(--accent); }

/* D5 — the ONE insight-card idiom: every "here's what's going on" card (Day-at-a-glance,
   FRIDAY brief, Week-coached, "The bottom line", etc.) shares this accent-border wrapper
   so five renderers stop inventing five looks. Tone defaults to accent; --ok is reserved
   for the daily recap card, --warn/--danger only when the card's lead item warrants it. */
:root { --insight-tone: var(--accent); }
.insight { border-left: 3px solid var(--insight-tone, var(--accent)); }
/* tone modifiers — App.el's style-object merge can't set a custom property reliably
   (no setProperty path), so tone is a class, not an inline style. */
.insight--ok { --insight-tone: var(--ok); }
.insight--warn { --insight-tone: var(--warn); }
.insight--danger { --insight-tone: var(--danger); }

/* FRIDAY-SLIM 2026-08-12 — the opening moment (spec section A/C/D). Class hooks
   only (`fri-*`, the existing .fri-cite precedent) — friday.js applies these,
   no new hexes/fonts/gradients. Tokens only, so dark mode is zero extra work
   (verified once anyway — the champagne hairline swaps under [data-theme="dark"]). */

/* C1 — the hero card: .fri-hero sits alongside `card card-pad insight` (D5's
   idiom, accent left border kept); the champagne top hairline is the one
   "expensive" decorative move the token comment explicitly permits. */
.fri-hero { padding: var(--space-5); border-top: 1px solid var(--accent-warm); }

/* C2 — the headline sentence: Fraunces, the same editorial voice as .view-title. */
.fri-headline { font-family: var(--font-serif); font-size: var(--fs-lg); line-height: var(--lh-snug); font-weight: var(--fw-semibold); letter-spacing: var(--ls-tight); color: var(--text); font-variant-numeric: tabular-nums; }
@media (min-width: 861px) { .fri-headline { font-size: var(--fs-h1); } }

/* C4 — action rows: dot + one-line title + optional trailing meta; whole row
   is the tap target (App.rowActivate wires role=button/keyboard in friday.js). */
.fri-row { display: flex; align-items: center; gap: var(--space-2); padding: var(--space-2) 0; border-top: 1px solid var(--border); min-height: 40px; cursor: pointer; }
.fri-row:hover { background: var(--subtle); }
.fri-row-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.fri-row-title { font-size: var(--fs-caption); font-weight: var(--fw-semibold); flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fri-row-meta { font-size: var(--fs-meta); color: var(--muted); flex: 0 0 auto; font-variant-numeric: tabular-nums; }

/* C5 — disclosure buttons: "N more ▸", "which ones? ▸", the utility link row.
   The ▸/▾ glyph is a literal text swap in friday.js, not a CSS transform —
   cheaper and reduced-motion-proof (pairs with C9). */
.fri-more { background: none; border: 0; padding: var(--space-2) 0; font: inherit; font-size: var(--fs-meta); font-weight: var(--fw-medium); color: var(--muted); cursor: pointer; letter-spacing: var(--ls-label); text-transform: uppercase; }
.fri-more:hover { color: var(--accent); }

/* C6 — composer */
.fri-composer { margin-top: var(--space-4); }
.fri-composer .textarea { font-size: var(--fs-body); box-shadow: var(--shadow-sm); }
.fri-composer .textarea:focus { box-shadow: var(--focus-ring-soft); }

/* C7 — disclosure line, restyled + moved under the composer (full tab only;
   the docked panel keeps its original inline styling, unchanged, in friday.js). */
.fri-disclosure { font-size: var(--fs-micro); color: var(--faint); margin-top: var(--space-2); line-height: 1.4; }

/* C9 — one considered entrance, hero card only, once per arrival (friday.js
   guards the repeat with a 2s App._fridayEnteredAt stamp so App.refresh()'s
   re-render never replays it mid-session). Plain CSS class — never wired
   through startViewTransition (that API defers cross-view renders). */
@keyframes fri-enter { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.fri-enter { animation: fri-enter var(--t-slow) var(--ease-spring) both; }
@media (prefers-reduced-motion: reduce) { .fri-enter { animation: none; } }

/* C8 — thread rail row title (was inline fontSize:'12.5px' in friday.js).
   Active-thread background stays the already-tokened var(--accent-soft)
   inline style in friday.js — no other rail changes. */
.fri-thread-title { font-size: var(--fs-caption); }

/* SPEC348 — Monday coaching digest */
.coach-item { display: flex; align-items: flex-start; gap: 10px; padding: 8px 2px; border-bottom: 1px solid var(--border); }
/* TRUTH-CHECK 2026-08-18 — TAPFLOOR ratchet repair (§I.1 LAW 1, floor 44px at 375×812).
   Home's coach rows are real tap targets and measured 315×41 — three of them were live
   in the ten-screen sweep and pushed the ratchet from 17 to 19 the moment the §A canary
   row ("Only your changes reached the team this week") joined them. A 3px min-height on
   the INTERACTIVE variants only clears all three; the plain <div> rows are untouched. */
button.coach-item, a.coach-item, .coach-item[role="button"] { min-height: 44px; }
.coach-item:last-child { border-bottom: 0; }
.coach-item-ico { font-size: var(--fs-md); flex: 0 0 auto; margin-top: 1px; }

/* RECAP 2026-08-10 — start-of-day / end-of-day recap card (Today, top of view).
   Reuses .coach-item's row layout for each line; conforms to .insight (D5) with tone --ok
   so it stays visually distinguishable from the accent-toned FRIDAY/coach cards. */
.recap-item:hover { background: var(--subtle); border-radius: 6px; }

/* SPEC349 — Setter Desk */
.setter-form .input, .setter-form textarea.input { display: block; width: 100%; box-sizing: border-box; margin-top: 8px; }
.setter-form .select { margin-top: 8px; }
.setter-drop { display: block; width: 100%; padding: 14px; margin: 8px 0 0; border: 2px dashed var(--border-strong); border-radius: 10px; background: var(--subtle); cursor: pointer; font: inherit; font-size: var(--fs-meta); color: var(--muted); text-align: center; transition: border-color .12s, color .12s; }
.setter-drop:hover, .setter-drop.on { border-color: var(--accent); color: var(--accent); }
.setter-variant { border: 1px solid var(--border); border-radius: 10px; padding: 10px 12px; margin-top: 8px; background: var(--subtle); }
.setter-win { border-bottom: 1px solid var(--border); padding: 8px 2px; }
.setter-temp-hot { background: rgba(220, 80, 60, .14); }
.setter-temp-warm { background: rgba(220, 160, 40, .14); }
.setter-temp-cold { background: rgba(90, 140, 220, .14); }

/* CONSOL — Post & Review merged board: the lens toggle sits above the delegated board */
.postreview-modes { margin: 0 0 14px; }

/* CONSOL — generic lens wrapper toggle spacing */
.lens-modes { margin: 0 0 14px; }

/* ============================================================
   golive#13 — mobile bottom tab bar. A one-thumb accelerator over the
   SPEC86 drawer (☰), which stays fully intact — the bar's 5th "More"
   cell just toggles body.nav-open, exactly like the ☰ burger already
   does (index.html). Built + role-filtered in core.js (buildTabbar,
   next to buildQuickAddFab); every id it renders already passed the
   live App.canViewId gate, so this block is pure presentation.
   Mobile-only: #tabbar is display:none outside the ≤860px query (the
   SAME breakpoint the drawer itself switches on, styles.css:757), so
   desktop has zero layout change. Self-contained — delete this block
   + the buildTabbar()/renderTabbarActive() calls in core.js to revert.
   ============================================================ */
#tabbar { display: none; }
@media (max-width: 860px) {
  #tabbar {
    display: block; position: fixed; left: 0; right: 0; bottom: 0; z-index: 58;
    background: var(--sidebar-bg); border-top: 1px solid var(--sidebar-border);
    padding-bottom: env(safe-area-inset-bottom, 0px);
    box-shadow: 0 -4px 18px rgba(0,0,0,.22);
  }
  #tabbar .tb-row { display: grid; grid-template-columns: repeat(5, 1fr); }
  #tabbar .tb-item {
    position: relative; box-sizing: border-box; display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 3px; min-height: 56px;
    padding: 6px 2px; border: 0; background: none; cursor: pointer; font: inherit;
    color: var(--sidebar-text); font-size: 10.5px; font-weight: var(--fw-bold); letter-spacing: .01em;
    -webkit-tap-highlight-color: transparent;
  }
  #tabbar .tb-ico svg { width: 21px; height: 21px; }
  #tabbar .tb-lbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
  #tabbar .tb-item:active { background: rgba(255,255,255,.05); }
  #tabbar .tb-item.active { color: var(--sidebar-active); }
  #tabbar .tb-item.active::before {
    content: ''; position: absolute; top: 0; left: 22%; right: 22%; height: 3px;
    border-radius: 0 0 4px 4px; background: var(--accent);
  }

  /* clear the fixed bar: the existing bottom padding PLUS its own content height
     (56px item + 1px border ≈ 57px; 62px leaves a hair of breathing room). Safe-area
     is already handled — the bar pads itself, so content only needs the flat height. */
  #view { padding-bottom: calc(50px + 62px); }

  /* the FAB cluster (quick-add ＋ / voice mic / bug report / FRIDAY Listens 📞 call-fab
     — SPEC303/SPEC310/SPEC328) sits bottom-right and would now sit UNDER the bar —
     lift every one of them by its height. These mirror the EXISTING base selectors
     above (same specificity); being appended after them in the file, they win the
     cascade at this breakpoint without touching the desktop-only declarations. */
  .quick-add-fab, .call-fab { bottom: calc(22px + 62px); }
  .voice-fab { bottom: calc(22px + 62px); }
  .voice-fab.stacked { bottom: calc(86px + 62px); }
  .bug-fab { bottom: calc(150px + 62px); }
  body[data-view="chat"] .quick-add-fab, body[data-view="chat"] .call-fab { bottom: calc(140px + 62px); }
  body[data-view="chat"] .bug-fab { bottom: calc(206px + 62px); }
}
@media (max-width: 640px) {
  /* D7 — one FAB to clear, not the old 5-deep stack: 24px gap + safe-area + tab-bar
     clearance (62px) + the dial button's own footprint (72px), not 96px sized for a
     212px-tall cluster. */
  #view { padding-bottom: calc(24px + env(safe-area-inset-bottom, 0px) + 62px + 72px); }
  .quick-add-fab, .call-fab { bottom: calc(16px + env(safe-area-inset-bottom, 0px) + 62px); }
  .voice-fab { bottom: calc(16px + env(safe-area-inset-bottom, 0px) + 62px); }
  .voice-fab.stacked { bottom: calc(80px + env(safe-area-inset-bottom, 0px) + 62px); }
  .bug-fab { bottom: calc(150px + env(safe-area-inset-bottom, 0px) + 62px); }
  body[data-view="chat"] .quick-add-fab, body[data-view="chat"] .call-fab { bottom: calc(140px + env(safe-area-inset-bottom, 0px) + 62px); }
  body[data-view="chat"] .bug-fab { bottom: calc(206px + env(safe-area-inset-bottom, 0px) + 62px); }
}
@media (prefers-reduced-motion: reduce) { #tabbar .tb-item { transition: none; } }
/* golive#13 — the on-screen keyboard toggle (index.html, visualViewport listener next
   to the SPEC86 drawer wiring) hides the bar entirely while typing, so it never sits
   above a focused input. #view/FAB offsets are left as-is: the keyboard already pushes
   everything above it, so there's nothing left at the old tab-bar height to clear. */
body.kb-open #tabbar { display: none; }


/* ==========================================================================
   ==  2026-07-30 SURFACE VISUAL PASS — five builder blocks, merged in one    ==
   ==  integrator pass. Appended at the END on purpose: several blocks are    ==
   ==  deliberate same-specificity overrides of earlier rules and rely on     ==
   ==  source order. Token-only, no !important, no new custom properties.     ==
   ========================================================================== */


/* ##########################################################################
   CHAT — visual pass (chat.js). scratchpad/css-chat.css
   Merged by the INTEGRATOR pass, 2026-07-30. Source: builder scratch file.
   ########################################################################## */
/* ============================================================
   CHAT — visual pass, 2026-07-30
   Owner: chat surface builder. Appends verbatim to styles.css.

   NO new CSS variables. Every value below is an existing design token, so both
   themes come for free (--ok, --panel, --bg, --hover, --accent, --faint and the
   --fs- / --space- / --fw- scales all flip under html[data-theme="dark"]).
   NO raw hex. NO !important. Every selector is scoped to a .chat-* class.

   Three feature blocks (presence dots / read receipts / pinned bar) then the
   depth pass. Sizes quoted in comments are MEASURED off the live DOM before
   this file, not read off the source.
   ============================================================ */

/* ============================================================
   A · PRESENCE DOTS  (Discord/Whop: the dot is CUT OUT of the avatar)
   The ring is drawn in the surface colour behind the avatar so the dot never
   muddies the avatar hue. Only two states exist — filled = active (<=10 min),
   ring = recent (<=2 h). There is deliberately NO "offline" dot: chat.js
   renders no node at all when the app has no evidence for a person.
   Semantic --ok, kept off --accent per the standing rule.
   ============================================================ */
/* align-self is load-bearing: .chat-msg is a flex row with the default
   align-items:stretch, so without it the wrapper grows to the FULL row height and
   the bottom-right dot floats away from the avatar (measured: dot at y=897 on a
   34px avatar sitting at y=744). */
.chat-avwrap { position: relative; display: inline-flex; flex: 0 0 auto; align-self: flex-start; }
.chat-presence {
  position: absolute; right: -1px; bottom: -1px;
  width: 10px; height: 10px; border-radius: 50%;
  box-shadow: 0 0 0 2px var(--bg);          /* the cut-out ring — chat sits on --bg, not --panel */
  pointer-events: none;
}
.chat-presence--active { background: var(--ok); }
.chat-presence--recent { background: var(--bg); box-shadow: 0 0 0 2px var(--bg), inset 0 0 0 2px var(--ok); }
/* the ring tracks the surface actually behind it in the three states that exist */
.chat-msg:hover .chat-presence { box-shadow: 0 0 0 2px var(--subtle); }
.chat-msg:hover .chat-presence--recent { box-shadow: 0 0 0 2px var(--subtle), inset 0 0 0 2px var(--ok); }
.chat-ch:hover .chat-presence { box-shadow: 0 0 0 2px var(--hover); }
.chat-ch:hover .chat-presence--recent { box-shadow: 0 0 0 2px var(--hover), inset 0 0 0 2px var(--ok); }
.chat-ch.active .chat-presence { box-shadow: 0 0 0 2px var(--accent-soft); }
.chat-ch.active .chat-presence--recent { box-shadow: 0 0 0 2px var(--accent-soft), inset 0 0 0 2px var(--ok); }
/* rail avatars are 22px, so the dot steps down to keep Whop's ~1:2.5 proportion */
.chat-ch .chat-presence { width: 8px; height: 8px; }

/* ============================================================
   B · READ RECEIPT. Whop / Instagram / Basecamp all converge on the same
   treatment — faint microtype under the last message, no chip, no icon, no
   avatar stack — and this takes that. It does NOT take their right-alignment:
   MEASURED, a right-aligned receipt landed at x 544-1106 / y 800-816 and the
   app's own quick-add FAB occupies x 1074-1126 / y 784-836, so the count sat
   underneath a floating button. Aligning it to the 52px message column (the
   avatar gutter) puts it directly under the text it annotates, clears every
   FAB at every width, and is what Basecamp's left-aligned "Delivered" does.
   ============================================================ */
.chat-receipt {
  margin: var(--space-1) 0 var(--space-2) 52px;
  width: max-content; max-width: 100%;   /* hug the text so the title tooltip has no dead full-width hit area */
  font-size: var(--fs-micro); font-weight: var(--fw-medium); color: var(--faint);
}

/* ============================================================
   C · PINNED MESSAGE BAR  (Whop / Campsite: one un-carded line separated from
   the feed by a hairline, NOT a floating card. It is a flex sibling of the
   scroller rather than sticky INSIDE it, which makes it permanently visible
   instead of merely sticky — same intent, less coupling to renderList.)
   ============================================================ */
.chat-pinbar {
  display: flex; align-items: center; gap: var(--space-2); flex: 0 0 auto;
  padding: var(--space-2) var(--space-3);
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  box-shadow: inset 3px 0 0 var(--accent);
  font-size: var(--fs-meta);
}
.chat-pinbar-label {
  flex: 0 0 auto; color: var(--accent);
  font-size: var(--fs-micro); font-weight: var(--fw-black);
  letter-spacing: var(--ls-label); text-transform: uppercase;
}
/* the 1/N cycler — a real button, but styled as the label it replaces */
.chat-pinbar-cycle { border: 0; background: none; padding: 0; margin: 0; cursor: pointer; font-family: inherit; }
.chat-pinbar-cycle:hover { color: var(--accent-hover); text-decoration: underline; }
.chat-pinbar-cycle:focus-visible { outline: 2px solid var(--accent); outline-offset: var(--focus-offset); border-radius: var(--radius-sm); }
.chat-pinbar-hit {
  flex: 1 1 auto; min-width: 0; display: flex; align-items: baseline; gap: var(--space-2);
  cursor: pointer; overflow: hidden;
}
.chat-pinbar-text {
  flex: 0 1 auto; min-width: 0; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chat-pinbar-who { flex: 0 0 auto; color: var(--muted); white-space: nowrap; }
.chat-pinbar-hit:hover .chat-pinbar-text { color: var(--accent); }
.chat-pinbar-hit:focus-visible { outline: 2px solid var(--accent); outline-offset: var(--focus-offset); border-radius: var(--radius-sm); }
.chat-pinbar-x {
  flex: 0 0 auto; border: 0; background: none; cursor: pointer;
  color: var(--muted); font-size: var(--fs-caption); line-height: 1;
  padding: var(--space-1) var(--space-2); border-radius: var(--radius-sm);
}
.chat-pinbar-x:hover { background: var(--hover); color: var(--danger); }
.chat-pinbar-x:focus-visible { outline: 2px solid var(--accent); outline-offset: var(--focus-offset); }

/* ============================================================
   D1 · COLLAPSE THE TYPE SCALE.
   Measured inside .chat-layout before this file: 15 distinct font sizes, five of
   them (13.5 / 12.5 / 11.5 / 10.5 / 10px) off the token scale entirely — hand-typed
   one-offs. Message body text was 13.5px/19.575px, BELOW the app's own --fs-body,
   on the one surface where people read paragraphs.
   Everything below moves onto --fs-micro 11 / --fs-meta 12 / --fs-caption 13 /
   --fs-body 14, so the hierarchy reads as steps instead of a half-pixel smear.
   (Emoji GLYPH sizes — .chat-tool 17px, .chat-tool--plus 20px, .chat-voice-ico
   15px — are deliberately left alone: they size a picture, not text.)
   ============================================================ */
.chat-text { font-size: var(--fs-body); line-height: var(--lh-normal); }
.chat-author { font-size: var(--fs-body); }
.chat-ch { font-size: var(--fs-caption); }
.chat-rail-head { font-size: var(--fs-micro); letter-spacing: var(--ls-label); }
.chat-ch-badge { font-size: var(--fs-micro); }
.chat-status { font-size: var(--fs-micro); }
.chat-gutter-time { font-size: var(--fs-micro); }
.chat-jobcard-sub { font-size: var(--fs-micro); }
.chat-file { font-size: var(--fs-meta); }
.chat-thread-link { font-size: var(--fs-meta); }
.chat-bot-sum { font-size: var(--fs-meta); }
.chat-thread-title strong { font-size: var(--fs-md); }
.chat-new-divider span { font-size: var(--fs-micro); }
.chat-thread-avs .chat-av { font-size: var(--fs-micro); }   /* thread-pill avatars rendered their initials at 9px */
.emoji-pop-edit { font-size: var(--fs-micro); }

/* ============================================================
   D2 · MESSAGE GROUPING IS ALIVE AGAIN.
   chat.js now emits the `grouped` class it has always computed, so this rule —
   which used to match EVERY row — finally distinguishes a new speaker from a
   same-speaker continuation. Measured before: inter-row gaps were a uniform
   [4,4,4,51,4,4,4,4,4,4,4,4,4]; the only air in the feed came from day dividers.
   ============================================================ */
.chat-msg:not(.grouped) { margin-top: var(--space-3); }
.chat-msg.grouped { margin-top: 0; }
.chat-list > .chat-msg:first-child, .chat-thread-list > .chat-msg:first-child { margin-top: 0; }

/* ============================================================
   D3 · THE ROLE PILL BECOMES MICROTYPE.
   Measured: 11 filled grey pills marching down a 14-row feed, competing with body
   text that was smaller than they were. Same words, none of the noise.
   ============================================================ */
.chat-role {
  background: none; padding: 0; border-radius: 0;
  color: var(--faint); font-size: var(--fs-micro); font-weight: var(--fw-medium);
}

/* ============================================================
   D4 · THE CONSOL-1 ROW BECOMES ONE REAL FLOATING ACTION BAR.
   Vincent's 2026-07-11 call stands — reactions + reply live in ONE
   hover/focus-revealed row UNDER the message and never also in a corner toolbar.
   This does not move it; it makes it look like one object instead of five loose
   pills (Whop/Basecamp: one container, one elevation, borderless children).
   Buttons go from a measured 36x21 to 30x28 minimum.
   ============================================================ */
.chat-ghost-row {
  gap: 0; margin-top: var(--space-2); padding: 2px;
  flex-wrap: nowrap; width: max-content; max-width: 100%;
  border: 1px solid var(--border); border-radius: 999px;
  background: var(--panel); box-shadow: var(--shadow-sm);
}
.chat-ghost-react {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-1);
  border: 0; border-color: transparent; background: none; border-radius: 999px;
  min-width: 30px; height: 28px; padding: 0 var(--space-2);
  font-size: var(--fs-caption); line-height: 1; color: var(--text);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
/* scale(1.1) inside a bordered bar reads as a glitch — the bar is the frame now */
.chat-ghost-react:hover { background: var(--hover); border-color: transparent; transform: none; }
.chat-ghost-react:focus-visible { background: var(--hover); box-shadow: var(--focus-ring); outline: none; }
/* labelled actions sit after a hairline, borderless, same height as the emoji */
.chat-ghost-row .chat-thread-ghost, .chat-ghost-row .chat-ghost-pin {
  border: 0; border-left: 1px solid var(--border); border-radius: 999px;
  height: 28px; margin-top: 0; padding: 0 var(--space-3);
  background: none; font-size: var(--fs-meta); font-weight: var(--fw-semibold);
}
.chat-ghost-row .chat-ghost-pin { color: var(--muted); }
.chat-ghost-row .chat-ghost-pin.on { color: var(--accent); }
.chat-ghost-row .chat-ghost-pin:hover { background: var(--accent-soft); color: var(--accent); }
.chat-ghost-row .chat-thread-ghost:hover { background: var(--accent-soft); border-color: var(--border); border-style: solid; }
@media (prefers-reduced-motion: reduce) { .chat-ghost-react { transition: none; } }

/* ============================================================
   D5 · A COMMITTED REACTION STOPS LOOKING LIKE AN OFFERED ONE (Twist).
   Measured before: .chat-react (46x25, 999px, --panel fill, --border stroke) and
   .chat-ghost-react (36x21, 999px, --panel fill, --border stroke) were the same
   object stacked 4px apart. Now: committed = FILLED, no outline; offered =
   borderless glyph inside an outlined bar. .chat-react.mine keeps its accent
   treatment (its 2-class rule already outranks this one).
   ============================================================ */
.chat-react {
  background: var(--subtle); border-color: transparent;
  font-size: var(--fs-meta); font-variant-numeric: tabular-nums;
  padding: 2px 10px; line-height: 20px;
}
.chat-react:hover { background: var(--hover); }
.chat-react:focus-visible { outline: 2px solid var(--accent); outline-offset: var(--focus-offset); }

/* ============================================================
   D7 · THE MOBILE LAYOUT CORRECTION. One declaration, measured.
   Before, at 375x812: .chat-main was 1847px tall inside a 662px .chat-layout —
   the classic flex min-height:auto floor — so .chat-list never became a scroller
   (clientHeight === scrollHeight), the composer sat at y=1855 (far below an 812px
   viewport, behind the tab bar) and the rail/header scrolled out of reach.
   Everything else on mobile is decoration on a broken box without this.
   ============================================================ */
.chat-main, .chat-list, .chat-thread-list { min-height: 0; }

/* ============================================================
   D9 · RAIL SECTION LABELS SURVIVE A LONG ROSTER.
   ============================================================ */
.chat-rail-head { position: sticky; top: 0; z-index: 1; background: var(--bg); }

/* D8 · MOBILE HEAD BUDGET. Measured before at 375px: rail 43 + head 93 (the channel
   name wrapped to two lines beside "Kudos: on" / "Members" / "Local only") + composer
   111 = 247px of 812 = 30% of the viewport consumed before one message renders.
   The channel name gets its own full-width line and can never be squeezed out — an
   earlier attempt at squeezing all four onto one line measured the title at 0px wide,
   which is worse than the wrap it replaced. The control group keeps every control and
   scrolls sideways inside itself if a future channel adds another one. */
@media (max-width: 760px) {
  .chat-head { flex-wrap: wrap; row-gap: var(--space-1); padding-bottom: var(--space-2); }
  .chat-head-title {
    flex: 1 1 100%; min-width: 0; font-size: var(--fs-body);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .chat-head > .row-line {
    flex: 1 1 100%; min-width: 0; justify-content: flex-start;
    overflow-x: auto; scrollbar-width: none;
  }
  .chat-head > .row-line::-webkit-scrollbar { display: none; }
}

/* ============================================================
   D6 · MOBILE: ONE REACT BUTTON INSTEAD OF FIVE.
   Measured before at 375px: the always-on quick-react bar rendered on 14 of 14
   rows — 463px of ghost chrome inside a 1639px feed, 28.2% of everything you
   scroll — and every button was 36x21, under half the 44px touch minimum.
   NOTHING becomes unreachable: .chat-ghost-more still opens the full picker
   (chat.js emojiPopover), and App.quickReacts / the editor are untouched, so the
   quick reacts move exactly one tap away. Pin is exempt from the hide so a
   channel manager can still pin from a phone.
   ============================================================ */
@media (max-width: 640px), (hover: none) {
  .chat-ghost-react:not(.chat-ghost-more):not(.chat-ghost-pin) { display: none; }
  .chat-ghost-row .chat-ghost-more,
  .chat-ghost-row .chat-ghost-pin,
  .chat-ghost-row .chat-thread-ghost { min-width: 44px; height: 44px; }
}
/* MEASURED HONESTLY: this cuts the BUTTON COUNT on touch from 5 to 1 and lifts every
   target from 36x21 to 44x44, but because 44px is taller than the 21px it replaces,
   the bar's SHARE of the scrollable feed went 28.2% -> 33.9%, not down. The 44px
   minimum is not negotiable, so the only way to actually shrink that share is to stop
   rendering the bar on every row and reveal it on the tapped message instead
   (.chat-msg already carries tabindex=0, so :focus-within would do it with no JS).
   That turns SPEC337's one-tap react into two taps, which is Vincent's call, not mine
   — so it is NOT done here. */


/* ##########################################################################
   JOB TRACKER — table + kanban (tracker.js). scratchpad/css-tracker.css
   Merged by the INTEGRATOR pass, 2026-07-30. Source: builder scratch file.
   ########################################################################## */
/* ============================================================================
   JOB TRACKER (tracker.js) — table + kanban.  07-30.
   Pairs with the tracker.js pass of the same date. Everything here is token-only
   (no raw hex, no new custom properties) and themes itself through the existing
   light/dark token pairs.

   SCOPING — three hooks added by tracker.js in this same pass, because every
   structural class this surface uses is SHARED:
     .jt-view        the Job Tracker's view wrapper   (.toolbar / .view-header are app-wide)
     .jt-table-wrap  its table scrollport             (.table-wrap is used by ~30 panels)
     .jt-board       its kanban board                 (.kanban is also Leads / Tasks /
                                                       Marketing / Pipelines / Video)
   Nothing below changes another surface EXCEPT the two blocks explicitly marked
   "INTENTIONALLY GLOBAL" (§6 .cell-select, §7 urgency ink) — see the notes there.
   Verified live: the Leads, Tasks and Pipelines boards still compute
   max-height:none, position:static heads and the original --bg-2 column fill.

   NO new CSS variables. NO !important.
   ============================================================================ */


/* ─────────────────────────────────────────────────────────────────────────────
   §1  TABLE — a real scrollport, so the header can actually stick.
   ─────────────────────────────────────────────────────────────────────────────
   MEASURED DEFECT: the table is 1713px tall in a 900px viewport and `thead`
   computes `position: static`, so scrolled to the bottom the header row sits at
   top:-5630px on a full board. The status is written in words ONLY in the group
   header, and that scrolls away too — past the fold the table is anonymous.

   Sticky against the PAGE does not work here: `.table-wrap` already declares
   `overflow-x: auto`, which forces overflow-y off `visible` (computed: auto), so
   the wrap — not the page — is the nearest scrollport. Verified live: a sticky
   `th` measured against #main ended at top:-882px. The fix must therefore give
   the wrap a real height to scroll WITHIN. */
.jt-table-wrap {
  overflow: auto;
  /* the floor keeps the table usable if the toolbar ever wraps to four rows;
     320px of chrome is the measured view-header + toolbar stack (327px). */
  max-height: max(340px, calc(100vh - 320px));
  overscroll-behavior: contain;   /* don't chain the page scroll when the table bottoms out */
}
/* sticky rows must be OPAQUE. --subtle is the header fill the table already uses.
   `border-bottom` is unreliable on a sticky cell in a border-collapse table
   (Chrome drops it), so the hairline is redrawn as an inset shadow. */
.jt-table-wrap table.table thead th {
  position: sticky;
  top: 0;
  z-index: 4;
  background: var(--subtle);
  box-shadow: inset 0 -1px 0 var(--border);
}
/* The "＋ add custom column" button is what actually sets the header height (a
   32px .btn-sm inside a 12px cell). Shrinking it makes the header a predictable
   36px, which is what the group-head offset below is pinned to. */
.jt-table-wrap table.table thead th .btn {
  padding: 1px 7px;
  font-size: var(--fs-micro);
  line-height: var(--lh-snug);
}
/* Group headers stack UNDER the column header — the status name in words stays on
   screen for the whole group instead of scrolling out of the board.

   The `top` offsets are the MEASURED header heights per density preset (25.3 /
   33.3 / 49.4px, live in this browser), each rounded DOWN. Rounding down matters:
   a value below the real header height makes the group head slide a hair BEHIND
   the header (z-index 3 < 4) — invisible. A value above it would open a gap that
   table rows scroll through. */
.jt-table-wrap table.table tr.group-head > td {
  position: sticky;
  top: 32px;
  z-index: 3;
  font-size: var(--fs-meta);
}
.jt-table-wrap.density-compact table.table tr.group-head > td { top: 24px; }
.jt-table-wrap.density-big table.table tr.group-head > td { top: 48px; }


/* ─────────────────────────────────────────────────────────────────────────────
   §2  TABLE DENSITY — 136px average row → ~46px.
   ─────────────────────────────────────────────────────────────────────────────
   MEASURED DEFECT: average row 136px (min 94, max 189) = 6.6 rows per 900px
   viewport on a 45-row board; Linear/Asana fit 20–25. Two drivers: a 3-block
   vertical stack in the Address cell, and 12px vertical cell padding.

   Scoped to `.density-comfortable` ONLY. The Compact and Big presets are real
   features with their own (0,2,2) rules in styles.css; a bare `.jt-table-wrap
   table.table td` would tie on specificity, land later in the file, and silently
   overwrite BOTH presets. */
.jt-table-wrap.density-comfortable table.table td { padding: 8px 12px; }
.jt-table-wrap.density-comfortable table.table th { padding: 7px 12px; }

/* The address column needs room for one line of a real LA address (it measured
   190px, which wrapped every address to three lines) — but it must NOT be allowed
   to take as much as it likes. MEASURED: uncapped, `white-space: nowrap` on four
   inline items pushed the column from 172px to 570px and the whole table from
   1471px to 1786px, dropping fully-visible columns from 8 to 5. SLEEK 08-12 (A5):
   the orderId's ~104px share left the cell with the A1 removal, so the cap
   tightens 360px → 300px and the header floor 260px → 220px. The shrink
   priorities below decide who gives way: the address never drops below 90px; the
   tags — a label, recoverable on hover or in the modal — yield first. */
.jt-table-wrap table.table thead th:nth-child(2) { min-width: 220px; }

/* Address cell — ONE line: address (ellipsised, full value on hover) · flags ·
   tag chips. tracker.js builds the nodes; this lays them out. (SLEEK 08-12 — the
   dim mono orderId left this inventory: directive A1 took the node off the row.) */
.jt-table-wrap .jt-addr {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  max-width: 300px;
}
.jt-table-wrap .jt-addr > * { flex: 0 0 auto; }
.jt-table-wrap .jt-addr-text {
  flex: 1 1 auto;
  min-width: 90px;
  font-weight: var(--fw-semibold);
  font-size: var(--fs-body);   /* SLEEK 08-12 (A4) — the anchor reads one step stronger than the data cells around it, which inherit the table's smaller size. Decided: stays Inter, never Fraunces at 13-14px table scale. */
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* (SLEEK 08-12, A3 — the `.jt-order` dim-identifier rule that lived here was
   removed with the node itself: A1 took the Tonomo order id off the row. The id
   survives on the address hover title, the job modal, and data-side search.) */
/* tags trail the row; they never justify a second line */
.jt-table-wrap .jt-addr .tag-chips { flex: 0 1 auto; flex-wrap: nowrap; overflow: hidden; max-width: 92px; }

/* ── FROZEN IDENTITY COLUMN ──────────────────────────────────────────────────
   The board carries 14 columns and measured 1471px wide against a 986px wrap
   BEFORE this pass — i.e. it already scrolled horizontally, and the moment you
   reached Status / Price / Payment you had lost the address and no longer knew
   which job the row was. Freezing the checkbox + address cells (Airtable / Excel)
   makes that scroll cheap, and it is what pays for the slightly wider address
   column above.

   Every selector below excludes tr.group-head — its single colspan=14 <td> IS a
   `td:first-child`, so an unqualified rule silently stole its z-index and its
   status tint.

   Z-ORDER (all four layers matter, and a tie is decided by DOM order — which is
   wrong here, because the LATER, scrolled-away columns would win):
     6  thead corner cells (sticky top AND left)
     4  the rest of thead        (sticky top)
     3  the status group band    (sticky top, spans every column)
     2  the frozen body cells    (sticky left)                                 */
.jt-table-wrap table.table thead th:first-child,
.jt-table-wrap table.table thead th:nth-child(2) { z-index: 6; }   /* corner cells: sticky on BOTH axes */
.jt-table-wrap table.table thead th:first-child,
.jt-table-wrap table.table tbody tr:not(.group-head) > td:first-child { position: sticky; left: 0; }
/* The address column's `left` is the MEASURED width of the bulk-select column in
   each density preset (34 / 42 / 50px live in this browser). It cannot be forced
   from CSS: tracker.js sets `width: 34px` as an INLINE style on that <th>, and the
   auto table layout then adds each preset's own cell padding on top. A wrong value
   here is visible — too small and the address overlaps the checkbox, too large and
   scrolled content shows through the seam. */
.jt-table-wrap table.table thead th:nth-child(2),
.jt-table-wrap table.table tbody tr:not(.group-head) > td:nth-child(2) { position: sticky; left: 42px; }
.jt-table-wrap.density-compact table.table thead th:nth-child(2),
.jt-table-wrap.density-compact table.table tbody tr:not(.group-head) > td:nth-child(2) { left: 34px; }
.jt-table-wrap.density-big table.table thead th:nth-child(2),
.jt-table-wrap.density-big table.table tbody tr:not(.group-head) > td:nth-child(2) { left: 50px; }
.jt-table-wrap table.table tbody tr:not(.group-head) > td:first-child,
.jt-table-wrap table.table tbody tr:not(.group-head) > td:nth-child(2) {
  z-index: 2;
  background: var(--panel);                 /* sticky cells MUST be opaque */
}
/* a hairline so the frozen edge reads as an edge once the rest scrolls under it */
.jt-table-wrap table.table tbody tr:not(.group-head) > td:nth-child(2) { box-shadow: inset -1px 0 0 var(--border); }
/* keep the row-level feedback (hover rail, bulk selection) working on the frozen
   cells — an opaque cell would otherwise punch a hole through both */
.jt-table-wrap table.table tbody tr:not(.group-head):hover > td:first-child,
.jt-table-wrap table.table tbody tr:not(.group-head):hover > td:nth-child(2) { background: var(--hover); }
/* the group band spans every column, so its chip would scroll away too — pin the
   band's own content instead, and it rides along at the left edge. Its z-index is
   restated here because the frozen-column block above sits later in the cascade. */
.jt-table-wrap table.table tbody tr.group-head > td { z-index: 3; }
.jt-table-wrap table.table tr.group-head > td > span { position: sticky; left: var(--space-3); }

/* content-visibility placeholder height MUST track the new density or the
   scrollbar thrashes as off-screen rows resolve (contain-intrinsic-size was
   pinned at 96px against a 42px row).
   Values are the MEASURED post-change row heights: 21.0 / 42.3 / 145.8px. */
.jt-table-wrap table.table tbody tr.cv-row { contain-intrinsic-size: auto 44px; }
.jt-table-wrap.density-compact table.table tbody tr.cv-row { contain-intrinsic-size: auto 21px; }
.jt-table-wrap.density-big table.table tbody tr.cv-row { contain-intrinsic-size: auto 120px; }


/* ─────────────────────────────────────────────────────────────────────────────
   §3  KANBAN — the board gets its own scrollport and the column heads stick.
   ─────────────────────────────────────────────────────────────────────────────
   MEASURED DEFECT: the tallest column is 1431px in a 900px viewport and
   `.kanban-col-head` computes `position: static`, so at the bottom of that column
   its header sits at top:-601px. The card carries NO status cue of its own —
   status is encoded ONLY by which column you are in — so once you scroll, the
   board is anonymous.

   THE SCROLLER IS THE COLUMN, NOT THE BOARD. I built it the other way first —
   board scrolls vertically, heads sticky inside it — and measured the result: at
   scrollTop 400 the two TALL columns pinned their heads at offset 0, but every
   SHORT column had scrolled off the top entirely (heads at -21, -107, -159px),
   taking its cards with it. A sticky element can never outlive its containing
   block. Giving each COLUMN the scrollport instead means the board scrolls only
   horizontally, no column ever leaves the screen, every head is always visible,
   and each column scrolls independently — which is also what Trello / Jira /
   Linear do. `overflow-x: auto` + `overflow-y: hidden` is a legal pair (unlike
   auto + visible, which is what silently created the old phantom scrollport). */
.jt-board {
  overflow-x: auto;
  overflow-y: hidden;
  align-items: flex-start;     /* columns must not stretch — restated, it is load-bearing */
  gap: var(--space-3);
  padding-bottom: var(--space-3);
}
/* the column supplies horizontal padding only; the sticky head supplies the top
   padding itself, so it pins flush at offset 0 with no gap above it */
.jt-board .kanban-col {
  max-height: max(300px, calc(100vh - 300px));
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
  padding: 0 var(--space-2) var(--space-2);
  min-height: 0;
}
.jt-board .kanban-col::-webkit-scrollbar { width: 8px; }
.jt-board .kanban-col::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; }
.jt-board .kanban-col-head {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg-2);     /* MUST be opaque, and MUST match .kanban-col */
  padding: var(--space-2) 2px var(--space-2);
  margin-bottom: var(--space-2);
  border-bottom: 1px solid var(--border);
  border-radius: var(--radius) var(--radius) 0 0;
  /* tracker.js paints `inset 0 3px 0 0 <status colour>` here inline, so the
     column's identity survives BOTH axes of scroll (ClickUp / Slack Lists). */
}
/* the COUNT is what you scan a board for. It was an 11px dim `.badge` floated to
   the far right — the weakest thing in the header. It now leads, immediately
   after the status chip, and the money sum takes the trailing slot. */
.jt-board .kanban-col-head .count {
  margin-left: 0;
  padding: 0;
  background: transparent;
  color: var(--text);
  font-size: var(--fs-caption);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}
.jt-board .kanban-col-head .kcol-sum {
  margin-left: auto;
  color: var(--muted);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}


/* ─────────────────────────────────────────────────────────────────────────────
   §4  KANBAN — empty columns: a drop target, and a rail for the ones that are
       empty by definition.
   ─────────────────────────────────────────────────────────────────────────────
   MEASURED DEFECT: in Active scope the board still renders "Completed · 0" and
   "Cancelled · 0" as full 260px columns — 544px of permanently empty board, 20%
   of it — while "Stuck · 7 jobs · $6,417", the one column that needs a PM, starts
   at x≈2176px, entirely off-screen (board scrollWidth 2708 vs 1148 visible).

   They are COLLAPSED, not removed: a done column is a legitimate drag target
   ("deliver this job"), and deleting that gesture is an IA decision, not styling. */
.jt-board .kanban-col-empty {
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--faint);
  font-size: var(--fs-meta);
  text-align: center;
  padding: var(--space-4) var(--space-2);
}
.jt-board .kanban-col.drag-over .kanban-col-empty {
  border-color: var(--accent);
  border-style: solid;
  color: var(--accent);
}

/* the rail: a measured 44px instead of 260px, reclaiming ~430px of board width
   (board scrollWidth 2708 → 2276 on the live board). Still a full drop target,
   still labelled, still counted. Vertical writing mode is the standard
   collapsed-column idiom (Jira / Trello) — it reads as "this column is folded",
   which is exactly what is true. */
.jt-board .kanban-col.is-rail {
  flex: 0 0 48px;
  min-width: 0;
  padding: 0;
  max-height: 240px;
  overflow: hidden;
}
.jt-board .kanban-col.is-rail .kanban-col-head {
  writing-mode: vertical-rl;      /* inline axis runs top→bottom: chip, then count */
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-2);
  height: 100%;
  padding: var(--space-3) var(--space-1);
  margin: 0;
  border-bottom: none;
  border-radius: var(--radius);
}
.jt-board .kanban-col.is-rail .kanban-col-empty { display: none; }
/* dragging over a folded column opens it, so the drop is never a blind gesture */
.jt-board .kanban-col.is-rail.drag-over { flex: 0 0 200px; max-height: max(300px, calc(100vh - 300px)); overflow-y: auto; }
.jt-board .kanban-col.is-rail.drag-over .kanban-col-head {
  writing-mode: horizontal-tb;
  height: auto;
  padding: var(--space-2);
  border-bottom: 1px solid var(--border);
  border-radius: var(--radius) var(--radius) 0 0;
}
.jt-board .kanban-col.is-rail.drag-over .kanban-col-empty { display: block; margin: var(--space-2) var(--space-2) 0; }
@media (prefers-reduced-motion: no-preference) {
  .jt-board .kanban-col { transition: flex-basis var(--t-fast) var(--ease); }
}


/* ─────────────────────────────────────────────────────────────────────────────
   §5  KANBAN CARD — three bands instead of one soup row.
   ─────────────────────────────────────────────────────────────────────────────
   MEASURED DEFECT: title 13px/700 vs meta 12.5px/400 — HALF A PIXEL of size
   separation between the headline and everything supporting it. Card 0 carried
   ten distinct fontSize/weight/colour combinations, all metadata lived in one
   undifferentiated flex-wrap row (so the client who owns the job read exactly
   like "Jul 16"), and card heights ran 104→204px.

   Bands: 1 WHAT (address + flags) · 2 WHO (client + crew) · 3 WHEN (dates,
   priority, price). Title is now var(--fs-body)/600 against var(--fs-meta)/400 —
   a real 2px + 200-weight step. */
.jt-board .kanban-card {
  padding: var(--space-2) var(--space-3);
  margin-bottom: var(--space-2);
  font-size: var(--fs-meta);
  line-height: var(--lh-snug);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);   /* the ONE rhythm between bands */
}
/* one bar + at most one tag row now, so the intrinsic-size guess drops with it */
.jt-board .kanban-card.cv-card { contain-intrinsic-size: auto 104px; }

/* band 1 — WHAT. Read this first. */
.jt-board .kanban-card .kc-head {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  min-width: 0;
}
.jt-board .kanban-card .kc-title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--fs-body);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  color: var(--text);
  letter-spacing: var(--ls-tight);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.jt-board .kanban-card .kc-flags {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
}
/* the aging / upsell / QC flags ride at the right edge of the title line and must
   never out-shout it — they are exceptions, not content */
.jt-board .kanban-card .kc-flags:empty { display: none; }

/* band 2 — WHO. The client owns the job; they get real ink. */
.jt-board .kanban-card .kc-who {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 0;
  min-height: 22px;   /* the avatar height — keeps band 3 at a constant offset */
}
.jt-board .kanban-card .kc-client {
  flex: 0 1 auto;
  min-width: 0;
  font-size: var(--fs-meta);
  font-weight: var(--fw-semibold);
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.jt-board .kanban-card .kc-who .avatar-stack { margin-left: auto; flex: 0 0 auto; }

/* band 3 — WHEN + HOW MUCH. Fixed order: shoot · due · priority · price. */
.jt-board .kanban-card .kc-facts {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  font-size: var(--fs-meta);
  color: var(--muted);
}
.jt-board .kanban-card .kc-fact { display: inline-flex; align-items: center; white-space: nowrap; }
.jt-board .kanban-card .kc-prio {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-weight: var(--fw-bold);
  white-space: nowrap;
}
.jt-board .kanban-card .kc-prio-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; flex: 0 0 auto; }
/* price is the one right-aligned figure, so a column of cards forms a money rail */
.jt-board .kanban-card .kc-price {
  margin-left: auto;
  color: var(--text);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.jt-board .kanban-card .kc-bar,
.jt-board .kanban-card .kc-tags { min-width: 0; }
.jt-board .kanban-card .kc-tags .tag-chips { max-width: 100%; }

/* the primary gesture on a card is DRAG. Lifting it 1px on hover and swapping in
   the biggest shadow in the system fights that — the card should look ready to be
   picked up, not already floating. */
.jt-board .kanban-card:hover {
  transform: none;
  box-shadow: var(--shadow);
  border-color: var(--border-strong);
}
.jt-board .kanban-card:focus-visible { box-shadow: var(--focus-ring); }

/* DARK MODE — measured: `.kanban-col` (--bg-2 #16202e) and `.kanban-card`
   (--panel #1a1d27) sit at a luminance ratio of 1.02:1, and the COLUMN is the
   lighter surface — so the light-mode "cards float on a tray" relationship is
   inverted and only the 1px --border holds a card together. Dropping the tray to
   --bg (#101722) puts it BELOW the card again (1.09:1) and restores the direction.
   Light mode is untouched and already reads correctly (#f6f6f4 page / #eef0f4
   tray / #ffffff card). */
html[data-theme="dark"] .jt-board .kanban-col { background: var(--bg); }
html[data-theme="dark"] .jt-board .kanban-col-head { background: var(--bg); }
html[data-theme="dark"] .jt-board .kanban-card { border-color: var(--border-strong); }


/* ─────────────────────────────────────────────────────────────────────────────
   §6  ONE STATUS, ONE COSTUME  —  INTENTIONALLY GLOBAL (2 surfaces).
   ─────────────────────────────────────────────────────────────────────────────
   MEASURED DEFECT: the same datum wore four costumes — an App.chip pill in the
   table group header, a 127×32px tinted native <select> in the row (90 form
   controls on one page at 45 rows), an App.chip pill in the kanban column head,
   and NOTHING on the kanban card. The loudest of the four was the least readable.

   `.cell-select` is created ONLY by tracker.js's statusCellSelect /
   priorityCellSelect (exported as App.statusCellSelect / App.priorityCellSelect),
   so this rule reaches exactly two surfaces: the Job Tracker and the Video
   Tracker. Both should look the same — that is the point of one system.

   It stays a <select>. It is NOT converted to a click-to-edit chip: that would
   route around statusCellSelect's must-fix-QC red gate (tracker.js:188–200),
   App.logActivity and App.deliveredMoment, and it would turn a one-gesture
   dropdown into two. tintSelect() already writes the status colour inline as
   background/border/ink, so the resting state now matches the App.chip in the
   group header above it pixel for pixel — and the row loses ~14px. */
/* SLEEK 08-12 — status becomes the row's single strongest color signal: a
   left-aligned, token-sized pill. This supersedes the 07-30 rationale above
   (which centered the control to match `.chip` pixel-for-pixel) — Fable's
   call is that left alignment scans faster down a column of pills. The tint
   itself (tintSelect's inline background/border/ink) is untouched; do NOT
   edit tintSelect/statusCellSelect/priorityCellSelect JS. Still shared with
   the Video Tracker via this same global .cell-select (see §6 above), which
   is the desired parity. SPECIFICITY NOTE: `select.select, select.input, …
   { padding-right: 30px }` (styles.css ~485, chevron clearance for the OTHER
   selects in the app) is `(0,1,1)` — one class ABOVE this rule's bare
   `.cell-select` `(0,1,0)`, so a same-shorthand `padding` here loses just the
   padding-right longhand regardless of source order, leaving a lopsided
   30px-right pill. Selector bumped to `select.cell-select` `(0,1,1)` to tie
   and win on source order (this rule is later in the file). */
select.cell-select {
  appearance: none;
  -webkit-appearance: none;
  background-image: none;
  border-radius: 999px;
  padding: 3px 12px;
  min-height: 0;
  height: auto;
  min-width: 0;
  width: auto;
  font-size: var(--fs-meta);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  letter-spacing: .1px;
  cursor: pointer;
  text-align: left;
}
/* appearance:none removes the native disclosure arrow — decided: no replacement
   chevron (tintSelect's inline `background` would clobber a background-image).
   The affordance is carried entirely by hover/focus below; it must be
   unmistakable. */
/* DESIGNA 2026-08-19 — the ring tokens alone measured 1.25:1 (hover) / 1.73:1 (focus)
   against the white panel: invisible, on the control whose own comment above demands an
   UNMISTAKABLE affordance. tintSelect writes background/border-color INLINE, so a CSS
   border change can never win here — outline can (nothing writes it inline). --accent on
   --panel = 6.62:1, and the 2px accent outline is this file's own :focus-visible idiom
   (see ~:3921). The soft rings stay underneath for the glow. */
.cell-select:hover { box-shadow: var(--focus-ring-soft); outline: 1px solid var(--accent); outline-offset: 1px; }
.cell-select:focus-visible { box-shadow: var(--focus-ring); outline: 2px solid var(--accent); outline-offset: 2px; }
/* the Big density preset stays roomy (its own font-size rule already wins) */
.jt-table-wrap.density-big .cell-select { padding: 6px 13px; }
/* SLEEK 08-12 — Compact tightens the pill to match the row's shrunken padding */
.jt-table-wrap.density-compact .cell-select { padding: 1px 9px; }
/* LAW-A 2026-08-15 (#24 follow-up, mobile only) — LIVE-VERIFIED at 375×812: this is the
   status control a crew member taps most (every row, both trackers), and it measured
   24px tall via getBoundingClientRect (min-height:0/height:auto above) — the worst
   tap-target gap found this pass, well under half the 44px floor. §I.4 of the plan
   names this control explicitly: stay a native <select> (unchanged — do NOT convert to
   a popover), just make it 44px tall. Scoped to phones only, same as the .btn/select
   fixes above — SLEEK 08-12's deliberate compact-pill density on desktop/tablet (mouse,
   not a finger) is untouched. NOTE (corrected DESIGNJ 2026-08-19): the claim that the
   density-preset overrides above "are also desktop-only in practice" was an ASSUMPTION,
   not an enforcement — see the rule below. */
@media (max-width: 640px) {
  select.cell-select { min-height: 44px; font-size: var(--fs-md); }   /* DESIGNA 2026-08-19 — was 12px (--fs-meta): iOS auto-zoomed on the most-tapped control in both trackers; ≥16px joins the anti-zoom law */
  /* DESIGNJ 2026-08-19 (judge pass on DESIGNA) — the rule above is (0,1,1) and LOSES to
     `.table-wrap.density-compact select` (:633) and `.table-wrap.density-big select` (:642),
     both (0,2,1). The ⚙ Display › Row size picker has NO width gate (tracker.js:4041,
     per-device localStorage), so a phone set to Compact measured 11px / min-height:0 /
     17.75px tall LIVE at 390×844 — iOS auto-zoom returns AND the LAW-A 44px floor collapses
     to under half. TAPFLOOR cannot see this: its sweep reblanks to zero data, so no row
     control exists to measure. (0,3,1) here outranks both regardless of order; scoped to
     .jt-table-wrap because tracker.js:4229 is the ONLY site that emits a density-* class
     and it always emits both, and it matches this file's own idiom at :7789/:7791.
     Phones only — desktop/tablet Compact and Big are byte-identical to before. */
  .jt-table-wrap.density-compact select.cell-select,
  .jt-table-wrap.density-big select.cell-select { min-height: 44px; font-size: var(--fs-md); }
}


/* ─────────────────────────────────────────────────────────────────────────────
   §7  URGENCY COLOUR  —  INTENTIONALLY GLOBAL (accessibility).
   ─────────────────────────────────────────────────────────────────────────────
   FOUR MEASURED AA FAILURES in light mode, all on the signals a PM must not miss:
     .due-today            #dc6803 @ 12.5px/700  →  3.49:1   (needs 4.5)
     .due-soon             #dc6803 @ 12.5px/400  →  3.49:1
     .age-badge.age-warm   #dc6803 on --warn-soft @ 10.5/700 →  3.34:1
     .age-badge.age-hot    #d92d20 on --danger-soft          →  4.44:1
     .due-overdue          4.83:1 on --panel but 4.38:1 on a status-tinted row

   Identical root cause in all five: they use the FILL tokens --warn / --danger as
   text ink. The repo already fixed exactly this for .chip.is-warn / .chip.is-danger
   (styles.css:620–622) by switching to --warn-ink / --danger-ink. This is that same
   one-line swap, nothing new.

   Left GLOBAL on purpose: scoping an AA fix to one view would leave the identical
   failure on every other surface that renders a due date. Dark mode is a no-op —
   --warn-ink / --danger-ink alias --warn / --danger under html[data-theme="dark"],
   and dark already measured 6.03–8.24:1. If the styles.css owner lands the same
   swap this pass, these three lines are a harmless duplicate; drop them then. */
.due-overdue, .overdue { color: var(--danger-ink); }
.due-today { color: var(--warn-ink); }
.due-soon { color: var(--warn-ink); font-weight: var(--fw-semibold); }   /* + a real 3-step ramp: soft → semibold → bold */
.age-badge.age-warm { color: var(--warn-ink); }
.age-badge.age-hot { color: var(--danger-ink); }


/* ══════════════════════════════════════════════════════════════════════════
   TRACKER-SLEEK 2026-08-12 — width fix (progressive column collapse) + look
   directives (Fable's spec, sections B-tiers / C / D). Builder scope: this
   file only. Pairs with the same-date tracker.js/core.js pass (row-level
   orderId removal, Priority+Package demoted out of the default column set —
   see App.getTrackerColumns' `_jtSlimCols0812` migration). Tokens only, no
   new custom properties, no !important.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── SLEEK 08-12 · PROGRESSIVE COLUMN COLLAPSE ────────────────────────────────
   Width-driven, VIEW-ONLY hiding by stable per-key class (D17(c) pattern, see the
   640px block below): the synced trackerColumns setting is never touched, the ⚙
   picker still governs the master set, and every hidden datum stays one row-click
   away in the job modal. Tiers use the 08-12 measured widths (pane = viewport −
   ~294px sidebar): default table ≈1311px after the Priority/Package demotion and
   the 300px address cap.
   VERIFIED 08-12 (closer, headless live measure, default columns / Cozy / no
   custom fields / no dragged widths — after the A5 caps, the ≤1179 280px address
   step and the .col-resize grip fix below): ZERO horizontal scroll at BOTH hard
   targets, Owner AND Editor — 1280 → 986/986, 1024 → 730/730; boundaries 1599 →
   1278/1278, 1440 → 1146/1146, 1179 → 885/885 all zero. Known, accepted gaps
   OUTSIDE the spec's hard target: 1680 → +44px and 1180 → +17px (the pane sits
   just above a tier boundary; the next tier's hides don't apply yet). */
@media (max-width: 1599px) {   /* pane < ~1306px: services + editor step out (5.5% / 0.6% filled all-time) */
  .jt-table-wrap .jt-col-services,
  .jt-table-wrap .jt-col-editor { display: none; }
}
@media (max-width: 1439px) {   /* pane < ~1146px: photographer + price step out */
  .jt-table-wrap .jt-col-photographer,
  .jt-table-wrap .jt-col-price { display: none; }
}
@media (max-width: 1179px) {   /* pane < ~886px (incl. 1024 laptops): payment + links + the "+ add column" cell step out; Due and its urgency ink stay to the last */
  .jt-table-wrap .jt-col-payment { display: none; }
  /* STAGE1-FIX 2026-08-14 (checker 2) — the Stage 1 `links` column ships ON by
     default now (tracker.js migrateLinksColumnOn), and it is the one column this
     progressive-collapse ladder never got a tier for, so it re-broke the 1024
     target this whole block exists to hold. MEASURED at 1024x800, Owner, default
     columns, Cozy, no dragged widths: links OFF -> 730/730 (0 overflow, matching
     the 08-12 verified number above); links ON -> 804/730 (+74px of side-scroll,
     the column itself measuring 87px). It steps out in THIS tier, beside payment,
     because it is the lowest-value glance column of the survivors — three icon
     links whose real home is the job modal (and whose targets open in a new tab
     from there), against Address/Client/Status/Shoot/Due which are the row's
     identity and its urgency. View-only, per-key class, synced trackerColumns
     untouched — same contract as every other line in this block. */
  .jt-table-wrap .jt-col-links { display: none; }
  .jt-table-wrap table.table thead th:last-child,
  .jt-table-wrap table.table tbody tr:not(.group-head) > td:last-child { display: none; }
  /* SLEEK 08-12 closer addendum (measured, not taste): even with A5's 300px cap the
     demo-shaped long addresses render cap-bound, and a 1024 laptop still measured
     741px of table against a 730px pane (+11px Owner — A5 paid back 60 of the 71px
     the checker found). One more address step inside THIS tier pays the remaining
     table width: the address is the spec's shrink-first column ("the shrink
     priorities … decide who gives way"), 280px stays far above the 90px text
     floor, and the id/tags already yield on hover. Delete this one line to give
     the address its 20px back if Vincent prefers a sliver of side-scroll on small
     laptops. (The final ~4px was never the table at all — see the .col-resize
     note below the C2/C3 rules.) */
  .jt-table-wrap .jt-addr { max-width: 280px; }
}
/* STAGE1-FIX 2026-08-14 (checker 2) — the OTHER hard target. Above the tier above,
   `links` stays visible (that is the point of shipping it), and it costs 81px the
   1280 pane does not have: MEASURED at 1280x900, Owner, default columns, a row
   carrying three links — links OFF 986/986 (the 08-12 verified number), links ON
   1004/986, +18px. Rather than hide the column at 1280 too — which would mean the
   Stage 1 feature renders on neither hard target — the 18px comes out of the same
   column the tier above already takes it from: the address, the spec's shrink-first
   column, 300px -> 282px, still 3x its 90px text floor and still ellipsised with the
   full value on the cell title and in the job modal. Conditioned on the links column
   actually being present, so a person who hides it via the ⚙ picker gets the full
   300px back; where :has() is unsupported the rule is simply dropped and the board
   degrades to today's +18px rather than to a wrong width. VERIFIED live: 986/986,
   zero, address 282, links 81. */
@media (min-width: 1180px) {
  .jt-table-wrap:has(.jt-col-links) .jt-addr { max-width: 282px; }
}

/* SLEEK 08-12 closer fix (measured DEFECT, width-independent, not taste): the
   CONSOL-3 column-resize grip is `right: -4px; width: 9px` — it deliberately
   straddles the column boundary. On the LAST visible resizable column those 4px
   poke past the table's right edge and become phantom scrollable overflow: at
   ≤1179 the "+ add column" cell (which has no grip) is display:none, so a
   resizable column IS last, and every snug pane measured a constant +4px
   (1024: 734 vs 730; 1179: 889 vs 885) even after the table itself fit exactly.
   Scoped to the tracker wrap only: pull the grip fully inside its column and move
   its hover hairline from right:4px to right:0 so the visible line still hugs the
   column edge exactly as before — same 9px grab, same look, zero phantom pixels.
   The generic .col-resize (styles.css ~626) and every other resizable table are
   untouched. */
.jt-table-wrap .col-resize { right: 0; }
.jt-table-wrap .col-resize::after { right: 0; }

/* SLEEK 08-12 — C2 header discipline: quiet uppercase micro-labels, the DATA is
   the ink, the header is the whisper. `.table th` (styles.css ~598) already sets
   text-align:left, font-size 11.5px, text-transform:uppercase, letter-spacing
   .4px and color:var(--muted) — already at/near the spec's target values. The
   one real delta is weight (currently the browser default ~400 via inherited
   normal); add only that. */
.jt-table-wrap table.table th { font-weight: var(--fw-semibold); }

/* SLEEK 08-12 — C3 kill vertical rules, keep the scan line: `.table td`/`th`
   (~598-604) already carry only a bottom hairline, no left/right border exists
   to override — this makes that contract explicit for this surface so a future
   generic-table border addition can't silently leak a vertical rule in here.
   The frozen column's own inset box-shadow (FROZEN block, td:nth-child(2)) is a
   separate, load-bearing rule — untouched. */
.jt-table-wrap table.table th, .jt-table-wrap table.table td { border-left: 0; border-right: 0; }


/* ─────────────────────────────────────────────────────────────────────────────
   §8  MOBILE (≤640px) — the board starts above the fold.
   ─────────────────────────────────────────────────────────────────────────────
   MEASURED DEFECT at 375×812: the board's top edge sat at y=601 — 74% of the
   first screen was chrome (view header, Save view, Active/All seg, search, three
   selects, Filters, a 4-up mode seg and New job, each on its own wrapped row)
   before a single job appeared. And there was no responsive rule for `.kanban` or
   `.kanban-col` anywhere in styles.css: the column stayed a hard 260px.

   Every control is KEPT — nothing is hidden on a small screen, the rows just
   become one horizontally-scrollable rail (Notion / Asana iOS pattern). */
@media (max-width: 640px) {
  .jt-view .view-header { margin-bottom: var(--space-3); padding-bottom: var(--space-2); }
  .jt-view .view-title { font-size: var(--fs-h1); }
  .jt-view .view-sub { margin-top: var(--space-1); font-size: var(--fs-meta); }

  .jt-view .toolbar,
  .jt-view .toolbar-more {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    margin-bottom: var(--space-2);
    padding-bottom: 2px;
  }
  .jt-view .toolbar::-webkit-scrollbar,
  .jt-view .toolbar-more::-webkit-scrollbar { display: none; }
  .jt-view .toolbar > *,
  .jt-view .toolbar-more > * { flex: 0 0 auto; }
  .jt-view .toolbar .spacer { display: none; }          /* a flex:1 spacer in a scroll rail is dead width */
  .jt-view .toolbar .search-input { min-width: 190px; }

  /* the next column peeks ~16% and the board snaps to it, so the swipe advertises
     itself instead of the column being cut off at an arbitrary pixel */
  .jt-board { scroll-snap-type: x mandatory; }
  .jt-board .kanban-col { flex: 0 0 84vw; scroll-snap-align: start; max-height: max(300px, calc(100vh - 250px)); }
  .jt-board .kanban-col.is-rail { flex: 0 0 48px; }
  .jt-board .kanban-col.is-rail.drag-over { flex: 0 0 84vw; }

  .jt-table-wrap { max-height: max(340px, calc(100vh - 240px)); }

  /* D17 — the table clipped mid-badge with no signal (measured: age/trend chips
     half-cut at the right edge). (a) the scroll-fade above now shows there's more;
     (b) the scroll advertises itself the same way .jt-board already does above;
     (c) un-crowd: the address column gets a floor so it never shrinks to the point
     the badge cluster crowds it out. (SLEEK 08-12, A3 — the order-id hash-chip
     hide that lived here was removed as dead CSS: A1 took the `.jt-order` node off
     the row app-wide, so there is nothing left to hide on a phone.) */
  /* STAGE1-FIX 2026-08-14 (checker 2) — THIS is the "D9 sticky column bleed" the
     design doc lists, and it is a snap bug, not a paint bug. The snapport's start edge
     was the wrap's own left, but the FROZEN gutter cell is pinned over the first 42px
     of it (`left: 0`, and the address is pinned at `left: 42px` — see the FROZEN
     IDENTITY COLUMN block), so `scroll-snap-align: start` parked the board 42px too far
     right and the Client column came to rest UNDERNEATH the frozen address.
     MEASURED at 375x812, Owner, default columns, resting (snapped) scroll position:
     scrollLeft 45.5, address cell [57,217], Client cell [175,297] -> 42px of Client
     hidden behind the address, so "Pamela Vidal" reads "ela Vidal" and the header
     "CLIENT" reads "NT". Note a getBoundingClientRect/hit-test check PASSES here — the
     frozen cell is correctly opaque and correctly on top; only a screenshot (or this
     left-edge arithmetic) shows the half-word. Insetting the snapport by the gutter's
     own 42px re-snaps to scrollLeft 3.5 and Client to [217,339] — 0px hidden, measured,
     with the freeze itself untouched. */
  .jt-table-wrap { scroll-snap-type: x proximity; scroll-padding-left: 42px; }
  .jt-table-wrap table.table thead th:nth-child(2),
  .jt-table-wrap table.table tbody tr:not(.group-head) > td:nth-child(2) { scroll-snap-align: start; min-width: 160px; }
  /* D17(c) — "collapse services/package columns behind Compact" for THIS app means
     hiding them, view-only, at this breakpoint: App.getTrackerColumns is a synced,
     cross-device user PREFERENCE (App.state.settings.trackerColumns) — writing a
     phone-only default into it would silently change what the same person sees on
     their desktop too. This hides by stable per-key class (jt-col-*, tracker.js
     rth/cell hooks), regardless of the user's own column order, without touching
     that setting. SLEEK 08-12 — `services` is now redundant here: the ≤1599px
     PROGRESSIVE COLLAPSE tier above (see TRACKER-SLEEK 08-12 block) already hides
     it well before this breakpoint, so that line was dropped rather than kept as
     dead CSS. `package` stays: it is out of the default column set (B2 demotion)
     but not locked — a user can re-add it via the ⚙ Display picker, and on a
     phone it should still hide even then. */
  .jt-table-wrap .jt-col-package { display: none; }

  /* ── TRACKER-FROZEN-PHONE 2026-08-13 — the frozen column ate the whole pane ──
     MEASURED DEFECT at 375×812 (headless, focus-emulated, Owner, default
     columns, long-address fixture): the pane is 345px and the two FROZEN cells
     pinned 346px of it. Clear pane: 1px. Scrolled fully right, ALL FOUR data
     columns — Client / Status / Shoot / Due — measured ZERO visible pixels: the
     screenshot at max scroll showed the single header "ADDRESS" and nothing
     else. So on a phone the horizontal scroll the FROZEN IDENTITY COLUMN block
     exists to make cheap bought you literally nothing — you could scroll, but
     the address you were keeping in view was the only thing there was room for.
     Pre-existing 07-30 geometry (the freeze), not caused by the 08-12 sleek
     round; the ≤1179 tier's 280px `.jt-addr` step is already in force here and
     is what makes the cell 304px rather than wider.

     max-width MEETS the min-width the rule above already declares, so the
     frozen address cell is now EXACTLY 160px on a phone at every density
     (measured 160/160/160 for compact/comfortable/big — capping the inner
     `.jt-addr` instead does NOT do this: the div→cell delta is cell padding,
     which is a density preset, so that route measured 160/160/168). The cap is
     on the CELL for that reason, and it lands on 160 rather than a taste value
     because below 160 the min-width above simply wins and nothing changes.
     Clear pane goes 1px → 152/144/136px, which fits the widest data column at
     compact and comfortable. Address text keeps its 90px floor and still
     ellipsises; the full value stays on the cell's title ("address · Order
     <id>") and in the job modal, exactly as the uncapped cell did.

     overflow:hidden is LOAD-BEARING, not tidiness. `.jt-addr > *` is
     `flex: 0 0 auto`, so nothing in the badge cluster can shrink, and
     App.qcStateChip (qc.js) is a whole sentence in a chip — "⚠ shipped past a
     pending review — reason on file", measured 274px. That chip ALREADY
     overflowed the uncapped cell by 137px and, the cell being sticky and
     z-index 2, painted straight over the data columns (confirmed by hit-test,
     not by rect arithmetic — getBoundingClientRect reports layout and cannot
     see clipping). Capping the cell without clipping it would have taken that
     to 289px. Measured after: 10-19 rows still overflow in LAYOUT, zero paint
     over the data at any density. Cost: on a phone the trend/aging chips can be
     clipped where they used to spill — they remain in the job modal, and the
     tags were already the designated yield-first element here.

     KNOWN, ACCEPTED GAP (measured, stated rather than hidden): at `big` density
     the Client cell is 141px against a 136px clear pane, so ~5px of it can sit
     under the frozen edge at the extreme scroll position. 160px cannot be
     tightened to close it — the min-width above is the floor, and lowering that
     would push the address text under its 90px floor and clip the aging chip
     outright. compact and comfortable (the default) have 14-22px of margin. */
  .jt-table-wrap table.table thead th:nth-child(2),
  .jt-table-wrap table.table tbody tr:not(.group-head) > td:nth-child(2) { max-width: 160px; overflow: hidden; }

  /* ── TRACKER-PHONE-BADGES 2026-08-13 — the clip above cut chips mid-glyph ───
     The block directly above is right that the clip is load-bearing, and it
     stays. This is the other half of it: a HARD CLIP has no opinion about WHERE
     it lands, so on a phone it landed inside a chip.

     MEASURED BEFORE, 375x812 headless (focus-emulated, Owner, default columns,
     density-comfortable, first-run welcome dismissed), worst-case row = long
     unit-bearing LA address + stale statusSince + growth plays + an open-red
     delivery + qcOverride + 3 tags. `.jt-addr` content 370px in a 136px box:
         .jt-addr-text  90px (its floor)  → 90px drawn, ellipsised   ✓
         aging chip "24d"      34px       → 34px drawn                ✓
         growth chip "GRAPH 6" 37px       → *** 2px drawn ***         ✗
         delivered-open-red   179px       → 0px
         qc override chip     274px       → 0px  (the 274px sentence)
         tag chips              -         → 0px
     That 2px is the defect: a 2px vertical slice of a rounded pill, sitting at
     the frozen edge, reading as damage rather than as truncation. Note what the
     rest of the column says — at 375px the cell has ~38px of slack after the
     address's 90px floor, and the cluster wants 524px. Four of the six items
     were ALREADY invisible before this block; only the boundary item was cut.

     WHY NOT `min-width: 0` + ellipsis (the obvious fix, measured and rejected).
     Flexbox shrinks proportionally to base-size, so handing the cluster 38px of
     space for 524px of content shrinks EVERYTHING to ~7%. Measured, same row:
     the aging chip went 34px -> 14px (i.e. the one chip that reads correctly
     today became a cut chip), growth 37 -> 12, delivered 179 -> 12, qc -> 0.
     Six sub-20px stubs instead of one 2px stub is a worse picture, not a
     better one, and `text-overflow: ellipsis` cannot rescue it: `.chip` and
     `.age-badge` are `display: inline-flex`, and ellipsis does not apply to a
     flex container's content. Ordered shrink (escalating `flex-shrink` down the
     cluster) measured identically — it also has to eat the aging chip before it
     reaches the two chips that actually overflow.

     WHAT THIS DOES INSTEAD — all-or-nothing, by DOM order. `.jt-addr` wraps, and
     the wrapped line is pushed 100px down and clipped away. A flag therefore
     either fits on line 1 and is drawn WHOLE, or it is not drawn at all; there
     is no state in which part of one is on screen. The yield order falls out of
     the existing DOM order (aging, growth, open-red, qc, tags) with no new
     classes and no JS change, and it already agrees with the block above: tags
     yield first. `flex-basis: 90px` on the text is what makes this adaptive —
     flex breaks lines on UNFLEXED sizes, so with the default `auto` basis a
     465px address claims line 1 by itself and every flag wraps away even when
     one would have fitted (measured: that variant lost the aging chip too).
     Pinning the basis to the floor the rule already declares lets the flags
     compete for the real remainder, and the text still GROWS into whatever the
     flags leave (`flex-grow: 1` is untouched).

     `padding-right: 0` is not cosmetic. `overflow: hidden` clips at the cell's
     PADDING box, so content already paints through that 12px and is cut at
     160px — the right padding was never a barrier, it only made flex break
     lines 12px earlier than the clip actually falls. Zeroing it aligns the two,
     which is exactly what buys the aging chip its place at every density.

     MEASURED AFTER, same row: address 100px (was 90 — the flags' dead space
     goes back to the address), aging chip 34px WHOLE, everything else 0px.
     Partially-drawn flags: 0 at compact, comfortable AND big (was 2/2/0). Row
     heights unchanged: 23/41/65 across the three densities.

     THE ONE MAGIC NUMBER, swept rather than guessed. `max-height` has to clear
     line 1 (or the clip cuts a horizontal BAND off the chips — the same defect
     rotated 90 degrees) and stay under the row's content box (or rows grow and
     the UI-BOARD 07-30 density contract breaks). Measured pass windows:
         compact      17-20px   (16 clips 0.8px; 21 grows rows 23 -> 24)
         comfortable  21-24px   (20 clips 1px;   25 grows rows 41 -> 42)
         big          23-33px   (22 clips 0.4px; row has 33px of content box)
     There is no value common to all three, so it is per density, each picked
     two off its floor. The 100px row-gap means the upper end is only ever about
     row height — no value in these windows can leak a sliver of line 2. Both
     bounds are asserted in tests/suite.js (FROZEN-PHONE-BADGES 2026-08-13), so
     a future token change that moves a line box fails loudly instead of
     quietly cutting chips again.

     ACCEPTED COST, stated not hidden: on a phone a row with an open QC override
     or an open-red delivery now looks exactly like a clean row in this cell.
     That is NOT a regression — both chips measured 0 visible px before this
     block too — but it is not a fix either. Both remain one tap away in the job
     modal (tracker.js field('Status', ... App.qcStateChip)), which is where the
     block above already sends them. The invariant that block establishes is
     untouched and re-hit-tested here: nothing from the frozen cell paints over
     the data columns. */
  .jt-table-wrap table.table tbody tr:not(.group-head) > td:nth-child(2) { padding-right: 0; }
  .jt-table-wrap .jt-addr { flex-wrap: wrap; align-content: flex-start; row-gap: 100px; max-height: 23px; overflow: hidden; }
  .jt-table-wrap.density-compact .jt-addr { max-height: 19px; }
  .jt-table-wrap.density-big .jt-addr { max-height: 25px; }
  .jt-table-wrap .jt-addr-text { flex-basis: 90px; }
}


/* ##########################################################################
   TASKS — surface restyle (tasks.js). scratchpad/css-tasks.css
   Merged by the INTEGRATOR pass, 2026-07-30. Source: builder scratch file.
   ########################################################################## */
/* ============================================================================
   TASKS — surface restyle · 07-30
   Ships with the tasks.js changes of the same date. tasks.js references every
   .tk-* class below, so the two MUST land in the same pass — until this block
   is merged the board renders unstyled-but-functional.

   NO new CSS variables. Every value is an existing design token, so both themes
   are covered by the html[data-theme="dark"] overrides already in :root.

   SCOPING NOTE — the Tasks board reuses the app-wide .kanban / .kanban-col /
   .kanban-card / .toolbar classes, which leads.js, tracker.js and
   postpipeline.js also use. Every rule here is therefore gated behind a
   Tasks-only ancestor or companion class (.tk-board, .tk-cards-zone, .tk-zone,
   .tk-card, .tk-toolbar) so NOTHING leaks onto the other boards.

   INTEGRATOR NOTE (out of my file ownership, do not silently skip):
   styles.css:653 `.kanban-card.cv-card { contain-intrinsic-size: auto 140px }`.
   Tasks cards do NOT carry .cv-card (only tracker.js adds it), so this pass does
   not invalidate that estimate — no change needed. Flagged only so the next
   reader does not re-derive it.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   1 · DUE-BUCKET GROUP HEADERS
   The urgency colour lives HERE, on one header, instead of on every row
   (Jobber). Only .is-late is inked; every other bucket is quiet --muted.
   A plain div, not a heading — it must not inject a level into the view's
   h1 -> h2 outline.
   --------------------------------------------------------------------------- */
.tk-bucket-head {
  display: flex; align-items: center; gap: var(--space-2);
  font-size: var(--fs-micro); font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label); text-transform: uppercase;
  color: var(--muted);
  padding: var(--space-3) 2px var(--space-1);
}
.tk-bucket-head:first-child { padding-top: var(--space-1); }
.tk-bucket-label { flex: 1 1 auto; min-width: 0; }
.tk-bucket-count {
  flex: 0 0 auto; letter-spacing: var(--ls-body); font-weight: var(--fw-semibold);
  font-variant-numeric: tabular-nums; color: var(--faint);
}
.tk-bucket-head.is-late { color: var(--danger-ink); }
.tk-bucket-head.is-late .tk-bucket-count { color: var(--danger-ink); opacity: .85; }

/* Cards mode: the header spans the full grid width above its own sub-grid */
.tk-cards-zone .tk-bucket-head { padding: var(--space-5) 2px var(--space-2); }
.tk-cards-zone .tk-bucket-head:first-child { padding-top: 0; }

/* ---------------------------------------------------------------------------
   2 · COLUMNS — no panel fill; the head rule + bucket headers carry structure
   In dark this also removes the measured 1.02:1 card-vs-column collapse at its
   source (both were near-identical dark greys).
   --------------------------------------------------------------------------- */
.tk-board .kanban-col {
  background: transparent;
  border-radius: 0;
  padding: 0 var(--space-1) 0 0;
  flex: 0 0 300px;   /* was 260px — holds the 14px title on two lines, not three */
}
.tk-board .kanban-col-head {
  border-bottom: 1px solid var(--border);
  padding: 2px 2px var(--space-2);
  margin-bottom: 2px;
}
/* the drop target must keep its resting silhouette back while dragging — a
   transparent column has none, so restate it at higher specificity than the
   transparent rule above (both are two-class selectors; order alone is fragile) */
.tk-board .kanban-col.drag-over {
  background: var(--accent-soft);
  border-radius: var(--radius);
  outline: 2px dashed var(--accent);
  outline-offset: -2px;
  padding: 0 var(--space-1);
}

/* empty column / overflow lines — ONE empty voice on this surface (was three) */
.tk-col-empty {
  font-size: var(--fs-meta); color: var(--faint);
  text-align: center; padding: var(--space-4) 0;
}
.tk-col-more {
  font-size: var(--fs-meta); color: var(--muted);
  text-align: center; padding: var(--space-2) 0 0;
}

/* ---------------------------------------------------------------------------
   3 · THE CARD — flex row: tick + a min-width:0 content column
   (a grid pushed the title below the tick's baseline at narrow widths)
   --------------------------------------------------------------------------- */
.kanban-card.tk-card {
  position: relative;
  border-color: var(--border-strong);   /* dark edge definition 1.23:1 -> 1.76:1 */
  padding: var(--space-3) var(--space-3) 11px;
}
.kanban-card.tk-card:focus-visible {
  outline: 2px solid var(--accent); outline-offset: var(--focus-offset);
}
.tk-row { display: flex; align-items: flex-start; gap: var(--space-3); }
.tk-body { flex: 1 1 auto; min-width: 0; }

/* the title is finally its own type step: +1px over the column head, +1.5px
   over card body, and no longer forced to win on weight alone */
.kanban-card.tk-card .kc-title {
  font-size: var(--fs-body);
  font-weight: var(--fw-semibold);
  line-height: var(--lh-snug);
  color: var(--text);
  margin-bottom: 2px;
  padding-right: 20px;   /* clears the absolutely-positioned bulk checkbox */
}

/* ---------------------------------------------------------------------------
   4 · THE LEADING TICK — completes the task (same meaning as Today's checkbox)
   19px visually, 33px hit area via the ::before overlay so the real target
   clears comfortably without changing the card's layout metrics.
   --------------------------------------------------------------------------- */
.tk-tick {
  position: relative; flex: 0 0 auto;
  width: 19px; height: 19px; margin-top: 1px; padding: 0;
  border: 1.5px solid var(--border-strong); border-radius: 999px;
  background: transparent; color: transparent;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease);
}
.tk-tick::before { content: ''; position: absolute; inset: -7px; border-radius: 999px; }
.tk-tick svg { width: 12px; height: 12px; }
.tk-tick:hover:not(:disabled),
.tk-tick:focus-visible { border-color: var(--ok); color: var(--ok); }
.tk-tick:focus-visible { outline: 2px solid var(--accent); outline-offset: var(--focus-offset); }
.tk-tick:disabled { cursor: default; }

/* ---------------------------------------------------------------------------
   5 · DONE CARDS RECEDE — a FILLED tick instead of a strikethrough.
   Strikethrough + dimming double-encodes and costs legibility; a filled marker
   is what Attio/Linear use. Measured: done title 6.32:1 light / 6.00:1 dark.
   --------------------------------------------------------------------------- */
.kanban-card.tk-card.is-done {
  background: var(--subtle);
  box-shadow: none;
  border-color: var(--border);
}
.kanban-card.tk-card.is-done:hover { box-shadow: var(--shadow-sm); }
.kanban-card.tk-card.is-done .kc-title {
  color: var(--muted); font-weight: var(--fw-medium);
}
/* --on-danger is this design system's ONLY "ink that sits on a saturated fill"
   token, and it flips correctly for this use (#fff on light --ok #079455;
   #2a0a08 on dark --ok #3ccb7f). Named for its first caller, not its scope. */
.kanban-card.tk-card.is-done .tk-tick {
  border-color: var(--ok); background: var(--ok); color: var(--on-danger);
}

/* ---------------------------------------------------------------------------
   6 · META ROW — assignee avatar, monochrome kind glyph, three-tier due
   --------------------------------------------------------------------------- */
.tk-asg {
  display: inline-flex; align-items: center; gap: 5px; min-width: 0;
  font-size: 11.5px; color: var(--muted);
}
.tk-asg .avatar { flex: 0 0 auto; }
.tk-asg.is-unassigned { opacity: .65; }

.tk-kind { display: inline-flex; align-items: center; color: var(--faint); }
.tk-kind svg { width: 13px; height: 13px; }

.tk-due {
  display: inline-flex; align-items: center; gap: var(--space-1);
  font-size: 11.5px; color: var(--muted);
}
/* --danger-ink / --warn-ink are the TEXT reds/ambers per the token comments
   (--danger / --warn stay fill+stroke). Measured on the card in light:
   4.83:1 -> 6.57:1 late, 5.43:1 today. Scoped classes, so the GLOBAL `.overdue`
   rule (shared with .pl-next.overdue and .tss-pulse-cell.overdue) is untouched. */
.tk-due.is-late { color: var(--danger-ink); font-weight: var(--fw-bold); }
.tk-due.is-today { color: var(--warn-ink); font-weight: var(--fw-bold); }

/* ---------------------------------------------------------------------------
   7 · JOB / CLIENT LINK — street only, quiet until hovered
   --------------------------------------------------------------------------- */
.kanban-card.tk-card .task-link {
  display: flex; align-items: center; gap: 5px;
  margin-top: 7px; font-size: 11.5px;
  color: var(--muted); text-decoration: none;
  transition: color var(--t-fast) var(--ease);
}
.kanban-card.tk-card .task-link .tk-link-text {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.kanban-card.tk-card .task-link:hover { color: var(--accent); text-decoration: underline; }
.kanban-card.tk-card .task-link:focus-visible {
  outline: 2px solid var(--accent); outline-offset: var(--focus-offset);
  border-radius: var(--radius-sm);
}

/* the one-tap auto-task action, demoted off btn-primary in tasks.js */
.kanban-card.tk-card .tk-action { font-size: var(--fs-micro); padding: 5px 10px; }

/* ---------------------------------------------------------------------------
   8 · BULK SELECT MOVES TO HOVER (Linear) so it stops competing with the tick
   Kept permanently visible on TOUCH (no hover state exists there) and whenever
   a selection is already active — losing bulk-select on mobile would be a
   regression, not a simplification.
   --------------------------------------------------------------------------- */
.kanban-card.tk-card .kc-sel {
  position: absolute; top: var(--space-2); right: var(--space-3);
  float: none; margin: 0; z-index: 1;
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease);
}
.kanban-card.tk-card:hover .kc-sel,
.kanban-card.tk-card:focus-within .kc-sel,
.kanban-card.tk-card .kc-sel:focus-visible,
.kanban-card.tk-card .kc-sel:checked,
.tk-zone.has-sel .kanban-card.tk-card .kc-sel { opacity: 1; }
/* D16 — on a touch device wider than 640px (iPad etc.) there's room for both the
   tick and the select box to read as distinct controls, so the old "always visible
   on touch" behavior stays. ≤640px is the phone case the audit flagged: two
   identical empty squares. There the select box stays hidden until selection mode
   starts (first long-press — tasks.js — or a selection already active), matching
   the desktop hover-to-reveal behavior instead of showing both at rest. */
@media (hover: none) and (min-width: 641px) {
  .kanban-card.tk-card .kc-sel { opacity: 1; }
}

/* ---------------------------------------------------------------------------
   9 · TOOLBAR WIDTH CAPS (moved off inline styles in tasks.js so the mobile
   rule below can actually release them)
   --------------------------------------------------------------------------- */
.toolbar.tk-toolbar .tk-sel { max-width: 190px; }

/* ---------------------------------------------------------------------------
   10 · MOBILE — one-line toolbar, one column per swipe
   Measured on the prototype at 375x812: toolbar 191px -> 52px,
   first-card-top 463px -> 351px.
   --------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .toolbar.tk-toolbar {
    flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .toolbar.tk-toolbar::-webkit-scrollbar { display: none; }
  .toolbar.tk-toolbar > * { flex: 0 0 auto; }
  /* the "Assignee / Status / Tag" text labels are redundant with each select's
     own visible value; tasks.js gives every select an aria-label + title so the
     accessible name survives them being hidden */
  .toolbar.tk-toolbar > .tk-fl { display: none; }
  .toolbar.tk-toolbar .spacer { display: none; }
  .toolbar.tk-toolbar .tk-sel { max-width: none; }

  .tk-board { scroll-snap-type: x mandatory; }
  .tk-board .kanban-col { flex: 0 0 88%; scroll-snap-align: start; }
}

/* ---------------------------------------------------------------------------
   11 · MOTION GUARD
   (the existing styles.css:2634 reduced-motion rule already covers .kanban-card
   itself; these are the elements this pass added)
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .tk-tick,
  .kanban-card.tk-card .kc-sel,
  .kanban-card.tk-card .task-link { transition: none; }
}
/* ===================== end TASKS restyle 07-30 ===================== */


/* ##########################################################################
   CALENDAR / SCHEDULE — visual pass (calendar.js). scratchpad/css-calendar.css
   Merged by the INTEGRATOR pass, 2026-07-30. Source: builder scratch file.
   ########################################################################## */
/* ============================================================================
   CALENDAR / SCHEDULE — visual pass, 07-30                 (calendar.js only)
   ----------------------------------------------------------------------------
   NO NEW CSS VARIABLES. Every value below is an existing design token, so this
   block themes itself through the html[data-theme="dark"] overrides already in
   :root. No raw hex, no !important, no new colour system.

   READ THIS FIRST — WHY EVERY SELECTOR STARTS WITH `.calview`:
   `.cal-grid`, `.cal-cell`, `.cal-dow` and `.cal-more` are each declared TWICE
   in styles.css — once in the Calendar block (~1010) and again, LATER and
   therefore winning, in the SPEC223 Tasks-view calendar block (~4299, owned by
   core.js). Measured proof of the collision on the live DOM: this view's
   `.cal-cell` computed to border-radius 8px (the Tasks value) instead of
   var(--radius-sm)=7px, and padding 5px instead of 5px 6px. So a rule written
   into the Calendar block for `.cal-cell` was silently overridden, and any
   change made there bled into the Tasks calendar.
   calendar.js's render() now wraps the whole surface in `.calview`, and every
   rule here is `.calview .cal-*` — specificity (0,2,0) beats the Tasks block's
   (0,1,0) regardless of source order, and nothing leaks the other way.
   Nothing here touches schedule.js's board either: `.sched-off` / `.sched-busy`
   are retuned only INSIDE `.calview`.

   ONE IDIOM WORTH NAMING: the filled "today" date pill uses `var(--bg)` as its
   ink on a `var(--accent)` fill. --chip-ink is exactly backwards for this job
   (light theme = near-black ink on a DARK accent; dark theme = white ink on a
   LIGHT accent — both fail). --bg is guaranteed to sit on the opposite side of
   --accent in both themes: measured 6.12:1 in light (#f6f6f4 on #2b608f) and
   5.36:1 in dark (#101722 on #5f92b4). Both clear AA.
   ========================================================================= */

/* ---- grid + cells --------------------------------------------------------
   The single worst measured defect on this surface lived here: `.cal-cell`
   was max-height:150px / overflow-y:auto while each chip carried an inline
   min-height:44px. On a 6-shoot Thursday that clipped 41px — the operator saw
   3 shoots and the "+3 more" row that exists to announce the other 3 sat at
   top=167px inside a 148px box, i.e. BELOW THE FOLD, and macOS overlay
   scrollbars gave no visual cue at all. 6 of 35 cells overflowed this way.
   The cell no longer scrolls; the chip is one line; four fit. */
.calview .cal-grid { align-items: start; }
.calview .cal-cell {
  min-height: 104px;
  max-height: none;
  overflow: visible;                    /* also stops clipping a chip's focus ring */
  /* REQUIRED, not cosmetic. A grid item's automatic minimum size is min-content, and
     that only stops applying when the item's overflow is NOT visible — so the old
     `overflow-y:auto` was the ONLY thing keeping these columns equal. Restoring
     `overflow:visible` without this made the seven 1fr columns resolve to
     201/151/172/222/173/209/198px and pushed 213px of horizontal overflow onto #main. */
  min-width: 0;
  border-radius: var(--radius-sm);
  padding: var(--space-1) 6px 5px;
  gap: 2px;
}
.calview .cal-dow > div { min-width: 0; }

/* Out-of-month cells: recede via SURFACE, not via opacity on the whole cell.
   The old `opacity:.6` dimmed the day number below AA, and would have compounded
   with the new `.past` chip dim (.6 x .6 = .36). Split so neither stacks. */
.calview .cal-cell.other-month { opacity: 1; background: var(--subtle); }
.calview .cal-cell.other-month .cal-daynum { color: var(--faint); }

/* Let the past recede. Measured before: all 27 week chips carried IDENTICAL
   weight (11px / 600 / 13.3% tint / 3px stripe), so a shoot completed 24 days
   ago read exactly as loudly as one happening tomorrow — nine hues at one alpha
   were carrying 100% of the differentiation. Dim the CHIPS only, never the
   cell, so day numbers stay AA. Future days are deliberately untouched. */
.calview .cal-cell.past .cal-event,
.calview .cal-cell.other-month .cal-event { opacity: .6; }

/* --fw-semibold, not --fw-bold: 34 day numbers at 700 were a third of the whole
   surface's bold count (measured 98 elements at 700 across the calendar subtree —
   when nearly everything is bold, nothing is). Today's number is the one that
   escalates, to --fw-black inside its accent pill below. */
.calview .cal-daynum {
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  color: var(--muted);
  line-height: var(--lh-tight);
  letter-spacing: 0;
}

/* ---- weekday header ------------------------------------------------------ */
.calview .cal-dow {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
  margin-bottom: var(--space-1);
  padding: 0;
}
.calview .cal-dow > div {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 5px;
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  color: var(--faint);
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  text-align: center;
  padding: 2px 0 4px;
}
/* the per-day load figure (ClickUp / Fresha). Rendered only when > 0 — a "0" in
   every empty column is noise, and the empty cell below already says it. */
.calview .cal-dowcount {
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  color: var(--muted);
  letter-spacing: 0;
  text-transform: none;
  font-variant-numeric: tabular-nums;
}

/* ---- TODAY ---------------------------------------------------------------
   Measured before: today's cell and a random past cell had IDENTICAL background
   (#fff) and IDENTICAL border colour (#e4e7ec); today's weekday HEADER cell was
   11px/700/--faint — exactly the same as the other six. The only two deltas in
   the whole 35-cell grid were a 2px outline and the day number's colour, and the
   eye landed on a red "Stuck" chip long before it found today. Now: accent
   header + tinted surface + a filled date pill, and the ring gets QUIETER
   because it no longer has to do the work alone. */
.calview .cal-dow > div.today { color: var(--accent); font-weight: var(--fw-black); }
.calview .cal-dow > div.today .cal-dowcount { color: var(--accent); }
.calview .cal-cell.today {
  background: var(--accent-soft);
  outline: 1.5px solid var(--accent);
  outline-offset: -1.5px;
}
/* the pill is a MONTH affordance; in Week the tinted column + accent header
   carry it, and the week cell's day label is a full "Thu Jul 30" agenda header
   that a 20px circle would mangle. */
.calview .cal-cell:not(.cal-cell-week).today .cal-daynum {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--accent);
  color: var(--bg);            /* see the contrast note in the banner */
  font-size: var(--fs-micro);
  font-weight: var(--fw-black);
}
/* Craft's phrasing — the day header stays plain and only the word "Today" is
   accented. Cheapest possible today-emphasis for an agenda row. */
.calview .cal-today-tag { color: var(--accent); font-weight: var(--fw-black); }

/* ---- the shoot chip, density 1 of 2: MONTH ------------------------------
   `● 8a  1420 Coldwater Canyon Dr` on one ~18px line. No fill, no left edge, no
   44px floor — the touch target is the cell, which is already role=button via
   App.rowActivate and is >=104px tall. This is what turns 3-visible-of-6 into
   4-visible plus an always-visible "+2 more". */
.calview .cal-event--dense {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 0;
  padding: 1px 3px;
  border-left: 0;
  background: transparent;
  border-radius: 4px;
  line-height: var(--lh-snug);
  white-space: nowrap;
}
/* a transparent chip has nothing for brightness() to act on, so the hover
   feedback becomes a surface change. No transition, no lift, no shadow — and
   therefore nothing that needs a prefers-reduced-motion guard. */
.calview .cal-event--dense:hover { filter: none; background: var(--hover); }
.calview .cal-ev-dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  flex: 0 0 auto;
}
.calview .cal-event--dense .cal-ev-time {
  flex: 0 0 auto;
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.calview .cal-event--dense .cal-ev-street {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  color: var(--text);
}

/* ---- the shoot chip, density 2 of 2: WEEK / DAY COLUMNS ------------------
   Tinted body + solid status edge (the Rise posture). Two lines, because one
   line measurably could not do it: 27 of 27 week chips truncated, the widest at
   376px of label inside a 102px column, and the photographer name the old
   `withWho` concatenated was NEVER once visible at any viewport. Line 1 carries
   the clock, the weather and the crew AVATAR; line 2 gets the full street on up
   to two lines instead of one ellipsed sliver. */
.calview .cal-event:not(.cal-event--dense) {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-height: 34px;
  padding: 3px 7px 4px;
  border-radius: 6px;
  white-space: normal;
  text-overflow: clip;
}
.calview .cal-ev-top {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 15px;
}
.calview .cal-ev-top .cal-ev-time {
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.calview .cal-ev-av { flex: 0 0 auto; margin-left: auto; }
.calview .cal-event:not(.cal-event--dense) .cal-ev-street {
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  color: var(--text);
  line-height: var(--lh-snug);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ---- "+N more" -----------------------------------------------------------
   margin-top:auto pins it to the bottom of a cell that no longer scrolls, so the
   one row announcing the hidden shoots is always the last VISIBLE line. */
.calview .cal-more {
  margin-top: auto;
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  color: var(--muted);
  padding: 2px 3px 0;
  letter-spacing: 0;
  background: transparent;
  border-radius: 4px;
}
.calview .cal-more:hover,
.calview .cal-more:focus-visible { color: var(--accent); background: transparent; }

/* ---- weather chip (SPEC21 §C) — token sizes, unchanged behaviour --------- */
.calview .cal-wx {
  margin-left: 0;
  font-size: var(--fs-micro);
  font-weight: var(--fw-bold);
  color: var(--muted);
}
.calview .cal-event .cal-wx { color: var(--muted); opacity: 1; }

/* ---- WEEK ----------------------------------------------------------------
   Measured before: all 7 columns were exactly 370px tall regardless of content,
   because `max-height:420px` + a stretch grid let Wednesday's 7 shoots set the
   row height — Sunday held ONE shoot in 370px, ~300px of it empty white. With
   `align-items:start` on the grid each column is now as tall as its own day. */
.calview .cal-cell-week {
  min-height: 120px;
  max-height: none;
  padding: 6px;
  gap: 3px;
}
/* The header cell one row up already says "MON 27", so this in-cell label was a
   duplicated 17px line x 7. Hidden above 700px EXCEPT on the 1st — the month
   boundary a Jul 27 – Aug 2 week genuinely needs — and shown at every width
   below, where it becomes the stacked agenda's day header. */
.calview .cal-cell-week > .cal-daynum { display: none; }
.calview .cal-cell-week > .cal-daynum.is-first {
  display: block;
  color: var(--text);
  font-weight: var(--fw-black);
}

/* ---- blocked time: DEMOTED below the work it constrains ------------------
   Measured before: `.sched-off` was 11px / 700 / colour --ok on --ok-soft with a
   dashed --ok border, while every actual shoot was 600 at a 13% tint. So
   "Jeffrey off" outranked every real job on the board, and in dark mode it was
   the single brightest element on screen. --ok is the semantic SUCCESS colour; a
   teammate being unavailable is a CONSTRAINT, not a success. Retuned INSIDE
   .calview only — schedule.js's own board keeps its existing treatment. */
.calview .sched-off {
  align-self: flex-start;
  max-width: 100%;
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  color: var(--muted);
  background: var(--subtle);
  border: 1px dashed var(--border);
  border-radius: 5px;
  padding: 2px 6px;
  margin-bottom: 0;
}
/* `white-space:nowrap` ellipsed "Vincent: 12p–1p Dentist" down to "12p–…" in a
   102px column — the label was 100% chrome and 0% information. It wraps now. */
.calview .sched-busy {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
  display: flex;
  align-items: flex-start;
  gap: 3px;
  font-size: var(--fs-micro);
  line-height: var(--lh-snug);
  margin-bottom: 0;
}
.calview .sched-busy svg { flex: 0 0 auto; margin-top: 2px; }

/* ---- DAY view: the time gutter it never had -----------------------------
   The one mode with unlimited width was the only mode showing no clock value at
   all. Fixed 62px right-aligned gutter (Outlook iOS / Binance), then a status
   dot, then address + crew. The em-dash here is the HONEST case: it means the
   job genuinely has neither a shoot time nor an arrival window. */
.calview .cal-dayrow {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: 10px 4px;
}
.calview .cal-daytime {
  flex: 0 0 62px;
  text-align: right;
  font-size: var(--fs-caption);
  font-weight: var(--fw-bold);
  color: var(--text);
  line-height: var(--lh-snug);
  font-variant-numeric: tabular-nums;
}
.calview .cal-daytime--none { color: var(--faint); font-weight: var(--fw-semibold); }
.calview .cal-dayedge { width: 8px; height: 8px; }
.calview .cal-dayaddr {
  font-size: var(--fs-body);
  font-weight: var(--fw-semibold);
  color: var(--text);
  line-height: var(--lh-snug);
}
/* the '📷 Vincent  ·  ✂ Ava' emoji sub-line becomes the same avatar the rest of
   the app uses for a teammate (SPEC208 line-icon posture). */
.calview .cal-daywho {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 5px;
  margin-top: 4px;
  font-size: var(--fs-meta);
  font-weight: var(--fw-medium);
  color: var(--muted);
}
.calview .cal-daywho .avatar { flex: 0 0 auto; }
.calview .cal-daywho .avatar + span { margin-right: 6px; }

/* ---- PER-PERSON lanes (admin Week/Day) -----------------------------------
   These were inline style objects in calendar.js, which is precisely why a lane
   could not respond to the viewport: measured lane heights of 92 / 92 / 103 /
   179 / 197px for 1 / 2 / 4 / 11 / 12 chips, with a hard 180px floor under a
   one-shoot lane. The gutter also showed a colour bar plus a dot in the SAME
   colour — redundant — and carried no load figure. Now: avatar + name + count
   (Fresha / Motion). A COUNT only: no hours, no money, so App.canSeeMoney() is
   not implicated. Only borderLeftColor stays inline — that is per-person DATA. */
.calview .cal-lane {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  margin-bottom: var(--space-2);
}
.calview .cal-lane-head { margin-bottom: var(--space-1); }
.calview .cal-lane-name {
  flex: 0 0 138px;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 7px var(--space-2);
  border-left: 3px solid var(--muted);
  background: var(--subtle);
  border-radius: var(--radius-sm);
}
.calview .cal-lane-name--ghost {
  background: transparent;
  border-left-color: transparent;
  padding: 0;
}
.calview .cal-lane-id { min-width: 0; }
.calview .cal-lane-who {
  font-size: var(--fs-meta);
  font-weight: var(--fw-bold);
  color: var(--text);
  line-height: var(--lh-snug);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.calview .cal-lane-load {
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  color: var(--muted);
  line-height: var(--lh-snug);
  font-variant-numeric: tabular-nums;
}
.calview .cal-lane-strip { flex: 1 1 auto; min-width: 0; margin-bottom: 0; }
.calview .cal-cell-lane { min-height: 64px; }

/* per-person DAY: side-by-side columns, scrolling inside their OWN container so
   the page body never scrolls sideways (unchanged behaviour, now in classes). */
.calview .cal-daycols {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  overflow-x: auto;
  padding-bottom: var(--space-1);
}
.calview .cal-daycol {
  flex: 0 0 210px;
  min-width: 190px;
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}
.calview .cal-daycol-title { margin-bottom: var(--space-3); }

/* ---- toolbar ------------------------------------------------------------- */
.calview .cal-count { font-size: var(--fs-meta); }

/* ---- <= 700px: stop pretending 7 equal columns fit ----------------------
   Measured before at 375px: a week `.cal-cell` was 44px wide, its chip 32x44px,
   and the whole label rendered as "08:001" — a truncated TIME and nothing else,
   x27 shoots. Month was the same ("08:0(", "16:0").
   Both fixes are CSS-only ON PURPOSE. The alternative — a second JS render path
   gated on matchMedia — would have duplicated dayJobRow, and would have changed
   what the view produces at narrow widths, which the existing permission suite
   asserts on via textContent. Nothing here changes the DOM.
     WEEK  -> the 7-col strip restacks into a day-grouped agenda: the shared
              header row drops out and each cell's own "Thu Jul 30 · Today"
              label (already rendered, hidden above 700px) becomes its header.
     MONTH -> keeps its 7 columns, because it still works as an overview and a
              date picker, but each chip collapses to its dot + time — a 46px
              cell demonstrably cannot hold a street. Tapping the cell opens the
              Day view via App.rowActivate, which is where the detail lives. */
@media (max-width: 700px) {
  .calview .cal-dow-week { display: none; }
  .calview .cal-grid-week { grid-template-columns: 1fr; gap: var(--space-2); }
  .calview .cal-cell-week { min-height: 0; padding: var(--space-2); }
  .calview .cal-cell-week > .cal-daynum {
    display: block;
    font-size: var(--fs-caption);
    font-weight: var(--fw-black);
    color: var(--text);
    text-transform: none;
    letter-spacing: 0;
    padding-bottom: 3px;
  }
  /* full-width rows have room again — restore a 44px touch target */
  .calview .cal-event:not(.cal-event--dense) { min-height: 44px; justify-content: center; }
  .calview .cal-event:not(.cal-event--dense) .cal-ev-street { -webkit-line-clamp: 1; }

  /* MONTH -> density dots (Todoist / Midday). Measured at 375px: a month cell is 44px
     wide, and a chip carrying a half-hour time spills 5–12px past it on 6 of 32 shoots
     ("11:30a" needs ~48px). Ellipsing a clock value would be a LIE about the time, so
     the time comes off entirely and the row of dots becomes the density signal. Each dot
     keeps its own title/aria-label and opens its job; the CELL is the primary target and
     opens the Day view, which is where every detail lives at this width. */
  .calview .cal-cell:not(.cal-cell-week) {
    flex-direction: row;
    flex-wrap: wrap;
    align-content: flex-start;
    align-items: center;
    min-height: 62px;
    padding: 4px 3px;
    gap: 2px;
  }
  .calview .cal-cell:not(.cal-cell-week) > .cal-daynum,
  .calview .cal-cell:not(.cal-cell-week) > .sched-off { flex: 1 0 100%; }
  .calview .cal-cell:not(.cal-cell-week) .cal-event--dense {
    flex: 0 0 auto;
    gap: 0;
    padding: 5px 3px;      /* a bigger hit area than the 7px dot it draws */
  }
  .calview .cal-event--dense .cal-ev-time,
  .calview .cal-event--dense .cal-ev-street { display: none; }
  .calview .cal-cell:not(.cal-cell-week) .cal-ev-dot { width: 7px; height: 7px; }
  .calview .cal-cell:not(.cal-cell-week).today .cal-daynum { min-width: 18px; height: 18px; padding: 0 4px; }
  /* "+3 more" cannot fit a 44px cell on one line at --fs-micro (~42px of text in ~38px of
     interior), so it takes its own full-width line and wraps deliberately rather than
     ellipsing — an ellipsed count would hide the very number it exists to report. */
  .calview .cal-cell:not(.cal-cell-week) .cal-more {
    flex: 1 0 100%;
    margin-top: 3px;
    padding: 0;
    text-align: center;
    line-height: var(--lh-tight);
  }

  /* lanes: the gutter goes full-width above its own strip, and the strip keeps
     7 readable columns inside its OWN horizontal scroller */
  .calview .cal-lane { flex-wrap: wrap; }
  .calview .cal-lane-head { display: none; }
  .calview .cal-lane-name { flex: 1 1 100%; }
  .calview .cal-lane-strip { overflow-x: auto; grid-template-columns: repeat(7, minmax(88px, 1fr)); }
  .calview .cal-cell-lane { min-height: 56px; }
}


/* ##########################################################################
   HOME ▸ TODAY — hierarchy + rhythm (today.js). scratchpad/css-home.css
   Merged by the INTEGRATOR pass, 2026-07-30. Source: builder scratch file.
   ########################################################################## */
/* ============================================================
   HOME → TODAY — hierarchy + rhythm pass.  2026-07-30
   Surface: Home ▸ Today (today.js) and the FRIDAY brief card that
   sits at the top of it (dailybrief.js).

   INTEGRATOR: append this block at the END of styles.css (it must land
   AFTER the existing ".today-*" block at ~line 1615 and after the SPEC28
   ".card-title { letter-spacing: .35px }" at ~line 1657). Every selector
   here is already more specific than what it overrides, so order is belt-
   and-braces rather than load-bearing.

   Scoped entirely to classes emitted ONLY by today.js + dailybrief.js
   (grep-verified: .today-* and .jarvis-* appear in no other JS file), so
   nothing here can leak to another surface. No bare .card / .list-row /
   .card-title selector exists in this file.

   Tokens only — no raw hex, no new CSS variables, no !important. The
   html[data-theme="dark"] overrides already in styles.css theme all of
   this for free. No new animation, so no new prefers-reduced-motion guard
   is needed (the existing .jarvis-brief-orb guard at ~6069 still stands).
   No focus styles are touched: .today-shoot keeps its :focus-visible
   outline and every demoted button keeps .btn's global ring + 40px target.
   ============================================================ */

/* ---- 1. rung heads: one real type step above row text --------------
   Measured before: the largest thing below the 28px h1 on an 8,146px page
   was 15px, and "Late · 27" was set in the SAME 13px muted uppercase as
   "Listing-iversary" and "Backup reminder". `.card-title` is deliberately
   NOT restyled globally — 19 other cards and the whole app use it; only the
   two Today heading families are promoted. */
.today-section-head h3.card-title,
.today-group > h3.card-title {
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  color: var(--text);
  text-transform: none;
  letter-spacing: var(--ls-tight);
  line-height: var(--lh-snug);
  /* gap:0 (not the inherited 7px) because the count span carries its OWN " · "
     separator inside the h3's textContent — a flex gap on top of that reads as
     "Late  ·  10". The icon gets its space back explicitly, one line down. */
  gap: 0;
}
.today-section-head h3.card-title { margin: 0; }          /* the head row owns the spacing */
.today-group > h3.card-title { margin: 0 0 var(--space-3); }

/* the icon gets back the space `gap: 0` above took away, and stays secondary to
   the words it labels. App.icon wraps its <svg> in a <span class="icon"> and the
   svg strokes with currentColor — so the colour has to land on that SPAN, not on
   a `> svg` that is never a direct child. */
.today-section-head h3.card-title > .icon,
.today-group > h3.card-title > .icon { margin-right: var(--space-2); color: var(--muted); }

/* the count reads as a NUMBER, not as more label. The literal " · N" lives
   inside this span — tests/suite.js:27110 matches /Due today · (\d+)/ against
   the h3's own textContent, so the separator must stay in the text, not become
   a ::before. */
.today-count {
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  white-space: pre;   /* the leading space in " · N" IS the separator — never collapse it */
}

/* ---- 2. tone — ONLY the two rungs that mean "act now" ---------------
   Jobber's schedule: colour the SECTION HEAD, keep every row visually flat.
   Two tinted rungs on the page (Late = danger, Blocked on you = warn), never
   eight. The title text stays var(--text) so contrast never depends on the
   tone in either theme; only the icon, the count and a 3px rail carry it. */
.today-section--danger .today-count,
.today-section--danger .today-section-head h3.card-title > .icon { color: var(--danger); }
.today-section--warn .today-count,
.today-section--warn .today-section-head h3.card-title > .icon { color: var(--warn); }

.today-section--danger > .card,
.today-section--warn > .card { position: relative; }
.today-section--danger > .card::before,
.today-section--warn > .card::before {
  content: '';
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 3px;
  border-radius: var(--radius-lg) 0 0 var(--radius-lg);
}
.today-section--danger > .card::before { background: var(--danger); }
.today-section--warn > .card::before { background: var(--warn); }

/* ---- 3. shoot card: a fixed time gutter ----------------------------
   Timepage's day view. The time was absent from the card entirely while the
   brief chip 400px above printed it. `.today-shoot` becomes a 2-column grid;
   today.js moves ALL of the card's former children into .today-shoot-body,
   so nothing can strand itself in the gutter. */
.today-shoot {
  display: grid;
  grid-template-columns: 62px minmax(0, 1fr);
  column-gap: var(--space-3);
  align-items: start;
}
.today-shoot-body { min-width: 0; }
.today-shoot-time {
  font-family: var(--font-serif);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-tight);
  font-variant-numeric: tabular-nums;
  line-height: var(--lh-snug);
  color: var(--text);
  padding-top: 1px;
}
.today-shoot-time .today-shoot-ampm {
  display: block;
  font-family: var(--font);
  font-size: var(--fs-micro);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--muted);
}
/* an untimed shoot renders an honest '—', never a fabricated clock time */
.today-shoot-time.is-untimed { color: var(--faint); }

/* the weather line's glyphs now go through App.labelIcon (SVG, currentColor)
   instead of raw OS emoji — each icon+value pair is one atom that wraps
   together rather than the icon orphaning onto the previous line. */
.today-wx { display: inline-flex; align-items: center; gap: var(--space-1); }

/* ---- 4. the FRIDAY brief ------------------------------------------- */
/* its head was the same 13px muted uppercase as a Layer-2 collapse label,
   despite being the first thing on the page. Same promotion as the rungs. */
.jarvis-brief-head .card-title {
  font-size: var(--fs-md);
  font-weight: var(--fw-bold);
  color: var(--text);
  text-transform: none;
  letter-spacing: var(--ls-tight);
  line-height: var(--lh-snug);
}
/* a chip that wraps to two lines should read like a SENTENCE, not a centred
   banner. <button> defaults to text-align:center, so four of seven chips
   rendered as centred ragged pills at 375px. Only --spot had this fix. */
.jarvis-chip { text-align: left; justify-content: flex-start; }

/* INTEGRATOR: the builder's two .jarvis-chip--warn / --red overrides are NOT
   appended here. The raw hex they existed to neutralise (styles.css:6074-6075,
   #cab641 / #e2445c) was swapped to var(--warn) / var(--danger) IN PLACE in that
   same block, which is the better fix: identical computed result, one rule not
   two, and no raw hex left in the file. */

/* ---- 5. mobile: the identity column never collapses -----------------
   Measured at 375px in the Late list, `.list-row > .grow` was 211px with no
   action, 53–59px with a Nudge button, and 19px with a chip + Log button —
   the task title rendered as "C…" inside a 317px row while the secondary
   meta and the button kept their full width. Scoped to this surface's two
   list containers; the global `.list-row .grow { flex: 1 }` is untouched. */
@media (max-width: 640px) {
  .today-section .list-row,
  .today-group .list-row {
    flex-wrap: wrap;
    row-gap: var(--space-2);
    align-items: center;
    min-height: 44px;
  }
  /* claim line 1 (next to a leading checkbox); chips / actions / due wrap below */
  .today-section .list-row > .grow,
  .today-group .list-row > .grow { flex: 1 1 calc(100% - 40px); min-width: 0; }
  .today-section .list-row > .nowrap:last-child,
  .today-group .list-row > .nowrap:last-child { margin-left: auto; }

  .today-shoot { grid-template-columns: 54px minmax(0, 1fr); column-gap: var(--space-2); }
}
/* ============================================================ */

/* ============================================================
   ROLE LADDER  (ladder-view.js)  —  .lad-* only.
   Tokens only: every color, radius, space and weight below is a var(), so both
   themes reflow off :root / html[data-theme="dark"] with no per-theme override
   needed here. The four state colors use the app's *-ink text tokens (which
   already flip per theme) on *-soft fills — never a raw hex.
   ============================================================ */
.lad-toolbar { margin-bottom: var(--space-4); gap: var(--space-2); flex-wrap: wrap; align-items: center; }
.lad-who { max-width: 210px; }
.lad-who-k, .lad-selfnote { font-size: var(--fs-meta); font-weight: var(--fw-bold); }
.lad-selfname { font-weight: var(--fw-black); font-size: var(--fs-md); }

/* ---- the identity header ---- */
.lad-head { margin-bottom: var(--space-3); }
.lad-head-id { display: flex; align-items: center; gap: var(--space-3); }
.lad-name { font-family: var(--font-serif); font-size: var(--fs-h1); font-weight: var(--fw-semibold); margin: 0; line-height: var(--lh-tight); }
.lad-head-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-top: var(--space-1); }
.lad-headline { font-size: var(--fs-md); font-weight: var(--fw-semibold); color: var(--text); margin: var(--space-3) 0 0; line-height: var(--lh-snug); }
.lad-progress { margin-top: var(--space-3); }
.lad-progress .databar { width: 100%; }
.lad-note { font-size: var(--fs-meta); margin-top: var(--space-2); line-height: var(--lh-normal); }
.lad-blurb { color: var(--muted); font-size: var(--fs-caption); margin: 0 0 var(--space-3); }

.lad-banner { margin-top: var(--space-3); padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); font-size: var(--fs-meta); line-height: var(--lh-normal); border: 1px solid var(--border); }
.lad-banner-info { background: var(--info-soft); border-color: color-mix(in srgb, var(--info) 30%, transparent); color: var(--text); }
.lad-banner-warn { background: var(--warn-soft); border-color: color-mix(in srgb, var(--warn) 30%, transparent); color: var(--text); }

/* ---- criterion rows ---- */
.lad-crit-list { display: flex; flex-direction: column; gap: var(--space-2); }
.lad-crit { display: flex; align-items: flex-start; gap: var(--space-3); padding: var(--space-3); border: 1px solid var(--border); border-radius: var(--radius); background: var(--subtle); }
.lad-crit-main { flex: 1 1 auto; min-width: 0; }
.lad-crit-side { display: flex; flex-direction: column; align-items: flex-end; gap: var(--space-2); flex: 0 0 auto; }
.lad-crit-label { font-weight: var(--fw-semibold); font-size: var(--fs-caption); line-height: var(--lh-snug); }
.lad-crit-meta { font-size: var(--fs-meta); color: var(--muted); margin-top: var(--space-1); line-height: var(--lh-normal); }
.lad-crit-why { font-size: var(--fs-meta); color: var(--faint); margin-top: var(--space-1); line-height: var(--lh-normal); }
.lad-crit-nums { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-1); }
.lad-actual { font-size: var(--fs-lg); font-weight: var(--fw-black); letter-spacing: var(--ls-tight); }
.lad-target { font-size: var(--fs-meta); color: var(--muted); font-weight: var(--fw-semibold); }
.lad-n { font-size: var(--fs-micro); color: var(--faint); }
/* THIN is never a failure: muted ink, no fill, no number. */
.lad-thin { color: var(--muted); font-style: italic; }
.lad-crit.lad-st-thin .lad-crit-label { color: var(--muted); }

.lad-disc { margin-top: var(--space-2); }
.lad-disc > summary { font-size: var(--fs-micro); color: var(--faint); cursor: pointer; }
.lad-disc-body { font-size: var(--fs-micro); color: var(--muted); line-height: var(--lh-normal); margin-top: var(--space-1); }

/* ---- state pills ---- */
.lad-pill { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: var(--fs-micro); font-weight: var(--fw-bold); white-space: nowrap; border: 1px solid transparent; }
.lad-pill.lad-st-met { background: var(--ok-soft); color: var(--ok-ink); border-color: color-mix(in srgb, var(--ok) 30%, transparent); }
.lad-pill.lad-st-unmet { background: var(--warn-soft); color: var(--warn-ink); border-color: color-mix(in srgb, var(--warn) 30%, transparent); }
.lad-pill.lad-st-thin { background: var(--hover); color: var(--muted); border-color: var(--border); }
.lad-pill.lad-st-manual { background: var(--info-soft); color: var(--text); border-color: color-mix(in srgb, var(--info) 30%, transparent); }
.lad-crit.lad-st-met { border-left: 3px solid var(--ok); }
.lad-crit.lad-st-unmet { border-left: 3px solid var(--warn); }
.lad-crit.lad-st-thin { border-left: 3px solid var(--border-strong); }
.lad-crit.lad-st-manual { border-left: 3px solid var(--info); }

/* ---- pay band ---- */
.lad-comp { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.lad-comp-cell { flex: 1 1 160px; background: var(--subtle); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-3); }
.lad-comp-k { font-size: var(--fs-micro); color: var(--muted); font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .4px; }
.lad-comp-v { font-size: var(--fs-lg); font-weight: var(--fw-black); margin-top: var(--space-1); }
.lad-comp-note { flex: 1 1 100%; font-size: var(--fs-micro); }
.lad-comp-empty { font-size: var(--fs-meta); }

/* ---- owner controls ---- */
.lad-owner { margin-bottom: var(--space-3); }
.lad-owner-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.lad-owner-k { font-size: var(--fs-meta); font-weight: var(--fw-bold); }
.lad-owner-note { font-size: var(--fs-micro); margin-top: var(--space-2); }

/* ---- the PIP ---- */
.lad-pip { margin-bottom: var(--space-3); border-left: 3px solid var(--info); }
.lad-pip-late { border-left-color: var(--danger); }
.lad-pip-head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; }
.lad-pip-title { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-md); font-weight: var(--fw-black); margin: 0; }
.lad-pip-dates { font-size: var(--fs-meta); margin-top: var(--space-1); }
.lad-pip-note { margin-top: var(--space-2); font-size: var(--fs-caption); line-height: var(--lh-normal); white-space: pre-wrap; }
.lad-pip-score { margin: var(--space-3) 0 var(--space-2); font-size: var(--fs-caption); }
.lad-pip-actions { margin-top: var(--space-3); display: flex; gap: var(--space-2); flex-wrap: wrap; }
.lad-pip-foot { font-size: var(--fs-micro); margin-top: var(--space-2); line-height: var(--lh-normal); }

.lad-pick { display: flex; flex-direction: column; gap: var(--space-1); margin: var(--space-3) 0; }
.lad-pick-row { display: flex; align-items: flex-start; gap: var(--space-2); padding: var(--space-2); border: 1px solid var(--border); border-radius: var(--radius-sm); cursor: pointer; background: var(--subtle); }
.lad-pick-row:hover { background: var(--hover); }
.lad-pick-label { display: block; font-size: var(--fs-caption); font-weight: var(--fw-semibold); line-height: var(--lh-snug); }
.lad-pick-meta { display: block; font-size: var(--fs-micro); margin-top: 2px; }
.lad-form { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.lad-form > .field { flex: 1 1 150px; }
.lad-err { color: var(--danger-ink); font-size: var(--fs-meta); font-weight: var(--fw-semibold); min-height: 18px; margin-top: var(--space-2); }

/* ---- team overview ---- */
.lad-list { display: flex; flex-direction: column; }
.lad-row { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-2); border-bottom: 1px solid var(--border); cursor: pointer; border-radius: var(--radius-sm); }
.lad-row:last-child { border-bottom: none; }
.lad-row:hover { background: var(--hover); }
.lad-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.lad-row-name { font-weight: var(--fw-bold); font-size: var(--fs-caption); }
.lad-row-meta { font-size: var(--fs-meta); margin-top: 2px; }
.lad-row-chips { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-top: var(--space-1); }
.lad-row-score { font-size: var(--fs-caption); font-weight: var(--fw-black); color: var(--muted); white-space: nowrap; }
.lad-ready-note { font-size: var(--fs-meta); margin: 0 0 var(--space-2); line-height: var(--lh-normal); }

/* ---- owner setup + the refused record ---- */
.lad-setup, .lad-refused { margin-top: var(--space-3); }
.lad-setup > summary, .lad-refused > summary { font-weight: var(--fw-bold); cursor: pointer; font-size: var(--fs-caption); }
.lad-setup-warn { font-size: var(--fs-micro); }
.lad-setup-track { margin-top: var(--space-3); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-3); }
.lad-setup-track > summary { font-weight: var(--fw-bold); cursor: pointer; font-size: var(--fs-caption); }
.lad-setup-level { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px dashed var(--border); }
.lad-setup-lvhead { font-weight: var(--fw-black); font-size: var(--fs-caption); margin-bottom: var(--space-2); }
.lad-setup-grid { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.lad-setup-grid > .field { flex: 1 1 150px; min-width: 0; }
.lad-setup-crit { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: flex-end; margin-top: var(--space-2); padding: var(--space-2); background: var(--subtle); border-radius: var(--radius-sm); }
.lad-setup-crit > .field { flex: 1 1 140px; min-width: 0; }
.lad-setup-crit > .field.grow { flex: 3 1 220px; }
/* participates in the row's wrap (flex 1 1) instead of overflowing the card edge —
   measured at 800px, where an inline-flex label ran past the card border. */
.lad-setup-manual { display: inline-flex; align-items: center; gap: 6px; flex: 1 1 150px; min-width: 0; font-size: var(--fs-meta); font-weight: var(--fw-semibold); }
.lad-setup-engine { flex: 1 1 100%; font-size: var(--fs-micro); line-height: var(--lh-normal); word-break: break-word; }
.lad-setup-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-top: var(--space-4); }
.lad-refused-row { padding: var(--space-3) 0; border-bottom: 1px solid var(--border); }
.lad-refused-row:last-child { border-bottom: none; }
.lad-refused-sig { font-weight: var(--fw-bold); font-size: var(--fs-caption); }
.lad-refused-why { font-size: var(--fs-meta); margin-top: var(--space-1); line-height: var(--lh-normal); }
.lad-refused-build { font-size: var(--fs-micro); color: var(--faint); margin-top: var(--space-1); line-height: var(--lh-normal); }

.lad-hold { margin-top: var(--space-3); }
.lad-hold > summary { font-weight: var(--fw-bold); cursor: pointer; font-size: var(--fs-caption); }
.lad-hold .lad-crit-list { margin-top: var(--space-3); }

/* dark theme: the two soft banner fills are the only places a token pair needs a
   nudge — --info-soft/--warn-soft are near-white in light and near-black in dark,
   and the mixed borders can wash out at 30%. Ink stays the theme-flipping token. */
html[data-theme="dark"] .lad-banner-info,
html[data-theme="dark"] .lad-banner-warn { background: color-mix(in srgb, var(--panel) 88%, var(--text)); }
html[data-theme="dark"] .lad-pill.lad-st-met { background: color-mix(in srgb, var(--ok) 18%, transparent); }
html[data-theme="dark"] .lad-pill.lad-st-unmet { background: color-mix(in srgb, var(--warn) 18%, transparent); }
html[data-theme="dark"] .lad-pill.lad-st-manual { background: color-mix(in srgb, var(--info) 18%, transparent); }

/* 375px: the criterion row stacks its pill under the text instead of squeezing
   the label to two characters (the exact failure mode the Today rows had). */
@media (max-width: 640px) {
  .lad-crit { flex-wrap: wrap; }
  .lad-crit-side { flex-direction: row; align-items: center; width: 100%; justify-content: flex-start; }
  .lad-head-id { flex-wrap: wrap; }
  .lad-row { flex-wrap: wrap; row-gap: var(--space-2); }
  .lad-row > .grow { flex: 1 1 calc(100% - 46px); min-width: 0; }
  .lad-row-score { margin-left: auto; }
  .lad-comp-cell { flex: 1 1 100%; }
  .lad-who { max-width: 100%; width: 100%; }
  .lad-setup-crit > .field, .lad-setup-crit > .field.grow, .lad-setup-grid > .field { flex: 1 1 100%; }
}

/* AUDIT 08-01 — a cancelled/archived shoot on the Calendar was visually identical to a live
   one (measured: same bg, colour, opacity, no strikethrough) and only said so in a hover
   title, which does not exist on a phone. Crew read the Calendar to decide where to drive.
   Keep the event (the calendar suites assert it renders and is counted) — but make it
   unmistakable at a glance, in both themes, without relying on colour alone. */
.cal-event--dead { opacity: .55; }
/* SWEEP 08-02 — the strikethrough half of the fix above never rendered: it targeted
   `.cal-event-title` and `.cal-ev-addr`, and NEITHER class exists anywhere in the app.
   calendar.js's eventChip builds the address as `.cal-ev-street` (both the dense month
   chip and the week/day chip). Measured on a cancelled shoot in the live month grid:
   computed text-decoration-line "none" on the chip AND on its address element. Only
   opacity + the ::after badge were doing any work, so the one marker that survives a
   phone-width month cell — where `.calview .cal-event--dense .cal-ev-street` is
   display:none — was the badge alone. Point it at the real class. */
.cal-event--dead .cal-ev-street { text-decoration: line-through; }
.cal-event--dead::after {
  content: 'cancelled';
  margin-left: 6px; font-size: var(--fs-micro); font-weight: var(--fw-bold);
  letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--danger);
}

/* AUDIT 08-01 #7 — the Tracker's twin of the above. A cancelled/archived job's Due date
   was painted in `overdue due-overdue` danger red, identical to a genuinely late live
   job, so the board's late total disagreed with Today's and a dead shoot read as the
   most urgent row on the screen. Same posture as the Calendar: MARK it dead (dim +
   strike, reason on hover) rather than hide it or shout. Colour is not the only cue. */
.jt-due-dead { color: var(--muted); text-decoration: line-through; font-weight: 400; }
.kanban-card .kc-fact.jt-due-dead { opacity: .7; }

/* ============================================================
   @media print  —  AUDIT-GAPS-2026-08-04 C1 (client-facing) + ST1 (structural)
   ------------------------------------------------------------
   Until 2026-08-04 this file had ZERO print rules and it is the only stylesheet
   index.html loads, so every in-app print path inherited the whole screen chrome.
   The repo's one other @media print block lives in marketing.css:1008, which the
   app never loads.

   MEASURED on the real artifact — Retainers → Sawyer Vance → 📊 Client report →
   🖨 Print / PDF, printed to Letter at 0.4in margins (= 739px CSS content width),
   pdftotext -layout, verbatim from page 1:
       1 / VVT Hub
       Directory  Top Agents  Leads  Pipelines  Retainers  Consult  Coaching
       Coaching KB  Opportunities  Sales Plays  Call Scores
       ← Back                                    Send to client   🖨 Print / PDF
   and where the milestones belong:
       YOUR MILESTONES
       🏆Plan                        🏅 Best month yet for reach
       1  Skip to content
       🚀VVT / 1 / Hub   Doubled their monthly reach
   The agent's own progress report arrived with our internal sales sub-navigation
   stamped across the top — Leads, Pipelines, Opportunities, Call Scores — and the
   mobile tab bar painted through the milestone block on both pages.

   THE TRAP, and why a naive rule misses it: at paper width the app is already past
   its own ≤860px breakpoint, so #sidebar is off-canvas at left:-275px and does NOT
   land on the page — the MOBILE chrome does. And .subtabs (711×90, the sales
   sub-nav) is position:static, in NORMAL FLOW. A rule that only hides fixed-position
   chrome leaves the worst offender untouched. Both classes are handled below.

   SCOPE: hide app chrome, keep the report. retainers.js:2281 is the ONLY
   window.print() that prints the live SPA; core.js:16217 and :16501
   (printShootBrief / printRetainerRecap) window.open a standalone document that
   carries its own @media print and is unaffected by anything here.

   Anything added later that is screen furniture — a dock, a banner, a coach-mark —
   belongs in the hide list below or should carry the .no-print utility class.
   ============================================================ */
@media print {

  /* ---- 0. the PAPER itself. Round 2 set `background:#fff` on html/body and stopped
     there; MEASURED 2026-08-05 (headless Chrome --print-to-pdf, Letter, control page
     alongside) that is not enough — a printed page of the client report carried a solid
     #121212 band on all four margins, both pages.
     Why `background:#fff` cannot fix it: Chrome's print dialog defaults "Background
     graphics" to OFF, so element backgrounds are not painted at all and the UA's own
     page CANVAS shows through — and the canvas colour is chosen by `color-scheme`,
     which :root sets to `dark` in the dark theme (styles.css:147). The app boots dark
     whenever the OS is in Dark Mode (index.html pre-paint script) or the person
     printing has used the theme toggle, so Erika printing from a dark-mode Mac hands
     the client an artifact framed in near-black ink on every sheet.
     Forcing the light color-scheme for print makes the canvas white with no dependency
     on the background-graphics checkbox. The report's own palette is already pinned
     separately at .tss-report below. */
  html { color-scheme: light !important; }

  /* ---- 0b. PAPER PALETTE, app-wide.  ADDED 2026-08-05 (round 4).
     ------------------------------------------------------------------
     0a above forces the page canvas WHITE for every printed screen. But until now
     the matching LIGHT ink was pinned only inside `.tss-report` (section 4 below),
     so on every OTHER screen the dark theme kept `--text: #e7e9ee` (styles.css:114)
     while the paper underneath it was white.
     MEASURED 2026-08-05, headless Chrome, Emulation.setEmulatedMedia media=print,
     html[data-theme="dark"], view=dashboard:
         body  color = rgb(231,233,238)  background = rgb(255,255,255)  → 1.19:1
     That is Erika's job sheet printed from a dark-mode Mac. Chrome's own ink-economy
     pass drags the glyphs partway back toward grey, which is why the sheet reads as
     washed-out rather than literally empty — but 1.19:1 is what the page ASKS the
     printer for, it is below every legibility floor, and it is not something to
     rely on a UA heuristic to rescue.

     Fix: re-pin the LIGHT theme's own :root values for print. Paper is a light
     surface, so the light palette is the correct one on every screen, not just the
     client report — which is what anyone pressing Print expects from a printer.

     WHY `!important`, and why `:root` is not enough on its own: the dark palette is
     declared at `html[data-theme="dark"]` — specificity (0,1,1) — which outranks
     `:root` (0,1,0) no matter how far down the file this block sits. `!important`
     wins on the root element regardless of selector, so this stays correct if the
     theme selector is ever changed or another one is added.

     WHY THIS DOES NOT DISTURB `.tss-report`: the cascade runs per element. These
     declarations land on the ROOT element; `.tss-report`'s own local custom
     properties (section 4) are declarations on the REPORT element, and a
     declaration on an element always beats an inherited value — importance does
     not cross the inheritance boundary. The report keeps its pinned palette and
     additionally stops inheriting dark values for the handful of tokens it does
     not pin itself (--subtle, --warn, --ok-soft, --danger-soft, --info …), which
     is the same direction it was already pinned in.

     Every token `html[data-theme="dark"]` overrides is re-pinned below, in the same
     order, to the value the light `:root` block gives it. Keep the two in step: if
     a token is added to the dark block it belongs here too. */
  :root {
    --bg: #f6f6f4 !important;
    --bg-2: #eef0f4 !important;
    --panel: #ffffff !important;
    --card: #ffffff !important;
    --text-soft: #565e6b !important;
    --subtle: #fbfbfa !important;
    --hover: #f2f4f7 !important;
    --chip-ink: #0b0d13 !important;
    --border: #e4e7ec !important;
    --border-strong: #d0d5dd !important;
    --text: #101828 !important;
    --muted: #565e6b !important;
    --faint: #656d7b !important;
    --accent: #2b608f !important;
    --accent-hover: #1e3f66 !important;
    --accent-soft: #eaf1f7 !important;
    --accent-warm: #b18f52 !important;
    --accent-warm-soft: #f0e6d4 !important;
    --gold: #c19a4e !important;
    --danger: #d92d20 !important;
    --danger-soft: #fef3f2 !important;
    --danger-ink: #b42318 !important;
    --on-danger: #ffffff !important;
    --ok: #079455 !important;
    --ok-soft: #ecfdf3 !important;
    --warn: #dc6803 !important;
    --warn-soft: #fffaeb !important;
    --ok-ink: #067647 !important;
    --warn-ink: #b54708 !important;
    /* LAW-A 2026-08-15 (closer) — the new --info-ink (styles.css:50 light / :139 dark)
       needs its print pin like every other token the dark theme overrides. Without it
       the suite's own r4/A4 guard goes red ("dark-theme tokens with no print pin:
       --info-ink") and a page printed from a dark-mode Mac would keep the DARK ink
       #53b1fd on white paper — measured 2.31:1 on #ffffff, below every legibility
       floor. Pinned to the LIGHT value (r4/A5 requires exactly that): #175cd3 measures
       5.99:1 on white paper. */
    --info-ink: #175cd3 !important;
    --info: #2e90fa !important;
    --info-soft: #eff8ff !important;
    --code-bg: #f6f8fa !important;
    --code-text: #1a1a1a !important;
    --ring-rgb: 43, 96, 143 !important;
    --shadow-sm: 0 1px 2px rgba(16,24,40,.04), 0 1px 1px rgba(16,24,40,.03) !important;
    --shadow: 0 1px 2px rgba(16,24,40,.05), 0 2px 6px -1px rgba(16,24,40,.08) !important;
    --shadow-lg: 0 18px 40px -12px rgba(16,24,40,.18), 0 6px 14px -6px rgba(16,24,40,.08) !important;
    --card-hi: inset 0 1px 0 rgba(255,255,255,.5) !important;
    /* sidebar rail tokens: the rail is dark navy in BOTH themes and every element
       that uses them is display:none below, so these change nothing on paper —
       they are here so "every dark-theme token is re-pinned" stays literally true
       and a test can check it. */
    --sidebar-bg: #16202e !important;
    --sidebar-border: #232639 !important;
    --sidebar-text: #9aa1b9 !important;
    --sidebar-active: #ffffff !important;
    --sidebar-active-bg: color-mix(in srgb, var(--accent) 16%, transparent) !important;
    /* D2 (2026-08-11 design pass) added --ghost-border to the dark block; per this
       block's own rule above ("if a token is added to the dark block it belongs
       here too") it is re-pinned to its LIGHT :root value — same pattern, no other
       token here touched. Verified against r4/A4 (every dark token has a print pin)
       and r4/A5 (the print value matches light). */
    --ghost-border: transparent !important;
  }

  /* ---- 1. the page box: undo the fixed-height, internally-scrolling app shell.
     html/body are height:100%, #app is height:100vh and #main is overflow-y:auto —
     an internally scrolling box is exactly what clips a long document to one page. */
  html, body { height: auto !important; overflow: visible !important; background: #fff !important; }
  #app { display: block !important; height: auto !important; overflow: visible !important; }
  #main {
    flex: none !important; overflow: visible !important;
    height: auto !important; max-height: none !important;
    /* the ≤860px block adds padding-top:52px to clear the mobile topbar we just hid */
    padding-top: 0 !important; padding-bottom: 0 !important;
    margin-left: 0 !important;
  }
  #view {
    overflow: visible !important; height: auto !important; max-height: none !important;
    max-width: none !important; margin: 0 !important; padding: 0 !important;
  }

  /* ---- 2. FIXED chrome. #sidebar is listed even though it is off-canvas at Letter
     width: A4 LANDSCAPE at 0.4in margins is 1122px, which is back above the 860px
     breakpoint and would put the whole nav — every client-facing viewer's internal
     menu — on the paper. !important beats the JS-set inline styles on the FABs. */
  .skip-link,
  #mobile-topbar,
  #sidebar,
  #nav-backdrop,
  #tabbar,
  #quick-add-fab,
  #voice-fab,
  #bug-fab,
  #callFab,
  #demo-ribbon,
  #overlays,
  #toast-zone,
  #nologin-banner,
  #storage-banner,
  .no-print { display: none !important; }

  /* ---- 3. IN-FLOW chrome — the part a fixed-position-only rule misses.
     .subtabs is the internal sales sub-nav (Leads / Pipelines / Opportunities /
     Call Scores). It is 711×90 and position:static, so it prints in normal flow. */
  .subtabs { display: none !important; }

  /* ...but the client report REUSES .subtabs for its own growth-chart metric picker
     (retainers.js:2313 — Followers / Reach / Avg views). That is report content, not
     app chrome: it is the only thing on the page that says WHICH series the chart is
     showing. Keep the selected one, as a plain label rather than a dead button. */
  .tss-report .subtabs { display: block !important; margin: 0 0 6px !important; }
  .tss-report .subtabs .subtab { display: none !important; }
  .tss-report .subtabs .subtab.active {
    display: inline !important;
    background: none !important; border: 0 !important; box-shadow: none !important;
    padding: 0 !important; margin: 0 !important;
    font-weight: 700; color: inherit !important;
  }

  /* .view-header is the app-wide screen-controls row (← Back / Send to client /
     🖨 Print / PDF). Hide the CONTROLS, not the header — a view that puts a real
     heading in there keeps it on the paper. Then collapse the empty rule/space. */
  .view-header { margin: 0 !important; padding: 0 !important; border-bottom: 0 !important; gap: 0 !important; }
  .view-header button,
  .view-header .btn,
  .view-header input,
  .view-header select { display: none !important; }

  /* ---- 4. give the report the whole page ---- */
  .tss-report {
    max-width: none !important; margin: 0 !important;

    /* Chrome's print dialog defaults "Background graphics" to OFF, which strips the
       hero gradient and the stat-card fills and leaves a luxury client artifact
       looking like a fax. print-color-adjust INHERITS, so declaring it once here
       forces colour on the whole report and on nothing else in the app. */
    -webkit-print-color-adjust: exact !important;
    print-color-adjust: exact !important;

    /* PAPER PALETTE — pinned so the artifact the agent receives is identical no
       matter which theme the person printing happens to be using. MEASURED: with
       html[data-theme="dark"] the same report printed as a near-solid black page
       (stat cards #1a1d27, section cards black, sign-off line at 2.59:1 contrast on
       the white page margin) — legible, ink-drenched, and not what a client should
       get. These are the LIGHT theme's own :root values (styles.css :root block),
       set as local custom properties so every descendant inherits them; nothing
       outside .tss-report is touched. Keep in step with :root if the palette moves. */
    --bg: #f6f6f4; --bg-2: #eef0f4; --panel: #ffffff; --card: #ffffff;
    --border: #e4e7ec; --border-strong: #d0d5dd;
    --text: #101828; --muted: #565e6b; --faint: #656d7b;
    --accent: #2b608f; --accent-hover: #1e3f66; --accent-soft: #eaf1f7;
    --ok: #079455; --danger: #d92d20;
    background: #ffffff !important;
    color: var(--text) !important;
  }

  /* Screen depth cues do not survive the trip to paper: with colour forced on (above)
     the hero's shadow-lg prints as a grey smudge across the top of page 1, right where
     the stat cards sit. MEASURED at 739px: a ~160×20px grey band under .tss-hero.
     Shadows carry no information here — drop them for the printed report. */
  .tss-report, .tss-report * { box-shadow: none !important; text-shadow: none !important; }

  /* ---- 5. page breaks: never split a stat card, a milestone chip or a
     before/after column across two sheets, and never strand a section heading
     at the foot of a page. ---- */
  .tss-stat, .tss-badge, .tss-ba-col, .tss-hero { break-inside: avoid; page-break-inside: avoid; }
  .card-title { break-after: avoid; page-break-after: avoid; }
  /* whole sections stay whole. Safe here because the report's tallest card is the
     growth chart at ~230px — nothing in it can outgrow a sheet and strand a blank page. */
  .tss-report .card { break-inside: avoid; page-break-inside: avoid; }
}

/* MOBILE BELL 2026-08-10 — the top-bar alert button. Push is off, so the in-app bell is the
   team's only alert channel; on a phone it used to sit at the bottom of the hamburger drawer.
   Sized to the same 44px tap target as the burger/search either side of it. Its unread count
   reuses .notif-bell-badge, positioned relative to this button. */
#mobile-topbar .mt-bell {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: 0 0 auto;
  background: transparent; border: 0; border-radius: 12px; cursor: pointer;
  /* NOT `inherit` — that resolved to the page text colour (near-black #101828) on a
     near-black bar (#16202e), so the bell was effectively invisible while the burger
     beside it was white. Measured, not guessed. Match the burger explicitly. */
  color: #fff; padding: 0;
}
#mobile-topbar .mt-bell:active { background: rgba(255,255,255,.12); }
#mobile-topbar .mt-bell .notif-bell-badge {
  position: absolute; top: 4px; right: 4px;
  min-width: 17px; height: 17px; padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10.5px; font-weight: 700; line-height: 1;
  color: #fff; background: var(--danger, #dc2626);
  border-radius: 999px; box-shadow: 0 0 0 2px var(--topbar-bg, #101828);
}

/* ============================================================
   MOBILE MODAL FOOTER FIX 2026-08-10 (P0) — .modal-foot (~line 691) is
   `display:flex; justify-content:flex-end` with no wrap, ever. Every .btn is
   `white-space:nowrap` (~line 348) by design — buttons never shrink below their
   text width — so on a narrow phone any footer with THREE children (a leading
   caption/marker + two-plus buttons) has nowhere for the excess width to go but
   the caption: it gets squeezed toward zero and its wrapped text visually runs
   under/over the buttons beside it. Worst offender: the welcome modal's "Closing
   this won't show it again" caption (App.showWelcome, core.js) crushed to ~41px
   next to "Keyboard shortcuts" + "Got it — let's go" — Erika's first screen.
   Same shape hits any modal whose footer uses the .left marker on a Delete
   button (callcoach.js/calls.js/pipelines.js/dashboards.js/social.js/
   timesheets.js/snippets.js/examples.js, clients.js's plain '.left') next to
   Cancel/Save.
   Fix, mobile-only (this file is append-only for this task; the base rule at
   ~691 is left untouched so every screen above 480px is byte-identical to
   before): let the footer wrap, and give the caption/left-marked element its
   own full-width line ABOVE the buttons instead of fighting them for space in
   one nowrap row. Buttons keep their native nowrap sizing and simply wrap to a
   second row themselves if two don't fit side by side. */
@media (max-width: 480px) {
  .modal-foot { flex-wrap: wrap; row-gap: 8px; }
  .modal-foot > .faint,
  .modal-foot > .left {
    flex: 1 1 100%;
    order: -1;
    white-space: normal;
    margin-right: 0;
  }
}

/* ============================================================
   STAGECARD 2026-08-19 — the job modal's identity band + stage face
   (PLAN-STAGECARD §8). The band is always visible; the face is the
   stage's own open middle state (the modal used to be binary —
   553px or 3,847px). Every new control is a full-width, text-
   labelled row ≥44px (TAPFLOOR/ICONGRAM-safe: no icon-only glyphs).
   ============================================================ */
.jm-band { margin-bottom: 10px; }
.jm-onsite {
  display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: center;
  margin-top: 10px; padding: 9px 12px; min-height: 44px;
  background: var(--accent-soft); border: 1px solid var(--border);
  border-radius: 10px; font-size: 12.5px; font-weight: 600;
}
.jm-onsite-tag {
  font-size: 10.5px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase;
  color: var(--accent); flex: 0 0 auto;
}
.jm-onsite-bit { display: inline-flex; align-items: center; gap: 4px; min-width: 0; }
.jm-face {
  border: 1px solid var(--border); border-radius: 12px;
  padding: 12px; margin-bottom: 12px; background: var(--bg-2);
}
.jm-face-head {
  font-size: 11px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 8px;
}
.jm-stuck {
  display: flex; align-items: center; gap: 6px; min-height: 44px;
  padding: 8px 12px; margin-bottom: 10px; border-radius: 10px;
  background: color-mix(in srgb, var(--danger, #e2445c) 12%, transparent);
  color: var(--danger, #e2445c); font-weight: 700; font-size: 12.5px;
}
.jm-pay-headline { font-size: 14px; font-weight: 700; margin-top: 6px; }
.jm-strip { display: flex; flex-direction: column; gap: 6px; margin: 10px 0 4px; }
.jm-strip-seg {
  display: flex; align-items: center; gap: 6px; width: 100%; min-height: 44px;
  padding: 8px 12px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--bg); color: var(--text); font-size: 13px; cursor: pointer; text-align: left;
}
.jm-strip-seg:hover { border-color: var(--border-strong); }
.jm-strip-name { font-weight: 700; flex: 0 0 auto; }
.jm-strip-sub { color: var(--muted); min-width: 0; }
.jm-strip-seg.jm-late { border-color: var(--danger, #e2445c); }
.jm-strip-seg.jm-late .jm-strip-sub { color: var(--danger, #e2445c); font-weight: 700; }
.jm-pop {
  display: flex; align-items: center; gap: 6px; width: 100%; min-height: 44px;
  padding: 9px 12px; border-radius: 10px; font-size: 13px; text-align: left;
  border: 1px solid var(--border); background: var(--bg);
}
button.jm-pop { cursor: pointer; color: var(--text); }
.jm-pop-act { border-color: var(--accent); color: var(--accent); font-weight: 700; }
.jm-pop-ok { color: var(--ok, #00c875); font-weight: 600; }
.jm-pop-warn { border-color: var(--warn, #f5a623); color: var(--warn, #b97900); font-weight: 600; }
.jm-pop-due { border-color: var(--danger, #e2445c); color: var(--danger, #e2445c); font-weight: 700; }
.jm-face-links { margin-top: 8px; }
.jm-face-prog { margin-top: 4px; }
.jm-count { font-weight: 400; color: var(--muted); font-size: 12px; }
.jm-wxline { margin-top: 6px; }
.jm-aftercare .jm-care { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; font-size: 12.5px; cursor: pointer; }
.jt-board .kanban-card .kc-owed { color: var(--danger, #e2445c); font-weight: 700; }

/* STAGECARD 2026-08-19 — phone-density pass, scoped to the stage-card EDIT modal
   only (.jm-modal is set by openJobModal on edit jobs; every other modal and the
   whole desktop layout are byte-identical). The 512px visible phone body must fit
   the band + the DONE face's Record-payment row on screen 1 (0 scroll), and the
   working view must land ≤6.0 screens: the app-wide .field margin-bottom (12px)
   is redundant INSIDE a 12px-gap grid, and 4 stacked textareas at full height
   were ~25% of the fold. */
@media (max-width: 640px) {
  .jm-modal .form-grid { gap: 8px; }
  .jm-modal .form-grid > .field { margin-bottom: 0; }
  .jm-modal .textarea { min-height: 56px; }
  .jm-modal .jm-face { padding: 8px; }
  .jm-modal .jm-band { margin-bottom: 6px; }
  .jm-modal .jm-onsite { padding: 7px 10px; }
  /* the un-buried Service progress block carries its old in-fold divider chrome
     (border-top + 10px pad + 4px margin as inline styles) — redundant inside the
     face's own bordered card on a phone */
  .jm-modal .jm-face-prog > .full { border-top: 0 !important; padding-top: 0 !important; margin-top: 0 !important; }
  .jm-modal .jm-strip { margin: 6px 0 2px; }
  .jm-modal .jm-face-links { margin-top: 4px; }
}
