/* ServicingCaptain CSP Console — design tokens + shell
   Density targets from enterprise-UI research: 8pt grid, 36-40px dense rows,
   sticky headers, right-aligned tabular numerals, semantic five-palette tokens. */

:root {
  /* neutral */
  --n0:#ffffff; --n50:#f7f8fa; --n100:#eef0f3; --n200:#dfe3e8; --n300:#c4cad3;
  --n500:#8a94a2; --n600:#5f6b7a; --n700:#414c5b; --n800:#2b3440; --n900:#1a212b;
  /* primary (deep navy-blue, used sparingly) */
  --p500:#1d4ed8; --p600:#1e40af; --p50:#eef4ff;
  /* semantic */
  --ok:#15803d;  --ok-bg:#ecfdf3;
  --warn:#b45309; --warn-bg:#fffbeb;
  --danger:#b91c1c; --danger-bg:#fef2f2;
  --info:#6d28d9; --info-bg:#f5f3ff;   /* compliance / legal posture */
  /* type */
  --font: -apple-system, "Segoe UI", system-ui, Roboto, sans-serif;
  --mono: "Cascadia Code", Consolas, ui-monospace, monospace;
  /* spacing: 8pt grid */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px;
  --radius:6px;
  --top:#1a212b;   /* topbar/toast surface — stays dark in every theme */
  --shadow:0 1px 2px rgba(16,24,40,.06), 0 1px 3px rgba(16,24,40,.10);
}

* { box-sizing:border-box; margin:0; padding:0; }
html,body { height:100%; }
body {
  font-family:var(--font); font-size:13.5px; color:var(--n800);
  background:var(--n50); min-width:1100px;
}
.hidden { display:none !important; }
kbd {
  font-family:var(--mono); font-size:11px; background:var(--n100);
  border:1px solid var(--n300); border-bottom-width:2px; border-radius:4px;
  padding:1px 5px; color:var(--n700);
}
.num { font-variant-numeric: tabular-nums; }

/* ---------- top bar ---------- */
.topbar {
  display:flex; align-items:center; gap:var(--s5);
  height:52px; padding:0 var(--s5);
  background:var(--top); color:#fff;
  position:sticky; top:0; z-index:50;
}
.brand { font-weight:700; font-size:15px; letter-spacing:.2px; white-space:nowrap; }
/* the wordmark's second half: BRAND.md's reversed gold, for dark ground */
.brand span { color:#E2BE5C; }
/* min-width is load-bearing: flex:1 alone let a crowded topbar crush the
   search to a sliver, and the results dropdown inherited the sliver. */
.search-wrap { position:relative; flex:1 1 220px; min-width:170px; max-width:620px; }
/* The topbar keeps its own dark surface in EVERY theme (--top, see :root), so
   the search box sits on dark ground whatever the user picked. Its text must
   therefore be a fixed light colour rather than a theme variable.

   It used var(--n0) - the SURFACE colour - which is white in the light themes
   and DARK in the dark ones. In Ocean that put rgb(16,40,65) text on a
   rgb(6,19,33) bar: about 1.3:1, which is not low contrast, it is invisible.
   Four of the six themes were affected and the light two hid it. */
#global-search {
  width:100%; height:34px; padding:0 var(--s3);
  font:inherit; color:#f2f6fb; caret-color:#7ea6ff;
  background:rgba(255,255,255,.10); border:1px solid rgba(255,255,255,.18);
  border-radius:var(--radius); outline:none;
}
#global-search::placeholder { color:rgba(255,255,255,.62); }
#global-search:focus {
  background:rgba(255,255,255,.18); border-color:#7ea6ff;
  box-shadow:0 0 0 3px rgba(126,166,255,.18);
}
.topbar-right { margin-left:auto; display:flex; align-items:center; gap:var(--s3); }
.mock-badge {
  font-size:10.5px; font-weight:700; letter-spacing:.8px;
  color:#fbbf24; border:1px solid #fbbf24; border-radius:4px; padding:2px 7px;
}
.user-chip { font-size:12.5px; color:var(--n300); }

/* search results dropdown. Its own min-width: results must be readable even
   when the topbar has narrowed the input they hang from. */
.search-results {
  position:absolute; top:40px; left:0; right:0;
  min-width:min(480px, 88vw);
  background:var(--n0); color:var(--n800);
  border:1px solid var(--n200); border-radius:var(--radius);
  box-shadow:0 8px 24px rgba(16,24,40,.16); overflow:hidden;
}
.sr-row {
  display:grid; grid-template-columns: 1fr auto auto; gap:var(--s4);
  align-items:center; padding:var(--s2) var(--s4); min-height:40px; cursor:pointer;
  border-top:1px solid var(--n100);
}
.sr-row:first-child { border-top:none; }
.sr-row:hover, .sr-row.active { background:var(--p50); }
.sr-name { font-weight:600; }
.sr-sub { color:var(--n600); font-size:12px; }
.sr-loan { font-family:var(--mono); font-size:12px; color:var(--n700); }
.sr-empty { padding:var(--s4); color:var(--n600); }

/* ---------- home ---------- */
.home { display:flex; justify-content:center; padding-top:9vh; }
.home-inner { text-align:center; max-width:560px; }
.home h1 { font-size:22px; color:var(--n900); margin-bottom:var(--s2); }
.home p { color:var(--n600); line-height:1.6; margin-bottom:var(--s5); }
.home-hints { display:flex; gap:var(--s4); justify-content:center; margin-bottom:var(--s6); }
.hint { color:var(--n600); font-size:12.5px; }
.home-queue { text-align:left; }
.hq-title { font-size:11.5px; font-weight:700; letter-spacing:.8px; color:var(--n600);
  text-transform:uppercase; margin-bottom:var(--s2); }
.hq-item {
  display:flex; justify-content:space-between; gap:var(--s4);
  background:var(--n0); border:1px solid var(--n200); border-radius:var(--radius);
  padding:var(--s3) var(--s4); margin-bottom:var(--s2); cursor:pointer;
}
.hq-item:hover { border-color:var(--p500); }
.hq-why { color:var(--n600); font-size:12.5px; }

