﻿/* === bundle-components.css === */
/* Generated 2026-06-22 20:27 — DO NOT EDIT DIRECTLY */

/* --- voice-playback.css --- */
/* ============================================================
   ATLAS â€” Voice Playback widget (R&D view)  Â· Wave 13-W165
   Anna / Grace last-5 call list + transcript/audio modal.
   Token-only (both light + dark auto-valid), layout-neutral
   (the list scrolls internally â€” the 1080 frame never does),
   self-contained (the modal is a fixed, centered overlay).
   ============================================================ */

.vp-panel { display: flex; flex-direction: column; min-height: 0; }

.vp-pill {
  font: 700 9px/1 var(--mono, monospace); letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--accent, #00d2ff); background: rgba(var(--accent-rgb, 0 210 255), 0.12);
  border: 1px solid rgba(var(--accent-rgb, 0 210 255), 0.32);
  padding: 3px 7px; border-radius: 999px; margin-left: 8px;
}
.vp-pill.is-empty { color: var(--text-muted, #8a93a6); background: var(--panel2, rgba(255,255,255,0.04)); border-color: var(--border, rgba(255,255,255,0.10)); }

/* â”€â”€ call list â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.vp-list {
  margin: 4px 0 0; padding: 2px 2px 2px 0;
  display: flex; flex-direction: column;
  overflow: auto; min-height: 0; max-height: 100%;
}
.vp-row {
  display: grid; grid-template-columns: 96px 1fr auto;
  align-items: center; gap: 14px; width: 100%; text-align: left;
  padding: 10px 10px 10px 4px; cursor: pointer;
  background: transparent; border: none; border-bottom: 1px solid var(--border, rgba(255,255,255,0.06));
  transition: background .14s ease, transform .12s ease;
  font-family: inherit; color: inherit;
}
.vp-row:last-child { border-bottom: none; }
.vp-row:hover { background: var(--panel2, rgba(255,255,255,0.035)); transform: translateX(2px); }
.vp-row:focus-visible { outline: 2px solid var(--accent, #00d2ff); outline-offset: -2px; border-radius: 8px; }

.vp-row-l { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.vp-when { font: 600 9.5px/1.2 var(--mono, monospace); letter-spacing: 0.02em; text-transform: uppercase; color: var(--text-muted, #8a93a6); white-space: nowrap; }

/* agent badge (Anna / Grace) â€” semantic colour per agent */
.vp-agent {
  font: 700 9px/1 var(--mono, monospace); letter-spacing: 0.05em; text-transform: uppercase;
  padding: 3px 7px; border-radius: 6px; white-space: nowrap; width: fit-content;
  color: var(--accent, #00d2ff); background: rgba(var(--accent-rgb, 0 210 255), 0.12);
  border: 1px solid rgba(var(--accent-rgb, 0 210 255), 0.30);
}
.vp-agent[data-agent="grace"] {
  color: var(--accent2, #b98bff); background: rgba(var(--accent2-rgb, 185 139 255), 0.14);
  border-color: rgba(var(--accent2-rgb, 185 139 255), 0.30);
}

.vp-row-m { min-width: 0; }
.vp-snippet {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  font: 400 11.5px/1.45 var(--sans, system-ui); color: var(--text-dim, #9aa7b8);
}
.vp-contact { display: block; margin-top: 3px; font: 600 9.5px/1.2 var(--mono, monospace); color: var(--text-muted, #8a93a6); }

.vp-row-r { display: flex; align-items: center; gap: 8px; white-space: nowrap; }
.vp-has-audio { font-size: 9px; color: var(--accent, #00d2ff); line-height: 1; }

/* auto-label badge â€” colour comes ONLY from the pipeline tone (never re-derived) */
.vp-label {
  font: 700 8.5px/1 var(--mono, monospace); letter-spacing: 0.05em; text-transform: uppercase;
  padding: 4px 7px; border-radius: 6px; white-space: nowrap;
  color: var(--text-muted, #8a93a6); background: var(--panel2, rgba(255,255,255,0.04));
  border: 1px solid var(--border, rgba(255,255,255,0.08));
}
.vp-label[data-empty="1"] { opacity: 0.85; font-style: normal; }
.vp-label[data-tone="good"] { color: var(--good, #3affad); background: rgba(var(--good-rgb, 58 255 173), 0.12); border-color: rgba(var(--good-rgb, 58 255 173), 0.3); }
.vp-label[data-tone="warn"] { color: var(--warn, #ffb648); background: rgba(var(--warn-rgb, 255 182 72), 0.12); border-color: rgba(var(--warn-rgb, 255 182 72), 0.3); }
.vp-label[data-tone="bad"]  { color: var(--bad,  #ff5b3a); background: rgba(var(--bad-rgb, 255 91 58), 0.12); border-color: rgba(var(--bad-rgb, 255 91 58), 0.3); }

.vp-empty { padding: 28px 16px; text-align: center; color: var(--text-muted, #8a93a6); font: 500 12px/1.5 var(--sans, system-ui); }

/* â”€â”€ modal (centered, fixed overlay â€” never affects the 1080 frame) â”€â”€ */
.vp-overlay {
  position: fixed; inset: 0; z-index: 9100; display: none;
  background: rgba(4, 8, 16, 0.6); backdrop-filter: blur(3px);
}
.vp-overlay.visible { display: grid; place-items: center; animation: vp-fade .16s ease; }
@keyframes vp-fade { from { opacity: 0; } to { opacity: 1; } }
.vp-modal {
  width: min(620px, 94vw); max-height: 86vh; display: flex; flex-direction: column;
  background: var(--panel, #0d1320); color: var(--text, #e8ecf3);
  border: 1px solid var(--border2, rgba(255,255,255,0.14)); border-radius: 14px;
  box-shadow: 0 30px 80px rgba(0,0,0,0.55);
  transform: translateY(10px) scale(0.985); opacity: 0;
  transition: transform .22s cubic-bezier(0.16,1,0.3,1), opacity .2s ease;
}
.vp-overlay.visible .vp-modal { transform: translateY(0) scale(1); opacity: 1; }

.vp-m-head {
  display: flex; align-items: flex-start; gap: 12px; flex: 0 0 auto;
  padding: 16px 18px 13px; border-bottom: 1px solid var(--border, rgba(255,255,255,0.08));
}
.vp-m-titles { min-width: 0; flex: 1; }
.vp-m-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.vp-m-sub { display: block; margin-top: 7px; font: 600 10px/1.3 var(--mono, monospace); letter-spacing: 0.03em; text-transform: uppercase; color: var(--text-muted, #8a93a6); }
.vp-m-x {
  flex: 0 0 auto; cursor: pointer; width: 30px; height: 30px; display: grid; place-items: center;
  border-radius: 8px; font-size: 15px; color: var(--text-muted, #8a93a6);
  background: transparent; border: 1px solid var(--border, rgba(255,255,255,0.08));
}
.vp-m-x:hover { color: var(--text, #fff); background: var(--panel2, rgba(255,255,255,0.05)); }
.vp-m-x:focus-visible { outline: 2px solid var(--accent, #00d2ff); outline-offset: 2px; }

.vp-m-body { flex: 1 1 auto; overflow: auto; padding: 16px 18px 22px; }

/* audio */
.vp-audio { margin: 0 0 14px; }
.vp-audio audio { width: 100%; height: 38px; }
.vp-audio-none {
  font: 500 11px/1.5 var(--sans, system-ui); color: var(--text-muted, #8a93a6);
  background: var(--bg2, rgba(255,255,255,0.03)); border: 1px dashed var(--border, rgba(255,255,255,0.10));
  border-radius: 8px; padding: 10px 12px;
}

/* judge / auto-label detail */
.vp-judge {
  margin: 0 0 16px; border: 1px solid var(--border, rgba(255,255,255,0.08)); border-radius: 10px;
  background: var(--bg2, rgba(255,255,255,0.025)); overflow: hidden;
}
.vp-j-row { display: grid; grid-template-columns: 116px 1fr; gap: 10px; padding: 8px 12px; border-bottom: 1px solid var(--border, rgba(255,255,255,0.05)); }
.vp-j-row:last-child { border-bottom: none; }
.vp-j-k { font: 700 9px/1.5 var(--mono, monospace); letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-muted, #8a93a6); }
.vp-j-v { font: 400 12px/1.5 var(--sans, system-ui); color: var(--text, #e8ecf3); }

/* transcript */
.vp-tx-head { font: 700 9.5px/1 var(--mono, monospace); letter-spacing: 0.06em; text-transform: uppercase; color: var(--accent, #00d2ff); margin: 0 0 9px; }
.vp-tx {
  font: 400 12.5px/1.6 var(--sans, system-ui); color: var(--text, #e8ecf3);
  background: var(--bg2, rgba(255,255,255,0.02)); border: 1px solid var(--border, rgba(255,255,255,0.07));
  border-radius: 10px; padding: 12px 14px;
}
.vp-tx-line { margin: 0 0 5px; }
.vp-tx-gap { height: 8px; }
.vp-tx-spk { font-weight: 700; color: var(--accent, #00d2ff); }
.vp-tx-line.vp-tx-note { color: var(--text-dim, #9aa7b8); font-style: italic; }

/* â”€â”€ mobile â”€â”€ */
@media (max-width: 760px) {
  .vp-row { grid-template-columns: 80px 1fr; gap: 10px; }
  .vp-row-r { grid-column: 2; justify-self: start; margin-top: 4px; }
  .vp-modal { width: 100vw; max-height: 92vh; border-radius: 12px 12px 0 0; }
  .vp-j-row { grid-template-columns: 96px 1fr; }
}

/* --- polish.css --- */
/* polish.css â€” ATLAS department-view polish layer (loaded LAST).
 *
 * PURPOSE: lift the 8 in-page department views (Listings, Transactions, Sales,
 * Marketing, Client Care, Agent, Admin & Ops, AI Build / R&D) + the Training
 * Center from a flat "dashboard-by-numbers" look to the factory $10â€“20K bar â€”
 * depth, type hierarchy, semantic per-dept colour, hand-crafted hover/focus,
 * and motion that clarifies flow. Adapts the documented JARVIS HUD vocabulary
 * (ATLAS_UI_DESIGN_VOCABULARY.md) â€” never pixel-copies any other product.
 *
 * THREE HARD GUARANTEES (so this file is safe to drop in last):
 *  1. THEME-SAFE â€” references ONLY the shared design tokens (--bg/--panel/
 *     --accent/--accent-rgb/--good/--warn/--bad/--accent2â€¦), which north_star
 *     redefines for BOTH :root (dark) and :root[data-theme="light"]. No literal
 *     colours except inside dark-only luminous effects, which are gated behind
 *     :root:not([data-theme="light"]).
 *  2. LAYOUT-NEUTRAL / NO-SCROLL â€” only paints (background, border-colour,
 *     box-shadow, border-radius, colour, type within existing line-heights) and
 *     compositor-only transforms/opacity. It NEVER changes the .frame/.canvas/
 *     view flex heights, never adds block margins to the flex chain â€” so the
 *     locked 1920Ã—1080 frame still totals 1080 (feedback_dashboard_scroll_rule).
 *  3. SCOPED â€” every selector is a dept/training primitive (.tc-*/.dept-*) or a
 *     #view-<dept> container. The Command Center home view (.kpi-tile/.agent-
 *     card/.bp-card/.alerts-colâ€¦) is deliberately untouched.
 *
 * Sales view (#view-sales) is being added by a parallel dispatch; it reuses the
 * same .tc-*/.dept-* primitives, so it inherits this polish automatically. The
 * per-dept accent block below pre-declares #view-sales defensively (harmless if
 * absent).
 */

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 1. SEMANTIC PER-DEPARTMENT ACCENT  (quality 5 â€” colour used semantically)
 *    --da     = the department's signature colour (any token, incl. warn/bad)
 *    --da-rgb = an rgb-triple-backed token for low-alpha glows (accent/good/
 *               accent2 only â€” warn/bad have no -rgb token, so glows borrow the
 *               nearest warm/cool rgb while the solid tick stays semantic).
 *    Both themes resolve because every token below is defined in both.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
#view-listings    { --da: var(--accent);   --da-rgb: var(--accent-rgb);  }
#view-transactions{ --da: var(--good);     --da-rgb: var(--good-rgb);    }
#view-sales       { --da: var(--accent2);  --da-rgb: var(--accent2-rgb); }
#view-marketing   { --da: var(--warn);     --da-rgb: var(--accent2-rgb); }
#view-clientcare  { --da: var(--accent);   --da-rgb: var(--accent-rgb);  }
#view-agent       { --da: var(--accent2);  --da-rgb: var(--accent2-rgb); }
#view-admin       { --da: var(--text-dim); --da-rgb: var(--accent-rgb);  }
#view-rd          { --da: var(--good);     --da-rgb: var(--good-rgb);    }
#view-training    { --da: var(--accent);   --da-rgb: var(--accent-rgb);  }

/* Global default so any primitive that reads --da/--da-rgb outside a declared
 * view still resolves (non-cyclic â€” NOT self-referential). Per-view #view-*
 * selectors above (specificity 1,0,0) override this :root default (0,1,0), and
 * custom properties inherit down to the panels. */
:root { --da: var(--accent); --da-rgb: var(--accent-rgb); }

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 2. VIEW ATMOSPHERE  (quality 8 â€” texture/atmosphere fitting the HUD)
 *    A single soft directional glow in the dept's signature hue, top-right,
 *    plus a whisper of grain via a layered radial. Painted on the view's own
 *    background (behind the panels) so it reads as ambient depth, not a box.
 *    Background-only â†’ zero layout effect.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
#view-listings, #view-transactions, #view-sales, #view-marketing,
#view-clientcare, #view-agent, #view-admin, #view-rd, #view-training {
  background-image:
    radial-gradient(115% 75% at 100% -8%, rgba(var(--da-rgb), 0.055), transparent 58%),
    radial-gradient(90% 60% at -6% 110%, rgba(var(--accent2-rgb), 0.035), transparent 60%);
  background-repeat: no-repeat;
}

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 3. PANEL DEPTH  (quality 3 â€” depth via layered surfaces + shadow)
 *    Re-skins the shared .tc-panel (used by every dept + training panel) with a
 *    top-lit gradient surface, a real drop shadow, and an inset hairline
 *    highlight that fakes a bevelled top edge. Border-radius nudged up. A left
 *    accent rail keyed to the dept colour anchors each panel.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.tc-panel {
  position: relative;
  border-color: var(--border);
  border-radius: 11px;
  background:
    linear-gradient(180deg, rgba(var(--da-rgb), 0.05), rgba(var(--da-rgb), 0) 34%),
    var(--panel);
  box-shadow:
    0 1px 0 rgba(var(--accent-rgb), 0.05) inset,
    0 10px 26px -16px rgba(0, 0, 0, 0.62);
  transition: border-color 0.2s ease, box-shadow 0.22s ease, transform 0.22s cubic-bezier(0.16, 1, 0.3, 1);
}
/* Signature left rail â€” semantic, not decorative (the dept's colour). */
.tc-panel::after {
  content: "";
  position: absolute;
  left: 0; top: 10px; bottom: 10px;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, var(--da), transparent 88%);
  opacity: 0.55;
  transition: opacity 0.22s ease, box-shadow 0.22s ease;
  pointer-events: none;
}
/* Hand-crafted hover (quality 6) â€” lift + rim-light + the rail ignites. */
.tc-panel:hover {
  border-color: rgba(var(--da-rgb), 0.5);
  transform: translateY(-2px);
  box-shadow:
    0 1px 0 rgba(var(--da-rgb), 0.16) inset,
    0 16px 34px -16px rgba(0, 0, 0, 0.7),
    0 0 0 1px rgba(var(--da-rgb), 0.12);
}
.tc-panel:hover::after { opacity: 1; box-shadow: 0 0 10px rgba(var(--da-rgb), 0.55); }

/* Dark-only luminous lift on the surface gradient (kept off light theme, where
 * north_star strips glow for a clean paper look). */
:root:not([data-theme="light"]) .tc-panel {
  box-shadow:
    0 1px 0 rgba(var(--accent-rgb), 0.07) inset,
    0 12px 30px -16px rgba(0, 0, 0, 0.75);
}

/* Panel header â€” give the shared .panel-h inside dept panels a tighter accent
 * tick + clearer label hierarchy. (Descendant-scoped so the home view's
 * .panel-h is never touched.) */
.tc-panel .panel-h { letter-spacing: 0.02em; }
.tc-panel .panel-h::before { background: linear-gradient(180deg, var(--da), transparent) !important; }

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 4. KPI TILES  (quality 1 â€” hierarchy via scale contrast; 3 â€” depth)
 *    Bigger, tabular, glowing value vs. a quieter wider-tracked label; a thin
 *    dept-accent rule across the top; depth + hover. Type stays within the
 *    existing line-heights so tile height barely moves (no-scroll-safe).
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.dept-kpi, .tc-stat {
  position: relative;
  border-color: var(--border);
  border-radius: 10px;
  background:
    linear-gradient(180deg, rgba(var(--da-rgb), 0.06), rgba(var(--da-rgb), 0) 60%),
    var(--panel);
  box-shadow: 0 6px 16px -12px rgba(0, 0, 0, 0.6);
  overflow: hidden;
  transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}
.dept-kpi::before, .tc-stat::before {
  content: "";
  position: absolute;
  left: 12%; right: 12%; top: 0;
  height: 2px;
  border-radius: 0 0 2px 2px;
  background: linear-gradient(90deg, transparent, var(--da), transparent);
  opacity: 0.6;
  transition: opacity 0.2s ease, left 0.25s ease, right 0.25s ease;
}
.dept-kpi:hover, .tc-stat:hover {
  border-color: rgba(var(--da-rgb), 0.45);
  transform: translateY(-1px);
  box-shadow: 0 10px 22px -12px rgba(0, 0, 0, 0.66);
}
.dept-kpi:hover::before, .tc-stat:hover::before { opacity: 1; left: 4%; right: 4%; }

.dept-kpi-val, .tc-stat-val {
  font-size: 25px;
  letter-spacing: -0.012em;
  font-variant-numeric: tabular-nums;
}
.dept-kpi-lab, .tc-stat-lab { letter-spacing: 0.14em; opacity: 0.92; }
/* Dark-only value glow â€” the HUD read; off in light theme. */
:root:not([data-theme="light"]) .dept-kpi-val,
:root:not([data-theme="light"]) .tc-stat-val,
:root:not([data-theme="light"]) .tc-prog-val {
  text-shadow: 0 0 16px rgba(var(--da-rgb), 0.28);
}
/* Text-valued KPI (e.g. Top Organic Query) keeps its readable size â€” no number
 * scale-up, just inherit the quieter colour. */
.dept-kpi-val.dept-kpi-text { font-size: 11px; text-shadow: none; }

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 5. LIST ROWS  (quality 2 â€” rhythm; 6 â€” hover/active)
 *    Rows get a subtle inset surface, a hover lift with a dept-accent left
 *    edge, and an active press. Badges/progress get a touch more presence.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.tc-row {
  position: relative;
  border-color: var(--border2);
  transition: background 0.16s ease, border-color 0.16s ease, transform 0.16s ease, box-shadow 0.16s ease;
}
.tc-row::before {
  content: "";
  position: absolute;
  left: -1px; top: 8%; bottom: 8%;
  width: 2px;
  border-radius: 2px;
  background: var(--da);
  opacity: 0;
  transition: opacity 0.16s ease;
}
.tc-row:hover {
  border-color: rgba(var(--da-rgb), 0.4);
  background: linear-gradient(90deg, rgba(var(--da-rgb), 0.07), rgba(var(--da-rgb), 0.015) 60%), var(--bg2);
  transform: translateX(2px);
  box-shadow: 0 6px 16px -12px rgba(0, 0, 0, 0.5);
}
.tc-row:hover::before { opacity: 0.85; }
.tc-row:active { transform: translateX(1px) scale(0.997); }

.tc-prog { box-shadow: 0 0 0 1px rgba(var(--accent-rgb), 0.05) inset; }
.tc-prog-fill { background: linear-gradient(90deg, var(--da), var(--accent)); }
.tc-badge { backdrop-filter: saturate(1.1); }

/* Status dots (AI-RD) + spend bars â€” give them a faint matching glow in dark. */
:root:not([data-theme="light"]) .rd-dot.is-green   { box-shadow: 0 0 7px rgba(var(--good-rgb), 0.6); }
:root:not([data-theme="light"]) .rd-dot.is-yellow  { box-shadow: 0 0 7px rgba(255, 184, 72, 0.55); }
:root:not([data-theme="light"]) .rd-dot.is-red     { box-shadow: 0 0 7px rgba(255, 74, 106, 0.55); }

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 6. HEADERS + TITLES  (quality 1/4 â€” hierarchy + type character)
 *    The dept/training title gets more scale + a fine cyan underglow; the org
 *    sub-line + Obsidian link get crisp focus states (quality 6, a11y).
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.dept-head .tc-title, .tc-head .tc-title {
  font-size: 24px;
  letter-spacing: 0.04em;
}
:root:not([data-theme="light"]) .dept-head .tc-title,
:root:not([data-theme="light"]) .tc-head .tc-title {
  text-shadow: 0 0 22px rgba(var(--da-rgb), 0.22);
}
.dept-obsidian-link:focus-visible,
.tc-search:focus-visible {
  outline: 2px solid var(--da);
  outline-offset: 2px;
}
.dept-obsidian-link:hover { border-color: var(--da); color: var(--da); }
.tc-search:focus { border-color: var(--da); box-shadow: 0 0 0 3px rgba(var(--da-rgb), 0.16); }

/* Internal scrollbars â€” accent thumb on hover, matches the HUD. */
.tc-body::-webkit-scrollbar-thumb:hover { background: rgba(var(--da-rgb), 0.55); }

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 7. MOTION  (quality 9 â€” motion that clarifies flow)
 *    When a dept view is revealed (its .view-off is removed â†’ display flips
 *    from none), the KPI strip and panels rise + fade in a short stagger, so
 *    the eye is led topâ†’down through the layout. Compositor-only (opacity +
 *    translateY) â†’ cheap + no reflow. Fully disabled under reduced-motion.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
@keyframes atlas-rise {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes atlas-kpi-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

.dept-kpis > .dept-kpi { animation: atlas-kpi-in 0.4s cubic-bezier(0.16, 1, 0.3, 1) both; }
.dept-kpis > .dept-kpi:nth-child(2) { animation-delay: 0.03s; }
.dept-kpis > .dept-kpi:nth-child(3) { animation-delay: 0.06s; }
.dept-kpis > .dept-kpi:nth-child(4) { animation-delay: 0.09s; }
.dept-kpis > .dept-kpi:nth-child(5) { animation-delay: 0.12s; }
.dept-kpis > .dept-kpi:nth-child(6) { animation-delay: 0.15s; }

.dept-grid > .tc-panel, .tc-grid > .tc-panel {
  animation: atlas-rise 0.46s cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: 0.08s;
}
.dept-grid > .tc-panel:nth-child(2), .tc-grid > .tc-panel:nth-child(2) { animation-delay: 0.13s; }
.dept-grid > .tc-panel:nth-child(3), .tc-grid > .tc-panel:nth-child(3) { animation-delay: 0.18s; }
.dept-grid > .tc-panel:nth-child(4), .tc-grid > .tc-panel:nth-child(4) { animation-delay: 0.23s; }
.dept-grid > .tc-panel:nth-child(5), .tc-grid > .tc-panel:nth-child(5) { animation-delay: 0.28s; }
.dept-grid > .tc-panel:nth-child(6), .tc-grid > .tc-panel:nth-child(6) { animation-delay: 0.33s; }
.dept-grid > .tc-panel:nth-child(7) { animation-delay: 0.38s; }

@media (prefers-reduced-motion: reduce) {
  .tc-panel, .dept-kpi, .tc-stat, .tc-row { transition: none; }
  .dept-kpis > .dept-kpi,
  .dept-grid > .tc-panel, .tc-grid > .tc-panel { animation: none; }
  .tc-panel:hover, .dept-kpi:hover, .tc-stat:hover, .tc-row:hover { transform: none; }
}

/* --- kpi-strip.css --- */
/* ============================================================
   kpi-strip.css â€” 6 equal-width KPI tiles + trend arrows + KPI detail modal.
   Loads after north_star_final.css + polish.css so these win. Reuses the
   existing .kpi-tile / .kpi-number / .kpi-label / .kpi-spark / .kpi-compare
   tokens; only adds the 6-column grid, the new .kpi-trend element, plain
   (gradient-free) sparkline paint, and the #kpi-modal internals. Theme-aware
   via existing vars (--text, --text-muted, --accent, --good, --bad). No-scroll
   safe: the strip keeps its fixed height from north_star_final.css.
   ============================================================ */

/* 6 equal columns (was a mixed 7-tile flex/grid) */
.kpi-strip {
  display: grid !important;
  grid-template-columns: repeat(6, 1fr) !important;
  gap: 10px !important;
  align-items: stretch !important;
}

/* tiles are now clickable */
.kpi-tile {
  cursor: pointer;
  transition: background var(--motion-fast, 0.15s) ease;
  border-right: 1px solid var(--line) !important;
}
.kpi-tile:last-child { border-right: none !important; }
.kpi-tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.kpi-tile:hover { background: var(--surface-2) !important; filter: none; }
.kpi-tile.active,
.kpi-tile:focus:not(:focus-visible) {
  background: var(--champagne-soft) !important;
  border-bottom: 2px solid var(--champagne) !important;
}

/* head holds label + trend on one row */
.kpi-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; }

/* label â€” 8.5px, all-caps (overrides north_star_final.css 7.5px; colors stay
   theme-aware via north_star_final.css light/dark rules) */
.kpi-strip .kpi-label {
  font-size: var(--typography-size-sm, 8.5px) !important;
  letter-spacing: 0.14em !important;
}

/* number â€” large bold value token */
.kpi-strip .kpi-number {
  font-size: var(--typography-size-4xl, 28px) !important;
  font-weight: var(--typography-weight-bold, 700) !important;
}

/* structural sparkline placeholder â€” flat line = no data yet (honest) */
.kpi-sparkline {
  width: 100%; height: 18px;
  display: block; margin: 2px 0 1px;
  opacity: 0.55;
  flex-shrink: 0;
}
/* CSS var in SVG presentation attr doesn't resolve â€” style via CSS instead */
.kpi-sparkline polyline {
  stroke: var(--border);
  stroke-width: 1.5;
  fill: none;
}
/* hide placeholder once live data renders in .kpi-spark */
.kpi-tile[data-state="live"] .kpi-sparkline { display: none; }

/* trend chip â€” CSS triangle (no unicode/emoji arrows per global rule) */
.kpi-trend {
  font-family: var(--mono); font-size: 9.5px; font-weight: 700;
  display: inline-flex; align-items: center; gap: 3px; color: var(--text-muted);
}
.kpi-trend::before { content: ""; width: 0; height: 0; display: inline-block; }
.kpi-trend[data-dir="good"] { color: var(--good); }
.kpi-trend[data-dir="good"]::before {
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-bottom: 6px solid currentColor;
}
.kpi-trend[data-dir="bad"] { color: var(--bad); }
.kpi-trend[data-dir="bad"]::before {
  border-left: 4px solid transparent; border-right: 4px solid transparent;
  border-top: 6px solid currentColor;
}
.kpi-trend[data-dir="flat"] { color: var(--text-muted); }
.kpi-trend[data-dir="flat"]::before { content: none; }

/* gradient-free sparkline, accent per metric via --ka */
.kpi-strip .kpi-spark-line { fill: none; stroke: var(--ka, var(--accent)); stroke-width: 1.4; vector-effect: non-scaling-stroke; }
.kpi-strip .kpi-spark-fill { fill: var(--ka, var(--accent)); opacity: .16; stroke: none; }

.kpi-tile[data-metric="ytd_volume"]        { --ka: #3affad; }
.kpi-tile[data-metric="pipeline_value"]    { --ka: #9c5cff; }
.kpi-tile[data-metric="upcoming_closings"] { --ka: #00e5ff; }
.kpi-tile[data-metric="avg_deal_ytd"]      { --ka: #ff9966; }
.kpi-tile[data-metric="new_7d"]            { --ka: #c084fc; }
.kpi-tile[data-metric="open_tasks"]        { --ka: #ffb648; }

/* honest non-live states */
.kpi-tile[data-state="empty"] .kpi-number,
.kpi-tile[data-state="error"] .kpi-number { opacity: .45; }
.kpi-tile[data-state="empty"] .kpi-compare { color: var(--text-muted); font-style: italic; }
.kpi-tile[data-state="error"] .kpi-compare { color: var(--bad); }

/* â”€â”€ Responsive grid â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
   <1400px â†’ 3Ã—2  (laptop portrait / narrow desktop)
   <900px  â†’ 2Ã—3  (small laptop / large tablet)
   Both keep height:auto so tiles don't clip. Separator logic resets
   so only rightmost tile in each row loses its border-right.          */
@media (max-width: 1400px) {
  .kpi-strip {
    grid-template-columns: repeat(3, 1fr) !important;
    height: auto !important;
  }
  .kpi-tile { border-right: 1px solid var(--line) !important; }
  .kpi-tile:nth-child(3n) { border-right: none !important; }
  .kpi-tile:last-child    { border-right: none !important; }
}
@media (max-width: 900px) {
  .kpi-strip { grid-template-columns: repeat(2, 1fr) !important; }
  .kpi-tile                { border-right: 1px solid var(--line) !important; }
  .kpi-tile:nth-child(2n)  { border-right: none !important; }
  .kpi-tile:last-child     { border-right: none !important; }
}

/* â”€â”€ KPI detail modal (scoped â€” does not touch other .atlas-modal cards) â”€â”€
   W154: tile click-through â†’ detail modal with 30-day line chart + category
   breakdown + source endpoint. The card is a bounded flex column so the body
   scrolls INTERNALLY (the base .atlas-modal-body already has overflow-y:auto;
   flex:1) â€” the dashboard's outer 1080 frame is never touched. --mxa is the
   per-metric accent set inline by kpi-strip.js openModal(). */
#kpi-modal { align-items: center; justify-content: center; }
#kpi-modal .atlas-modal-card {
  max-width: 540px; width: 92%; position: relative;
  max-height: 86vh; display: flex; flex-direction: column;
}
#kpi-modal .atlas-modal-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex: 0 0 auto; }
#kpi-modal .atlas-modal-head h2 { font-family: var(--display); font-size: 16px; margin: 0; color: var(--text); }
#kpi-modal .atlas-modal-x {
  position: absolute; top: 8px; right: 12px; background: none; border: none;
  color: var(--text-muted); font-size: 22px; line-height: 1; cursor: pointer; z-index: 2;
}
#kpi-modal .atlas-modal-x:hover { color: var(--text); }
.kpi-modal-org { font-family: var(--mono); font-size: 11px; color: var(--text-muted); margin-left: auto; }
.kpi-modal-hero { display: flex; align-items: baseline; gap: 12px; margin: 6px 0 4px; }
.kpi-modal-num { font-family: var(--display); font-size: 40px; font-weight: 700; color: var(--text); line-height: 1; }
.kpi-modal-trend { font-size: 14px; }
.kpi-modal-prev { font-size: 12px; color: var(--text-muted); margin: 0 0 12px; }
.kpi-modal-empty { font-size: 13px; color: var(--text-muted); }

/* sections */
.kpi-mx-sec { margin: 0 0 16px; }
.kpi-mx-sec:last-child { margin-bottom: 2px; }
.kpi-mx-h {
  font-family: var(--mono); font-size: 10px; font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-muted); margin: 0 0 7px;
  border-bottom: 1px solid var(--border); padding-bottom: 5px;
}
.kpi-mx-note { font-size: 11px; color: var(--text-muted); margin: 0 0 8px; font-style: italic; }
.kpi-mx-empty {
  font-size: 12px; color: var(--text-muted); font-style: italic;
  padding: 14px 10px; text-align: center; background: rgba(127,127,127,.07);
  border: 1px dashed var(--border); border-radius: 6px;
}

/* line chart */
.kpi-mx-chart { width: 100%; height: auto; display: block; }
.kpi-mx-grid { stroke: var(--border); stroke-width: 1; opacity: .55; }
.kpi-mx-area { fill: var(--mxa, var(--accent)); opacity: .14; stroke: none; }
.kpi-mx-line {
  fill: none; stroke: var(--mxa, var(--accent)); stroke-width: 2;
  stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke;
}
.kpi-mx-dot { fill: var(--mxa, var(--accent)); stroke: var(--bg3); stroke-width: 1.5; }
.kpi-mx-axt { fill: var(--text-muted); font-family: var(--mono); font-size: 11px; }

/* category breakdown bars */
.kpi-mx-bd { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 7px; }
.kpi-mx-bdrow { display: grid; grid-template-columns: minmax(72px, 34%) 1fr auto; align-items: center; gap: 9px; }
.kpi-mx-bdlab {
  font-size: 11.5px; color: var(--text); white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis;
}
.kpi-mx-bdtrack { height: 8px; border-radius: 4px; background: rgba(127,127,127,.14); overflow: hidden; }
.kpi-mx-bdfill { display: block; height: 100%; border-radius: 4px; background: var(--mxa, var(--accent)); opacity: .85; }
.kpi-mx-bdval { font-family: var(--mono); font-size: 10.5px; color: var(--text-muted); white-space: nowrap; }

/* source */
.kpi-mx-srcsec .kpi-modal-src { font-size: 10.5px; color: var(--text-muted); margin: 0 0 4px; word-break: break-all; }
.kpi-mx-srcsec code {
  font-family: var(--mono); font-size: 10px; color: var(--text);
  background: rgba(127,127,127,.12); padding: 1px 5px; border-radius: 3px;
}

/* mobile */
@media (max-width: 480px) {
  #kpi-modal .atlas-modal-card { width: 95%; max-height: 90vh; padding: 18px 16px; }
  .kpi-modal-num { font-size: 32px; }
  .kpi-mx-bdrow { grid-template-columns: minmax(60px, 40%) 1fr auto; gap: 6px; }
  .kpi-mx-axt { font-size: 13px; }
}

/* â”€â”€ KPI hover-card data preview (W175) â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
   A read-only peek overlay: position:fixed + pointer-events:none so it adds
   no layout and can never make the 1080 frame scroll. Hidden by default;
   .is-on fades it in. --mxa is the per-metric accent set inline by
   renderHoverCard(). Theme-aware via --bg2/--bg3/--text/--border vars. */
.kpi-hovercard {
  position: fixed; left: 0; top: 0; z-index: 1200;
  width: 252px; max-width: calc(100vw - 16px);
  padding: 11px 12px 10px;
  background: var(--bg2, #14181f);
  border: 1px solid var(--border, rgba(127,127,127,.25));
  border-top: 2px solid var(--mxa, var(--accent));
  border-radius: 9px;
  box-shadow: 0 12px 34px rgba(0,0,0,.42), 0 2px 8px rgba(0,0,0,.28);
  pointer-events: none;
  opacity: 0; transform: translateY(-4px);
  transition: opacity .14s ease, transform .14s ease;
}
.kpi-hovercard.is-on { opacity: 1; transform: translateY(0); }

.kpi-hc-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 8px; }
.kpi-hc-title {
  font-family: var(--mono); font-size: 9.5px; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-muted); line-height: 1.25;
}
.kpi-hc-val { font-family: var(--display); font-size: 19px; font-weight: 700; color: var(--text); line-height: 1; white-space: nowrap; }

.kpi-hc-vizlabel { font-family: var(--mono); font-size: 8.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--text-muted); margin-bottom: 4px; }
.kpi-hc-spark { width: 100%; height: 34px; display: block; }
.kpi-hc-line { fill: none; stroke: var(--mxa, var(--accent)); stroke-width: 1.6; stroke-linejoin: round; stroke-linecap: round; vector-effect: non-scaling-stroke; }
.kpi-hc-fill { fill: var(--mxa, var(--accent)); opacity: .15; stroke: none; }

.kpi-hc-pts { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 7px; }
.kpi-hc-chip {
  font-family: var(--mono); font-size: 9.5px; color: var(--text);
  background: rgba(127,127,127,.13); border-radius: 4px; padding: 1px 5px; line-height: 1.5;
}

.kpi-hc-empty {
  font-size: 11px; color: var(--text-muted); font-style: italic; text-align: center;
  padding: 12px 8px; background: rgba(127,127,127,.07);
  border: 1px dashed var(--border); border-radius: 6px;
}

.kpi-hc-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-top: 9px; padding-top: 7px; border-top: 1px solid var(--border);
}
.kpi-hc-ref { font-family: var(--mono); font-size: 9px; color: var(--text-muted); white-space: nowrap; }
.kpi-hc-ep {
  font-family: var(--mono); font-size: 8.5px; color: var(--text-muted);
  max-width: 138px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  direction: rtl; text-align: right;
}

@media (max-width: 480px) {
  .kpi-hovercard { width: 232px; }
  .kpi-hc-val { font-size: 17px; }
}

/* â”€â”€ KPI Detail Drawer (slide-in panel from right) â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
   Replaces the centered #kpi-modal overlay. kpi-strip.js calls
   window.openKpiDrawer(title, html) which adds .open to trigger the slide.
   z-index 600 sits above the dashboard frame (z 1) and hovercard (z 1200
   is only shown while the drawer is closed). Theme-aware via project vars. */
.kpi-drawer {
  position: fixed;
  top: 0; right: 0;
  width: min(420px, 95vw);
  height: 100vh;
  background: var(--bg2, #14181f);
  border-left: 1px solid var(--border, rgba(127,127,127,.25));
  z-index: 600;
  transform: translateX(100%);
  transition: transform 280ms cubic-bezier(.4,0,.2,1);
  display: flex; flex-direction: column;
  overflow: hidden;
}
.kpi-drawer.open { transform: translateX(0); }
.kpi-drawer-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border, rgba(127,127,127,.25));
  flex-shrink: 0;
}
.kpi-drawer-title {
  font-family: var(--mono); font-size: 13px; font-weight: 600;
  color: var(--text); letter-spacing: 0.02em;
}
.kpi-drawer-close {
  background: none; border: none; cursor: pointer;
  color: var(--text-muted); font-size: 16px; padding: 4px 6px;
  line-height: 1; border-radius: 4px;
}
.kpi-drawer-close:hover { color: var(--text); background: rgba(127,127,127,.12); }
.kpi-drawer-body { flex: 1; overflow-y: auto; padding: 20px; }
.kpi-drawer-backdrop {
  display: none;
  position: fixed; inset: 0;
  background: rgba(0,0,0,.35);
  z-index: 599;
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.kpi-drawer-backdrop.open { display: block; }

/* ── KPI Drawer enhanced context strip (W450) ─────────────────────────────*/
.kpi-drawer-enhanced {
  margin-top: 20px;
  border-top: 1px solid var(--border, rgba(127,127,127,.2));
  padding-top: 16px;
  display: flex; flex-direction: column; gap: 14px;
}
.kpi-drawer-spark-wrap { display: flex; flex-direction: column; gap: 6px; }
.kpi-drawer-spark-label {
  font-family: var(--mono, monospace); font-size: 10px; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-muted, rgba(255,255,255,.45));
}
.kpi-drawer-sparkline { width: 100%; height: 56px; display: block; overflow: visible; }
.kpi-drawer-spark-bar { fill: var(--accent, #c9a86c); opacity: 0.75; transition: opacity 180ms; }
.kpi-drawer-sparkline:hover .kpi-drawer-spark-bar { opacity: 1; }
.kpi-drawer-context {
  font-size: 12px; line-height: 1.6;
  color: var(--text-muted, rgba(255,255,255,.55));
  padding: 10px 12px;
  background: rgba(127,127,127,.06);
  border-radius: 6px;
  border-left: 2px solid var(--accent, #c9a86c);
}
.kpi-drawer-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.kpi-drawer-action-btn {
  display: inline-flex; align-items: center;
  padding: 7px 14px;
  background: transparent;
  border: 1px solid var(--accent, #c9a86c);
  border-radius: 6px;
  color: var(--accent, #c9a86c);
  font-family: var(--mono, monospace); font-size: 11px; font-weight: 600;
  letter-spacing: 0.04em; cursor: pointer;
  transition: background 160ms, color 160ms;
}
.kpi-drawer-action-btn:hover { background: var(--accent, #c9a86c); color: #0e1117; }
[data-theme="light"] .kpi-drawer-spark-bar { opacity: 0.65; }
[data-theme="light"] .kpi-drawer-context { background: rgba(0,0,0,.04); color: var(--text-muted, rgba(0,0,0,.5)); }

/* --- voice-dock.css --- */
/* â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
   voice-dock.css â€” Persistent voice dock (Part A, 2026-06-02)

   The voice cluster (orb Â· mic state Â· transcripts Â· LIVE tag Â· settings) was
   hoisted out of #view-home â€” which gets .view-off (display:none) on every view
   switch â€” into the always-visible #hint-bar footer. These rules make the moved
   elements (which previously sized themselves against the home Earth-hero) fit
   COMPACTLY inside the bottom command bar so:
     â€¢ spacebar PTT / orb / transcript feedback render on ALL 10 views
     â€¢ the 1920Ã—1080 frame never scrolls (the dock lives inside the fixed-height bar)
     â€¢ both light + dark themes resolve (colour comes from the elements' existing
       classes/tokens; only layout + sizing live here)

   Loaded LAST so it wins over the elements' Earth-context rules. Layout-only â€”
   no fabricated data, no JS hooks. IDs are untouched (zero JS change).
   â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• */

/* Host: the footer voice section becomes a tidy column with room for the dock. */
.qb-voice-section.vd-host {
  position: relative;            /* anchor for the pop-up settings popover */
  min-width: 200px;
  overflow: visible;             /* let the popover escape upward */
}

/* The dock row: orb + readout + live tag + gear, all on one compact line. */
.vd-dock {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 3px;
  max-height: 46px;              /* hard cap â†’ cannot grow the bar / cause scroll */
}

/* â”€â”€ Orb â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
   Override the Earth-mount sizing: in the bar the orb is a small 34px puck.
   It keeps its .orb-wrap state classes (listening/thinking/speaking) + rings,
   so voice.js animation still drives it â€” just at bar scale. */
.vd-orb.orb-wrap {
  position: static;
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  transform: none;
  margin: 0;
  cursor: pointer;
}
.vd-orb .orb {
  position: absolute;
  inset: 4px;
  width: auto;
  height: auto;
}
.vd-orb .orb-ring { position: absolute; inset: 0; }

/* â”€â”€ Readout: mic state + the two transcript lines, single-line + truncated â”€â”€ */
.vd-readout {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  min-width: 0;                  /* allow the truncation below to work */
  max-width: 320px;
}
.vd-mic.mic-indicator {
  position: static;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0;
  margin: 0;
  font-size: 8px;
  letter-spacing: .12em;
  white-space: nowrap;
  opacity: .9;
}
.vd-tx.dock-transcript {
  position: static;
  max-width: 320px;
  margin: 0;
  padding: 0;
  font-size: 9px;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-height: 0;
}
/* jarvis.css:422 force-hides .dock-transcript (display:none !important) â€” it was a
   legacy/hidden element on the Earth-hero. In the dock we DO want the transcript to
   surface, but only while voice.js has added .visible (i.e. there is speech to show).
   Idle/empty stays hidden so the bar reads clean. */
.vd-tx.dock-transcript.visible:not(:empty) { display: block !important; }

/* â”€â”€ LIVE tag + settings gear â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.vd-livetag.tag.live { font-size: 7.5px; padding: 1px 5px; }
.vd-gear.hero-settings-btn {
  position: static;
  display: inline-flex !important;   /* beat jarvis.css:422 .hero-settings-btn{display:none!important} */
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  font-size: 12px;
  line-height: 1;
  border-radius: 6px;
  cursor: pointer;
  opacity: .75;
  transition: opacity .15s ease, transform .15s ease;
}
.vd-gear.hero-settings-btn:hover { opacity: 1; transform: rotate(35deg); }

/* â”€â”€ Settings popover: pop UP out of the bar (absolute â†’ no layout growth) â”€â”€ */
.vd-popover.voice-settings-popover {
  position: absolute;
  right: 4px;
  bottom: calc(100% + 8px);      /* float above the bar */
  top: auto;
  left: auto;
  z-index: 60;
  /* Hidden by default â€” the north_star migration dropped the base hide rule from
     jarvis.css, leaving the popover stuck open over the bottom analytics row.
     app.js toggles .visible via #dock-settings-btn; restore the reveal contract. */
  opacity: 0;
  pointer-events: none;
  transform: translateY(6px);
  transition: opacity 180ms ease, transform 180ms ease;
}
.vd-popover.voice-settings-popover.visible {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

/* When idle (no transcript text), let the original prompt show; once a transcript
   line has content the dock leads. Purely cosmetic ordering. */
.vd-host .qbvc-prompt { display: none; }   /* the dock's mic-state replaces the static prompt */

/* The legacy big mic button + the decorative waveform in the bar are now redundant
   with the dock orb (which also animates voice state). Hide both so the bar reads
   clean and the voice section fits the 60px bar without overflow. They stay in the
   DOM for any JS that binds them â€” spacebar and the orb remain the live triggers. */
#hint-bar .qb-mic-btn.qb-voice-btn-big { display: none !important; }
.vd-host .qbvc-waveform { display: none; }

/* Keep the whole voice section inside the 60px command bar (no vertical overflow). */
.qb-voice-section.vd-host {
  max-height: 58px;
  justify-content: center;
  gap: 2px;
}
.vd-dock { max-height: 40px; }


/* â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•
   V5 ENTERPRISE VISUAL UPGRADE â€” voice-dock.css addendum (2026-06-22)
   Pure CSS/visual additions only. All JS hook IDs, event-listener targets,
   existing keyframe animations, state classes, and orb ring rules are
   UNTOUCHED. New additions are clearly bracketed here at the end of the file
   so they can be reverted as a single contiguous block if needed.
   â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â•â• */

/* â”€â”€ Dock panel background â€” command-center depth â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* Dark (default `:root`): use --bg3 = #0d1420, deeper than sidebar bg2. */
/* Light ([data-theme="light"]): clean white surface + subtle border.     */
.qb-voice-section.vd-host {
  background: var(--bg3);
  border-top: 1px solid var(--line);
}
:root[data-theme="light"] .qb-voice-section.vd-host {
  background: var(--surface);
}

/* â”€â”€ Status bar â€” state text, text only, zero animation â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* Shows READY / LISTENINGâ€¦ / PROCESSING / SPEAKING above the dock row.  */
/* Text is driven by :has() reading the orb-wrap state classes that       */
/* voice.js already toggles â€” zero JS change required.                   */
.vd-status-bar {
  font-family: var(--display, "Inter", system-ui, sans-serif);
  font-size: 8px;
  letter-spacing: .14em;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--soft);
  line-height: 1;
  min-height: 10px;
  padding-bottom: 1px;
  display: block;
}
/* Default idle state */
.vd-status-bar::after {
  content: 'READY';
  color: var(--soft);
}
/* State overrides via :has() â€” reads orb-wrap classes from voice.js */
.vd-host:has(.orb-wrap.listening) .vd-status-bar::after {
  content: 'LISTENING\2026'; /* U+2026 = â€¦ */
  color: var(--accent);
}
.vd-host:has(.orb-wrap.thinking) .vd-status-bar::after {
  content: 'PROCESSING';
  color: var(--champagne);
}
.vd-host:has(.orb-wrap.speaking) .vd-status-bar::after {
  content: 'SPEAKING';
  color: var(--accent);
}

/* â”€â”€ ATLAS brand label â€” tiny champagne caption above the orb â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* Pure CSS via ::before on .vd-orb.orb-wrap â€” no HTML element needed.  */
/* Override position: static (set earlier in this file) to enable        */
/* absolute positioning of the ::before label. Flex behavior is          */
/* unchanged since position: relative keeps the element in the flow.     */
.vd-orb.orb-wrap {
  position: relative; /* overrides the `position: static` above */
}
.vd-orb.orb-wrap::before {
  content: 'ATLAS';
  position: absolute;
  top: -14px;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--display, "Inter", system-ui, sans-serif);
  font-size: 8px;
  letter-spacing: .15em;
  font-weight: 700;
  color: var(--champagne);
  text-transform: uppercase;
  white-space: nowrap;
  pointer-events: none;
  line-height: 1;
}

/* â”€â”€ Orb idle glow â€” NEW additive keyframes, not replacing existing â”€â”€â”€â”€ */
/* Subtle box-shadow breathe on the inner .orb div while voice is idle.  */
/* scale(1.0â†’1.02) + opacity(1.0â†’0.85) character expressed as shadow     */
/* variance rather than transform, to avoid conflicting with voice.js     */
/* active-state animations which also use transform on .orb.              */
@keyframes vd-orb-idle-glow {
  0%, 100% {
    box-shadow: 0 0 6px 2px rgba(var(--accent-rgb, 0,214,255), 0.20);
  }
  50% {
    box-shadow: 0 0 14px 5px rgba(var(--accent-rgb, 0,214,255), 0.08);
  }
}
/* Apply to the orb div only when parent is in idle state */
.vd-orb .orb {
  animation: vd-orb-idle-glow 3s ease-in-out infinite;
}
/* Suspend idle glow while voice is active â€” existing JS-driven state
   animations on .orb-wrap.listening/thinking/speaking take precedence. */
.orb-wrap.listening .orb,
.orb-wrap.thinking  .orb,
.orb-wrap.speaking  .orb {
  animation: none;
}

/* â”€â”€ Transcript typography â€” Inter 14px, 1.5 leading â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* Upgrades readability from the compact 9px bar-scale font to the       */
/* command-center voice transcript standard. Ellipsis truncation is       */
/* preserved from the base rule above.                                    */
.vd-tx.dock-transcript {
  font-family: var(--display, "Inter", system-ui, sans-serif);
  font-size: 14px !important;
  line-height: 1.5 !important;
}

/* â”€â”€ Atlas TTS reply accent â€” champagne left-rule â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* Visually distinguishes the Atlas reply from user input in the readout. */
/* border-left: 2px solid var(--champagne) per V5 spec.                  */
.vd-tx.dock-transcript-reply {
  border-left: 2px solid var(--champagne);
  padding-left: 6px;
}

/* â”€â”€ prefers-reduced-motion â€” all new animations gated â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
@media (prefers-reduced-motion: reduce) {
  .vd-orb .orb,
  .orb-wrap.listening .orb,
  .orb-wrap.thinking  .orb,
  .orb-wrap.speaking  .orb {
    animation: none !important;
  }
}

/* --- home-polish.css --- */
/* home-polish.css â€” ATLAS Command Center (home view) polish layer (loaded LAST).
 *
 * COMPANION to polish.css. polish.css deliberately scoped itself to the in-page
 * DEPARTMENT views (.tc-*/.dept-*) and left the home / Command Center view
 * untouched. This file lifts that home view to the same factory $10â€“20K bar:
 * KPI-strip depth, tabular numerals, hand-crafted hover/focus/active, graceful
 * loading + empty states, and one real light-theme colour-harmony fix.
 *
 * Built 2026-06-07 (Week-3 launch polish push). Evidence baseline + before/after
 * captured in Scheduled/outputs/atlas_vo_polish/COMPARE/.
 *
 * THREE HARD GUARANTEES (same contract as polish.css, so this is safe to drop last):
 *  1. THEME-SAFE â€” references ONLY shared design tokens (--accent/--accent-rgb/
 *     --accent2-rgb/--good-rgb/--bad/--panel/--bg2/--border/--text/--text-muted)
 *     which north_star_final defines for BOTH :root (dark) and
 *     :root[data-theme="light"]. The per-metric --ka (set in kpi-strip.css) is
 *     reused for solid accents. Every literal colour lives inside a dark-only
 *     luminous effect gated behind :root:not([data-theme="light"]).
 *  2. LAYOUT-NEUTRAL / NO-SCROLL â€” only paints (background, border-colour,
 *     box-shadow, border-radius, colour, letter-spacing, font-variant-numeric)
 *     and compositor-only transforms/opacity. NO font-size or box-model changes
 *     to the flex/grid chain, so the locked 1920Ã—1080 frame still totals its
 *     viewport height (feedback_dashboard_scroll_rule).
 *  3. SCOPED â€” every selector is a Command Center home primitive (.kpi-tile,
 *     .agent-card, .alert-row, .cal-row, .bp-card, .tasks-donut). The dept views
 *     (.tc-*/.dept-*, owned by polish.css) and the voice dock are untouched.
 */

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 1. KPI STRIP â€” DEPTH + NUMERALS  (quality 1 hierarchy Â· 3 depth Â· 5 colour)
 *    The tiles were flat (box-shadow:none, radius 8, transition:"all"). Give
 *    them a top-lit surface, a real drop shadow, a per-metric top accent rule
 *    keyed to the existing --ka, and crisp tabular numerals so values don't
 *    jitter as live data ticks. Heights are unchanged (paint-only).
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.kpi-tile {
  position: relative;
  border-radius: 10px;
  overflow: hidden;
  background:
    linear-gradient(180deg, rgba(var(--accent-rgb), 0.045), rgba(var(--accent-rgb), 0) 55%),
    var(--panel);
  box-shadow: 0 8px 22px -14px rgba(0, 0, 0, 0.55);
  transition:
    border-color 0.2s ease,
    box-shadow 0.22s ease,
    transform 0.22s cubic-bezier(0.16, 1, 0.3, 1),
    filter 0.18s ease;
}
/* Per-metric top accent rule â€” semantic colour, reuses kpi-strip.css --ka. */
.kpi-tile::before {
  content: "";
  position: absolute;
  left: 10%; right: 10%; top: 0;
  height: 2px;
  border-radius: 0 0 2px 2px;
  background: linear-gradient(90deg, transparent, var(--ka, var(--accent)), transparent);
  opacity: 0.55;
  transition: opacity 0.22s ease, left 0.28s ease, right 0.28s ease;
  z-index: 1;
}
.kpi-tile:hover {
  transform: translateY(-2px);
  border-color: rgba(var(--accent-rgb), 0.45);
  box-shadow:
    0 16px 32px -16px rgba(0, 0, 0, 0.62),
    0 0 0 1px rgba(var(--accent-rgb), 0.10);
}
.kpi-tile:hover::before { opacity: 1; left: 3%; right: 3%; }
.kpi-tile:active { transform: translateY(-1px) scale(0.995); }

/* Tabular numerals â€” clean, non-jittering values (quality 4 type character). */
.kpi-number, .agent-tasks-num, .tc-prog-val, .bp-num, .goal-num {
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
/* Dark-only luminous lift on the surface (off in the light "paper" theme). */
:root:not([data-theme="light"]) .kpi-tile {
  box-shadow:
    0 1px 0 rgba(var(--accent-rgb), 0.06) inset,
    0 10px 26px -15px rgba(0, 0, 0, 0.7);
}

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 2. LOADING STATE  (loading-states polish)
 *    KPI tiles render with NO data-state until kpi-strip.js resolves the fetch
 *    (then it sets live/empty/error). So `:not([data-state])` IS the pre-fetch
 *    loading window â€” pure-CSS, auto-clears the instant JS sets a state. We
 *    gently pulse the placeholder so a fresh load reads as "working", not broken.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
@keyframes atlas-kpi-pulse {
  0%, 100% { opacity: 0.34; }
  50%      { opacity: 0.62; }
}
.kpi-tile:not([data-state]) .kpi-number,
.kpi-tile:not([data-state]) .kpi-compare {
  animation: atlas-kpi-pulse 1.25s ease-in-out infinite;
}
/* Shared text loading strips used by the pipeline / marketing panels. */
.lp-loading, .mk-loading {
  color: var(--text-muted);
  font-style: italic;
  text-align: center;
  padding: 18px 8px;
  animation: atlas-kpi-pulse 1.25s ease-in-out infinite;
}

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 3. EMPTY-STATE GRACE  (empty-state polish Â· honours data-integrity em-dash)
 *    The "â€”" + "feed not wired" states are HONEST (never fabricate). Make them
 *    read as a calm, intentional "awaiting feed" rather than a broken tile:
 *    quiet the number, keep the label crisp, settle the dead sparkline.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.kpi-tile[data-state="empty"] { box-shadow: 0 6px 18px -15px rgba(0, 0, 0, 0.4); }
.kpi-tile[data-state="empty"]::before,
.kpi-tile[data-state="error"]::before { opacity: 0.22; }
.kpi-tile[data-state="empty"] .kpi-number { opacity: 0.4; font-weight: 600; }
.kpi-tile[data-state="empty"] .kpi-compare { letter-spacing: 0.02em; }
/* A neutral baseline behind the empty sparkline so the SVG area doesn't read
 * as a rendering glitch. */
.kpi-tile[data-state="empty"] .kpi-spark,
.kpi-tile[data-state="error"] .kpi-spark {
  background: linear-gradient(180deg, transparent 49%, rgba(127, 127, 127, 0.14) 50%, transparent 51%);
}

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 4. AGENT CARDS  (quality 6 hover/focus Â· a11y Â· colour fix)
 *    Cards are clickable (role=button â†’ open agent modal) but lacked a visible
 *    keyboard focus ring + active press. Add both. AND fix a real light-theme
 *    bug: .agent-name was hardcoded #e2f0ff (dark-theme light-blue) and did not
 *    flip â†’ near-invisible on the paper background. Bind it to --text; keep the
 *    dark-theme glow gated to dark only.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.agent-name { color: var(--text) !important; }
:root:not([data-theme="light"]) .agent-name {
  text-shadow: 0 0 14px rgba(var(--accent-rgb), 0.18);
}
.agent-card { transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.2s ease, border-color 0.2s ease; }
.agent-card:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.agent-card:active { transform: translateY(-1px) scale(0.996); }

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 5. LIST ROWS  (quality 2 rhythm Â· 6 hover/active)
 *    Alert + calendar rows get a smooth, specific transition (was "all") and a
 *    subtle active press, so the feed feels responsive under the cursor.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.alert-row, .cal-row {
  transition: background-color 0.16s ease, border-color 0.16s ease, transform 0.16s ease;
}
.alert-row:hover, .cal-row:hover { transform: translateX(1px); }
.alert-row:active, .cal-row:active { transform: translateX(0) scale(0.998); }

/* Pipeline / progress cards â€” gentle hover lift + crisp focus for clickables. */
.bp-card { transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.2s ease, border-color 0.2s ease; }
.bp-card:hover { transform: translateY(-1px); }
.bp-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
 * 6. MOTION GUARD  (a11y â€” respect reduced-motion)
 *    Kill every transition / keyframe / hover-transform this file introduced.
 * â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
@media (prefers-reduced-motion: reduce) {
  .kpi-tile, .agent-card, .alert-row, .cal-row, .bp-card { transition: none; }
  .kpi-tile:not([data-state]) .kpi-number,
  .kpi-tile:not([data-state]) .kpi-compare,
  .lp-loading, .mk-loading { animation: none; }
  .kpi-tile:hover, .agent-card:hover, .alert-row:hover, .cal-row:hover, .bp-card:hover,
  .kpi-tile:active, .agent-card:active, .alert-row:active, .cal-row:active { transform: none; }
}

/* --- launch-banner.css --- */
/* launch-banner.css â€” persistent launch-countdown banner (Wave 9-W79).
 *
 * A slim bar at the very top of .main-col, ABOVE the status bar. It is a flex
 * child of the existing flex-column .main-col, so it shrinks the flex:1 .canvas
 * â€” the outer 100vh frame (overflow:hidden) NEVER scrolls. The no-scroll 1080
 * rule (atlas-dashboard.md #3) is preserved: internal panels absorb the ~30px.
 *
 * Self-themed (sets its own background + foreground) so it reads correctly in
 * BOTH light and dark themes regardless of [data-theme]. GPR-org-only visibility
 * is enforced in js/countdown.js; .is-hidden removes it from layout entirely.
 */

.launch-banner {
  flex-shrink: 0;
  height: 30px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 0 14px;
  text-decoration: none;
  font-family: "Rajdhani", "JetBrains Mono", system-ui, sans-serif;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: #fff;
  cursor: pointer;
  border-bottom: 1px solid rgba(0, 0, 0, 0.25);
  overflow: hidden;
  white-space: nowrap;
  transition: background-color 0.4s ease;
  -webkit-user-select: none;
  user-select: none;
}

.launch-banner.is-hidden { display: none !important; }

.launch-banner .lb-rocket {
  font-size: 14px;
  line-height: 1;
  filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.4));
}
.launch-banner .lb-msg {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  min-width: 0;
}
.launch-banner .lb-label {
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}
.launch-banner .lb-count {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.launch-banner .lb-cta {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  opacity: 0.85;
  padding: 2px 8px;
  border: 1px solid rgba(255, 255, 255, 0.55);
  border-radius: 999px;
  transition: opacity 0.2s ease, background-color 0.2s ease;
}
.launch-banner:hover .lb-cta,
.launch-banner:focus-visible .lb-cta {
  opacity: 1;
  background: rgba(255, 255, 255, 0.16);
}
.launch-banner:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.9);
  outline-offset: -3px;
}

/* â”€â”€ state colors â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.launch-banner.lb-green  { background: linear-gradient(90deg, #0f7a43, #16a34a 55%, #22c55e); }
.launch-banner.lb-yellow { background: linear-gradient(90deg, #b45309, #d97706 55%, #f59e0b); }
.launch-banner.lb-red    { background: linear-gradient(90deg, #991b1b, #dc2626 55%, #ef4444); }

/* red = final-stretch urgency â†’ gentle inner pulse */
.launch-banner.lb-red { animation: lb-pulse 1.8s ease-in-out infinite; }
@keyframes lb-pulse {
  0%, 100% { box-shadow: inset 0 0 0 0 rgba(255, 90, 90, 0); }
  50%      { box-shadow: inset 0 0 40px 0 rgba(255, 90, 90, 0.45); }
}
@media (prefers-reduced-motion: reduce) {
  .launch-banner.lb-red { animation: none; }
}

/* â”€â”€ mobile â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€
   mobile.css (loaded after this file) unlocks the no-scroll frame â‰¤1024px, so
   the banner simply rides at the top of the scrolling page. Keep it legible and
   reclaim horizontal room on narrow phones. */
@media (max-width: 767px) {
  .launch-banner {
    height: 28px;
    font-size: 12px;
    gap: 8px;
    padding: 0 10px;
    letter-spacing: 0.03em;
  }
  .launch-banner .lb-cta { display: none; }   /* save room on phones */
}
@media (max-width: 480px) {
  .launch-banner { font-size: 11px; }
  .launch-banner .lb-label { letter-spacing: 0.05em; }
}

/* --- notifications.css --- */
/* notifications.css â€” ATLAS Notification Center (Wave 10-W101).
 *
 * The top-bar bell (#btn-notifications) opens a single inbox panel
 * (#notif-center) aggregating every draft/alert surface.
 *
 * NO-SCROLL RULE (atlas-dashboard.md #3): the panel is position:fixed â€” it is
 * an OVERLAY and never participates in the .main-col flex flow, so the outer
 * 1080 frame is untouched. Only the panel's own list scrolls internally.
 *
 * BOTH THEMES (#4): every color is a theme var (--panel/--border/--text/
 * --accent/--good/--warn/--bad â€¦) so light + dark + per-tenant brand theming
 * (W82, which overrides --accent*) all read correctly with zero hardcoded hues.
 */

/* â”€â”€ bell badge (replaces the static "8") â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
/* The bell reuses .sa-btn; we only need the live badge + a subtle unread cue. */
#notif-badge[hidden] { display: none !important; }
.sa-notif[data-unread="1"] {
  border-color: rgba(var(--accent-rgb), .5);
  color: var(--accent);
}
.sa-notif .sa-badge {           /* live count pill â€” color comes from --bad */
  background: var(--bad);
  color: #fff;
  border-radius: 8px;
  font-size: 7.5px;
  font-weight: 700;
  padding: 1px 4px;
  min-width: 14px;
  text-align: center;
  line-height: 1.4;
}

/* â”€â”€ panel shell â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.notif-center {
  position: fixed;
  top: 92px;                    /* under the launch banner (30) + statusbar (~56) */
  right: 18px;
  width: 384px;
  max-width: calc(100vw - 28px);
  max-height: min(72vh, 680px);
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 18px 48px rgba(0, 0, 0, .45), 0 0 0 1px rgba(var(--accent-rgb), .06);
  z-index: 1200;               /* above canvas; below full-screen modals */
  overflow: hidden;
  color: var(--text);
  font-family: var(--mono, "JetBrains Mono", system-ui, sans-serif);
  animation: notif-in .16s ease;
}
.notif-center[hidden] { display: none !important; }

@keyframes notif-in {
  from { opacity: 0; transform: translateY(-6px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .notif-center { animation: none; }
}

/* â”€â”€ header â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.notif-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 13px;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(180deg, rgba(var(--accent-rgb), .05), transparent);
  flex-shrink: 0;
}
.notif-head .nh-title {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text);
}
.notif-head .nh-scope {
  font-size: 8.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--accent);
  padding: 2px 7px;
  border: 1px solid rgba(var(--accent-rgb), .3);
  border-radius: 999px;
}
.notif-head .nh-spacer { flex: 1; }
.notif-head .nh-btn {
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 5px;
  color: var(--text-dim);
  font-family: inherit;
  font-size: 8.5px;
  letter-spacing: .08em;
  text-transform: uppercase;
  padding: 4px 8px;
  cursor: pointer;
  transition: all .14s;
}
.notif-head .nh-btn:hover:not(:disabled) { border-color: rgba(var(--accent-rgb), .45); color: var(--accent); }
.notif-head .nh-btn:disabled { opacity: .4; cursor: default; }
.notif-head .nh-close {
  width: 24px; height: 24px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; line-height: 1;
}

/* â”€â”€ scroll body â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.notif-list {
  overflow-y: auto;
  overflow-x: hidden;
  flex: 1;
  padding: 4px 0 6px;
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--accent-rgb), .3) transparent;
}
.notif-list::-webkit-scrollbar { width: 8px; }
.notif-list::-webkit-scrollbar-thumb {
  background: rgba(var(--accent-rgb), .25);
  border-radius: 8px;
}

/* â”€â”€ source group â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.notif-group { padding: 2px 0; }
.notif-group + .notif-group { border-top: 1px solid var(--border2, var(--border)); }
.notif-group-head {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 7px 13px 4px;
}
.notif-group-head .ng-icon { font-size: 11px; line-height: 1; opacity: .9; }
.notif-group-head .ng-label {
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-dim);
  flex: 1;
}
.notif-group-head .ng-count {
  font-size: 8px;
  font-weight: 700;
  background: var(--accent);
  color: var(--bg, #04080f);
  border-radius: 999px;
  min-width: 15px;
  text-align: center;
  padding: 1px 5px;
}
/* priority category chip (W441) â€” surfaces why an item ranks where it does */
.notif-group-head .ng-cat {
  font-size: 7px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 1px 5px;
  margin-right: 2px;
}
.notif-group-head .ng-cat-security { color: var(--bad);  border-color: rgba(var(--bad-rgb, 220,60,60), .5); }
.notif-group-head .ng-cat-deal     { color: var(--good); border-color: rgba(var(--good-rgb, 60,180,120), .5); }
.notif-group-head .ng-cat-client   { color: var(--accent); border-color: rgba(var(--accent-rgb), .45); }

/* â”€â”€ item row â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.notif-row {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  padding: 8px 13px;
  position: relative;
  transition: background .12s;
}
.notif-row[data-url] { cursor: pointer; }
.notif-row[data-url]:hover { background: rgba(var(--accent-rgb), .07); }
.notif-row[data-url]:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.notif-row .nr-dot {
  width: 7px; height: 7px; border-radius: 50%;
  margin-top: 5px; flex-shrink: 0;
  background: var(--accent);
}
.notif-row.sev-warning .nr-dot  { background: var(--warn); }
.notif-row.sev-critical .nr-dot { background: var(--bad); }
.notif-row.sev-success .nr-dot  { background: var(--good, #3cb478); }

.notif-row .nr-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.notif-row .nr-title {
  font-size: 11px;
  line-height: 1.35;
  color: var(--text);
  font-family: var(--sans, system-ui, sans-serif);
  word-break: break-word;
}
.notif-row .nr-sub {
  font-size: 8.5px;
  letter-spacing: .04em;
  color: var(--text-muted);
  text-transform: uppercase;
}
.notif-row .nr-age {
  font-size: 8.5px;
  color: var(--text-muted);
  flex-shrink: 0;
  margin-top: 1px;
  font-variant-numeric: tabular-nums;
}
.notif-row .nr-read {
  background: transparent;
  border: none;
  color: var(--text-muted);
  font-size: 13px;
  line-height: 1;
  cursor: pointer;
  padding: 0 2px;
  flex-shrink: 0;
  transition: color .12s;
}
.notif-row .nr-read:hover:not(:disabled) { color: var(--accent); }
.notif-row .nr-read:disabled { color: var(--good); cursor: default; }

/* read items: dimmed, dot hollowed */
.notif-row.is-read { opacity: .5; }
.notif-row.is-read .nr-dot { background: transparent; border: 1px solid var(--text-muted); }

/* stub rows (not wired / unreachable / all clear) */
.notif-row.is-stub { padding: 6px 13px 9px; }
.notif-row.is-stub .nr-note {
  font-size: 9px;
  line-height: 1.45;
  color: var(--text-muted);
  font-style: italic;
}
.notif-row.is-stub.is-warn .nr-note { color: var(--warn); font-style: normal; }

/* â”€â”€ footer â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.notif-foot {
  flex-shrink: 0;
  padding: 8px 13px;
  border-top: 1px solid var(--border);
  font-size: 8px;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
  background: var(--bg2, transparent);
}

/* â”€â”€ light theme: soften the heavy drop shadow â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
[data-theme="light"] .notif-center {
  box-shadow: 0 16px 40px rgba(36, 66, 50, .18), 0 0 0 1px rgba(var(--accent-rgb), .08);
}
[data-theme="light"] .notif-group-head .ng-count { color: #fff; }

/* â”€â”€ mobile (mobile.css unlocks the no-scroll frame â‰¤1024px) â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
@media (max-width: 600px) {
  .notif-center {
    top: 64px;
    right: 8px;
    left: 8px;
    width: auto;
    max-width: none;
    max-height: 78vh;
  }
  /* let the 4 header actions wrap instead of overflowing a narrow panel */
  .notif-head { flex-wrap: wrap; row-gap: 6px; }
  .notif-head .nh-btn { font-size: 8px; padding: 4px 6px; }
  /* roomier tap targets for the per-row mark-read + bigger title on phones */
  .notif-row { padding: 10px 13px; }
  .notif-row .nr-read { font-size: 16px; padding: 0 6px; }
  .notif-row .nr-title { font-size: 12px; }
}

/* --- pwa.css --- */
/* ============================================================
   ATLAS â€” PWA install / update affordances (Wave 11-W122)

   All elements are position:fixed overlays injected by js/pwa-install.js â€” they
   NEVER participate in the dashboard frame layout, so the no-scroll-at-1920Ã—1080
   rule is untouched. Themed for both light + dark via the same tokens the rest
   of ATLAS uses, with hard fallbacks so it renders even if a token is missing.
   ============================================================ */

.pwa-install,
.pwa-toast {
  --pwa-surface: var(--surface-2, var(--panel, #111824));
  --pwa-border:  var(--border, rgba(255,255,255,.12));
  --pwa-text:    var(--text, #e9f4fa);
  --pwa-sub:     var(--text-2, #9fb0c0);
  --pwa-accent:  var(--accent, #00d6ff);
  --pwa-accent-ink: #04121a;
}

/* â”€â”€ install pill â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.pwa-install {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translate(-50%, 140%);
  z-index: 4000;
  display: flex;
  align-items: center;
  gap: 12px;
  max-width: min(460px, calc(100vw - 28px));
  padding: 12px 14px;
  border-radius: 16px;
  background: var(--pwa-surface);
  border: 1px solid var(--pwa-border);
  box-shadow: 0 18px 50px -12px rgba(0,0,0,.6), 0 0 0 1px rgba(255,255,255,.02) inset;
  color: var(--pwa-text);
  font-family: var(--sans, "Rajdhani", system-ui, sans-serif);
  opacity: 0;
  transition: transform .32s cubic-bezier(.16,1,.3,1), opacity .32s ease;
  backdrop-filter: blur(8px);
}
.pwa-install.is-in { transform: translate(-50%, 0); opacity: 1; }

.pwa-install-icon {
  flex: 0 0 auto;
  width: 40px; height: 40px;
  border-radius: 10px;
  box-shadow: 0 0 18px -4px var(--pwa-accent);
}
.pwa-install-text { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.pwa-install-text strong { font-size: 14px; letter-spacing: .02em; }
.pwa-install-sub { font-size: 12px; color: var(--pwa-sub); }

.pwa-install-cta {
  flex: 0 0 auto;
  appearance: none;
  border: 0;
  cursor: pointer;
  padding: 8px 16px;
  border-radius: 10px;
  font: inherit;
  font-weight: 700;
  font-size: 13px;
  letter-spacing: .03em;
  color: var(--pwa-accent-ink);
  background: var(--pwa-accent);
  transition: filter .15s ease, transform .1s ease;
}
.pwa-install-cta:hover { filter: brightness(1.08); }
.pwa-install-cta:active { transform: translateY(1px); }
.pwa-install-cta:focus-visible { outline: 2px solid var(--pwa-accent); outline-offset: 2px; }

.pwa-install-x {
  flex: 0 0 auto;
  appearance: none;
  border: 0; background: transparent;
  color: var(--pwa-sub);
  font-size: 20px; line-height: 1;
  cursor: pointer;
  padding: 2px 4px;
  border-radius: 6px;
}
.pwa-install-x:hover { color: var(--pwa-text); }
.pwa-install-x:focus-visible { outline: 2px solid var(--pwa-accent); outline-offset: 2px; }

/* iOS instructions row â€” full width below the pill row when expanded */
.pwa-ios-steps {
  flex-basis: 100%;
  order: 99;
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px solid var(--pwa-border);
  font-size: 12.5px;
  color: var(--pwa-sub);
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
}
.pwa-ios-steps svg { vertical-align: middle; color: var(--pwa-accent); }
/* honor the default-hidden state: the `display:flex` above otherwise overrides the
   [hidden] attribute, leaking the iOS steps into the Android native pill (W266 fix). */
.pwa-ios-steps[hidden] { display: none; }
.pwa-install.show-steps { flex-wrap: wrap; }

/* â”€â”€ update toast â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€â”€ */
.pwa-toast {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translate(-50%, 140%);
  z-index: 4001;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 11px 14px;
  border-radius: 14px;
  background: var(--pwa-surface);
  border: 1px solid var(--pwa-border);
  box-shadow: 0 18px 50px -12px rgba(0,0,0,.6);
  color: var(--pwa-text);
  font-family: var(--sans, "Rajdhani", system-ui, sans-serif);
  font-size: 13.5px;
  opacity: 0;
  transition: transform .32s cubic-bezier(.16,1,.3,1), opacity .32s ease;
}
.pwa-toast.is-in { transform: translate(-50%, 0); opacity: 1; }
.pwa-toast-btn {
  appearance: none; border: 0; cursor: pointer;
  padding: 7px 14px; border-radius: 9px;
  font: inherit; font-weight: 700;
  color: var(--pwa-accent-ink); background: var(--pwa-accent);
}
.pwa-toast-btn:hover { filter: brightness(1.08); }
.pwa-toast-btn:focus-visible { outline: 2px solid var(--pwa-accent); outline-offset: 2px; }

/* respect reduced motion */
@media (prefers-reduced-motion: reduce) {
  .pwa-install, .pwa-toast { transition: opacity .2s ease; transform: translate(-50%, 0); }
  .pwa-install:not(.is-in), .pwa-toast:not(.is-in) { opacity: 0; pointer-events: none; }
}

/* phones: let the pill breathe full-width */
@media (max-width: 520px) {
  .pwa-install, .pwa-toast { left: 12px; right: 12px; bottom: 12px; transform: translateY(140%); max-width: none; }
  .pwa-install.is-in, .pwa-toast.is-in { transform: translateY(0); }
  /* W340: comfortable tap targets on the install/update pill (was 61Ã—31 / 20Ã—24) */
  .pwa-install-cta, .pwa-toast-btn { min-height: 44px; padding: 10px 18px; }
  .pwa-install-x { min-width: 40px; min-height: 40px; font-size: 24px; }
}

/* â”€â”€ persistent status-bar "Install App" CTA (#btn-install-pwa, Wave 18-W266) â”€â”€
   Inherits the base .sa-btn geometry from jarvis.css; this only adds the accent
   treatment so it reads as a primary call-to-action next to the neutral status
   actions. Both themes covered via the same --accent token the rest of ATLAS uses. */
.sa-btn.sa-install {
  border-color: rgba(var(--accent-rgb), .55);
  color: var(--accent, #00d6ff);
  box-shadow: 0 0 0 1px rgba(var(--accent-rgb), .12) inset, 0 0 14px -6px var(--accent, #00d6ff);
}
.sa-btn.sa-install:hover {
  border-color: var(--accent, #00d6ff);
  background: rgba(var(--accent-rgb), .10);
  color: var(--accent, #00d6ff);
}
.sa-btn.sa-install:focus-visible { outline: 2px solid var(--accent, #00d6ff); outline-offset: 2px; }
.sa-install-label { font-weight: 700; letter-spacing: .04em; }

/* --- export-pdf.css --- */
/* ATLAS â€” PDF / Print Export (Wave 14-W180)
 * Button states + download toast. Additive only; the base .sa-btn look comes
 * from north_star_final.css. Theme-aware via existing custom props with safe
 * fallbacks, so both light + dark stay correct. */

.sa-btn.sa-export[data-export-state="working"] { opacity: .72; cursor: progress; }
.sa-btn.sa-export[data-export-state="working"] svg { animation: sa-export-spin .9s linear infinite; transform-origin: 50% 50%; }
.sa-btn.sa-export[data-export-state="done"]  { color: var(--accent2, #2e7d4f); }
.sa-btn.sa-export[data-export-state="error"] { color: var(--danger, #e5484d); }

@keyframes sa-export-spin { to { transform: rotate(360deg); } }

.export-pdf-toast {
  position: fixed;
  right: 18px;
  bottom: 18px;
  z-index: 9999;
  max-width: 360px;
  padding: 10px 14px;
  border-radius: 10px;
  font: 600 12px/1.45 var(--font-ui, system-ui, -apple-system, Segoe UI, sans-serif);
  letter-spacing: .02em;
  background: var(--panel, #14181f);
  color: var(--text, #e8eef6);
  border: 1px solid var(--border, rgba(255,255,255,.12));
  box-shadow: 0 8px 30px rgba(0,0,0,.35);
  opacity: 0;
  transform: translateY(8px);
  pointer-events: none;
  transition: opacity .25s ease, transform .25s ease;
}
.export-pdf-toast.show { opacity: 1; transform: translateY(0); }
.export-pdf-toast[data-kind="ok"]    { border-color: var(--accent2, #2e7d4f); }
.export-pdf-toast[data-kind="error"] { border-color: var(--danger, #e5484d); }

[data-theme="light"] .export-pdf-toast {
  background: #ffffff;
  color: #1a2230;
  border-color: rgba(0,0,0,.12);
  box-shadow: 0 8px 30px rgba(0,0,0,.15);
}

/* ── N0b (2026-07-03): dock transcript copy + selectable text ──────────── */
/* Transcript lines must be highlightable — override any inherited lock.   */
.vd-tx.dock-transcript,
.vd-tx.dock-transcript .word {
  -webkit-user-select: text;
  user-select: text;
  cursor: text;
}
/* Copy button shares .vd-gear sizing; kill the gear's rotate on hover.    */
.vd-copy.hero-settings-btn:hover { transform: none; }
.vd-copy.is-copied { color: var(--good, #3fbf7f); opacity: 1; }
.vd-copy svg { width: 13px; height: 13px; }