/* ---------- banners & compliance strip ---------- */
.banner {
  display:flex; align-items:center; gap:var(--s3);
  padding:var(--s2) var(--s5); font-weight:600; font-size:13px;
}
.banner.danger { background:var(--danger-bg); color:var(--danger); border-bottom:1px solid #fecaca; }
.banner.warn   { background:var(--warn-bg);  color:var(--warn);   border-bottom:1px solid #fde68a; }
.compliance-strip {
  background:var(--info-bg); color:var(--info); border-bottom:1px solid #ddd6fe;
  padding:var(--s2) var(--s5); font-size:12.5px; display:flex; gap:var(--s4); align-items:center;
}
.compliance-strip .script {
  font-style:italic; color:#4c1d95; background:#ede9fe; border-radius:4px; padding:2px 8px;
}

/* ---------- loan header ---------- */
.loan-header {
  background:var(--n0); border-bottom:1px solid var(--n200);
  padding:var(--s3) var(--s5) 0; position:sticky; top:52px; z-index:40;
  box-shadow:var(--shadow);
}
.lh-id { display:flex; align-items:baseline; gap:var(--s4); flex-wrap:wrap; }
.lh-name { font-size:17px; font-weight:700; color:var(--n900); }
.lh-loan { font-family:var(--mono); color:var(--n600); }
.lh-product { color:var(--n600); }
.lh-status {
  font-size:11px; font-weight:700; letter-spacing:.6px; border-radius:4px; padding:2px 8px;
}
.lh-status.ACTIVE { background:var(--ok-bg); color:var(--ok); }
.lh-status.DELINQUENT { background:var(--danger-bg); color:var(--danger); }
.owner-chip {
  font-size:11px; font-weight:700; border-radius:4px; padding:2px 8px;
  background:var(--n100); color:var(--n700); border:1px solid var(--n200);
}
.owner-chip.placed { background:var(--info-bg); color:var(--info); border-color:#ddd6fe; }
.answer-as {
  display:inline-flex; align-items:center; gap:6px;
  font-size:11px; font-weight:700; color:var(--n700);
  border:1.5px solid var(--n800); border-radius:4px; padding:2px 8px;
  background:var(--n0);
}
.answer-as img { height:18px; width:auto; display:block; }
.answer-as.pl { border-color:var(--warn); }
.answer-as.pl b { color:var(--warn); }
.pl-tag {
  font-size:9px; letter-spacing:.8px; color:#fff; background:var(--warn);
  border-radius:3px; padding:1px 5px;
}
.lh-sub { color:var(--n600); font-size:12.5px; margin-top:2px; }
.lh-sub .callable { color:var(--ok); font-weight:600; }
.lh-sub .not-callable { color:var(--danger); font-weight:600; }

.stat-row {
  display:grid; grid-template-columns:repeat(4, 1fr); gap:var(--s4);
  margin:var(--s3) 0;
}
.stat {
  border:1px solid var(--n200); border-radius:var(--radius);
  padding:var(--s2) var(--s3); background:var(--n50);
}
.stat .label { font-size:11px; font-weight:700; letter-spacing:.7px; color:var(--n600);
  text-transform:uppercase; display:flex; justify-content:space-between; }
.stat .value { font-size:20px; font-weight:700; color:var(--n900); margin:2px 0;
  font-variant-numeric:tabular-nums; }
.stat .value.danger { color:var(--danger); }
.stat .sub { font-size:12px; color:var(--n600); }
.copy-btn {
  border:none; background:none; cursor:pointer; color:var(--n500); font-size:12px;
  padding:0 2px; border-radius:3px;
}
.copy-btn:hover { color:var(--p500); background:var(--p50); }

.lh-lastpay {
  display:flex; gap:var(--s5); padding:var(--s2) 0; border-top:1px solid var(--n100);
  color:var(--n700); font-size:12.5px; flex-wrap:wrap;
}
.lh-lastpay .pending { color:var(--warn); font-weight:600; }
.lh-lastpay .applied { color:var(--ok); font-weight:600; }
.lh-lastpay .unapplied-warn { color:var(--warn); font-weight:700; }

/* ---------- tabs ---------- */
.tabbar {
  display:flex; gap:2px; background:var(--n0); border-bottom:1px solid var(--n200);
  padding:0 var(--s5); position:sticky; top: calc(52px + var(--header-h, 148px)); z-index:30;
}
.wu-open-btn { margin-left:auto; }
.tab {
  padding:var(--s2) var(--s4); cursor:pointer; color:var(--n600);
  border-bottom:2px solid transparent; font-weight:600; font-size:13px;
  background:none; border-top:none; border-left:none; border-right:none; font-family:inherit;
}
.tab:hover { color:var(--n900); }
.tab.active { color:var(--p600); border-bottom-color:var(--p600); }
/* These numbers ARE the shortcut hint - nothing else on screen says which key
   opens which tab - so they have to be legible.

   They asked for --n400, which is not in the palette, so every theme silently
   fell back to --n300: the faintest neutral there is. --n500 was still only
   3.07:1 in Daylight. --n600 is the label's own colour and clears 4.5:1 on all
   six themes; the numbers stay subordinate on SIZE and position rather than on
   contrast, which is the right trade for a hint somebody has to read. */
.tab .kbd-hint { font-size:10.5px; font-weight:600; color:var(--n600); margin-left:5px; }
.tab.active .kbd-hint { color:var(--p500); }

.tab-content { padding:var(--s5); max-width:1280px; }

/* ---------- panels & tables ---------- */
.panel {
  background:var(--n0); border:1px solid var(--n200); border-radius:var(--radius);
  margin-bottom:var(--s4); overflow:hidden;
}
.panel-title {
  font-size:11.5px; font-weight:700; letter-spacing:.8px; text-transform:uppercase;
  color:var(--n600); padding:var(--s3) var(--s4); border-bottom:1px solid var(--n100);
  display:flex; justify-content:space-between; align-items:center;
}
.panel-body { padding:var(--s4); }
.kv { display:grid; grid-template-columns:180px 1fr; gap:var(--s1) var(--s4); }
.kv dt { color:var(--n600); padding:3px 0; }
.kv dd { color:var(--n800); padding:3px 0; font-weight:500; }

table.data { width:100%; border-collapse:collapse; }
table.data th {
  position:sticky; top:0; background:var(--n50); z-index:5;
  font-size:11px; font-weight:700; letter-spacing:.6px; text-transform:uppercase;
  color:var(--n600); text-align:left; padding:var(--s2) var(--s3);
  border-bottom:1px solid var(--n200); white-space:nowrap;
}
table.data td {
  padding:var(--s2) var(--s3); border-bottom:1px solid var(--n100);
  height:38px; white-space:nowrap;
}
table.data th.r, table.data td.r { text-align:right; font-variant-numeric:tabular-nums; }
table.data tr.expandable { cursor:pointer; }
table.data tr.expandable:hover { background:var(--p50); }
table.data tr.expand-detail td { background:var(--n50); height:auto; }
table.data tr.actual-diverged td { background:#fffdf5; }
.badge { font-size:11px; font-weight:700; border-radius:4px; padding:2px 7px; }
.badge.ok { background:var(--ok-bg); color:var(--ok); }
.badge.warn { background:var(--warn-bg); color:var(--warn); }
.badge.danger { background:var(--danger-bg); color:var(--danger); }
.badge.info { background:var(--info-bg); color:var(--info); }
.badge.neutral { background:var(--n100); color:var(--n700); }

/* allocation detail inside payments */
.alloc { display:flex; gap:var(--s5); padding:var(--s2) 0 var(--s2) var(--s5); font-size:12.5px; }
.alloc div b { font-variant-numeric:tabular-nums; }

/* ---------- timeline ---------- */
.timeline { list-style:none; }
.tl-item {
  display:grid; grid-template-columns:110px 26px 1fr; gap:var(--s3);
  padding:var(--s3) 0; border-bottom:1px solid var(--n100);
}
.tl-when { color:var(--n600); font-size:12px; padding-top:2px; }
.tl-icon { text-align:center; font-size:14px; }
.tl-body .tl-head { display:flex; gap:var(--s3); align-items:center; margin-bottom:2px; }
.tl-type { font-weight:700; font-size:12px; }
.tl-actor { color:var(--n600); font-size:12px; }
.tl-text { color:var(--n800); line-height:1.5; max-width:70ch; }
.tl-item.system .tl-text { color:var(--n600); font-style:italic; }
.tl-item.pinned { background:var(--warn-bg); border-radius:var(--radius); padding:var(--s3); }

/* note composer */
.composer { display:flex; flex-direction:column; gap:var(--s2); margin-bottom:var(--s4); }
.composer textarea {
  font:inherit; padding:var(--s3); border:1px solid var(--n200); border-radius:var(--radius);
  min-height:64px; resize:vertical; outline:none;
}
.composer textarea:focus { border-color:var(--p500); }
.composer-row { display:flex; gap:var(--s2); align-items:center; }
.composer select {
  font:inherit; font-size:12.5px; padding:var(--s1) var(--s2);
  border:1px solid var(--n200); border-radius:var(--radius); background:var(--n0);
}
.btn {
  font:inherit; font-weight:600; font-size:13px; cursor:pointer;
  border-radius:var(--radius); padding:var(--s2) var(--s4);
  border:1px solid var(--n200); background:var(--n0); color:var(--n800);
}
.btn:hover { border-color:var(--n300); background:var(--n50); }
.btn.primary { background:var(--p600); border-color:var(--p600); color:#fff; }
.btn.primary:hover { background:var(--p500); }

/* verification panel */
.verify-bar {
  display:flex; align-items:center; gap:var(--s3);
  background:var(--warn-bg); border:1px solid #fde68a; border-radius:var(--radius);
  padding:var(--s2) var(--s3); margin-bottom:var(--s4); font-size:12.5px;
}
.verify-bar input {
  font:inherit; width:110px; padding:var(--s1) var(--s2);
  border:1px solid var(--n300); border-radius:4px;
}
.verify-result.match { color:var(--ok); font-weight:700; }
.verify-result.nomatch { color:var(--danger); font-weight:700; }

/* payoff tool */
.payoff-grid { display:grid; grid-template-columns: 320px 1fr; gap:var(--s4); }
.payoff-item { display:flex; justify-content:space-between; padding:4px 0;
  border-bottom:1px dashed var(--n200); }
.payoff-item.total { border-bottom:none; border-top:2px solid var(--n800);
  font-weight:700; font-size:15px; margin-top:var(--s2); padding-top:var(--s2); }
.payoff-note { color:var(--n600); font-size:12px; line-height:1.5; margin-top:var(--s3);
  font-style:italic; }
.sim-badge { font-size:10px; font-weight:700; letter-spacing:.6px; color:var(--warn);
  border:1px solid var(--warn); border-radius:3px; padding:1px 5px; }

/* ---------- complaint cases (spec §5.1) ---------- */
.case-strip {
  background:var(--warn-bg); color:var(--warn); border-bottom:1px solid #fde68a;
  padding:var(--s2) var(--s5); font-size:12.5px; display:flex; gap:var(--s3);
  align-items:center; flex-wrap:wrap;
}
.case-card {
  background:var(--n0); border:1px solid #ddd6fe; border-left:3px solid var(--info);
  border-radius:var(--radius); padding:var(--s3) var(--s4); margin-bottom:var(--s4);
}
.case-card.closed { border-left-color:var(--n300); border-color:var(--n200); opacity:.75; }
.case-head { display:flex; gap:var(--s3); align-items:center; margin-bottom:var(--s2); flex-wrap:wrap; }
.case-clocks { display:flex; gap:var(--s2); margin:var(--s2) 0; flex-wrap:wrap; }
.case-actions { display:flex; gap:var(--s2); margin:var(--s2) 0; }
.case-history { border-top:1px solid var(--n100); padding-top:var(--s2); margin-top:var(--s2); }

/* ---------- wrap-up drawer (spec §4.6) ---------- */
.wrapup {
  position:fixed; top:52px; right:0; bottom:0; width:420px; z-index:60;
  background:var(--n0); border-left:1px solid var(--n200);
  box-shadow:-8px 0 24px rgba(16,24,40,.12);
  display:flex; flex-direction:column;
}
.wu-head {
  display:flex; align-items:center; gap:var(--s3);
  padding:var(--s3) var(--s4); border-bottom:1px solid var(--n200);
}
.wu-title { font-weight:700; font-size:14px; }
.wu-timer {
  margin-left:auto; font-family:var(--mono); font-size:12.5px; color:var(--n600);
  background:var(--n100); border-radius:4px; padding:2px 8px;
}
.wu-timer.slow { color:var(--warn); background:var(--warn-bg); font-weight:700; }
.wu-body { padding:var(--s4); overflow-y:auto; flex:1;
  display:flex; flex-direction:column; gap:var(--s4); }
.wu-field label { display:block; font-size:11.5px; font-weight:700;
  letter-spacing:.6px; text-transform:uppercase; color:var(--n600);
  margin-bottom:var(--s1); }
.wu-seg { display:flex; gap:var(--s1); flex-wrap:wrap; }
.wu-seg button {
  font:inherit; font-size:12.5px; cursor:pointer; padding:var(--s1) var(--s3);
  border:1px solid var(--n200); background:var(--n0); border-radius:99px; color:var(--n700);
}
.wu-seg button:hover { border-color:var(--n300); }
.wu-seg button.sel { background:var(--p600); border-color:var(--p600); color:#fff; }
.wu-field input[type="date"], .wu-field input[type="text"], .wu-field input[type="number"] {
  font:inherit; padding:var(--s2); border:1px solid var(--n200);
  border-radius:var(--radius); width:100%;
}
.wu-field textarea {
  font:inherit; padding:var(--s2); border:1px solid var(--n200);
  border-radius:var(--radius); width:100%; min-height:72px; resize:vertical;
}
.wu-field textarea:focus, .wu-field input:focus { outline:none; border-color:var(--p500); }
.wu-inline { display:flex; gap:var(--s2); }
.wu-inline > * { flex:1; }
.wu-guard {
  background:var(--danger-bg); color:var(--danger); border:1px solid #fecaca;
  border-radius:var(--radius); padding:var(--s2) var(--s3); font-size:12.5px; font-weight:600;
}
.wu-verify-chip { font-size:12px; padding:2px 8px; border-radius:99px; }
.wu-verify-chip.match { background:var(--ok-bg); color:var(--ok); font-weight:700; }
.wu-verify-chip.none { background:var(--n100); color:var(--n600); }
.wu-foot {
  padding:var(--s3) var(--s4); border-top:1px solid var(--n200);
  display:flex; gap:var(--s2); align-items:center;
}
.wu-foot .sr-sub { margin-left:auto; }

/* ---------- CSF call guide drawer (left) ---------- */
.guide {
  position:fixed; top:52px; left:0; bottom:0; width:400px; z-index:60;
  background:var(--n0); border-right:1px solid var(--n200);
  box-shadow:8px 0 24px rgba(16,24,40,.12);
  display:flex; flex-direction:column;
}
.guide .wu-head { border-bottom:1px solid var(--n200); }
.guide .wu-body { padding:var(--s4); overflow-y:auto; flex:1;
  display:flex; flex-direction:column; gap:var(--s4); }
.csf-frames { font-size:11px; color:var(--n600); letter-spacing:.4px; }
.csf-frames b { color:var(--info); }
.q-list { margin:var(--s2) 0 0; padding-left:18px; }
.q-list li { padding:3px 0; color:var(--n800); line-height:1.45; }
.ladder { display:flex; flex-direction:column; gap:var(--s1); }
.ladder-step {
  display:flex; justify-content:space-between; gap:var(--s2);
  border:1px solid var(--n200); border-radius:var(--radius);
  padding:var(--s2) var(--s3); font-size:12.5px;
}
.ladder-step b { font-variant-numeric:tabular-nums; white-space:nowrap; }
.ladder-step.floor { border-color:var(--danger); color:var(--danger); font-weight:600; }
.obj { border-top:1px solid var(--n100); padding:var(--s2) 0; }
.obj .o { font-weight:600; color:var(--n800); }
.obj .r { color:var(--n600); font-size:12.5px; line-height:1.45; margin-top:2px; }
.guide-open-btn { margin-left:var(--s2); }

/* ---------- CSF training simulator ---------- */
.practice {
  position:fixed; top:52px; left:0; right:0; bottom:0; z-index:70;
  background:var(--n50); overflow-y:auto; padding:var(--s5);
}
.practice-inner { max-width:820px; margin:0 auto; }
.chat { display:flex; flex-direction:column; gap:var(--s2); margin:var(--s4) 0; }
.chat-msg { max-width:75%; padding:var(--s2) var(--s3); border-radius:10px;
  font-size:13.5px; line-height:1.5; }
.chat-msg.customer { align-self:flex-start; background:var(--n0);
  border:1px solid var(--n200); border-bottom-left-radius:3px; }
.chat-msg.csp { align-self:flex-end; background:var(--p600); color:#fff;
  border-bottom-right-radius:3px; }
.chat-msg .who { font-size:10px; font-weight:700; letter-spacing:.6px;
  opacity:.7; text-transform:uppercase; margin-bottom:2px; }
.chat-input { display:flex; gap:var(--s2); }
.chat-input textarea { flex:1; font:inherit; padding:var(--s2) var(--s3);
  border:1px solid var(--n200); border-radius:var(--radius); resize:none; height:56px; }
.chat-input textarea:focus { outline:none; border-color:var(--p500); }
.typing { color:var(--n500); font-style:italic; font-size:12.5px; }

/* ---------- login (identity module) ---------- */
.login-screen {
  position:fixed; inset:0; z-index:100; background:var(--n50);
  display:flex; align-items:center; justify-content:center;
}
.login-card {
  background:var(--n0); border:1px solid var(--n200); border-radius:8px;
  box-shadow:0 12px 32px rgba(16,24,40,.12); padding:32px; width:360px;
}
.login-logo { display:block; margin:0 auto 14px; height:52px; width:auto; }

.login-label {
  display:block; font-size:11.5px; font-weight:700; letter-spacing:.6px;
  text-transform:uppercase; color:var(--n600); margin:12px 0 4px;
}
.login-card input {
  font:inherit; width:100%; padding:8px 10px;
  border:1px solid var(--n200); border-radius:6px; outline:none;
}
.login-card input:focus { border-color:var(--p500); }
.login-error {
  margin-top:12px; background:var(--danger-bg); color:var(--danger);
  border:1px solid #fecaca; border-radius:6px; padding:8px 10px; font-size:12.5px;
}
.modal-dim { background:rgba(16,24,40,.45); }

/* ---------- module launcher ---------- */
.launcher { padding:56px 24px; }
.launcher-inner { max-width:1440px; margin:0 auto; }
.launcher-inner h1 { font-size:26px; color:var(--n800); margin-bottom:6px; }
.launcher-grid {
  display:grid; grid-template-columns:repeat(auto-fill, minmax(290px, 1fr));
  gap:var(--s4); margin-top:var(--s5);
}
.module-tile {
  background:var(--n0); border:1px solid var(--n200); border-radius:8px;
  padding:18px 20px; cursor:pointer; box-shadow:var(--shadow);
  transition:border-color .12s;
}
.module-tile:hover { border-color:var(--p500); }
.module-tile.soon { cursor:default; opacity:.75; }
.module-tile.soon:hover { border-color:var(--n200); }
.module-name { font-size:15.5px; font-weight:700; color:var(--n800);
  display:flex; align-items:center; gap:8px; }
.module-blurb { font-size:12.5px; color:var(--n600); margin-top:6px; line-height:1.4; }
.theme-row { margin-top:14px; display:flex; gap:8px; align-items:center;
  font-size:12px; color:var(--n600); }
.theme-btn.sel { background:var(--p600); border-color:var(--p600); color:#fff; }
.helm { flex:none; }
.launcher-inner h1 { display:flex; align-items:center; gap:10px; color:var(--n800); }
.launcher-inner h1 .helm { color:var(--p500); }

/* The helm turns. Slowly on purpose: 20s per revolution is about 18 degrees a
   second, which reads as a ship under way rather than a loading spinner. A
   spinner says "wait"; this says "running". Hovering the heading spins it up,
   which is the only reason anyone will ever notice it is interactive.

   transform-origin is set explicitly because the SVG is 24x24 inside a flex
   row, and the default 50% of the *box* drifts once the box is not square. */
.launcher-inner h1 .helm {
  transform-origin: 50% 50%;
  animation: helm-turn 20s linear infinite;
}
.launcher-inner h1:hover .helm { animation-duration: 2.4s; }

@keyframes helm-turn { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* Continuous motion is a vestibular trigger for some people, and this one runs
   for the whole session. Anyone who has asked their OS to reduce motion gets a
   still wheel. */
@media (prefers-reduced-motion: reduce) {
  .launcher-inner h1 .helm,
  .launcher-inner h1:hover .helm { animation: none; }
}

/* ---------- the photos on your desk ----------
   Beside the welcome line, the way frames sit on the corner of a desk. Small on
   purpose: a warm detail, not something competing with the stations below.

   All of them at once rather than one at a time. They used to cross-fade in a
   single frame every twelve seconds, so anyone with three photos saw one and
   had no reason to think there were others: a rotation slow enough not to
   distract is also slow enough to be invisible.

   See app-stations.js for why the photos never leave the account. */
.bridge-head { display:flex; gap:var(--s5); align-items:flex-start; }
.bridge-head-text { flex:1; min-width:0; }
.desk { flex:none; }
.desk-row { display:flex; gap:6px; align-items:flex-start; }

.desk-shot {
  position:relative; flex:none; width:96px; height:72px;
  border-radius:8px; overflow:hidden;
  background:var(--n100); border:1px solid var(--n200);
  display:block; padding:0;
}
.desk-shot img { width:100%; height:100%; object-fit:cover; display:block; }

/* The remove control appears on hover, so five little crosses are not sitting
   on someone's family all day. Focus shows it too, or it would be unreachable
   from the keyboard. */
.desk-drop {
  position:absolute; top:3px; right:3px; width:18px; height:18px;
  border:0; border-radius:50%; padding:0; cursor:pointer;
  background:rgba(0,0,0,.6); color:#fff; font:600 13px/1 system-ui;
  opacity:0; transition:opacity 120ms ease;
}
.desk-shot:hover .desk-drop, .desk-drop:focus-visible { opacity:1; }
.desk-drop:hover { background:var(--danger, #b4232a); }

.desk-empty {
  border-style:dashed; border-color:var(--n300); cursor:pointer;
  display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:2px; color:var(--n500); font:inherit;
}
.desk-empty:hover { border-color:var(--p500); color:var(--p500); }
.desk-plus { font-size:20px; line-height:1; }
.desk-empty-label { font-size:11px; }
/* Says the slot count. Without it the frame reads as room for one. */
.desk-empty-sub { font-size:10px; opacity:.75; }

.desk-cap { font-size:11px; color:var(--n500); text-align:right; margin-top:5px; }
.desk-note { margin-top:1px; }

/* The empty state is the only tile on screen, so it gets the old larger size
   rather than sitting in the corner looking like a thumbnail of nothing. */
.desk-row > .desk-empty:only-child { width:136px; height:102px; }

/* One column on a narrow window: the row would otherwise squeeze the welcome
   text into a sliver, and it wraps rather than overflowing. */
@media (max-width: 900px) {
  .bridge-head { flex-direction:column; gap:var(--s3); }
  .desk { align-self:flex-start; }
  .desk-cap { text-align:left; }
  .desk-row { flex-wrap:wrap; }
}

@media (prefers-reduced-motion: reduce) {
  .desk-drop { transition:none; }
}

/* ---------- the identities we present under ----------
   Not decoration. Which name an account is worked under decides whether the
   FDCPA applies to it, so the two marks and what each one means belong
   somewhere a CSP sees at the start of a shift.

   The logo sits in a fixed box rather than being sized directly: the two marks
   have very different aspect ratios, and letting them size themselves gave the
   wide one about half the card and wrapped its caption into a ten-line column. */
.bridge-flags {
  display:flex; flex-wrap:wrap; gap:var(--s3); margin:var(--s4) 0;
}
.flag {
  display:flex; align-items:center; gap:11px; flex:1 1 270px;
  background:var(--n0); border:1px solid var(--n200);
  border-radius:var(--radius); padding:10px 12px;
}
.flag-logo {
  flex:none; width:100px; height:26px;
  display:flex; align-items:center; justify-content:center;
}
.flag-logo img { max-width:100%; max-height:100%; width:auto; height:auto; display:block; }
.flag-mark { font-size:19px; color:var(--n500); line-height:1; }
.flag-text { flex:1; min-width:0; }
.flag-name { font-weight:600; color:var(--n800); font-size:12.5px; line-height:1.3; }
.flag-note { color:var(--n600); font-size:11.5px; line-height:1.4; }
.flag-count { flex:none; text-align:right; padding-left:4px; }
.flag-count b { display:block; font-size:17px; color:var(--n800); line-height:1.1; }
.flag-count span { font-size:10.5px; color:var(--n500); }


/* ---------- watch officer (AI crew) ---------- */
.watch-card {
  background:var(--n0); border:1px solid var(--n200); border-radius:var(--radius);
  padding:12px 16px; margin:14px 0 18px; text-align:left;
}
.watch-head { display:flex; gap:10px; align-items:center; flex-wrap:wrap; color:var(--n800); }
.watch-badge {
  font-size:10px; font-weight:800; letter-spacing:.8px; padding:3px 8px;
  border-radius:999px; background:var(--info-bg); color:var(--info);
}
.watch-digest { display:flex; gap:8px; flex-wrap:wrap; margin-top:10px; }
.watch-chip {
  font-size:12px; padding:4px 10px; border-radius:999px;
  background:var(--n100); color:var(--n700); border:1px solid var(--n200);
}
.watch-chip.ok { background:var(--ok-bg); color:var(--ok); border-color:var(--ok); }
.watch-chip.warn { background:var(--warn-bg); color:var(--warn); border-color:var(--warn); }
.watch-chip.danger { background:var(--danger-bg); color:var(--danger); border-color:var(--danger); }
.watch-exc-wrap { margin-top:10px; padding-top:8px; border-top:1px solid var(--n200); }
.watch-exc {
  display:flex; gap:8px; align-items:baseline; flex-wrap:wrap;
  padding:3px 0; font-size:12.5px; color:var(--n800);
}
.watch-brief { margin-top:12px; border-top:1px solid var(--n200); padding-top:10px; }
.watch-brief-text { color:var(--n800); font-size:13.5px; line-height:1.5; }
.watch-priorities { margin:8px 0 6px 20px; color:var(--n700); font-size:13px; }
.watch-priorities li { margin-bottom:4px; }

/* ---------- build chip ----------
   Lives in the topbar, not floating. The console declares a fixed 1200px
   viewport, so a position:fixed corner element sits at the corner of that
   canvas and scales away to nothing on a phone. */
#build-chip {
  font-size:11px; letter-spacing:.3px; padding:2px 7px; border-radius:4px;
  color:var(--n400); border:1px solid transparent; user-select:none;
  white-space:nowrap;
}
#build-chip.stale {
  color:#fbbf24; border-color:#fbbf24; font-weight:700; cursor:pointer;
}

/* ---------- users panel ---------- */
/* The card scrolls as a whole (the create form can make it taller than the
   viewport); the list additionally scrolls on its own so filters and the count
   stay put while paging through people. */
/* The CARD does not scroll - its LIST does (Chris, 2026-08-16: the Save
   was a scroll away, and touch scroll fell through to the page). Flex
   column: header and filters pinned, the list is the one scroll region,
   whatever follows (create form, Close) anchors below. */
.users-card { width:720px; max-width:94vw; max-height:86vh; overflow:hidden;
  display:flex; flex-direction:column; }
.users-top { display:flex; align-items:center; gap:12px; }
.users-top .btn { margin-left:auto; }
.users-controls { display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin:10px 0 6px; }
.users-controls input {
  flex:1; min-width:200px; font:inherit; font-size:13px; padding:7px 10px;
  border:1px solid var(--n200); border-radius:6px;
  background:var(--n0); color:var(--n800);
}
.users-filters { display:flex; gap:4px; }
.users-f { font-size:12px; padding:5px 10px; }
.users-f.sel { border-color:var(--p500); color:var(--p500); font-weight:700; }
/* The list scrolls, not the whole dialog: filters and the count stay put. */
.users-list { overflow-y:auto; overscroll-behavior:contain;
  flex:1 1 auto; min-height:0; margin-bottom:4px; }
/* A LIST, NOT NINE INDEPENDENT ROWS.

   This was flex with space-between and wrap, which means every row worked out
   its own layout from its own content: the role column landed anywhere from
   281px to 355px depending on how long the name was, a row with a Delete
   button dragged its whole button group 78px left of the rows without one,
   and one long display name pushed the buttons off the row entirely.
   
   Fixed columns instead. The name cell is the only flexible one, and it
   truncates rather than shoving its neighbours. */
.user-row { padding:8px 0; border-bottom:1px solid var(--n100); }
.user-head {
  display:grid;
  grid-template-columns:minmax(0,1fr) 176px 264px;
  gap:12px; align-items:center;
}
.user-who { display:flex; flex-direction:column; line-height:1.3; min-width:0; }
/* min-width:0 above and the three properties here are what make a long name
   shorten instead of widening the column. A grid item's default minimum is
   its content, so without this the whole row grows. */
.user-who > b, .user-who > .sr-sub {
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:100%;
}
.user-state {
  display:flex; gap:6px; align-items:center; flex-wrap:wrap;
  font-size:12px; color:var(--n600);
}
/* Four fixed slots, so Delete has a reserved place. When a user has history
   and cannot be deleted the fourth slot is simply empty, and Edit, Invite and
   Reset stay in the same three columns all the way down the list. */
.user-actions { display:grid; grid-template-columns:repeat(4,1fr); gap:6px; }
.user-actions .btn { width:100%; padding-left:0; padding-right:0; text-align:center; }

/* The card is max-width:94vw, so on a narrow window the fixed columns would
   overflow. Below that the row stacks instead of clipping. */
@media (max-width:640px) {
  .user-head { grid-template-columns:1fr; gap:6px; }
  .user-actions { grid-template-columns:repeat(4,1fr); }
}
.user-meta { font-size:11px; color:var(--n600); margin-top:2px; }
/* Editing takes over the card. The other rows and the filter hide, and the
   list's height cap comes off, so the form is not read through a letterbox. */
.users-list.editing { overflow-y:auto; }
.users-list.editing .user-row:not(.editing) { display:none; }
.users-list.editing .user-row.editing { border-bottom:0; }

.user-edit {
  margin:8px 0 4px; padding:14px 16px; background:var(--n50);
  border:1px solid var(--n200); border-radius:var(--radius);
}
/* Two columns of FIELDS, which halves the height - that height was what put
   Save below the fold. Each .uf holds a label above its input, so the grid
   never splits a label from the thing it names. */
.user-edit {
  display:grid; grid-template-columns:1fr 1fr; gap:10px 16px; align-items:start;
}
.user-edit .uf { display:flex; flex-direction:column; min-width:0; }
.user-edit .uf .login-label { margin:0 0 4px; }
.user-active, .user-edit-actions { grid-column:1 / -1; }

@media (max-width:640px) { .user-edit { grid-template-columns:1fr; } }
/* Every select in a form, themed. A hardcoded white background renders the
   themed (light) text invisible on Ocean and Midnight — the same defect the
   provisioning result panel had. */
.form-select, .user-edit select {
  font:inherit; width:100%; padding:8px 10px; border:1px solid var(--n200);
  border-radius:6px; background:var(--n0); color:var(--n800);
}
.form-select option, .user-edit select option {
  background:var(--n0); color:var(--n800);
}
.user-active {
  display:flex; gap:8px; align-items:flex-start; margin-top:12px;
  font-size:11.5px; color:var(--n600); line-height:1.35;
}
.user-active input { width:auto; flex:none; margin-top:2px; }
/* Always reachable: this is what "have to scroll to save" was about. */
.user-edit-actions {
  display:flex; gap:8px; align-items:center; margin-top:14px;
  padding-top:12px; border-top:1px solid var(--n200);
}
.user-edit-msg { font-size:12px; color:var(--n600); }

/* Provisioning result panel. Themed, not hardcoded cream: on Ocean and
   Midnight a fixed light panel renders light text on a pale background. */
.nu-result {
  margin-top:12px; padding:10px; border-radius:6px; font-size:12.5px;
  background:var(--warn-bg); border:1px solid var(--warn); color:var(--n800);
}
.nu-result .nu-line { padding:7px 0; border-top:1px solid var(--warn); }
.nu-result .nu-replaced { color:var(--warn); }
.nu-result .nu-alt { margin-top:6px; font-size:11.5px; color:var(--n600); }

/* ---------- copy block ----------
   Anything meant to be handed to someone else (setup links, one-time
   passwords) renders as a block with its own Copy button. Selecting a long
   token by hand is error-prone on a desktop and awful on a phone. */
.copy-block {
  display:flex; gap:8px; align-items:center; margin:6px 0;
  background:var(--n100); border:1px solid var(--n200);
  border-radius:var(--radius); padding:8px 10px;
}
.copy-block code {
  flex:1; min-width:0; font-family:ui-monospace, Consolas, monospace;
  font-size:12px; line-height:1.45; color:var(--n800); word-break:break-all;
  user-select:all;
}
.copy-block button { flex:none; }

/* ---------- campaigns (telephony work list) ---------- */
.camp {
  background:var(--n0); border:1px solid var(--n200); border-radius:var(--radius);
  padding:10px 12px; margin-bottom:10px;
}
.camp-head { display:flex; gap:10px; align-items:center; flex-wrap:wrap; color:var(--n800); }
.camp-row {
  display:flex; gap:8px; align-items:baseline; flex-wrap:wrap;
  padding:4px 0 4px 2px; font-size:12.5px; color:var(--n800);
}
.camp-out { margin-top:6px; font-size:12.5px; color:var(--n800); }

/* ---------- HOA assessments ---------- */
.hoa-total td { border-top:2px solid var(--n300); }
.hoa-calc { display:flex; gap:12px; align-items:center; flex-wrap:wrap; margin-bottom:8px; }
.hoa-opt {
  background:var(--n0); border:1px solid var(--n200); border-radius:var(--radius);
  padding:8px 14px; min-width:150px; opacity:.6;
}
.hoa-opt.wins, .hoa-opt.applied { opacity:1; border-color:var(--ok); }
.hoa-opt.applied { background:var(--ok-bg); }
.hoa-opt.applied .lgr-v { color:var(--ok); }
.hoa-vs { color:var(--n500); font-size:12px; font-weight:700; }

/* ---------- performance management ---------- */
.pm-funnel, .pm-commit {
  display:flex; gap:12px; align-items:center; flex-wrap:wrap;
  padding:8px 12px; margin-bottom:var(--s4);
  background:var(--n0); border:1px solid var(--n200); border-radius:var(--radius);
  font-size:12.5px; color:var(--n700);
}
.pm-commit { margin:var(--s4) 0 0; }
.pm-stat { font-weight:600; color:var(--n800); }
.pm-stat.bad { color:var(--danger); }

/* ---------- account boarding ---------- */
.bd-h { color:var(--n800); font-size:14px; margin:18px 0 8px; }
.bd-actions { display:flex; gap:12px; align-items:center; flex-wrap:wrap; margin-bottom:6px; }
.bd-select {
  font:inherit; font-size:12.5px; padding:4px 8px; border:1px solid var(--n200);
  border-radius:6px; background:var(--n0); color:var(--n800); max-width:230px;
}
.bd-err { color:var(--danger); font-size:12.5px; margin-bottom:2px; }
.bd-warn-line { color:var(--warn); font-size:12.5px; margin-bottom:2px; }
.bd-warn {
  background:var(--warn-bg); color:var(--warn); border:1px solid var(--warn);
  border-radius:var(--radius); padding:8px 12px; font-size:12.5px; margin-top:8px;
}
.bd-questions { font-size:12.5px; color:var(--n700); margin-top:4px; }
.bd-questions ul { margin:4px 0 0 18px; }
.bd-questions li { margin-bottom:3px; }
.bd-attest {
  display:flex; gap:14px; align-items:center; flex-wrap:wrap; margin-top:16px;
  padding:12px 14px; background:var(--n0); border:1px solid var(--n200); border-radius:var(--radius);
}
.bd-check { display:flex; gap:8px; align-items:center; font-size:13px; color:var(--n700); }
.bd-attested { color:var(--ok); font-weight:700; font-size:13.5px; }

/* ---------- compliance board / case officer ---------- */
.cl-draft-row td { background:var(--n0); }
.cl-draft-panel { padding:12px 14px; display:flex; flex-direction:column; gap:10px; }
.cl-assess { color:var(--n700); font-size:13px; }
.cl-letter {
  white-space:pre-wrap; background:var(--n100); border:1px solid var(--n200);
  border-radius:var(--radius); padding:14px 16px; color:var(--n800);
  font-size:13.5px; line-height:1.55; max-width:860px;
}
.cl-cautions { font-size:12.5px; color:var(--n700); }
.cl-cautions ul { margin:4px 0 0 18px; }
.cl-cautions li { margin-bottom:3px; }

/* ---------- decision science ---------- */
.ds-strip {
  display:flex; gap:12px; align-items:center; flex-wrap:wrap;
  margin-top:8px; padding:7px 12px; background:var(--n0);
  border:1px solid var(--n200); border-radius:var(--radius);
  font-size:12.5px; color:var(--n700);
}
.ds-k { font-size:10.5px; font-weight:700; letter-spacing:.6px; color:var(--n600); }
.ds-detail { color:var(--n600); }
.strat-bands { display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin-bottom:var(--s4); }
.strat-band {
  display:inline-flex; gap:8px; align-items:baseline; padding:4px 12px;
  background:var(--n0); border:1px solid var(--n200); border-radius:var(--radius);
  font-weight:700; color:var(--n700);
}
.strat-band .num { font-size:16px; }
.strat-move { max-width:220px; }

/* ---------- accounting sandbox ---------- */
.lgr-bal { display:flex; gap:var(--s3); margin-bottom:var(--s4); }
.lgr-cell {
  flex:1; background:var(--n0); border:1px solid var(--n200);
  border-radius:var(--radius); padding:10px 14px;
}
.lgr-k { font-size:10.5px; font-weight:700; letter-spacing:.6px; text-transform:uppercase; color:var(--n600); }
.lgr-v { font-size:20px; font-weight:700; color:var(--n800); margin-top:2px; }
.lgr-sched { display:flex; gap:8px; align-items:center; flex-wrap:wrap; margin-bottom:4px; }
.lgr-sched-k { font-size:10.5px; font-weight:700; letter-spacing:.6px; text-transform:uppercase; color:var(--n600); }
.lgr-inst {
  display:inline-flex; gap:6px; align-items:center; font-size:12.5px; color:var(--n700);
  background:var(--n0); border:1px solid var(--n200); border-radius:var(--radius);
  padding:4px 10px;
}
.lgr-inst.sat { border-color:var(--ok); }
.lgr-paidoff {
  background:var(--ok-bg); color:var(--ok); font-weight:700; font-size:13px;
  border:1px solid var(--ok); border-radius:var(--radius);
  padding:8px 14px; margin-bottom:var(--s4);
}
.lgr-ops { display:flex; gap:var(--s4); align-items:center; flex-wrap:wrap; margin-bottom:var(--s4); }
.lgr-op { display:flex; gap:6px; align-items:center; }
.lgr-op input {
  font:inherit; width:110px; padding:6px 8px;
  border:1px solid var(--n200); border-radius:6px; outline:none;
}
.lgr-table { width:100%; border-collapse:collapse; background:var(--n0);
  border:1px solid var(--n200); border-radius:var(--radius); font-size:12.5px; }
.lgr-table th { text-align:left; font-size:10.5px; letter-spacing:.6px; text-transform:uppercase;
  color:var(--n600); padding:8px 10px; border-bottom:1px solid var(--n200); }
.lgr-table td { padding:8px 10px; border-bottom:1px solid var(--n100); vertical-align:top; }
.lgr-line { display:flex; justify-content:space-between; gap:12px; }
.lgr-reversed td { color:var(--n500); }
.lgr-reversed .lgr-line { text-decoration:line-through; }

.auth-note {
  font-size:10.5px; font-weight:700; letter-spacing:.8px;
  color:var(--n300); border:1px solid var(--n600); border-radius:4px; padding:2px 7px;
}

/* ---------- messages (omni-channel) ---------- */
.convo-thread { display:flex; flex-direction:column; gap:8px; max-width:720px; margin-bottom:var(--s4); }
.convo-when { font-size:10px; opacity:.7; margin-top:4px; }
.convo-badge {
  display:inline-block; font-size:9px; font-weight:700; letter-spacing:.6px;
  text-transform:uppercase; border:1px solid currentColor; border-radius:4px;
  padding:1px 5px; margin-bottom:3px; opacity:.85;
}
.convo-subj { font-weight:700; margin-bottom:2px; }
.convo-compose { display:flex; gap:8px; max-width:720px; }
.convo-compose input {
  flex:1; font:inherit; padding:8px 10px;
  border:1px solid var(--n200); border-radius:6px; outline:none;
}
.convo-compose input:focus { border-color:var(--p500); }
.convo-mode.sel { background:var(--p600); border-color:var(--p600); color:#fff; }
.convo-split {
  display:grid; grid-template-columns:repeat(auto-fit, minmax(255px, 1fr));
  gap:var(--s4);
}
.convo-pane {
  border:1px solid var(--n200); border-radius:8px; background:var(--n0);
  display:flex; flex-direction:column; overflow:hidden;
}
.convo-pane.live { border-color:#22c55e; }
.convo-pane-head {
  display:flex; align-items:center; gap:6px; padding:8px 12px;
  border-bottom:1px solid var(--n100); cursor:pointer; font-size:12.5px;
}
.convo-pane-head:hover { background:var(--n100); }
.convo-pane-thread {
  display:flex; flex-direction:column; gap:8px; padding:10px;
  height:300px; overflow-y:auto;
}
.convo-pane-thread .chat-msg { font-size:12px; max-width:92%; }
.convo-compose.sm { padding:8px 10px; border-top:1px solid var(--n100); max-width:none; }
.convo-compose.sm input { min-width:0; }
.live-dot {
  display:inline-block; width:8px; height:8px; border-radius:50%;
  background:#22c55e; margin-right:5px; vertical-align:1px;
  animation:live-pulse 1.6s ease-in-out infinite;
}
.convo-live {
  display:flex; align-items:center; gap:4px; font-size:12px; font-weight:700;
  color:#22c55e; margin-bottom:var(--s3);
}
@keyframes live-pulse {
  0%, 100% { opacity:1; box-shadow:0 0 0 0 rgba(34,197,94,.45); }
  50% { opacity:.6; box-shadow:0 0 0 4px rgba(34,197,94,0); }
}

/* ---------- themes (user-selectable — Chris 2026-08-07) ----------
   Every component reads the token set, so a theme is a token remap.
   n0 = surface, n50 = page, n200 = borders, n800 = body text, n900 = strongest
   text. The topbar keeps its own --top surface in every theme. */
html[data-theme="ocean"] {
  --n0:#102841; --n50:#0b1c2c; --n100:#16324a; --n200:#24415c; --n300:#35526e;
  --n500:#7d97b0; --n600:#9fb8d0; --n700:#b6cade; --n800:#dce8f5; --n900:#f2f7fc;
  --p500:#4d94ff; --p600:#3b82f6; --p50:#0f2f52;
  --ok:#4ade80; --ok-bg:#0d2e21;
  --warn:#fbbf24; --warn-bg:#33270c;
  --danger:#f87171; --danger-bg:#391416;
  --info:#b79df5; --info-bg:#251743;
  --top:#061321;
  --shadow:0 1px 2px rgba(0,0,0,.35), 0 1px 3px rgba(0,0,0,.45);
}
html[data-theme="midnight"] {
  --n0:#191d23; --n50:#111418; --n100:#20252c; --n200:#2a313a; --n300:#3a434e;
  --n500:#8a94a2; --n600:#a7b1bd; --n700:#c2cbd6; --n800:#e2e6ea; --n900:#f4f6f8;
  --p500:#6ea8ff; --p600:#3b82f6; --p50:#122544;
  --ok:#4ade80; --ok-bg:#122b1e;
  --warn:#fbbf24; --warn-bg:#2e2510;
  --danger:#f87171; --danger-bg:#331518;
  --info:#c4b5fd; --info-bg:#231a3d;
  --top:#0a0c0f;
  --shadow:0 1px 2px rgba(0,0,0,.4), 0 1px 3px rgba(0,0,0,.5);
}
/* PARCHMENT - light and warm, where Daylight is light and cool. For anyone
   who finds a white screen tiring over a long shift; the surfaces are cream
   and the text is a warm near-black rather than pure grey. */
html[data-theme="parchment"] {
  --n0:#fdfaf3; --n50:#f5efe2; --n100:#efe7d7; --n200:#e0d5be; --n300:#c9bca1;
  --n500:#8a7e69; --n600:#675d4d; --n700:#4b4438; --n800:#332e26; --n900:#211d18;
  --p500:#2c4bb8; --p600:#22399a; --p50:#e9eefb;
  --ok:#2f6b3a;  --ok-bg:#edf4ea;
  --warn:#8f5a00; --warn-bg:#fbf2dd;
  --danger:#a72b28; --danger-bg:#faeceb;
  --info:#5f2fc0; --info-bg:#f0ebfb;
  --top:#2b2620;
  --shadow:0 1px 2px rgba(74,60,40,.08), 0 1px 3px rgba(74,60,40,.12);
}

/* FOREST - dark, green. Ocean is a blue dark and Midnight a neutral one; this
   is the third direction. The primary stays BLUE on purpose: a green accent
   would sit right next to the green that means "good", and a status colour
   that can be mistaken for a button is a status colour that stops working. */
html[data-theme="forest"] {
  --n0:#13211a; --n50:#0c1712; --n100:#1b2e24; --n200:#284031; --n300:#385442;
  --n500:#82a68f; --n600:#a0c2ab; --n700:#bcd6c5; --n800:#dcecdf; --n900:#f0f8f1;
  --p500:#6fb3ff; --p600:#4a95f0; --p50:#0f2b40;
  --ok:#56d98a;  --ok-bg:#113024;
  --warn:#f0c04d; --warn-bg:#33290f;
  --danger:#f47b7b; --danger-bg:#3a1618;
  --info:#b9a6f7; --info-bg:#241a41;
  --top:#071009;
  --shadow:0 1px 2px rgba(0,0,0,.38), 0 1px 3px rgba(0,0,0,.48);
}

/* EMBER - dark and warm, the counterpart to Parchment. Same reasoning on the
   accent: an orange primary would collide with the amber that means "warning"
   and the red that means "danger", so the one cool colour on screen is the one
   you are meant to click. */
html[data-theme="ember"] {
  --n0:#231d19; --n50:#171210; --n100:#2d2621; --n200:#3c322b; --n300:#4f433a;
  --n500:#9e8e82; --n600:#bcab9e; --n700:#d4c6ba; --n800:#ece3db; --n900:#f9f4ef;
  --p500:#7fb0ff; --p600:#5c93ea; --p50:#152538;
  --ok:#5fd393;  --ok-bg:#14301f;
  --warn:#f5c24d; --warn-bg:#33290d;
  --danger:#f87171; --danger-bg:#3a1a17;
  --info:#c3a8f7; --info-bg:#271b40;
  --top:#0d0a08;
  --shadow:0 1px 2px rgba(0,0,0,.4), 0 1px 3px rgba(0,0,0,.5);
}

/* literal-color spots that need dark-theme companions */
html[data-scheme="dark"] .compliance-strip .script { color:#d6c7ff; background:#2a1d52; }
html[data-scheme="dark"] table.data tr.actual-diverged td { background:#241f10; }
html[data-scheme="dark"] .banner.danger { border-bottom-color:#5b2020; }
html[data-scheme="dark"] .banner.warn { border-bottom-color:#5b4a12; }
html[data-scheme="dark"] .owner-chip.placed { border-color:#3d2f66; }
/* form fields follow the theme (the topbar search styles itself) */
html[data-scheme="dark"] input:not(#global-search),
html[data-scheme="dark"] textarea,
html[data-scheme="dark"] select {
  background:var(--n100); color:var(--n800); border-color:var(--n300);
  caret-color:var(--n800);
}
html[data-scheme="dark"] ::placeholder { color:var(--n500); }

/* brand marks ride a white plate so logos read on any theme */
.answer-as { background:#fff !important; color:#414c5b !important; }
.login-logo { background:#fff; border-radius:8px; padding:8px 14px; box-sizing:content-box; }
/* Same reason as .login-logo above: these marks are drawn for a light ground. */
.flag-logo:not(.flag-logo-none) { background:#fff; border-radius:6px;
  padding:4px 6px; box-sizing:content-box; }

/* toast */
.toast {
  position:fixed; bottom:24px; left:50%; transform:translateX(-50%);
  background:var(--top); color:#fff; border-radius:var(--radius);
  padding:var(--s2) var(--s4); font-size:13px; box-shadow:var(--shadow); z-index:99;
}

/* Enlarged desk photo. Built on demand and removed on close, so a family
   photo is not sitting in the DOM of every screen. */
.desk-lightbox{position:fixed;inset:0;z-index:1000;display:flex;align-items:center;
  justify-content:center;background:rgba(8,12,20,.86);backdrop-filter:blur(3px);
  animation:desk-lb-in .12s ease-out}
@keyframes desk-lb-in{from{opacity:0}to{opacity:1}}
.desk-lightbox img{max-width:88vw;max-height:86vh;border-radius:10px;
  box-shadow:0 24px 70px rgba(0,0,0,.6);cursor:default}
.desk-lb-close{position:absolute;top:14px;right:18px;width:38px;height:38px;
  border-radius:50%;border:0;cursor:pointer;font-size:22px;line-height:1;
  background:rgba(255,255,255,.14);color:#fff}
.desk-lb-close:hover{background:rgba(255,255,255,.26)}
.desk-lb-nav{position:absolute;top:50%;transform:translateY(-50%);width:46px;height:64px;
  border:0;border-radius:8px;cursor:pointer;font-size:30px;line-height:1;
  background:rgba(255,255,255,.12);color:#fff}
.desk-lb-nav:hover{background:rgba(255,255,255,.24)}
.desk-lb-nav.prev{left:16px} .desk-lb-nav.next{right:16px}
.desk-lb-count{position:absolute;bottom:18px;left:50%;transform:translateX(-50%);
  color:#cfd8e6;font-size:12px;letter-spacing:.04em}

/* ---------------- motion ----------------
   Short, and always disabled under prefers-reduced-motion. See app-core.js. */

@keyframes rise {
  from { opacity:0; transform:translateY(9px); }
  to   { opacity:1; transform:none; }
}

/* A station arriving. It moves like an object rather than blinking into
   place - the difference between the two is most of what "considered" means
   in an interface. */
.practice:not(.hidden) > .practice-inner {
  animation: panel-in .26s cubic-bezier(.2,.7,.3,1) both;
}
@keyframes panel-in {
  from { opacity:0; transform:translateY(10px) scale(.995); }
  to   { opacity:1; transform:none; }
}

/* Tiles lift toward the pointer. Small: 2px and a shadow is enough to say
   "this is a thing you can press" without the page appearing to breathe. */
.module-tile { transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease; }
.module-tile:not(.soon):hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 24px rgba(0,0,0,.16);
}

/* Stat cells settle in with their numbers. */
.lgr-cell { transition: background .2s ease; }

@media (prefers-reduced-motion: reduce) {
  .practice:not(.hidden) > .practice-inner,
  .module-tile,
  .lgr-cell { animation: none !important; transition: none !important; }
  .module-tile:not(.soon):hover { transform: none; }
}

/* ---------------- Mortgage station ---------------- */

/* The funnel reads as a shape, not a table. Bars are the point: seeing 100%
   collapse to 2% across seven steps says more about this business than the
   numbers beside them. */
.mtg-funnel { display:grid; gap:6px; margin:8px 0 4px; }
.mtg-step { display:grid; grid-template-columns:1fr 190px 96px; gap:10px; align-items:center; }
.mtg-bar { background:var(--n100); border-radius:4px; height:20px; overflow:hidden; }
.mtg-bar > span {
  display:block; height:100%; background:var(--p500); border-radius:4px;
  transition: width .5s cubic-bezier(.2,.7,.3,1);
}
.mtg-step-label { font-size:13px; color:var(--n700); }
.mtg-step-n { font-size:12px; color:var(--n500); text-align:right; }

/* An overdue file is tinted rather than shouted at - the badge already says
   so, and a table where a third of the rows are red stops meaning anything. */
tr.mtg-stale td { background:var(--warn-bg); }

.mtg-file { padding:10px 4px 14px; }
.mtg-why { font-size:14px; margin-bottom:6px; color:var(--n800); }

/* The pipeline as a track. Reached steps are solid, the rest are outlines, so
   where a file stopped is visible at a glance rather than read. */
.mtg-track { list-style:none; margin:0; padding:0; display:grid; gap:4px; }
.mtg-track li {
  display:grid; grid-template-columns:210px 1fr; gap:10px; padding:5px 8px;
  border-left:3px solid var(--n200); border-radius:0 4px 4px 0; background:var(--n50);
  color:var(--n500);
}
.mtg-track li.done { border-left-color:var(--p500); background:var(--n100); color:var(--n800); }
.mtg-track li b { font-weight:600; }



/* ---------------- the bridge hero ----------------

   A brand mark, not a diagram. The compass turns once every eighty seconds, a
   bearing sweeps and fades, and two swells drift beneath at different speeds
   so the water never quite repeats.

   Restraint is the design. A finance platform that sparkles looks like a toy,
   and somebody demonstrating this has it on screen for an hour - if it reads
   as "animated" rather than "alive", it is wrong. Everything is a transform or
   an opacity, so the compositor does the work and the main thread stays free.

   Colour is entirely theme variables, so the mark belongs to whichever of the
   six themes is on. */

.hero {
  margin: 4px 0 18px;
  border: 1px solid var(--n200);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  line-height: 0;
}
.hero svg { width: 100%; height: 168px; display: block; }

/* the ground: page colour into surface, so it sits in the theme rather than on it */
.hero-sky-a { stop-color: var(--n50); }
.hero-sky-b { stop-color: var(--n0); }
.hero-glow-a { stop-color: var(--p500); stop-opacity: .13; }
.hero-glow-b { stop-color: var(--p500); stop-opacity: 0; }

.hero-word {
  font-family: var(--font); font-size: 40px; font-weight: 700;
  fill: var(--n900); letter-spacing: -.5px;
}
.hero-word-b { fill: var(--p500); }
.hero-sub  { font-family: var(--font); font-size: 13px; fill: var(--n600);
             letter-spacing: .16em; text-transform: uppercase; }
.hero-rule { stroke: var(--p500); stroke-width: 2; opacity: .6; }
.hero-tag2 { font-family: var(--font); font-size: 12px; fill: var(--n500); }

.hero-ring-o, .hero-ring-i { fill: none; stroke: var(--n300); stroke-width: 1; }
.hero-ring-i { opacity: .6; }
.hero-tick { stroke: var(--n300); stroke-width: 1; opacity: .7; }
.hero-tick.long { stroke: var(--n500); stroke-width: 1.4; opacity: 1; }
.hero-point { fill: var(--p500); opacity: .30; }
.hero-point.sm { fill: var(--n500); opacity: .22; }
.hero-hub { fill: var(--p500); opacity: .75; }

.hero-sweep line {
  stroke: var(--p500); stroke-width: 2; stroke-linecap: round;
}

.hero-swell { fill: var(--p500); }
.hero-swell.far  { opacity: .07; }
.hero-swell.near { opacity: .11; }

/* --- motion. Slow on purpose; see the note above. --- */
.hero-ring  { animation: hero-turn 80s linear infinite; transform-origin: 0 0; }
.hero-rose  { animation: hero-turn 240s linear infinite reverse; transform-origin: 0 0; }
.hero-sweep { animation: hero-turn 9s linear infinite; transform-origin: 0 0; }
.hero-sweep line { animation: hero-fade 9s linear infinite; }
.hero-swell.far  { animation: hero-drift 34s linear infinite; }
.hero-swell.near { animation: hero-drift 21s linear infinite reverse; }

@keyframes hero-turn  { to { transform: rotate(360deg); } }
@keyframes hero-fade  { 0% { opacity: .55; } 70% { opacity: 0; } 100% { opacity: 0; } }
@keyframes hero-drift { to { transform: translateX(-360px); } }

@media (prefers-reduced-motion: reduce) {
  .hero-ring, .hero-rose, .hero-sweep, .hero-sweep line,
  .hero-swell.far, .hero-swell.near { animation: none; }
  .hero-sweep { opacity: .35; }
}

/* Below this the wordmark and the compass collide; the mark is worth more
   than the compass, so the compass goes. */
@media (max-width: 760px) { .hero svg { height: 118px; } }


/* ---------------- the vision panel ----------------
   Unbuilt stations open and say what they will do, rather than answering a
   click with a toast. A dead end in the middle of a demo makes the presenter
   talk over a screen that just refused them. */
.vis-replaces {
  display: flex; gap: 12px; align-items: baseline;
  background: var(--n50); border: 1px solid var(--n200);
  border-radius: var(--radius); padding: 10px 14px; margin-bottom: 16px;
}
.vis-k { font-size: 11px; letter-spacing: .12em; text-transform: uppercase;
         color: var(--n500); white-space: nowrap; }
.vis-v { font-size: 14px; color: var(--n800); font-weight: 600; }

.vis-list { margin: 4px 0 16px; padding: 0; list-style: none; }
.vis-list li {
  position: relative; padding: 6px 0 6px 22px; font-size: 14px;
  color: var(--n700); line-height: 1.5;
}
.vis-list li::before {
  content: ""; position: absolute; left: 4px; top: 14px;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--p500); opacity: .55;
}


/* ---------------- diagnostics ----------------
   A wall of errors is read by scanning, not reading, so the detail is
   monospaced and the paste block is one obvious slab. */
.diag-detail {
  margin: 6px 0 0; padding: 8px 10px; max-height: 180px; overflow: auto;
  background: var(--n50); border: 1px solid var(--n200); border-radius: 4px;
  font-family: var(--mono); font-size: 11.5px; color: var(--n700);
  white-space: pre-wrap; word-break: break-word;
}
.diag-block {
  margin: 6px 0 0; padding: 12px 14px; max-height: 340px; overflow: auto;
  background: var(--n50); border: 1px solid var(--n200); border-radius: var(--radius);
  font-family: var(--mono); font-size: 11.5px; line-height: 1.5; color: var(--n800);
  white-space: pre-wrap; word-break: break-word; user-select: all;
}

/* ---------------- clearing a text box ----------------

   A ✕ inside the box, shown only when there is something to clear. The wrapper
   exists so the button positions against the INPUT's box rather than its
   parent, which often holds several fields.

   --n600 is the one neutral that reads on every theme's surface: the palette
   inverts between the light and dark schemes (--n900 is near-black in Sand and
   near-white in Ocean), so a fixed grey would vanish in half of them. */
.clearable { position:relative; display:block; width:100%; }
/* The wrapper becomes the flex item its input used to be, so it inherits the
   stretching - and the input inside a plain block no longer does. Without this
   the note box, which fills its column, collapsed to a ~20-character default
   and left the clear button stranded at the far end of the row. */
.clearable > input, .clearable > textarea { width:100%; padding-right:30px; }
#global-search { padding-right:30px; }

.input-clear {
  position:absolute; right:6px; top:50%; transform:translateY(-50%);
  width:20px; height:20px; padding:0; margin:0;
  display:none; place-items:center;
  font:inherit; font-size:11px; line-height:1;
  color:var(--n600); background:transparent; border:0; border-radius:50%;
  cursor:pointer;
}
.clearable.has-text > .input-clear { display:grid; }
/* A textarea is several lines tall, so centring would float the ✕ in the
   middle of the text. It belongs in the corner. */
.clearable.is-area > .input-clear { top:8px; transform:none; }
.input-clear:hover { color:var(--n900); background:rgba(127,127,127,.20); }
.input-clear:active { background:rgba(127,127,127,.32); }

/* The topbar keeps its own dark surface in every theme (see --top), so the
   navigator's ✕ takes fixed light values for the same reason its text does. */
.search-wrap .input-clear { color:rgba(255,255,255,.70); }
.search-wrap .input-clear:hover { color:#fff; background:rgba(255,255,255,.20); }

/* The second hint row is subordinate to the first: those keys need an account
   open, so it reads as a caption rather than a peer of "/ search". */
/* The panel is 560px wide, so five hints and a label on one line wrapped every
   one of them onto two lines. The label takes its own line and the hints wrap
   under it as a group. */
.home-hints-sub {
  margin-top:2px; opacity:.8; flex-wrap:wrap; gap:var(--s3) var(--s4);
}
.home-hints-sub .hint-lead {
  flex-basis:100%; font-size:11px; letter-spacing:.4px; text-transform:uppercase;
  color:var(--n500); margin-bottom:2px;
}

/* The delete button. Distinct from the neighbouring actions because it is the
   only one on that row that cannot be undone, and muted rather than loud
   because it is a rare action sitting beside three common ones. */
.btn.danger-btn { color:#c05b5b; border-color:#c05b5b55; }
.btn.danger-btn:hover:not([disabled]) { color:#fff; background:#c05b5b; border-color:#c05b5b; }
/* Shown on every row so the actions line up, but only LIVE where the audit
   trail does not name the person. Muted rather than hidden: a missing button
   reads as a bug, and a disabled one that explains itself teaches the rule. */
.btn.danger-btn[disabled] {
  color:var(--n500); border-color:var(--n200); opacity:.55; cursor:not-allowed;
}

/* Confirming a removal. Replaces a native prompt(), which could not be sized
   and clipped its own instruction on a short window.

   This sits ON TOP of the Users modal, which is itself a .login-screen at
   z-index 100. Both are the same layer and #confirm-modal appears earlier in
   the document, so without this the panel it is asking about paints over the
   question - which is exactly what it did. */
#confirm-modal { z-index:120; }
.confirm-card { width:460px; max-width:94vw; background:var(--n0); }
.confirm-card h3 { font-size:16px; margin:0 0 2px; }
.confirm-card .confirm-who { font-size:12.5px; color:var(--n600); margin-bottom:12px; }
.confirm-card .confirm-count {
  font-size:13px; font-weight:600; color:var(--n800); margin:12px 0 6px;
}
.confirm-rows {
  margin:0 0 12px; padding:8px 10px; background:var(--n50);
  border:1px solid var(--n200); border-radius:var(--radius);
  max-height:150px; overflow:auto;
}
/* A grid, so the numbers line up. In the prompt they were space-padded, which
   proportional type ignores. */
.confirm-rows .cr { display:grid; grid-template-columns:70px 1fr; font-size:12.5px; }
.confirm-rows .cr b { text-align:right; padding-right:10px; font-variant-numeric:tabular-nums; }
.confirm-warn { font-size:12.5px; color:#c05b5b; margin:0 0 12px; line-height:1.4; }
.confirm-card .login-label { margin-top:0; }
.confirm-actions { display:flex; gap:8px; margin-top:14px; }
.confirm-actions .btn { flex:1; }

/* Who works an account. The unowned state is the loud one on purpose - an
   account nobody is working is the thing a supervisor needs to SEE, not
   discover. */
.worked-by { font-size:11px; color:var(--n600); cursor:pointer; padding:2px 8px;
  border:1px solid var(--n200); border-radius:10px; }
.worked-by b { color:var(--n800); font-weight:600; }
.worked-by.unowned { color:#fff; background:#c05b5b; border-color:#c05b5b;
  font-weight:700; letter-spacing:.3px; }

/* Choosing a person: buttons, not a type-the-number phone menu. */
.pick-list { display:grid; grid-template-columns:1fr 1fr; gap:6px; margin:6px 0 2px; }
.pick-one { text-align:left; justify-content:flex-start; }
.pick-one .sr-sub { margin-left:6px; }
.pick-none { grid-column:1 / -1; color:var(--n600); }

/* Practice tips: the scripts a trainee must say verbatim, on screen while
   they practise saying them. Hidden state keeps the toggle visible, so the
   way back is never a mystery. */
.pr-tips { margin:8px 0; border:1px solid var(--n200); border-radius:var(--radius);
  background:var(--n50); padding:8px 12px; }
.pr-tips-head { display:flex; align-items:center; justify-content:space-between; }
.pr-tips-body { display:grid; grid-template-columns:1fr 1fr; gap:8px 14px; margin-top:8px; }
.pr-tip-label { font-size:11px; font-weight:700; letter-spacing:.4px;
  text-transform:uppercase; color:var(--n600); }
.pr-tip-say { font-size:12.5px; color:var(--n800); font-style:italic; margin:2px 0; }
.pr-tip-note { font-size:11px; color:var(--n500); line-height:1.35; }
.pr-tip-ph { font-size:9px; font-weight:700; color:#b58a2c; border:1px solid #b58a2c66;
  border-radius:3px; padding:0 4px; margin-left:6px; letter-spacing:.5px; }
@media (max-width:700px) { .pr-tips-body { grid-template-columns:1fr; } }

/* Contact permissions on the account header. Shut channels read as shut at a
   glance; the reason sits beside them so nobody has to hover to know why.
   Matches .ds-strip, which sits directly above it. */
.contact-strip {
  display:flex; gap:8px; align-items:center; flex-wrap:wrap;
  margin-top:6px; padding:6px 12px; background:var(--n0);
  border:1px solid var(--n200); border-radius:var(--radius);
  font-size:12px; color:var(--n700);
}
.cs-k { font-size:10.5px; font-weight:700; letter-spacing:.6px; color:var(--n600); }
.cs-ch { padding:1px 8px; border-radius:10px; border:1px solid var(--n200); }
.cs-ch.open { color:var(--ok); background:var(--ok-bg); border-color:#bbf7d0; }
.cs-ch.shut { color:var(--danger); background:var(--danger-bg); border-color:#fecaca;
  text-decoration:line-through; }
.cs-why { color:var(--danger); margin-left:2px; }

/* A channel the gate has closed, in the conversation panes. */
.convo-refused { padding:7px 9px; font-size:12px; color:var(--danger);
  background:var(--danger-bg); border-top:1px solid #fecaca; }
.convo-refused.pending { color:var(--n600); background:var(--n50); border-top-color:var(--n200); }

/* The Guides menu. Anchored under its button, above everything, and wide
   enough that each entry's subtitle can say what the guide is for - a list of
   bare titles makes you open three to find the right one. */
.guides-wrap { position:relative; display:inline-block; }
/* The caret must never wrap under the word - on a narrow screen it did, and
   the button grew a second line and towered over its neighbours. */
#guides-btn { white-space:nowrap; }
.guides-menu {
  position:absolute; right:0; top:calc(100% + 6px); z-index:80;
  width:340px; max-width:min(340px, 92vw); padding:6px;
  background:var(--n0); border:1px solid var(--n200); border-radius:8px;
  box-shadow:0 4px 6px rgba(16,24,40,.06), 0 12px 28px rgba(16,24,40,.14);
  text-align:left;
}
.gm-k {
  font-size:10px; letter-spacing:.09em; text-transform:uppercase; font-weight:700;
  color:var(--n500); padding:9px 10px 5px;
}
.gm-item {
  display:block; width:100%; text-align:left; padding:9px 10px; border:0;
  border-radius:6px; background:none; cursor:pointer; text-decoration:none;
  font:inherit; color:inherit;
}
.gm-item:hover { background:var(--p50); }
.gm-title { display:block; font-size:13.5px; font-weight:600; color:var(--n800); }
.gm-sub { display:block; font-size:12px; color:var(--n600); line-height:1.45; margin-top:2px; }
.gm-foot, .gm-empty {
  font-size:11.5px; color:var(--n500); padding:9px 10px; line-height:1.45;
  border-top:1px solid var(--n100); margin-top:4px;
}
.gm-empty { border-top:0; margin-top:0; }

/* Fleet cards. Same shape as a station tile - a ship is a thing you go into. */
.ship-stats { display:flex; gap:14px; flex-wrap:wrap; margin-top:10px;
  font-size:12.5px; color:var(--n600); }
.ship-stats .num { color:var(--n800); }
.ship-warn .num { color:var(--warn); }
.ship-stop { color:var(--danger); }
.ship-stop .num { color:var(--danger); }
.ship-empty { margin-top:10px; font-size:12px; color:var(--n500); }

/* The client's mark on its ship. Rides a white plate like every other brand
   mark here, because a logo drawn for print rarely survives a dark surface. */
.ship-logo {
  background:#fff; border:1px solid var(--n200); border-radius:6px;
  padding:10px 14px; margin-bottom:12px; display:flex; align-items:center;
  min-height:52px;
}
.ship-logo img { max-width:100%; max-height:30px; width:auto; display:block; }

/* Which ship you are on. A LINE, not a banner - a ship organises the work and
   must never imply the rules, and anything that looked like a client header
   would invite exactly that. */
.ship-line {
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  margin-top:12px; padding:8px 12px; background:var(--n0);
  border:1px solid var(--n200); border-radius:var(--radius); font-size:13px;
}
.ship-line-k {
  font-size:10px; font-weight:700; letter-spacing:.09em; color:var(--n500);
}
.ship-line-logo {
  background:#fff; border:1px solid var(--n200); border-radius:4px;
  padding:3px 6px; display:inline-flex; align-items:center;
}
.ship-line-logo img { height:15px; width:auto; display:block; }
.ship-line .btn { margin-left:auto; }
.ship-line .btn + .btn { margin-left:0; }

.ship-identity {
  margin-top:10px; font-size:12.5px; color:var(--n600);
  display:flex; align-items:center; gap:8px; flex-wrap:wrap;
}
.ship-identity b { color:var(--n800); }
.ship-logo { position:relative; }
/* A drawn-here mark says so on its own face. An invented logo shown without a
   marker is a small lie that gets copied into a deck. */
.ship-logo-ph {
  /* Straddles the plate's bottom edge rather than sitting on the mark - at
     the fleet card's plate size the badge covered the drawing it was
     annotating, which defeated both. */
  position:absolute; right:-4px; bottom:-8px;
  font-size:8px; font-weight:700; letter-spacing:.08em;
  color:var(--warn); background:var(--warn-bg);
  border:1px solid #fde68a; border-radius:3px; padding:1px 4px;
  white-space:nowrap;
}
.ship-logo-none {
  color:var(--n500); font-size:12px; font-style:italic;
  background:var(--n50); border-style:dashed;
}

/* Fleet cards on the flag pattern - Chris pointed at the identity strip and
   said every ship should look like that. Same plate, same shape; the ship's
   numbers ride where the identity strip carries its count. */
.fleet-flags .flag { flex:1 1 420px; cursor:pointer; transition:border-color .12s; }
.fleet-flags .flag:hover { border-color:var(--p500); }
.fleet-flags .flag-logo { position:relative; width:110px; height:34px; }
.fleet-flags .flag-name { font-size:14px; display:flex; align-items:center; gap:8px; }
.fleet-flags .flag-note b { color:var(--n800); }
.ship-quiet { opacity:.75; }
.ship-warn { color:var(--warn); }
.ship-stop { color:var(--danger); }

/* Central Command: a fleet per operating identity, its ships beneath it. */
.fleet-block { margin-top:26px; }
.fleet-head {
  display:flex; align-items:center; gap:11px; padding:10px 12px;
  background:var(--n100); border:1px solid var(--n200);
  border-radius:var(--radius) var(--radius) 0 0; border-bottom:0;
}
.fleet-head .flag-name { font-size:15px; }
.fleet-block .fleet-flags { margin-top:0; padding:12px; border:1px solid var(--n200);
  border-radius:0 0 var(--radius) var(--radius); background:var(--n50); }

/* A3: the plate is universal. A ship without a mark used to render a bare
   diamond with no plate, so rows ragged; now every card carries the same box
   and the placeholder sits inside it. The metric line is reserved at a fixed
   min-height even when it only says "No accounts boarded yet", so cards in a
   row stay the same height whether or not a book has landed. */
.fleet-flags .flag-logo,
.fleet-flags .flag-logo.flag-logo-none {
  background:#fff; border:1px solid var(--n200); border-radius:6px;
  padding:6px 10px;
}
.fleet-flags .flag-logo-none { background:var(--n50); border-style:dashed; }
.ship-metrics { min-height:18px; }

/* The action rail: what you DO, under where you ARE. A zone with its own
   heading, so the buttons cannot read as another scope. */
.action-rail {
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  margin-top:8px; padding:8px 12px; background:var(--n0);
  border:1px solid var(--n200); border-radius:var(--radius); font-size:13px;
}
.rail-k { font-size:10px; font-weight:700; letter-spacing:.09em; color:var(--n500); }
.rail-note { color:var(--n500); font-size:11.5px; margin-left:auto; }

/* The desk strip: weather and headlines. Quiet - it is decoration and knows
   it, so it borrows the rail's grammar and never shouts. */
.desk-strip {
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  margin-top:8px; padding:8px 12px; background:var(--n0);
  border:1px solid var(--n200); border-radius:var(--radius); font-size:12.5px;
}
#desk-loc { font:inherit; font-size:12.5px; padding:4px 8px; width:130px;
  border:1px solid var(--n200); border-radius:5px; }
.desk-wx { color:var(--n700); }
.desk-news { display:flex; gap:8px; align-items:center; flex-wrap:wrap;
  color:var(--n600); min-width:0; }
.desk-news a { color:var(--n700); text-decoration:none; max-width:260px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; display:inline-block; }
.desk-news a:hover { color:var(--p500); text-decoration:underline; }
.desk-dot { color:var(--n300); }

/* The ship's book on the bridge: the visible proof that choosing a ship chose
   something. Compact rows, no pretence of being the full workspace. */
.ship-book { margin-top:8px; padding:8px 12px; background:var(--n0);
  border:1px solid var(--n200); border-radius:var(--radius); font-size:12.5px; }
.ship-book-head { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.ship-book-rows { display:flex; gap:6px 14px; flex-wrap:wrap; margin-top:8px; }
.sb-row { display:inline-flex; align-items:center; gap:6px; }

/* The hero, compact and top-left (Chris, 2026-08-14): the banner shrank, the
   compass deliberately did not shrink with it. The wordmark gave up the room
   instead, so the animation he likes is a BIGGER share of a smaller card. */
.hero { flex:none; width:340px; margin:0 16px 0 0; }
.hero svg { height:68px; }
.hero-word { font-size:26px; }
.hero-sub  { font-size:9px; letter-spacing:.14em; }
.hero-tag2 { font-size:8.5px; }
@media (max-width:900px) {
  .hero { width:100%; margin:0 0 12px; }
  .hero svg { height:82px; }
}

/* The personal column: photos, then the desk beneath them. Chris's placement -
   personalised things belong together, on the right, out of the way of the
   ship line and the actions. */
.bridge-personal { flex:none; width:210px; display:flex; flex-direction:column; gap:10px; }
.bridge-personal .desk-strip { margin-top:0; flex-direction:column;
  align-items:flex-start; gap:7px; }
.desk-loc-row { display:flex; gap:6px; width:100%; }
.bridge-personal #desk-loc { flex:1; width:auto; min-width:0; }
.bridge-personal .desk-news { flex-direction:column; align-items:flex-start; gap:4px; }
.bridge-personal .desk-news a { max-width:190px; }
.bridge-personal .desk-dot { display:none; }

/* THE mark. Brass, per BRAND.md, because it now stands alone rather than
   inside a blue banner - Chris asked for gold and gold is what the brand is.
   The motion classes are shared with the retired hero, so the animation he
   liked is literally the same code. */
.brandmark { display:block; overflow:visible; }
.brandmark .hero-point { fill:#D9B549; opacity:.92; }
.brandmark .hero-point.sm { fill:#8A6618; opacity:.85; }
.brandmark .hero-hub { fill:#FBEFC4; }
.brandmark .hero-ring-o, .brandmark .hero-ring-i { stroke:#8A6618; opacity:.75; }
.brandmark .hero-tick { stroke:#C9992E; opacity:.6; }
.brandmark .hero-tick.long { stroke:#E2BE5C; opacity:.95; }
.brandmark .hero-sweep line { stroke:#FBEFC4; stroke-width:2; opacity:.55; }
#brand-home { display:inline-flex; align-items:center; }
#brand-home:hover .brandmark { filter:brightness(1.15); }
.bridge-head-text h1 .brandmark { vertical-align:-4px; margin-right:8px; display:inline-block; }

/* Four congruent cards: the ship and the three identities, one row, one shape.
   NCA used to be a full-width bar beside three equal thirds, which is what
   Chris saw as "stretched way longer than the others". */
.bridge-flags .flag { flex:1 1 260px; align-items:flex-start; }
.bridge-flags .flag-logo { width:100px; height:30px; flex:none;
  background:#fff; border:1px solid var(--n200); border-radius:5px; padding:4px 7px; }
.bridge-flags .flag-logo-none { background:var(--n50); border-style:dashed; }
.ship-card .flag-name { display:flex; align-items:center; gap:7px; }
.ship-card a { color:var(--p500); text-decoration:none; }
.ship-card a:hover { text-decoration:underline; }

/* The upper-right quadrant is the personalised space: photos and the desk in
   one bounded column rather than two things that happen to sit near each
   other. */
.bridge-personal { width:230px; }

/* View as: quiet when off, unmissable when on. A preview nobody can see they
   are in becomes a bug report about missing stations. */
.viewas { display:flex; align-items:center; gap:9px; flex-wrap:wrap;
  margin-top:8px; padding:8px 12px; background:var(--n0);
  border:1px solid var(--n200); border-radius:var(--radius); font-size:12.5px; }
.viewas.on { background:var(--warn-bg); border-color:#fde68a; }
.viewas select { font:inherit; font-size:12.5px; padding:4px 8px;
  border:1px solid var(--n200); border-radius:5px; }
.viewas-on { color:var(--warn); }

/* 1. THE MARK, MOVING VISIBLY.
   The hero turned once per 80s across a 900px banner. Perceived motion is
   angle per second AT THE RIM, so shrinking the radius twenty-fold while
   keeping the period made it look static. These periods are chosen for the
   size the mark is actually drawn at, and the sweep is thicker and brighter
   because a hairline at 38px is not a line at all. */
.brandmark .hero-ring  { animation: hero-turn 26s linear infinite; }
.brandmark .hero-rose  { animation: hero-turn 60s linear infinite reverse; }
.brandmark .hero-sweep { animation: hero-turn 4.5s linear infinite; }
.brandmark .hero-sweep line { animation: hero-fade 4.5s linear infinite;
  stroke-width:4; stroke:#FBEFC4; }
.brandmark .hero-ring, .brandmark .hero-rose, .brandmark .hero-sweep {
  transform-origin: 0 0;
}
@media (prefers-reduced-motion: reduce) {
  .brandmark .hero-ring, .brandmark .hero-rose, .brandmark .hero-sweep,
  .brandmark .hero-sweep line { animation: none; }
}

/* 2. THE PERSONAL SPACE, FRAMED.
   One bordered panel with a brass hairline at its head, so the photos and the
   desk read as one thing that belongs to the user rather than two widgets
   parked in a corner. */
.bridge-personal {
  border:1px solid var(--n200); border-radius:var(--radius);
  background:var(--n0); padding:12px; box-shadow:var(--shadow);
  border-top:2px solid #C9992E;
}
.bridge-personal .desk-strip { border:0; background:none; padding:0; }

/* 3. the rail, wherever it is painted */
.action-rail-slot:empty { display:none; }
.action-rail-slot { margin:0 0 12px; }

/* The role suggestion under the job title. Quiet when it resolves, and clearly
   different when it will not - an unresolved title is a person somebody has to
   think about, not an error. */
.nu-suggest { margin:6px 0 2px; padding:8px 10px; font-size:12.5px;
  border:1px solid var(--n200); border-radius:var(--radius); background:var(--n0);
  display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.nu-suggest.unresolved { background:var(--warn-bg); border-color:#fde68a;
  color:var(--warn); display:block; }
.nu-suggest.applied { background:#ecfdf5; border-color:#a7f3d0; color:#065f46; }
.nu-suggest .btn { padding:2px 10px; font-size:12px; }

/* ---- the bridge, given room where the room was (Chris, 2026-08-14) ----

   1. THE PERSONAL COLUMN TAKES THE DEAD SPACE. VIEW AS and SHIP'S BOOK are
      short rows that were stretched the full width of the head, so the middle
      of the bridge was empty and the photos were squeezed into 230px beside
      it. The column is wider now and the bars simply end where their content
      does. */
.bridge-personal { width:340px; }
.bridge-personal .desk-news a { max-width:none; }
.bridge-head-text .viewas, .bridge-head-text .ship-book { max-width:760px; }

/* 2. IDENTITIES ON TOP, SHIPS BENEATH. Two rows, because they are two kinds of
      thing: a fleet is an operating identity - which is a legal-regime
      boundary - and a ship is a book of business. Four peers in one line said
      they were the same kind of thing. Two per row above, three per row below,
      and a card that wraps keeps its width instead of stretching. */
.bridge-flags.identity-row { display:grid; grid-template-columns:repeat(2, 1fr);
  gap:var(--s3); }
.bridge-flags.ship-row { display:grid; grid-template-columns:repeat(3, 1fr);
  gap:var(--s3); margin-top:0; }
.bridge-flags.identity-row .flag, .bridge-flags.ship-row .flag { flex:none; }
.ship-row-foot { grid-column:1 / -1; font-size:12px; color:var(--n500);
  margin-top:-2px; }
.ship-row-foot a { color:var(--p500); text-decoration:none; }
.ship-row-foot a:hover { text-decoration:underline; }

/* A ship card is a way onto that ship, so it has to look like one. */
.flag[data-ship] { cursor:pointer; transition:border-color .12s, box-shadow .12s; }
.flag[data-ship]:hover { border-color:#C9992E; box-shadow:var(--shadow); }
.flag[data-ship]:focus-visible { outline:2px solid #C9992E; outline-offset:2px; }
.flag[data-ship].sel { border-color:#C9992E; border-top:2px solid #C9992E; }
.flag-count { margin-left:auto; text-align:right; line-height:1.15; }
.flag-count b { font-size:15px; }
.flag-count span { display:block; font-size:10.5px; color:var(--n500); }

@media (max-width:1400px) {
  .bridge-flags.ship-row { grid-template-columns:repeat(2, 1fr); }
}

/* 3. THE HEADLINES CRAWL. They were three one-line links clipped with an
      ellipsis in a 190px column, which is not reading, it is guessing. Now
      they wrap in full and drift upward slowly enough to finish a sentence.

      The list is rendered TWICE and the crawl travels exactly half its own
      height, so the second copy arrives where the first began and the loop has
      no seam. The copy is aria-hidden and untabbable - a screen reader and the
      tab key should meet each headline once. */
.desk-news { display:block; width:100%; height:96px; overflow:hidden;
  position:relative; -webkit-mask-image:linear-gradient(to bottom,
    transparent 0, #000 14px, #000 calc(100% - 14px), transparent 100%);
  mask-image:linear-gradient(to bottom, transparent 0, #000 14px,
    #000 calc(100% - 14px), transparent 100%); }
.news-crawl { display:block; animation:news-crawl 48s linear infinite; }
.news-crawl a { display:block; white-space:normal; overflow:visible;
  text-overflow:clip; max-width:none; padding:5px 0; line-height:1.35;
  border-bottom:1px solid var(--n100); }
/* Stop for anyone actually reading one. */
.desk-news:hover .news-crawl, .desk-news:focus-within .news-crawl {
  animation-play-state:paused; }
@keyframes news-crawl { from { transform:translateY(0); }
                        to   { transform:translateY(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .desk-news { height:auto; overflow:visible; -webkit-mask-image:none; mask-image:none; }
  .news-crawl { animation:none; }
  /* Motion off means the duplicate is just a duplicate. */
  .news-crawl a[aria-hidden="true"] { display:none; }
}

/* The head is two columns and now says so: everything about the ship on the
   left, everything personal on the right. The rows used to sit BELOW the head,
   which left a tall empty band between the title and the photos - the space
   Chris drew a circle around. Nothing here is new, it is the same content in
   the column it belongs to. */
.bridge-head { align-items:stretch; }
.bridge-head-text { display:flex; flex-direction:column; gap:8px; }
.bridge-head-text .bridge-flags { margin:0; }
.bridge-head-text > p { margin-bottom:2px; }

/* Two per row, both rows, so the block is square. Four ships in three columns
   left one card alone on a second row - the same lopsidedness as NCA being
   stretched longer than the others. */
.bridge-flags.identity-row, .bridge-flags.ship-row {
  grid-template-columns:repeat(2, 1fr);
}
@media (max-width:1200px) {
  .bridge-flags.identity-row, .bridge-flags.ship-row {
    grid-template-columns:1fr;
  }
}

/* The personal column fills its side rather than floating at the top of it. */
.bridge-personal { align-self:stretch; }
.bridge-personal .desk-strip { flex:1; }

/* Two rows of identical cards, and only the lower one is clickable. The keys
   say which is which - a fleet is a name we work under, a ship is a book you
   board - using the same grammar as SHIP'S BOOK and YOUR DESK beside them. */
.row-key { font-size:10.5px; letter-spacing:.09em; font-weight:700;
  color:var(--n500); margin:4px 0 -2px; }
.row-key span { letter-spacing:0; font-weight:400; text-transform:none;
  color:var(--n400); }

/* Nothing to scroll: hold still and drop the duplicate. */
.desk-news.still { height:auto; overflow:visible;
  -webkit-mask-image:none; mask-image:none; }
.desk-news.still .news-crawl { animation:none; }
.desk-news.still .news-crawl a[aria-hidden="true"] { display:none; }

/* ---- Central Command ------------------------------------------------------

   The screen where somebody stands back and looks at the whole fleet. It used
   to be twelve identical cards, ten of them empty, each repeating the sentence
   its own fleet header had just said. */

.cc-head { display:flex; align-items:center; gap:20px; }
.cc-head-text { flex:1; min-width:0; }
.cc-head h1 { margin-bottom:4px; }

/* Boarded ships: three across, and every card the SAME HEIGHT. The old grid
   sized each card to its own text, so a long name wrapped to three lines and
   dragged its whole row taller than the next. */
.fleet-flags { display:grid; grid-template-columns:repeat(3, 1fr);
  gap:var(--s3); align-items:stretch; }
.fleet-flags .flag { flex:none; align-items:center; }
.ship-metrics b { color:var(--n800); font-size:14px; }
.ship-exception { color:#C9992E; }
.cc-none { margin:4px 0 0; }
.cc-foot { margin-top:18px; }

/* Unboarded ships: still real, still one click away, no longer shouting. */
.cc-empty { display:flex; align-items:center; gap:8px; flex-wrap:wrap;
  margin-top:10px; }
.cc-empty .rail-k { margin-right:2px; }
.ship-chip { display:inline-flex; align-items:center; gap:7px; cursor:pointer;
  padding:5px 11px 5px 6px; font-size:12.5px; color:var(--n700);
  background:var(--n0); border:1px solid var(--n200); border-radius:999px;
  transition:border-color .12s, color .12s; }
.ship-chip img { width:20px; height:14px; object-fit:contain; background:#fff;
  border-radius:2px; padding:1px 2px; }
.ship-chip:hover { border-color:#C9992E; color:var(--n900); }
.ship-chip:focus-visible { outline:2px solid #C9992E; outline-offset:2px; }
.ship-chip .flag-mark { color:var(--n400); }

@media (max-width:1300px) { .fleet-flags { grid-template-columns:repeat(2, 1fr); } }

/* ---- the satellite --------------------------------------------------------

   It travels a real ellipse rather than being spun on a transform, so the path
   can be inclined without the satellite tumbling with it. `offset-rotate:0deg`
   is what keeps it upright: the default follows the path's tangent, which
   flips the solar panels end over end at the turns.

   The ellipse in the CSS path and the one drawn in the SVG are the same shape
   and the same rotation. If one is edited the other has to be. */
.satmark { flex:none; overflow:visible; }
@keyframes sat-orbit { from { offset-distance:0%; } to { offset-distance:100%; } }

/* THE OLD SINGLE-MARK RULES WERE REMOVED HERE, NOT RESTYLED. The stale
   `.satmark .sat-orbit-ring { animation: sat-ring 90s }` outlived the mark it
   was written for and rotated the SCENE's rings around the old drawing's
   60-unit origin - so the rings slowly swung away from the flight paths while
   every automated measurement passed, because getPointAtLength reads path
   geometry and CSS transforms never touch it. Chris watched it live and saw
   "the orbits lost position". sat-check now also asserts no animation and no
   transform applies to any ring. */

/* The crew model survives the move to chips. Dedicated and pooled used to be a
   badge on every card; once the empty ships became chips that fact had nowhere
   to live, and every pooled ship is empty - so the distinction would have left
   this screen entirely. It is a group label now rather than a badge repeated
   ten times. */
.cc-empty-group { display:inline-flex; align-items:center; gap:7px;
  flex-wrap:wrap; }
.cc-empty-k { color:var(--n400); }

/* ==== the personal space, rebuilt =========================================

   Three plainly separated things - who you are (photos, above), where you are
   (place and weather), and what is going on (headlines) - in the order
   somebody reads them at the start of a shift. It was a label, a text box and
   three clipped links. */
.bridge-personal { width:360px; }
.desk-strip { display:block; padding:0; background:none; border:0; }
.desk-sec { padding:11px 13px; }
.desk-sec + .desk-sec { border-top:1px solid var(--n200); }
.desk-k { display:flex; align-items:baseline; justify-content:space-between;
  gap:8px; margin-bottom:8px; }
.desk-date { font-size:11.5px; color:var(--n500); }

/* The weather, readable across a room rather than parsed out of a sentence. */
.desk-now { display:flex; align-items:center; gap:13px; margin-bottom:10px; }
.desk-temp { font-size:35px; font-weight:600; line-height:1; color:var(--n900);
  letter-spacing:-.02em; }
.desk-cond { display:flex; flex-direction:column; gap:2px; min-width:0;
  font-size:12.5px; }
.desk-cond b { color:var(--n800); font-weight:600; }
.desk-cond .sr-sub { font-size:11.5px; }
.desk-loc-row { display:flex; gap:6px; width:100%; }
.bridge-personal #desk-loc { flex:1; width:auto; min-width:0; }

/* ---- the headlines --------------------------------------------------------

   They DID scroll before, which is not a defence: the window was 96px, so it
   showed barely two at a time and read as a clipped box rather than as
   something moving. Taller, spaced, the source named, and slow enough that a
   sentence can be finished - drift, not a scroll bar.

   Ten headlines now rather than five, because a five-item loop puts the same
   two on screen most of the time. */
.desk-newsbox .rail-k { display:block; margin-bottom:7px; }
.desk-news { display:block; width:100%; height:168px; overflow:hidden;
  position:relative;
  -webkit-mask-image:linear-gradient(to bottom, transparent 0, #000 18px,
    #000 calc(100% - 22px), transparent 100%);
  mask-image:linear-gradient(to bottom, transparent 0, #000 18px,
    #000 calc(100% - 22px), transparent 100%); }
.news-crawl { display:block; animation:news-crawl 96s linear infinite; }
.news-crawl a { display:block; text-decoration:none; padding:9px 0;
  border-bottom:1px solid var(--n100); }
.news-src { display:block; font-size:9.5px; letter-spacing:.1em;
  font-weight:700; color:var(--n400); margin-bottom:2px; }
.news-title { display:block; font-size:12.5px; line-height:1.42;
  color:var(--n700); white-space:normal; }
.news-crawl a:hover .news-title { color:var(--p500); }
.desk-news:hover .news-crawl, .desk-news:focus-within .news-crawl {
  animation-play-state:paused; }
@keyframes news-crawl { from { transform:translateY(0); }
                        to   { transform:translateY(-50%); } }
@media (prefers-reduced-motion: reduce) {
  .desk-news { height:auto; overflow:visible;
    -webkit-mask-image:none; mask-image:none; }
  .news-crawl { animation:none; }
  .news-crawl a[aria-hidden="true"] { display:none; }
}
.desk-news.still { height:auto; overflow:visible;
  -webkit-mask-image:none; mask-image:none; }
.desk-news.still .news-crawl { animation:none; }
.desk-news.still .news-crawl a[aria-hidden="true"] { display:none; }

/* ==== ships stack, and never run four wide ================================

   A boarded ship is a full-width row: the mark, the name, then the numbers
   right-aligned where the eye can compare them down a column instead of
   hunting across a grid. */
.fleet-flags { grid-template-columns:1fr; }
.fleet-flags .flag { align-items:center; }
.fleet-flags .flag-text { display:flex; align-items:baseline; gap:14px;
  flex-wrap:wrap; flex:1; }
.fleet-flags .ship-metrics { margin-left:auto; text-align:right; }
.fleet-flags .ship-exception { flex-basis:100%; }

/* Unboarded ships stack too, in two columns headed by crew model - not a
   six-across line of chips. */
.cc-empty { display:grid; grid-template-columns:repeat(2, minmax(0, 1fr));
  gap:4px 22px; align-items:start; }
.cc-empty > .rail-k { grid-column:1 / -1; margin-bottom:2px; }
.cc-empty-group { display:flex; flex-direction:column; align-items:stretch;
  gap:4px; }
.cc-empty-k { margin-bottom:2px; }
.ship-chip { justify-content:flex-start; border-radius:var(--radius); }
@media (max-width:1000px) { .cc-empty { grid-template-columns:1fr; } }

/* The photos, as a section of the panel rather than a box floating above it.

   The empty state was a 96x72 frame holding a plus sign, "Add photos" and
   "up to 5" - three things in seventy-two pixels, so the plus sat on top of
   the label. It is the first thing in the personal space and it looked broken.
   Full width, room to breathe, and the count said plainly. */
.desk.desk-sec { flex:none; }
.desk.desk-sec > .rail-k { display:block; margin-bottom:7px; }
.desk-empty {
  width:100%; height:auto; min-height:62px; padding:12px;
  flex-direction:row; gap:10px; justify-content:flex-start;
  border:1px dashed var(--n300); border-radius:8px; background:transparent;
}
.desk-empty .desk-plus { font-size:22px; opacity:.7; }
.desk-empty-label { font-size:12.5px; font-weight:600; }
.desk-empty-sub { font-size:11px; }
/* The two labels stack beside the plus instead of under it. */
.desk-empty { align-items:center; }
.desk-empty-label, .desk-empty-sub { display:block; text-align:left; }
.desk-empty > span:not(.desk-plus) { flex:none; }
.desk-empty-label + .desk-empty-sub { margin-top:1px; }
.desk-cap { text-align:left; margin-top:6px; }

/* The unboarded list, sized to its content.

   Stacking them fixed the six-across line and immediately over-corrected: a
   two-column grid stretched "General Mortgage" into a 900px bar. A row for a
   two-word name should be as wide as a two-word name. */
.ship-chip { max-width:330px; }

/* The chips belong INSIDE their fleet's block, not floating on the page below
   it - they are that fleet's ships, and a border that stops above them says
   they are something else. */
.fleet-block .cc-empty { margin:0; padding:12px 12px 14px;
  border:1px solid var(--n200); border-top:0;
  border-radius:0 0 var(--radius) var(--radius); background:var(--n50); }
.fleet-block .fleet-flags:has(+ .cc-empty) { border-radius:0;
  border-bottom:0; padding-bottom:4px; }

/* ==== the photos fit, and the page uses the screen ========================

   THE PHOTOS WERE CLIPPED. Five frames at a fixed 96px, laid out in a flex row
   that never wrapped, inside a 360px panel: 5 x 96 plus gaps is 504px of
   content in about 334px of room, so the fourth and fifth were cut off at the
   panel edge. They were sized when the row was the full width of the bridge
   and did not follow the panel when it moved to the right column.

   A grid instead of a row: three across, wrapping, each sized from the column
   it is in rather than from a number typed when the layout was different.
   Five photos read as 3 + 2 and nothing leaves the panel. */
.desk-row { display:grid; grid-template-columns:repeat(3, 1fr); gap:6px;
  align-items:start; }
.desk-shot { width:auto; height:auto; aspect-ratio:4 / 3; }
/* The add tile sits in the flow with them rather than after them. */
.desk-row .desk-empty { min-height:0; aspect-ratio:4 / 3; flex-direction:column;
  justify-content:center; gap:2px; padding:6px; }
.desk-row .desk-empty .desk-empty-sub { display:none; }

/* THE PAGE USES THE SCREEN. `.launcher-inner` was capped at 1440px, so anything
   wider than that got margins instead of content - on a 2560px monitor roughly
   a third of the width was doing nothing.

   Still capped, because a cap is doing real work: the station tiles are a
   `repeat(auto-fill, minmax(290px, 1fr))` grid, so an uncapped page keeps
   adding columns until the bridge reads as a spreadsheet, and prose lines get
   too long to track back to the left edge. 1800px is wide enough for six tile
   columns and the full personal panel. */
.launcher-inner { max-width:1800px; }

/* The scoped section lives in the head's left column, beside the personal
   panel rather than below it. Dropped underneath, the left column ran out of
   content long before the panel ran out of height, and the gap between the
   welcome line and the fleet was most of the screen. Same content, the column
   it belongs in. */
.bridge-head-text .fleet-block:first-of-type { margin-top:6px; }
.bridge-head-text .fleet-block { margin-top:14px; }
.bridge-head-text .cc-foot { margin-top:14px; }

/* The scoped section sits in the head's left column, beside the personal panel
   rather than below it. Dropped underneath, the left column ran out of content
   long before the panel ran out of height, so most of the screen between the
   welcome line and the fleet was empty. Same content, the column it belongs
   in - the third time this exact gap has been closed, which is the argument
   for the head being a real two-column layout rather than a row with a widget
   parked on the end. */
.bridge-head-text .fleet-block { margin-top:14px; }
.bridge-head-text .fleet-block:first-of-type { margin-top:8px; }
.bridge-head-text .cc-foot { margin-top:14px; }

/* A ship card is a SUMMARY of that ship, so its numbers are labelled stats you
   can compare down a column - not a run-on sentence you have to parse. */
.fleet-flags .ship-metrics { display:flex; gap:22px; margin-left:auto;
  align-items:baseline; }
.ship-metrics .sm { display:flex; flex-direction:column; align-items:flex-end;
  line-height:1.15; }
.ship-metrics .sm b { font-size:15px; color:var(--n800); }
.ship-metrics .sm i { font-style:normal; font-size:10.5px; color:var(--n500); }
.ship-metrics .sm.warn b { color:var(--warn); }
.ship-metrics .sm.stop b { color:var(--danger, #b4232a); }

/* The stations say which book they act on. The same tile means two different
   things depending on scope, and somebody who cannot tell which works the
   wrong book. */
.stations-key { margin-top:var(--s5); }

/* A ship card is a SUMMARY of that ship, so its numbers are labelled stats you
   can compare down a column - not a run-on sentence you have to parse. */
.fleet-flags .ship-metrics { display:flex; gap:22px; margin-left:auto;
  align-items:baseline; }
.ship-metrics .sm { display:flex; flex-direction:column; align-items:flex-end;
  line-height:1.15; }
.ship-metrics .sm b { font-size:15px; color:var(--n800); }
.ship-metrics .sm i { font-style:normal; font-size:10.5px; color:var(--n500); }
.ship-metrics .sm.warn b { color:var(--warn); }
.ship-metrics .sm.stop b { color:var(--danger, #b4232a); }

/* The stations say which book they act on. The same tile means two different
   things depending on scope, and somebody who cannot tell which works the
   wrong book. */
.stations-key { margin-top:var(--s5); }

/* ==== uniform ship cards ==================================================

   ONE SHAPE FOR EVERY SHIP. Boarded ships were full-width rows and empty ones
   were chips; a ship changed shape the day it boarded, and the eye had to
   learn two renderings of one thing. Same card now, zeros where there is
   nothing yet, three across so a card is roughly a third of the width the row
   used to take. */
/* AS MANY CARDS AS THE ROW HAS ROOM FOR (Chris, 2026-08-14: "seems like room
   for a few cards"). auto-fill against a minimum instead of a fixed three, so
   a wide monitor seats four and a narrow window seats two - the fixed count
   was stretching each card to a third of whatever the screen happened to be,
   which is the same mistake as the full-width rows, one division later. */
.fleet-flags { display:grid;
  grid-template-columns:repeat(auto-fill, minmax(330px, 1fr));
  gap:var(--s3); align-items:stretch; }
.fleet-flags .flag.ship-tile {
  display:flex; flex-direction:column; align-items:stretch; gap:6px;
  padding:12px 13px 11px; height:100%;
}
.ship-head { display:flex; align-items:center; gap:8px; }
.ship-head .flag-logo { width:86px; height:26px; margin-right:auto; }
.ship-name { font-weight:600; font-size:14px; color:var(--n900);
  display:flex; align-items:center; gap:7px; flex-wrap:wrap; }
.ship-sub { font-size:11.5px; color:var(--n500); }

/* The four numbers, two by two, so every card is the same height whatever the
   values are. */
.fleet-flags .ship-metrics { display:grid; grid-template-columns:1fr 1fr;
  gap:6px 12px; margin:4px 0 0; padding-top:9px;
  border-top:1px solid var(--n200); }
.fleet-flags .ship-metrics .sm { flex-direction:row; align-items:baseline;
  gap:5px; justify-content:flex-start; }
.fleet-flags .ship-metrics .sm b { font-size:14px; }
.fleet-flags .ship-metrics .sm i { font-size:10.5px; }

/* A ship with nothing on it is present and quiet, not absent. */
.ship-quiet { opacity:.72; }
.ship-quiet:hover { opacity:1; }

/* The scope picker in the topbar. */
.ship-pick { font:inherit; font-size:12.5px; padding:5px 9px; max-width:230px; }

/* No breakpoint needed: auto-fill reflows on its own. */

/* EVERY CARD THE SAME HEIGHT, across rows as well as within them. `stretch`
   equalises cards inside a row; grid rows still size to their own content, so
   the row holding a private-label note stood taller than the rest. Chris asked
   for one size regardless of the values, and a row that grows because one card
   has an extra line is the same defect as a card that does. */
.fleet-flags { grid-auto-rows:1fr; }
/* The numbers sit at the foot of the card whatever is above them. */
.fleet-flags .ship-tile .ship-metrics { margin-top:auto; }

/* A station that has nothing to act on here. Marked, not hidden: the mapping
   is a judgement, and a wrong guess that HIDES leaves a crew unable to
   discover the station exists, while a wrong guess that GREYS is a bug
   somebody reports in a day. It also does not open - a greyed control that
   still opens is the same lie in a different colour. */
.module-tile.not-on-book { opacity:.45; cursor:default; }
.module-tile.not-on-book:hover { border-color:var(--n200); box-shadow:none;
  transform:none; }

/* ==== the satellite scene =================================================

   In the open space between the fleet head's text and the personal panel
   (Chris, 2026-08-14: "put the satellite to the right open space and make it
   much bigger"). Its own flex column, in the flow, so it can never overlap a
   card - and pointer-events off, because decoration must not eat a click. */
.sat-scene-slot { flex:none; width:400px; align-self:flex-start;
  margin-top:-26px; pointer-events:none; }
.sat-scene { overflow:visible; display:block; }
@media (max-width:1500px) { .sat-scene-slot { display:none; } }

/* Three orbits, three speeds - low and fast to high and slow, so the motions
   never read as one rigid object. Paths are inline on each satellite, built
   from the same string as its ring; only timing lives here. */
.sat-scene .sat-body { offset-rotate:0deg; }
.sat-scene .sat-body[data-orbit="a"] { animation:sat-orbit 26s linear infinite; }
.sat-scene .sat-body[data-orbit="b"] { animation:sat-orbit 44s linear infinite;
  animation-delay:-18s; }
.sat-scene .sat-body[data-orbit="c"] { animation:sat-orbit 60s linear infinite;
  animation-delay:-31s; }
.sat-scene .sat-beacon { animation:sat-blink 2.4s steps(1) infinite; }
@keyframes sat-blink { 0%, 72% { opacity:1; } 73%, 100% { opacity:.15; } }
@media (prefers-reduced-motion: reduce) {
  .sat-scene .sat-body { animation:none; }
  .sat-scene .sat-body[data-orbit="a"] { offset-distance:12%; }
  .sat-scene .sat-body[data-orbit="b"] { offset-distance:46%; }
  .sat-scene .sat-body[data-orbit="c"] { offset-distance:78%; }
  .sat-scene .sat-beacon { animation:none; }
}

/* ==== scene v2 placement ==================================================

   FLOATED OVER THE EMPTY CORNER, not a column. v1 gave the scene its own flex
   column, which taxed the whole head to pay for decoration - the personal
   panel got squeezed and Chris said so. Absolute now, in the text column's
   coordinate space, behind its own content, pointer-events off: decoration
   gets space that was already empty or it gets nothing. */
.bridge-head-text { position:relative; }
.sat-scene-slot { position:absolute; top:-56px; right:118px; width:268px;
  z-index:0; pointer-events:none; }
/* The head's prose keeps out from under the globe. */
.bridge-head-text > h1, .bridge-head-text > p.sr-sub { max-width:860px; }
@media (max-width:1360px) { .sat-scene-slot { display:none; } }

/* ON THIS DAY: four quiet lines under the headlines. The year is the anchor
   the eye scans by, so it gets the weight and a fixed column. */
.desk-otd .rail-k { display:block; margin-bottom:6px; }
.otd-row { display:flex; gap:8px; padding:4px 0; font-size:12px;
  line-height:1.4; color:var(--n700); }
.otd-row + .otd-row { border-top:1px solid var(--n100); }
.otd-row b { flex:none; width:34px; color:var(--n800); font-size:12px; }
.otd-row i { font-style:normal; color:var(--n500); }

/* ==== the ship's mast (ship-scope counterpart of the satellites) ==========

   The radar reads as rotating because an open-array bar seen side-on
   foreshortens as it turns: scaleX about the mast line. The strobe is a
   masthead light, not a beacon - one long flash, a pause. */
.mast-scene { overflow:visible; display:block; }
.mast-scene .mast-radar { transform-origin:200px 89px;
  animation:mast-sweep 6s ease-in-out infinite; }
@keyframes mast-sweep {
  0% { transform:scaleX(1); } 25% { transform:scaleX(.12); }
  50% { transform:scaleX(-1); } 75% { transform:scaleX(-.12); }
  100% { transform:scaleX(1); }
}
.mast-scene .mast-strobe { animation:mast-flash 3s steps(1) infinite; }
@keyframes mast-flash { 0%, 8% { opacity:1; } 9%, 100% { opacity:.25; } }
.mast-scene .mast-pennant { transform-origin:246px 133px;
  animation:mast-flutter 2.6s ease-in-out infinite; }
@keyframes mast-flutter { 0%, 100% { transform:skewY(0deg); }
  50% { transform:skewY(-4deg); } }
@media (prefers-reduced-motion: reduce) {
  .mast-scene .mast-radar, .mast-scene .mast-strobe,
  .mast-scene .mast-pennant { animation:none; }
}

/* ==== client pickers on the user form =====================================

   Checkboxes rather than a native multi-select: All / None / some in one
   glance, and a typo is impossible - a typo in an ALLOW list is an outage for
   that person, in a DENY list an exposure. While ALL is on, the individual
   boxes are moot and look it. */
.mp .mp-links { display:flex; align-items:center; gap:10px; font-size:11.5px;
  margin:3px 0 5px; }
.mp .mp-links a { color:var(--p500); text-decoration:none; }
.mp .mp-links a:hover { text-decoration:underline; }
.mp-master { display:inline-flex; align-items:center; gap:5px; font-weight:600;
  color:var(--n800); }
.mp-sum { margin-left:auto; color:var(--n500); font-size:11px;
  border:1px solid var(--n200); border-radius:999px; padding:1px 8px; }
/* ONE COLUMN, FIXED HEIGHT (Chris, 2026-08-16: "clean elegant tight,
   symmetric"). Two columns wrapped every long client name onto three ragged
   lines, and content-sized boxes left allowed and denied at different
   heights - the fixed height is what makes the pairs read as pairs. */
.mp-opts { border:1px solid var(--n200); border-radius:6px; padding:4px;
  height:126px; overflow-y:auto; display:flex; flex-direction:column;
  gap:1px; background:var(--n0); }
.mp-opt { display:flex; align-items:center; gap:8px; font-size:12.5px;
  color:var(--n700); text-align:left; line-height:1.3; padding:3px 7px;
  border-radius:5px; flex:none; }
.mp-opt:hover { background:var(--n100); }
/* width:auto is load-bearing: the global input{width:100%} stretches each
   checkbox to the full row, which renders the box glyph centred and shoves
   the label past the right edge - the original "ragged" look. */
.mp-opt input, .mp .mp-links input { flex:none; width:auto; }
.mp-opts.mp-moot { opacity:.45; }
.mp-help { margin-top:4px; }

/* Skill chips: one click adds or removes; the input stays the record. */
.skill-chips { display:flex; gap:6px; margin-top:5px; flex-wrap:wrap; }
.chip { font-size:11px; padding:2px 9px; border-radius:999px; cursor:pointer;
  border:1px solid var(--n200); background:var(--n50); color:var(--n700); }
.chip:hover { border-color:var(--p500); color:var(--p500); }

/* ==== the desk drawer and the sign-in card ================================ */

/* The desk, following the user: a right-hand drawer above any station. */
.desk-drawer { position:fixed; top:56px; right:0; bottom:0; width:388px;
  z-index:60; background:var(--n50); border-left:1px solid var(--n200);
  border-top:2px solid #C9992E; box-shadow:-6px 0 22px rgba(0,0,0,.28);
  overflow-y:auto; padding:14px; }
.desk-drawer .bridge-personal { width:auto; border:0; box-shadow:none;
  padding:0; background:none; }

/* The sign-in card leads with our own mark, brass-topped like the personal
   panel, with both operating identities on white plates beneath it. */
.login-card { border-top:2px solid #C9992E; }
.login-lockup { display:block; height:58px; width:auto; margin:2px auto 12px; }
.login-idents { display:flex; gap:8px; justify-content:center; margin:0 0 6px; }
.login-ident { width:104px; height:30px; background:#fff; border-radius:6px;
  padding:4px 8px; display:flex; align-items:center; justify-content:center; }
.login-ident img { max-width:100%; max-height:100%; width:auto; height:auto; }

/* Settings: sections in a popover, so the next setting slots in without a
   redesign. The themes stack two across. */
.settings-wrap .guides-menu { min-width:230px; }
.settings-sec { padding:4px 2px; }
.settings-sec .rail-k { display:block; margin-bottom:7px; }
.settings-themes { display:flex; gap:9px; padding-top:2px; }
/* A theme swatch is the theme's own colours: page below, border above. The
   selected one wears a ring; .sw.sel outweighs .theme-btn.sel so the ring
   never paints over the colours it is meant to show. */
.theme-btn.sw { width:26px; height:26px; border-radius:50%; padding:0;
  border:1px solid var(--n300); cursor:pointer;
  background:linear-gradient(135deg, var(--sw2) 0 50%, var(--sw1) 50% 100%); }
.theme-btn.sw.sel { border-color:var(--p500);
  background:linear-gradient(135deg, var(--sw2) 0 50%, var(--sw1) 50% 100%);
  box-shadow:0 0 0 2px var(--n0), 0 0 0 4px var(--p500); }
#settings-btn { font-size:15px; line-height:1; }

/* ==== the bridge wallpaper =================================================

   The mast, full height and faint behind the whole bridge (Chris: "subtle
   behind everything... like wallpaper"). Absolute inside the launcher, no
   pointer events, and faded toward the content side so text never fights it.
   The station cards and panels carry their own backgrounds and simply sit on
   top; only the open canvas shows it. */
.launcher-inner { position:relative; }
.bridge-wallpaper { position:absolute; inset:0; overflow:hidden;
  pointer-events:none; z-index:0; opacity:.09; }
.bridge-wallpaper svg { position:absolute; right:-40px; top:0;
  height:100%; width:auto; }
.bridge-wallpaper .mast-scene {
  -webkit-mask-image:linear-gradient(to left, #000 55%, transparent 96%);
  mask-image:linear-gradient(to left, #000 55%, transparent 96%);
}
/* Everything else in the launcher stacks above the paper. */
.launcher-inner > *:not(.bridge-wallpaper) { position:relative; z-index:1; }

/* A settings item: its own label under the category, so a category can hold
   several without them blurring together. */
.settings-item-k { display:block; font-size:12px; color:var(--n700);
  margin-bottom:5px; }
.settings-sec + .settings-sec { border-top:1px solid var(--n200);
  margin-top:8px; padding-top:8px; }

/* The watch card and stations live in the head's left column now, beside the
   personal rail rather than below it. */
.bridge-head-text .watch-card { margin-top:14px; }

/* The info dot and its popover: the fleet caption, on demand instead of on a
   loop. */
.info-dot { border:0; background:none; color:#C9992E; cursor:pointer;
  padding:0; margin-left:6px; display:inline-flex; vertical-align:-2px; }
.info-dot:hover { color:#E2BE5C; }
.flag-text { position:relative; }
.info-pop { position:absolute; top:calc(100% + 8px); left:0; z-index:40;
  max-width:460px; padding:10px 13px; font-size:12.5px; line-height:1.5;
  color:var(--n700); background:var(--n0); border:1px solid var(--n200);
  border-top:2px solid #C9992E; border-radius:var(--radius);
  box-shadow:var(--shadow); }

/* The persona drawer inside VIEW AS: clients and skills under a disclosure,
   because the one-in-ten preview that needs them should not tax the nine
   that only need the role. */
.viewas-more { font-size:12px; }
.viewas-more summary { cursor:pointer; color:var(--p500); }
.viewas-panel { display:flex; gap:26px; padding:10px 2px 4px; flex-wrap:wrap; }
.viewas-clients { display:grid; grid-template-columns:1fr 1fr; gap:2px 14px; }
.viewas-clients .settings-item-k, .viewas-clients .sr-sub { grid-column:1 / -1; }
.viewas-skills input { font:inherit; font-size:12px; padding:4px 8px;
  border:1px solid var(--n200); border-radius:5px; min-width:190px; }

/* ==== the ship workspace ================================================== */
.sb-open { cursor:pointer; border-radius:5px; padding:1px 5px; margin:-1px -5px; }
.sb-open:hover { background:var(--n100); }
.sb-open:focus-visible { outline:2px solid #C9992E; outline-offset:1px; }
.book-grid { display:grid; grid-template-columns:1fr 1fr; gap:var(--s4);
  align-items:start; }
.book-card { background:var(--n0); border:1px solid var(--n200);
  border-radius:var(--radius); padding:12px 14px; }
.book-card .rail-k { display:block; margin:10px 0 7px; }
.book-card .rail-k:first-child { margin-top:0; }
.book-row { display:flex; justify-content:space-between; gap:14px;
  padding:4px 0; font-size:13px; border-bottom:1px solid var(--n100); }
.book-row:last-of-type { border-bottom:0; }
.book-note { padding:7px 0; border-bottom:1px solid var(--n100);
  font-size:13px; line-height:1.45; }
.book-note-form { display:flex; flex-direction:column; gap:7px; margin-bottom:8px; }
.book-note-form select, .book-note-form textarea { font:inherit; font-size:12.5px;
  padding:6px 9px; border:1px solid var(--n200); border-radius:6px; }
.book-note-form .btn { align-self:flex-start; }
.lh-bal.warn b, .lh-bal.warn { color:var(--warn); }
@media (max-width:1100px) { .book-grid { grid-template-columns:1fr; } }

/* The workspace header's right column: each figure with its label beside it,
   not fused to it. */
.lh-right { display:flex; flex-direction:column; gap:3px; align-items:flex-end; }
.lh-right .lh-bal { font-size:13px; }
.lh-right .lh-bal b { font-size:17px; }
.lh-right .lh-bal span { margin-left:7px; color:var(--n500); font-size:11.5px; }

/* The crew card: label column, answers left-aligned beside it. Breadth
   summarises, narrowness enumerates - long lists fold to their count and
   open on tap; the wall of twenty station names was one fact made
   unreadable. */
.crew-card .crew-head { display:flex; align-items:center; gap:8px;
  margin-bottom:6px; font-size:14px; }
.crew-card .crew-row { display:grid; grid-template-columns:78px 1fr;
  gap:2px 12px; padding:2px 0; font-size:13px; align-items:baseline; }
.crew-card .crew-row > span { color:var(--n500); }
.crew-card .crew-list summary { cursor:pointer; color:var(--p500);
  list-style-position:outside; }
.crew-card .crew-list div { color:var(--n700); font-size:12.5px;
  padding:3px 0 2px; line-height:1.5; }
.crew-card > .sr-sub { display:block; margin-top:8px; }

/* A preview-locked control: visible, dimmed, dead. Hiding it would show a
   tidier console than the previewed person really has. */
.preview-dim { opacity:.45; pointer-events:none; }

/* Insights: the ask row and the report table. */
.ins-ask { display:flex; gap:8px; margin-top:4px; }
.ins-ask input { flex:1; }
.ins-report { width:100%; max-width:520px; margin-top:4px; }
.ins-report td { padding:3px 8px 3px 0; font-size:13px; }

/* The editor's info popovers anchor to their own field, not the page. */
.user-edit .uf, .user-active { position:relative; }
.user-active .info-dot { vertical-align:-3px; }

/* A popover speaks in sentences even when its anchor label is uppercase. */
.info-pop { text-transform:none; letter-spacing:normal; font-weight:400; }

/* The workspace wrap-up: the demo's segment controls, on the real book. */
.book-wrap .wu-seg { margin:6px 0; }
.bw-ptp { display:flex; gap:8px; }
.bw-ptp input { max-width:170px; }

/* Section headings inside the search dropdown: the real book leads, the
   practice book follows under its own name. */
.sr-head { font-size:10.5px; letter-spacing:.08em; color:var(--n500);
  padding:7px 12px 3px; font-weight:700; }

/* The dedicated/pooled split inside a fleet block. */
.fleet-group-key { margin:10px 2px 4px; }
.fleet-flags + .fleet-group-key, .fleet-flags + .row-key { margin-top:14px; }

/* TOUCH SCROLL STAYS IN THE MODAL (Chris, 2026-08-16: scrolling the user box
   moved the page behind it). Three parts: the card contains its own
   overscroll so reaching its end does not chain to the page; the dim overlay
   contains too; and the body locks while any modal is open. */
.users-card, .login-card { overscroll-behavior:contain; }
.modal-dim { overscroll-behavior:contain; }
body.modal-open { overflow:hidden; }


/* The create form: fields scroll, the Create button stays put. */
#user-create { display:flex; flex-direction:column; min-height:0; }
#user-create.hidden { display:none; }
.nu-fields { overflow-y:auto; min-height:0; overscroll-behavior:contain;
  padding-right:2px; }

/* The email domain chip: type the name, @rtresolutions.com rides along. */
.email-split { display:flex; }
.email-split input { flex:1; min-width:0;
  border-top-right-radius:0; border-bottom-right-radius:0; }
.dom-chip { display:inline-flex; align-items:center; gap:7px; padding:0 10px;
  border:1px solid var(--n200); border-left:0; border-radius:0 6px 6px 0;
  background:var(--n100); color:var(--n700); font-size:13px;
  white-space:nowrap; }
.dom-chip button { border:0; background:none; color:var(--n500);
  cursor:pointer; font-size:12px; padding:2px; }
.dom-chip button:hover { color:var(--danger); }

/* The bankruptcy station: worklist rows and the chapter rules. */
.bk-row { cursor:pointer; }
.bk-row:hover { background:var(--n100); }
.bk-chapters { display:grid; grid-template-columns:1fr 1fr; gap:10px 18px;
  font-size:13px; line-height:1.5; margin:6px 0 8px; }
@media (max-width:720px) { .bk-chapters { grid-template-columns:1fr; } }

/* ==== THE PHONE (Chris, 2026-08-20: the mobile pass) =======================

   The page used to pin its viewport at 1200px, so a phone rendered the
   desktop layout shrunk to 40% - five-pixel text, two columns, miniature
   tables. The viewport now follows the device, and below this width every
   layout takes its phone shape. THE RULE OF THE PASS: nothing scrolls
   sideways. A screen that does has failed, and the suite measures it. */
@media (max-width: 640px) {
  /* The desktop floor comes off. body carries min-width:1100px so a narrow
     desktop window never collapses the two-column bridge; on a phone that
     same floor is the entire problem - it was the last thing holding the
     layout at 1100px after the viewport was freed. */
  body { min-width:0; }

  /* The topbar: controls wrap, the search drops to its own full row, and the
     status chips (build, mock, user) step aside - a phone topbar carries
     controls, not status. */
  .topbar { flex-wrap:wrap; height:auto; min-height:52px; padding:8px 10px; gap:6px 8px; }
  .brand { font-size:14px; }
  .search-wrap { order:10; flex:1 1 100%; max-width:none; min-width:0; }
  .topbar-right { margin-left:auto; gap:6px; flex-wrap:wrap; justify-content:flex-end; }
  .topbar-right .btn { padding:5px 9px; font-size:12px; }
  .mock-badge, #build-chip, .user-chip, .auth-note { display:none; }
  .ship-pick { max-width:44vw; }
  .search-results { min-width:0; left:0; right:0; }
  .guides-menu { max-width:94vw; }

  /* The bridge: one column. The personal rail follows the stations instead
     of standing beside them; the scenes that decorate a wide bridge go. */
  .bridge-head { flex-direction:column; align-items:stretch; }
  .bridge-personal { width:auto !important; }
  .launcher-inner { padding:0 10px; }
  .launcher-grid { grid-template-columns:1fr; }
  .fleet-flags { grid-template-columns:1fr !important; }
  .sat-scene-slot, .bridge-wallpaper { display:none; }
  .launcher h1 { font-size:22px; }
  .ship-book-rows { gap:6px 10px; }

  /* Accounts and stations: stacked headers, a tab bar that scrolls in place,
     tables that scroll inside their own frame. */
  .practice-inner { padding:0 10px; }
  .loan-header { padding:8px 10px 0; }
  .lh-right { align-items:flex-start; }
  .tabbar { overflow-x:auto; padding:0 10px; -webkit-overflow-scrolling:touch; }
  .tabbar .tab { white-space:nowrap; }
  .book-grid { grid-template-columns:1fr; }
  .comp-strip, .compliance-strip, .lh-id { flex-wrap:wrap; }
  table.data { display:block; max-width:100%; overflow-x:auto; }
  .lgr-bal { flex-wrap:wrap; }
  .lgr-cell { flex:1 1 45%; }
  .pm-funnel, .pm-commit, .watch-head { flex-wrap:wrap; }
  .bk-row, .book-row { flex-wrap:wrap; }

  /* Modals and drawers take the whole screen - a card with margins on a
     phone is a card that scrolls in two directions. */
  .users-card, .login-card { width:100vw; max-width:100vw; max-height:100vh;
    border-radius:0; }
  .desk-drawer { width:100vw; top:0; }
  .settings-themes { flex-wrap:wrap; }
  .crew-card .crew-row { grid-template-columns:72px 1fr; }
  .viewas-panel, .nu-fields { max-width:100%; }
  .email-split input { min-width:0; }
}


/* The foreclosure station: the stage board and its rows. */
.fc-board { display:grid; grid-template-columns:repeat(auto-fill, minmax(300px, 1fr));
  gap:12px; margin-bottom:12px; }
.fc-stage .rail-k { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.fc-await { margin:-2px 0 6px; }
.fc-row { cursor:pointer; }
.fc-row:hover { background:var(--n100); }
@media (max-width:640px) { .fc-board { grid-template-columns:1fr; } }

/* The investor station: the fund strip, the ageing buckets, the package lists. */
.inv-strip { margin:6px 0 8px; flex-wrap:wrap; }
.inv-strip .lgr-v { font-size:18px; white-space:nowrap; }
.inv-sub { font-size:11px; color:var(--n600); margin-top:2px; white-space:nowrap; }
/* LIVE wears the same box as MOCK DATA and SANDBOX, in the colour of a fact. */
.live-badge { font-size:10.5px; font-weight:700; letter-spacing:.8px;
  color:var(--ok); border:1px solid var(--ok); border-radius:4px; padding:2px 7px; }
.inv-buckets { display:flex; gap:6px; flex-wrap:wrap; margin:0 0 10px; }
.inv-cohorts { margin-top:4px; }
.inv-actions { display:flex; gap:8px; flex-wrap:wrap; margin:6px 0 8px; }
.inv-pkg { display:grid; grid-template-columns:1fr 1fr; gap:14px; margin:6px 0 8px; }
.inv-pkg ul { margin:4px 0 0 18px; padding:0; }
.inv-pkg li { margin:2px 0; }
@media (max-width:640px) { .inv-pkg { grid-template-columns:1fr; } }

/* The contract registry: a calm chain, a two-way pull, quiet terms. */
/* The selection: one tile per client, the same identity language. */
.ct-pickgrid { display:grid; grid-template-columns:repeat(auto-fill,minmax(300px,1fr));
  gap:10px; margin-top:10px; }
.ct-pick { display:flex; gap:12px; align-items:center; text-align:left;
  padding:14px 16px; background:var(--n0); border:1px solid var(--n200);
  border-radius:var(--radius); cursor:pointer; font-family:inherit; }
.ct-pick:hover { border-color:var(--ok); }
.ct-pick-ident { min-width:0; }
.ct-pick-name { display:block; font-size:15px; font-weight:700; color:var(--n900); }
.ct-pick-regime { display:block; font-size:12px; color:var(--n600); margin-top:2px; }
.ct-pick-meta { display:block; font-size:11px; color:var(--n500); margin-top:4px; }
.ct-back { margin-bottom:10px; }

/* The client header: plate + name + regime, provenance as a dot chip. */
.ct-client-head { display:grid; grid-template-columns:auto 1fr auto; gap:12px;
  align-items:center; padding-bottom:12px; margin-bottom:12px;
  border-bottom:1px solid var(--n100); }
.ct-plate { width:40px; height:40px; flex:none; display:flex;
  align-items:center; justify-content:center;
  border:1px solid var(--n200); border-radius:var(--radius); background:#fff; }
.ct-plate img { max-width:28px; max-height:28px; object-fit:contain; }
.ct-plate.mono { background:var(--n100); }
.ct-monogram { font-size:12.5px; font-weight:700; letter-spacing:.5px; color:var(--n700); }
.ct-client-name { font-size:20px; font-weight:700; letter-spacing:-.01em;
  line-height:1.2; color:var(--n900); margin:0; }
.ct-regime { font-size:12.5px; font-weight:400; color:var(--n600); margin:3px 0 0; }
.ct-src { align-self:start; margin-top:4px; display:inline-flex; align-items:center;
  gap:6px; font-size:10px; font-weight:600; letter-spacing:.08em;
  text-transform:uppercase; color:var(--n600); white-space:nowrap; }
.ct-src::before { content:""; width:6px; height:6px; border-radius:50%; }
.ct-src.real::before { background:var(--ok); }
.ct-src.mock::before { background:var(--warn); }


.ct-gov { font-size:13px; color:var(--n700); margin:2px 0 10px; }
.ct-quiet { color:var(--n500); font-weight:400; font-size:12px; letter-spacing:0; text-transform:none; }
.ct-docs { display:flex; flex-direction:column; gap:6px; }
.ct-doc { display:grid; grid-template-columns:1fr auto; gap:12px; align-items:center;
  padding:10px 14px; border:1px solid var(--n200); border-radius:var(--radius);
  background:var(--n0); }
.ct-doc.governing { border-left:3px solid var(--ok); }
.ct-doc.superseded { opacity:.55; }
.ct-doc.rides { margin-left:22px; }
.ct-kind { font-size:10px; font-weight:700; letter-spacing:.8px; color:var(--n500);
  border:1px solid var(--n300); border-radius:3px; padding:1px 5px; margin-right:6px; }
.ct-meta { font-size:12px; color:var(--n600); margin-top:2px; }
.ct-entity { color:var(--warn); }
.ct-doc-side { display:flex; flex-direction:column; align-items:flex-end; gap:6px; }
.ct-governs { font-size:10.5px; font-weight:700; letter-spacing:.6px; color:var(--ok); }
.ct-pulls { display:flex; gap:6px; }
.ct-var { font-size:12px; border-radius:999px; padding:3px 12px; border:1px solid var(--n300);
  background:transparent; color:var(--n700); cursor:pointer; font-family:inherit; }
.ct-var.ready:hover { border-color:var(--ok); color:var(--ok); }
.ct-var.pending, .ct-var.locked { color:var(--n500); cursor:default; border-style:dashed; }
.ct-termlist { display:flex; flex-direction:column; }
.ct-term { display:grid; grid-template-columns:auto 1fr auto; gap:10px; align-items:baseline;
  padding:9px 4px; border-bottom:1px solid var(--n200); }
.ct-term:last-child { border-bottom:none; }
.ct-dot { width:8px; height:8px; border-radius:50%; display:inline-block; position:relative; top:-1px; }
.ct-dot.ok { background:var(--ok); } .ct-dot.warn { background:var(--warn); }
.ct-dot.info { background:var(--info); } .ct-dot.neutral { background:var(--n500); }
.ct-term-text { font-size:13.5px; }
.ct-term-sub { font-size:11.5px; color:var(--n500); margin-top:1px; }
.ct-term-status { font-size:11px; font-weight:600; white-space:nowrap; }
.ct-term-status.ok { color:var(--ok); } .ct-term-status.warn { color:var(--warn); }
.ct-term-status.info { color:var(--info); } .ct-term-status.neutral { color:var(--n500); }
@media (max-width:640px) {
  .ct-doc { grid-template-columns:1fr; }
  .ct-doc-side { flex-direction:row; align-items:center; justify-content:space-between; }
}

/* The terms, three shapes: rate-sheet wells, a ruled WHEN->THEN ledger
   behind the compliance spine, and the checklist row. One status idiom. */
.ct-groupkey { margin-top:18px; }
.ct-econ { display:grid; grid-template-columns:repeat(3,1fr); gap:10px; margin-top:10px; }
.ct-econ-card { background:var(--n50); border:1px solid var(--n200); border-radius:var(--radius);
  padding:14px 16px 10px; display:flex; flex-direction:column; gap:4px; }
.ct-econ-figrow { display:flex; align-items:baseline; min-height:28px; }
.ct-econ-fig { font-size:24px; line-height:1.1; font-weight:650; letter-spacing:-.01em;
  color:var(--n900); font-variant-numeric:tabular-nums; }
.ct-econ-fig.word { font-size:16px; font-weight:600; }
.ct-econ-unit { font-size:12px; font-weight:500; color:var(--n600); margin-left:6px; }
.ct-econ-term { font-size:12.5px; color:var(--n800); }
.ct-econ-detail { font-size:11px; color:var(--n600); font-variant-numeric:tabular-nums; margin-top:2px; }
.ct-econ-sub { font-size:11px; color:var(--n500); margin-top:2px; }
.ct-econ-status { margin-top:auto; padding-top:8px; border-top:1px solid var(--n200);
  display:flex; align-items:center; gap:6px; }
.ct-econ-status .ct-dot { width:6px; height:6px; top:0; }
.ct-rules { border-left:2px solid var(--info); padding-left:14px; margin-top:10px; }
.ct-rules-head, .ct-rule { display:grid; grid-template-columns:220px 24px 1fr auto;
  gap:10px; align-items:start; }
.ct-rules-head { padding:2px 4px 6px; }
.ct-rules-head span { font-size:9.5px; font-weight:700; letter-spacing:1px;
  text-transform:uppercase; color:var(--n500); }
.ct-rule { padding:12px 4px; border-top:1px solid var(--n200); }
.ct-rule-when { font-size:13px; font-weight:600; color:var(--n800); }
.ct-rule-arrow { font-size:14px; color:var(--n500); line-height:1.4; }
.ct-rule-ob { font-size:13.5px; color:var(--n800); }
.ct-clock { font-family:var(--mono, ui-monospace, monospace); font-size:10.5px;
  letter-spacing:.5px; color:var(--n700); background:var(--n100);
  border:1px solid var(--n200); border-radius:4px; padding:2px 7px;
  margin-left:8px; white-space:nowrap; position:relative; top:-1px; }
.ct-rule-status { display:flex; align-items:center; gap:6px; justify-content:flex-end;
  white-space:nowrap; padding-top:1px; }
.ct-sla-fig { font-weight:650; color:var(--n900); font-variant-numeric:tabular-nums; }
@media (max-width:640px) {
  .ct-econ { grid-template-columns:1fr 1fr; }
  .ct-rules-head { display:none; }
  .ct-rules-head, .ct-rule { grid-template-columns:1fr; }
  .ct-rule-arrow { display:none; }
  .ct-rule-status { justify-content:flex-start; }
}

/* The fleet folds to its header; the chevron says which way it stands. */
.fleet-head { cursor:pointer; }
.fleet-chevron { font-size:14px; color:var(--n600); margin-right:8px; }
.fleet-block.folded .fleet-body { display:none; }
