/* Aegis Command — design system (BUILD_SPEC §3)
   Register: drawing office, not SaaS startup. Enterprise gravity, zero clutter.
   The one memorable thing is the chainage line (high-vis orange critical path);
   everything else stays quiet. */

:root {
  /* Palette — dark, meaning-coded */
  --ink: #101D2E;        /* page background — deep drawing-office blue */
  --panel: #182A40;      /* cards / panels */
  --panel-2: #1F3552;    /* raised elements, table header rows */
  --grid: #24405E;       /* hairlines, gridlines, faint blueprint grid */
  --paper: #E9EEF4;      /* primary text */
  --muted: #8CA3BC;      /* secondary text, axis labels */
  --signal: #FF6A2B;     /* critical path / High risk / breaches / overruns. High-vis safety orange */
  --extreme: #D21F12;    /* Extreme risk only — deeper, hotter red than High */
  --caution: #E3A93C;    /* amber states / Medium */
  --ok: #4CB782;         /* on-track / achieved / approved */

  /* ACTION blue — the colour of things you can press. Deliberately NOT --signal: an affordance
     must not share a colour with "critical path / High risk / breach", or the interface reads as
     alarmed everywhere there is a button. --signal is now purely semantic. Verified white-on-fill
     4.55:1 here (AA) — #3B82F6 was rejected at 3.68:1. */
  --action: #2F6FED;
  --action-hover: #3D7BF7;
  --action-active: #2560D8;
  --on-action: #FFFFFF;
  --action-tint: rgba(47, 111, 237, 0.14);

  --signal-tint: rgba(255, 106, 43, 0.10);
  --extreme-tint: rgba(210, 31, 18, 0.14);
  --caution-tint: rgba(227, 169, 60, 0.12);
  --ok-tint: rgba(76, 183, 130, 0.12);
  /* WASH — for large area fills (the divergent-status band). A tint calibrated for a chip becomes
     a colour when it covers a whole strip, so large fills get their own, weaker value. */
  --signal-wash: rgba(255, 106, 43, 0.07);

  /* Structural surfaces & states (tokenised so a second theme can re-derive them) */
  --surface-header: rgba(16, 29, 46, 0.92);   /* masthead */
  --surface-nav: rgba(24, 42, 64, 0.4);       /* tab bar */
  --row-hover: rgba(31, 53, 82, 0.35);        /* table row hover */
  --well: rgba(0, 0, 0, 0.22);                /* inline code / quiet chips in Ask */
  --select-bg: rgba(255, 255, 255, 0.06);     /* selected switcher chip */
  --hairline-soft: rgba(233, 238, 245, 0.18); /* maturity chip border */
  --hairline-strong: rgba(233, 238, 245, 0.4);
  --dot-off: rgba(233, 238, 245, 0.22);       /* unlit maturity dots */
  /* Text on solid semantic fills */
  --on-signal: #14100c;
  --on-ok: #06231a;
  --on-extreme: #FFEDE9;
  /* Risk heatmap cell tints (L×C matrix) */
  /* Risk heatmap fills. These MUST step hard: the old ramp ran 0.08/0.14/0.18/0.32, so Medium and
     High sat 0.04 apart and the grid read as one pastel wash with no readable bands. Each rung is
     now clearly darker than the one below it, and every fill keeps --paper legible on top. */
  --heat-extreme: rgba(210, 31, 18, 0.58);
  --heat-high: rgba(255, 106, 43, 0.42);
  --heat-medium: rgba(227, 169, 60, 0.30);
  --heat-low: rgba(76, 183, 130, 0.18);
  /* Divider between risks sharing one cell — light on the dark ground. */
  --heat-divider: rgba(233, 238, 245, 0.45);
  /* Status-form input hairline (status.ejs uses var(--line, …) fallbacks) */
  --line: #d3dae3;
  /* Submit-status button — was a pale-green board affordance; now follows --action so every
     pressable thing in the app shares one colour. Green is freed to mean on-track only. */
  --submit-bg: var(--action); --submit-border: var(--action-active); --submit-text: var(--on-action);
  --submit-bg-hover: var(--action-hover); --submit-bg-active: var(--action-active); --submit-border-active: var(--action-active);
  /* Status-form result banners + submitting spinner (status.ejs inline styles read these) */
  --ok-panel-bg: #e7f6ec; --ok-panel-border: #9ed3b0; --ok-panel-accent: #2f855a; --ok-panel-text: #1f5c3a;
  --err-panel-bg: #fdf0e8; --err-panel-border: #e6b79a; --err-panel-accent: #c05621; --err-panel-text: #8a3b13;
  --info-panel-bg: #eef3fb; --info-panel-border: #b9cbe8; --info-panel-accent: #2b6cb0; --info-panel-text: #22436b;
  --confirm-text: #3d7355;
  /* Form fields that sit on the (light) status form — white in both themes */
  --field-bg: #ffffff; --field-text: #16222f;

  /* The REPORT SHEET. Deliberately fixed, and NOT re-declared in the light theme: this is a
     printed document, so it is light in both themes and matches what comes out of Print/PDF.
     It previously used --paper for its background and --ink for its text, which reads correctly
     in the dark theme by coincidence — those tokens mean "primary text" and "page ground", and
     they SWAP on the light theme. The sheet inverted to dark while its hardcoded body colours
     stayed dark, so the whole report went invisible on light. */
  --doc-bg: #E9EEF4;
  --doc-ink: #101D2E;

  --radius: 5px;
  --hair: 1px solid var(--grid);

  --font-display: 'Archivo', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body: 'Inter', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'Chivo Mono', 'SFMono-Regular', 'Consolas', monospace;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 400;
  color: var(--paper);
  background-color: var(--ink);
  /* Faint 8px blueprint grid across the page background */
  background-image:
    linear-gradient(var(--grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: 8px 8px;
  background-position: -1px -1px;
  /* keep the grid whisper-quiet */
  background-blend-mode: normal;
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
/* Dim the page grid so it reads as texture, not a table */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  background: var(--ink);
  opacity: 0.86;
  z-index: -1;
  pointer-events: none;
}

/* Every figure is mono — that is what makes it read as an instrument */
.mono, .fig { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* ---------- links ----------
   There was no global anchor rule, so every link without a class fell through to the browser's
   own stylesheet: default blue, and VISITED PURPLE once clicked. That is where the purple on the
   baseline chips came from — not a palette choice. Component links (.chip, .btn, nav, tabs) carry
   their own colour, so the base rule inherits and gets out of their way; a bare link in prose gets
   a quiet underline instead. Orange is reserved for the critical path and breaches — never links. */
a { color: inherit; text-decoration: none; }
a:not([class]) {
  color: var(--paper);
  text-decoration: underline;
  text-decoration-color: var(--grid);
  text-underline-offset: 3px;
}
a:not([class]):hover { text-decoration-color: var(--muted); }

/* ---------- layout ---------- */

.wrap { max-width: 1240px; margin: 0 auto; padding: 0 24px; }

header.masthead {
  border-bottom: var(--hair);
  background: var(--surface-header);
  backdrop-filter: blur(2px);
  position: sticky; top: 0; z-index: 50;
}
.masthead .wrap {
  display: flex; align-items: center; gap: 24px;
  height: 60px;
}
.wordmark {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: 0.22em;
  font-size: 18px;
  color: var(--paper);
  text-decoration: none;
  white-space: nowrap;
}
.wordmark .tick { color: var(--signal); }

/* Scrolls sideways rather than widening the page. With two projects this never mattered; at six
   the switcher was 635px inside a 347px masthead and pushed the whole document to a horizontal
   scrollbar on mobile. Same treatment nav.screens .wrap already uses, including pinning overflow-y
   shut — overflow-x:auto makes overflow-y compute to auto too, which would add a second scrollbar. */
.project-switcher {
  display: flex; gap: 6px;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.project-switcher::-webkit-scrollbar { display: none; }
.project-switcher a { flex: 0 0 auto; white-space: nowrap; }
.project-switcher a {
  font-size: 12.5px; font-weight: 500;
  color: var(--muted); text-decoration: none;
  padding: 5px 11px; border: var(--hair); border-radius: var(--radius);
  background: var(--panel);
  letter-spacing: 0.02em;
  transition: color .15s, border-color .15s;
}
.project-switcher a:hover { color: var(--paper); border-color: var(--muted); }
.project-switcher a.active { color: var(--paper); border-color: var(--action); }
.project-switcher a .code { font-family: var(--font-mono); color: var(--signal); margin-right: 6px; }

.data-badge {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 12px; color: var(--muted);
  border: var(--hair); border-radius: var(--radius);
  padding: 5px 10px; white-space: nowrap;
  background: var(--panel);
}
.data-badge b { color: var(--paper); font-weight: 500; }

/* ---------- nav (demo order) ---------- */
nav.screens { border-bottom: var(--hair); background: var(--surface-nav); }
nav.screens .wrap {
  display: flex; gap: 2px; align-items: stretch; height: 44px;
  overflow-x: auto;
  /* overflow-x:auto makes overflow-y compute to auto as well, so the horizontal scrollbar eats
     height out of this 44px box and triggers a SECOND, vertical scrollbar. Pin it shut. */
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  /* Still scrollable (the head.ejs script centres the active tab, and keyboard focus scrolls into
     view) but never paints scrollbar chrome — a slider across the tab bar reads as a broken
     layout, not an affordance. */
  scrollbar-width: none;
  -ms-overflow-style: none;
}
nav.screens .wrap::-webkit-scrollbar { display: none; }
nav.screens a {
  display: flex; align-items: center; gap: 8px; white-space: nowrap;
  /* 12px not 16px: a PG project screen carries 8 tabs + Submit status + the maturity chip, which
     overflowed 1240px even before Inter widened it. The trim buys ~70px so it doesn't scroll. */
  padding: 0 12px;
  font-size: 13px; font-weight: 500; letter-spacing: 0.03em;
  color: var(--muted); text-decoration: none;
  border-bottom: 2px solid transparent;
  transition: color .15s, border-color .15s;
}
nav.screens a .step { font-family: var(--font-mono); font-size: 11px; color: var(--grid); }
nav.screens a:hover { color: var(--paper); }
nav.screens a.active { color: var(--paper); border-bottom-color: var(--action); }
nav.screens a.active .step { color: var(--action); }
/* Status tab: its own green-bordered button, on the same plane as tabs 01–05. It must not shrink or
   wrap when the nav gets crowded on a project screen — otherwise "Submit status" breaks onto two lines
   inside the fixed-height button. */
nav.screens a.status-tab {
  align-self: center; height: 30px; margin-left: 10px; padding: 0 15px;
  border: 1px solid var(--submit-border); border-radius: 6px;
  background: var(--submit-bg); color: var(--submit-text); font-weight: 600;
  flex-shrink: 0; white-space: nowrap;
}
nav.screens a.status-tab:hover { background: var(--submit-bg-hover); color: var(--submit-text); }
nav.screens a.status-tab.active { background: var(--submit-bg-active); color: var(--submit-text); border-color: var(--submit-border-active); }

/* Controls-maturity chip: how complete this project's DATA is, so what the app shows can be
   trusted. Sits right of the tabs, quiet by default — it's orientation, not an alarm. */
nav.screens a.maturity-chip {
  align-self: center; height: 26px; margin-left: auto; padding: 0 12px;
  border: 1px solid var(--hairline-soft); border-radius: 13px;
  font-size: 12px; letter-spacing: 0.02em; gap: 8px; white-space: nowrap;
}
nav.screens a.maturity-chip:hover { border-color: var(--hairline-strong); }
nav.screens a.maturity-chip b { color: var(--paper); font-weight: 600; }
nav.screens a.maturity-chip .dots { display: inline-flex; gap: 3px; }
nav.screens a.maturity-chip .dots i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--dot-off);
}
nav.screens a.maturity-chip .dots i.on { background: var(--signal); }

/* ---------- Ask Aegis — grounded Q&A panel ---------- */
.ask-launch {
  position: fixed; right: 20px; bottom: 20px; z-index: 60;
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 16px; border-radius: 22px;
  background: var(--panel-2); color: var(--paper); border: 1px solid var(--grid); cursor: pointer;
  font-family: var(--font-body); font-size: 13px; font-weight: 600; letter-spacing: 0.02em;
  box-shadow: 0 6px 20px rgba(0,0,0,0.35);
  transition: transform .12s ease, border-color .12s ease, opacity .15s ease;
}
.ask-launch:hover { border-color: var(--signal); transform: translateY(-1px); }
.ask-launch.hidden { opacity: 0; pointer-events: none; transform: translateY(8px); }
.ask-mark { color: var(--signal); }

.ask-scrim { position: fixed; inset: 0; background: rgba(6,12,20,0.45); z-index: 65; }

.ask-panel {
  position: fixed; top: 0; right: 0; bottom: 0; z-index: 70;
  width: 400px; max-width: 92vw;
  display: flex; flex-direction: column;
  background: var(--panel); border-left: 1px solid var(--grid);
  box-shadow: -12px 0 32px rgba(0,0,0,0.4);
  transform: translateX(100%); transition: transform .22s cubic-bezier(.4,0,.2,1);
}
.ask-panel.open { transform: translateX(0); }

.ask-head { display: flex; align-items: flex-start; gap: 12px; padding: 16px 18px; border-bottom: 1px solid var(--grid); }
.ask-head > div:first-child { flex: 1; }
.ask-title { font-weight: 700; font-size: 15px; display: flex; align-items: center; gap: 7px; }
.ask-sub { margin-top: 2px; }
.ask-close { background: none; border: 0; color: var(--muted); font-size: 22px; line-height: 1; cursor: pointer; padding: 0 4px; }
.ask-close:hover { color: var(--paper); }

.ask-transcript { flex: 1; overflow-y: auto; padding: 16px 18px; display: flex; flex-direction: column; gap: 12px; }
.ask-intro { line-height: 1.55; padding: 10px 12px; border-left: 2px solid var(--grid); }

.ask-msg { max-width: 90%; font-size: 13.5px; line-height: 1.55; }
.ask-msg.user { align-self: flex-end; background: var(--signal-tint); border: 1px solid var(--grid); border-radius: 12px 12px 2px 12px; padding: 9px 12px; white-space: pre-wrap; }
.ask-msg.ai { align-self: flex-start; width: 100%; }
.ask-msg.ai .ask-text { background: var(--panel-2); border: 1px solid var(--grid); border-radius: 12px 12px 12px 2px; padding: 10px 13px; }
.ask-msg.ai .ask-text code { font-family: var(--font-mono); background: var(--well); padding: 0 4px; border-radius: 3px; font-size: 12px; }

.ask-tools { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 6px; }
.ask-chip { font-size: 11px; color: var(--muted); background: var(--well); border: 1px solid var(--grid); border-radius: 11px; padding: 2px 9px; }
.ask-degraded { font-size: 11px; margin-top: 5px; }

.ask-note { align-self: center; text-align: center; font-size: 12.5px; color: var(--muted); padding: 8px 12px; max-width: 90%; }
.ask-note.caution { color: var(--caution); }

.ask-cursor { display: inline-block; width: 7px; height: 14px; margin-left: 1px; background: var(--signal); vertical-align: text-bottom; animation: ask-blink 1s steps(2) infinite; }
@keyframes ask-blink { 50% { opacity: 0; } }

/* Arriving from the risk page's "Assign owner & mitigation →" banner: briefly ring the target section
   so it's obvious why the page scrolled here. Fades out; respects reduced-motion. */
#risk-gaps:target { border-radius: 8px; animation: gap-flash 2s ease-out 1; }
@keyframes gap-flash {
  0%   { box-shadow: 0 0 0 2px var(--signal, #c05621), 0 0 0 6px rgba(192,86,33,0.25); }
  100% { box-shadow: 0 0 0 0 rgba(192,86,33,0); }
}
/* Reduced motion: no flash, but still a static ring so the affordance isn't lost entirely. */
@media (prefers-reduced-motion: reduce) { #risk-gaps:target { animation: none; box-shadow: 0 0 0 2px var(--signal, #c05621); } }

.ask-form { display: flex; align-items: flex-end; gap: 8px; padding: 12px 14px; border-top: 1px solid var(--grid); }
.ask-input { flex: 1; resize: none; background: var(--ink); color: var(--paper); border: 1px solid var(--grid); border-radius: 8px; padding: 9px 11px; font-family: var(--font-body); font-size: 13.5px; line-height: 1.45; max-height: 120px; }
.ask-input:focus { outline: none; border-color: var(--action); }
.ask-send { flex: none; width: 36px; height: 36px; border-radius: 8px; background: var(--signal); color: #fff; border: 0; font-size: 18px; cursor: pointer; }
.ask-send:disabled { opacity: 0.5; cursor: default; }
.ask-disclaimer { padding: 0 14px 12px; }

/* Ask Aegis — proposed-change confirm card (writes: propose → confirm → apply) */
.ask-proposal { align-self: stretch; border: 1px solid var(--caution); background: var(--caution-tint); border-radius: 10px; padding: 11px 13px; }
.ask-proposal-head { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--caution); font-weight: 600; }
.ask-proposal-body { margin-top: 5px; font-size: 13px; line-height: 1.5; }
.ask-proposal-actions { display: flex; gap: 8px; margin-top: 10px; }
.ask-apply { background: var(--ok); color: #06231a; border: 0; border-radius: 7px; padding: 6px 14px; font-weight: 600; font-size: 12.5px; cursor: pointer; }
.ask-apply:disabled { opacity: 0.6; cursor: default; }
.ask-discard { background: none; border: 1px solid var(--grid); color: var(--muted); border-radius: 7px; padding: 6px 12px; font-size: 12.5px; cursor: pointer; }
.ask-discard:hover { color: var(--paper); }
.ask-proposal-note { margin-top: 8px; }
.ask-proposal.applied { border-color: var(--ok); background: var(--ok-tint); }
.ask-proposal-done { color: var(--ok); font-size: 13px; font-weight: 600; }
.ask-proposal-err { color: var(--signal); font-size: 12px; margin-top: 8px; }

@media (max-width: 480px) {
  .ask-panel { width: 100vw; max-width: 100vw; }
  .ask-launch { right: 12px; bottom: 12px; }
}

/* Stale-data banner (shown when the last sync is too old) */
.stale-banner { background: rgba(224,163,60,0.14); border-top: 1px solid rgba(224,163,60,0.5); border-bottom: 1px solid rgba(224,163,60,0.5); }
.stale-banner .wrap { display: flex; gap: 10px; align-items: center; padding: 8px 0; font-size: 12.5px; color: var(--caution); }
.stale-banner b { color: var(--paper); }

/* Baseline / Actual view swap on the schedule Gantt */
.gantt-wrap .g-base { display: none; }
.gantt-wrap.baseline .g-base { display: inline; }
.gantt-wrap.baseline .g-cur { display: none; }

/* Critical-path emphasis — an INDEPENDENT axis from the baseline/actual swap above.
   Element-qualified so it outranks the .gantt-wrap.baseline rules regardless of source order
   (both are otherwise 3 classes); bar fills are swapped in JS, not here, because the what-if
   scenario sets fill as a presentation attribute that a CSS rule would silently override. */
.gantt-wrap.nocrit g.g-chain { display: none; }

/* ---------- page scaffolding ---------- */
main { padding: 26px 0 60px; }
/* Page head — title, subtitle, as-at, and whatever action the screen puts on the right. It gets a
   surface for the same reason the toolbar does: the blueprint grid is framing, and reading text is
   never set straight onto it. Applied here rather than per-view, so all 18 screens follow. */
.page-head {
  display: flex; align-items: baseline; gap: 16px; margin-bottom: 20px;
  background: var(--panel);
  border: 1px solid var(--grid);
  border-radius: var(--radius);
  padding: 14px 18px;
}
.page-head h1 { font-family: var(--font-display); font-weight: 600; font-size: 22px; margin: 0; letter-spacing: 0.01em; }
.page-head .sub { color: var(--muted); font-size: 13px; }
.page-head .as-at { margin-left: auto; font-family: var(--font-mono); font-size: 12px; color: var(--muted); }

.section-label {
  font-size: 11px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--muted); margin: 0 0 10px;
}

/* ---------- panels / cards ---------- */
.panel {
  background: var(--panel);
  border: var(--hair);
  border-radius: var(--radius);
  padding: 18px 20px;
}
.panel.raised { background: var(--panel-2); }

/* Chainage rule: any card/row on the critical path carries the continued orange line */
.on-critical { border-left: 2px solid var(--signal); }

/* ---------- figures & tone ---------- */
.tone-signal { color: var(--signal); }
.tone-caution { color: var(--caution); }
.tone-ok { color: var(--ok); }
.tone-muted { color: var(--muted); }

/* Compare strip — every project side by side, in attention order. Fixed-width cells so the health
   dials line up on a common baseline: a row of circles at different widths is a decoration, a row
   at the same width is a comparison. Scrolls sideways rather than widening the page (overflow-y
   pinned shut, or overflow-x:auto computes overflow-y to auto and adds a second scrollbar). */
.compare-strip {
  display: flex;
  gap: 0;
  overflow-x: auto;
  overflow-y: hidden;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.compare-cell {
  flex: 0 0 152px;
  /* min-width:0 or a flex item refuses to shrink below its content: the nowrap driver chip was
     stretching cells to 246px and the columns stopped being comparable, which is the whole point. */
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 14px 10px 16px;
  border-right: 1px solid var(--grid);
  text-decoration: none;
  color: inherit;
  transition: background .15s;
}
.compare-cell:last-child { border-right: 0; }
.compare-cell:hover { background: var(--row-hover); }
/* The chip wraps inside the strip rather than setting the column width. */
.compare-cell .driver-chip { white-space: normal; line-height: 1.35; }

.compare-name {
  font-size: 11.5px;
  color: var(--muted);
  margin-top: 2px;
  /* Two lines then ellipsis: project names are long and a ragged strip is unreadable. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.3;
}

/* "Driven by" chips on the portfolio position panel — the specific figure putting a project on the
   contributor list. Built on the existing semantic tokens, so the light theme re-derives them and
   the alarm colours stay consistent with the rest of the interface. */
.driver-chip {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 3px;
  font-size: 11.5px;
  font-family: var(--font-mono, ui-monospace, monospace);
  white-space: nowrap;
  border: 1px solid transparent;
}
.driver-chip.crit { color: var(--signal); background: var(--signal-tint); border-color: var(--signal-tint); }
.driver-chip.warn { color: var(--caution); background: var(--caution-tint); border-color: var(--caution-tint); }

/* ---------- chips ---------- */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 11.5px; font-weight: 500;
  padding: 2px 8px; border-radius: var(--radius);
  border: 1px solid var(--grid);
  letter-spacing: 0.02em; white-space: nowrap;
}
.chip.signal { color: var(--signal); border-color: var(--signal); background: var(--signal-tint); }
.chip.caution { color: var(--caution); border-color: var(--caution); background: var(--caution-tint); }
.chip.ok { color: var(--ok); border-color: var(--ok); background: var(--ok-tint); }
.chip.plain { color: var(--muted); }
/* Selected state for chips used as a switcher (e.g. the baseline register's BL1/BL2). Filled and
   paper-white against .plain's muted outline, so which one you are viewing is unambiguous. */
.chip.is-selected { color: var(--paper); border-color: var(--paper); background: var(--select-bg); }
a.chip:hover { border-color: var(--muted); }
a.chip.is-selected:hover { border-color: var(--paper); }
/* Risk band chips — High is orange outline, Extreme is a solid deep-red fill (clearly hotter) */
.chip.high { color: var(--signal); border-color: var(--signal); background: var(--signal-tint); font-weight: 600; }
.chip.extreme { color: var(--on-extreme); border-color: var(--extreme); background: var(--extreme); font-weight: 600; }
.tone-extreme { color: var(--extreme); }

/* RAG pip */
.rag { display: inline-flex; align-items: center; gap: 7px; font-weight: 500; font-size: 13px; }
.rag .pip { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }
.rag.Green .pip { background: var(--ok); } .rag.Green { color: var(--ok); }
.rag.Amber .pip { background: var(--caution); } .rag.Amber { color: var(--caution); }
/* RAG Red is a RED — it was wired to --signal (the high-vis ORANGE), so a "Red"
   status never actually read red in either theme. RAG (green/amber/red) is its own
   scale, separate from the orange critical-path/breach accent. */
.rag.Red .pip { background: var(--extreme); } .rag.Red { color: var(--extreme); }

/* ---------- tables ---------- */
table.grid-table { width: 100%; border-collapse: collapse; font-size: 13px; }
table.grid-table thead th {
  background: var(--panel-2);
  text-align: left; font-weight: 600; font-size: 11px;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted);
  padding: 9px 12px; border-bottom: var(--hair); white-space: nowrap;
}
table.grid-table tbody td { padding: 9px 12px; border-bottom: var(--hair); vertical-align: top; }
table.grid-table tbody tr:hover { background: var(--row-hover); }
table.grid-table td.num { font-family: var(--font-mono); text-align: right; font-variant-numeric: tabular-nums; }
table.grid-table thead th.num { text-align: right; }
table.grid-table td.code { font-family: var(--font-mono); color: var(--muted); }

/* ---------- buttons ---------- */
.btn {
  font-family: var(--font-body); font-weight: 500; font-size: 13px;
  color: var(--paper); background: var(--panel-2);
  border: 1px solid var(--grid); border-radius: var(--radius);
  padding: 9px 16px; cursor: pointer; letter-spacing: 0.02em;
  transition: border-color .15s, background .15s;
}
.btn:hover { border-color: var(--muted); }
.btn.primary { background: var(--action); border-color: var(--action); color: var(--on-action); font-weight: 600; }
.btn.primary:hover { background: var(--action-hover); border-color: var(--action-hover); }
.btn.primary:active { background: var(--action-active); border-color: var(--action-active); }
/* Focus follows the action colour too — a focus ring is an affordance, not an alarm. */
.btn:focus-visible, a:focus-visible, .toggle:focus-visible { outline: 2px solid var(--action); outline-offset: 2px; }

/* ---------- toggle switch ---------- */
.switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; user-select: none; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch .track {
  width: 42px; height: 22px; border-radius: 12px;
  background: var(--panel-2); border: 1px solid var(--grid);
  position: relative; transition: background .2s, border-color .2s;
}
.switch .track::after {
  content: ''; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--muted); transition: transform .2s, background .2s;
}
.switch input:checked + .track { background: var(--signal-tint); border-color: var(--signal); }
.switch input:checked + .track::after { transform: translateX(20px); background: var(--signal); }
.switch input:focus-visible + .track { outline: 2px solid var(--action); outline-offset: 2px; }

/* ---------- footer ---------- */
footer.foot {
  border-top: var(--hair); margin-top: 40px;
  color: var(--muted); font-size: 12px;
}
footer.foot .wrap { display: flex; align-items: center; gap: 12px; height: 48px; }
footer.foot .pos { letter-spacing: 0.02em; }
footer.foot .pos .tick { color: var(--signal); }

/* ---------- reveal (one page-load reveal max) ---------- */
@media (prefers-reduced-motion: no-preference) {
  .reveal { opacity: 0; transform: translateY(8px); animation: reveal .5s ease forwards; }
  .reveal:nth-child(2) { animation-delay: .07s; }
  .reveal:nth-child(3) { animation-delay: .14s; }
  @keyframes reveal { to { opacity: 1; transform: none; } }
}

/* ---------- utility ---------- */
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
.grid-2-1 { display: grid; grid-template-columns: 2fr 1fr; gap: 18px; }
.stack > * + * { margin-top: 18px; }
.row { display: flex; gap: 14px; align-items: center; }
.row.wrap { flex-wrap: wrap; }
.spacer { flex: 1; }
.small { font-size: 12px; }
.muted { color: var(--muted); }
hr.hair { border: 0; border-top: var(--hair); margin: 16px 0; }

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

/* ---------- Risk heatmap (L×C) ----------
   A cell holding more than one risk is DIVIDED, one segment per risk — two risks split it in
   half, three into thirds, four into quarters. Before this they were crammed side by side inside
   a single box, so a cell with two risks looked like a cell with one long label and the count
   had to be read rather than seen. Five or more falls back to a 2-column grid: past four the
   segments are too small to letter, and the honest read is "this cell is crowded". */
.heat-cell {
  aspect-ratio: 1;
  border: 1px solid var(--grid);
  border-radius: 3px;
  display: grid;
  overflow: hidden;              /* keeps segment dividers inside the rounded corners */
  background: var(--heat-low);
}
.heat-cell.heat-medium  { background: var(--heat-medium); }
.heat-cell.heat-high    { background: var(--heat-high); }
.heat-cell.heat-extreme { background: var(--heat-extreme); }
/* An occupied cell gets its band's full-strength edge, so it reads before you find the code. */
.heat-cell.occupied              { border-color: var(--ok); }
.heat-cell.occupied.heat-medium  { border-color: var(--caution); }
.heat-cell.occupied.heat-high    { border-color: var(--signal); }
.heat-cell.occupied.heat-extreme { border-color: var(--extreme); }

.heat-cell.n1    { grid-template-columns: 1fr; }
.heat-cell.n2    { grid-template-columns: repeat(2, 1fr); }
.heat-cell.n3    { grid-template-columns: repeat(3, 1fr); }
.heat-cell.n4    { grid-template-columns: repeat(2, 1fr); grid-template-rows: repeat(2, 1fr); }
.heat-cell.nmany { grid-template-columns: repeat(2, 1fr); }

.heat-seg { display: flex; align-items: center; justify-content: center; min-width: 0; padding: 1px; }
.heat-seg + .heat-seg { border-left: 1px solid var(--heat-divider); }
/* Quarters: the third segment starts a new row, so it takes a top rule and drops the left one. */
.heat-cell.n4 .heat-seg:nth-child(n + 3) { border-top: 1px solid var(--heat-divider); }
.heat-cell.n4 .heat-seg:nth-child(3)     { border-left: 0; }
.heat-cell.nmany .heat-seg:nth-child(odd) { border-left: 0; }
.heat-cell.nmany .heat-seg:nth-child(n + 3) { border-top: 1px solid var(--heat-divider); }

.heat-code {
  font-family: var(--font-mono); font-size: 9.5px; font-weight: 700;
  color: var(--paper); letter-spacing: -0.02em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- Aegis assessment (structured, dot-point) ----------
   Ruled like a control register: every section is a row with real cell borders, and the label
   column is divided from its findings. The borders are the point — without them the four sections
   ran together as one grey wall and nothing could be scanned. All from --grid, so light mode
   re-derives with no overrides. */
.assessment { display: grid; gap: 12px; }
.assessment.ruled {
  gap: 0;
  border: 1px solid var(--grid);
  border-radius: var(--radius);
  overflow: hidden;              /* keeps the row rules inside the rounded corners */
  background: var(--panel);
}
.assessment .a-sec { display: grid; grid-template-columns: 150px 1fr; gap: 12px; align-items: start; }
/* Wider than the unruled default: the icon takes 8px + 16px out of the label column, and the
   longest label ("Reported Status vs Actual Status") wrapped to three lines without this. */
.assessment.ruled .a-sec { gap: 0; border-bottom: 1px solid var(--grid); grid-template-columns: 178px 1fr; }
.assessment.ruled .a-sec:last-child { border-bottom: 0; }
.assessment.ruled .a-h { border-right: 1px solid var(--grid); padding: 12px 12px 12px 14px; }
.assessment.ruled ul { padding: 12px 16px; }
.assessment .a-h {
  font-size: 10.5px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--muted); padding-top: 1px;
  display: flex; gap: 8px; align-items: flex-start;
}
/* Nudge the glyph onto the cap-height of the first line of the label */
.assessment .a-h .icon { flex: none; margin-top: -1px; opacity: 0.85; }
.assessment ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 4px; }
.assessment li { position: relative; padding-left: 14px; font-size: 12.5px; line-height: 1.45; color: var(--paper); }
.assessment li::before { content: ''; position: absolute; left: 2px; top: 7px; width: 4px; height: 4px; border-radius: 50%; background: var(--muted); }
.assessment li.on-critical { color: var(--paper); }
.assessment li.on-critical::before { background: var(--signal); }
@media (max-width: 560px) {
  .assessment .a-sec { grid-template-columns: 1fr; gap: 3px; }
  /* Stacked: the divider has to become horizontal or it cuts the row in half */
  .assessment.ruled .a-sec { gap: 0; }
  .assessment.ruled .a-h { border-right: 0; border-bottom: 1px solid var(--grid); padding: 10px 14px; }
  .assessment.ruled ul { padding: 10px 14px; }
}

/* Section label with a leading glyph (Aegis assessment, Top exposures) */
.section-label.with-icon { display: flex; align-items: center; gap: 8px; }
.section-label.with-icon .icon { flex: none; opacity: 0.9; }

/* ---------- Top exposures (typed) — corporate, calm ---------- */
.exp { display: grid; gap: 8px; }
.exp-row { display: flex; gap: 13px; align-items: flex-start; padding: 11px 0; border-top: 1px solid var(--grid); }
.exp-row:first-child { border-top: 0; }
.exp-code {
  font-family: var(--font-mono); font-size: 11px; font-weight: 500; color: var(--muted);
  border: 1px solid var(--grid); background: var(--panel-2);
  padding: 3px 9px; border-radius: var(--radius); white-space: nowrap;
}
.exp-body { flex: 1; min-width: 0; }
.exp-title { font-size: 13.5px; font-weight: 500; }
.exp-meta { font-size: 12px; color: var(--muted); margin-top: 3px; line-height: 1.45; }
.exp-fig { text-align: right; white-space: nowrap; }
.exp-fig .ef { font-family: var(--font-mono); font-size: 13px; color: var(--paper); }
.exp-fig .efl { font-size: 11px; color: var(--muted); margin-left: 3px; }
/* corporate, not cyberpunk: exposure chips use the display face, sentence case */
.exp .chip { font-family: var(--font-body); letter-spacing: 0.01em; font-weight: 600; }

/* ---------- Gantt (SVG) ---------- */
.gantt-wrap { border: var(--hair); border-radius: var(--radius); overflow: hidden; background: var(--panel); }
.gantt-svg { display: block; width: 100%; height: auto; }
.gantt-svg text { font-family: var(--font-mono); }
.g-month { font-size: 10px; letter-spacing: 0.04em; }
.g-wbs { font-size: 10px; }
.g-name { font-family: var(--font-body) !important; font-size: 11.5px; font-weight: 500; }
.g-float { font-size: 10.5px; }
.g-colhead { font-size: 9.5px; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; }
.g-rule-lbl { font-size: 9px; letter-spacing: 0.08em; }

.g-rule-data { stroke: var(--paper); stroke-width: 1; stroke-dasharray: 3 3; opacity: 0.65; }
.g-rule-data-lbl { fill: var(--paper); opacity: 0.8; }
.g-rule-contract { stroke: var(--signal); stroke-width: 1.5; }
.g-rule-contract-lbl { fill: var(--signal); }
.g-rule-scenario { stroke: var(--signal); stroke-width: 1.5; stroke-dasharray: 4 3; }
.g-rule-scenario-lbl { fill: var(--signal); }

/* bars transition their geometry for the what-if swap (Chromium animates x/width) */
.g-bar { transition: x .38s cubic-bezier(.4,0,.2,1), width .38s cubic-bezier(.4,0,.2,1), fill .38s; }

/* delta chip lands last */
.delta-chip {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--font-mono); font-weight: 600; font-size: 14px;
  color: var(--signal); border: 1.5px solid var(--signal); background: var(--signal-tint);
  padding: 8px 14px; border-radius: var(--radius);
  opacity: 0; transform: translateY(6px) scale(.98);
}
.delta-chip.show { animation: chipland .4s ease .34s forwards; }
@keyframes chipland { to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .g-bar { transition: none; }
  .delta-chip.show { animation: none; opacity: 1; transform: none; }
}

/* callout / scenario panel */
.callout {
  border-left: 2px solid var(--signal); background: var(--signal-tint);
  padding: 14px 16px; border-radius: 0 var(--radius) var(--radius) 0;
}
/* A standalone explanatory note between panels (e.g. the working-calendar line on Schedule).
   Same rule as the toolbar: prose gets a surface, never the bare grid. */
.note-bar {
  background: var(--panel);
  border: 1px solid var(--grid);
  border-radius: var(--radius);
  padding: 10px 14px;
  line-height: 1.6;
}

/* Screen toolbar — switches, baseline chips and the legend. It sits between the page head and the
   first panel, which used to mean small 11–12px text sitting straight on the blueprint grid. The
   grid is framing; reading text always gets a solid surface, so the bar carries its own. */
.toolbar {
  background: var(--panel);
  border: 1px solid var(--grid);
  border-radius: var(--radius);
  padding: 12px 16px;
}
.legend { display: flex; gap: 18px; flex-wrap: wrap; font-size: 11.5px; color: var(--muted); }
.legend .k { display: inline-flex; align-items: center; gap: 6px; }
.legend .sw { width: 18px; height: 6px; border-radius: 2px; display: inline-block; }

/* ---------- EVM S-curve ---------- */
.evm-wrap { border: var(--hair); border-radius: var(--radius); overflow: hidden; background: var(--panel); }
.evm-svg { display: block; width: 100%; height: auto; font-family: var(--font-mono); }
.c-axis { font-size: 10px; }
.c-lbl { font-size: 10px; letter-spacing: 0.04em; }

/* KPI row */
.kpi-row { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; background: var(--grid); border: var(--hair); border-radius: var(--radius); overflow: hidden; }
.kpi { background: var(--panel); padding: 12px 14px; }
.kpi .k { font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--muted); }
.kpi .v { font-family: var(--font-mono); font-size: 18px; margin-top: 4px; font-variant-numeric: tabular-nums; }
@media (max-width: 900px) { .kpi-row { grid-template-columns: repeat(3, 1fr); } }

/* ---------- Status report (screen flips to light — the board artefact) ---------- */
/* The status form's task tables sit straight on the page, not inside a panel, so they need their
   own surface — three of them in status.ejs, hence a rule rather than a class on each. */
.status-grid {
  background: var(--panel);
  border: 1px solid var(--grid);
  border-radius: var(--radius);
}

/* Same surface rule as .toolbar — the badges and captions beside these buttons are reading text. */
.report-controls {
  display: flex; align-items: center; gap: 16px; margin-bottom: 18px;
  background: var(--panel); border: 1px solid var(--grid); border-radius: var(--radius);
  padding: 12px 16px; flex-wrap: wrap;
}
.gen-caption { font-family: var(--font-mono); font-size: 11.5px; color: var(--muted); line-height: 1.5; }

.paper {
  background: var(--doc-bg); color: var(--doc-ink);
  border-radius: var(--radius); border: 1px solid #c7d0dc;
  max-width: 840px; margin: 0 auto; padding: 48px 56px 40px;
  box-shadow: 0 8px 40px rgba(0,0,0,0.35);
  min-height: 300px;
}
.paper .p-head { display: flex; align-items: flex-start; border-bottom: 2px solid var(--doc-ink); padding-bottom: 14px; margin-bottom: 8px; }
.paper .p-wordmark { font-weight: 600; letter-spacing: 0.2em; font-size: 15px; color: var(--doc-ink); }
.paper .p-wordmark .tick { color: var(--signal); }
.paper .p-meta { margin-left: auto; text-align: right; font-family: var(--font-mono); font-size: 11px; color: #4a5b70; line-height: 1.6; }
.paper .p-body { font-size: 14px; line-height: 1.62; color: #16222f; }
.paper .p-body h1 { font-size: 21px; font-weight: 600; margin: 18px 0 6px; color: var(--doc-ink); }
.paper .p-body h2 { font-size: 14px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: #33475f; margin: 22px 0 6px; padding-bottom: 4px; border-bottom: 1px solid #c7d0dc; }
.paper .p-body p { margin: 8px 0; }
.paper .p-body ol { margin: 8px 0; padding-left: 22px; }
.paper .p-body li { margin: 5px 0; }
.paper .p-body strong { color: var(--doc-ink); }
.paper .p-body .fig, .paper .p-body code { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
/* Markdown tables in the report (e.g. the Risk register) — clean printed-document look. */
.paper .p-body .report-table { width: 100%; border-collapse: collapse; margin: 10px 0 16px; font-size: 12.5px; }
.paper .p-body .report-table th { text-align: left; font-weight: 600; color: #33475f; border-bottom: 1.5px solid #c7d0dc; padding: 6px 12px 6px 0; white-space: nowrap; }
.paper .p-body .report-table td { padding: 6px 12px 6px 0; border-bottom: 1px solid #e6ebf1; vertical-align: top; color: #16222f; }
.paper .p-body .report-table tbody tr:last-child td { border-bottom: none; }
.paper .p-foot { margin-top: 28px; border-top: 1px solid #c7d0dc; padding-top: 12px; font-size: 11px; color: #4a5b70; line-height: 1.6; }
.paper .p-foot .tick { color: var(--signal); }
.paper .cursor { display: inline-block; width: 7px; height: 15px; background: var(--signal); vertical-align: text-bottom; animation: blink 1s steps(2) infinite; }
@keyframes blink { 50% { opacity: 0; } }
.src-badge { font-family: var(--font-mono); font-size: 11px; padding: 3px 9px; border-radius: var(--radius); border: 1px solid var(--grid); color: var(--muted); }

/* ---------- Mobile pass (phones / small tablets) ---------- */
@media (max-width: 720px) {
  .wrap { padding: 0 14px; }
  .masthead .wrap { flex-wrap: wrap; height: auto; padding-top: 8px; padding-bottom: 8px; gap: 8px 12px; }
  .project-switcher { order: 3; width: 100%; }
  nav.screens .wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  nav.screens a { white-space: nowrap; padding: 0 12px; }
  nav.screens a.status-tab { margin-left: 6px; }
  .page-head { flex-wrap: wrap; gap: 4px 12px; }
  .page-head .as-at { margin-left: 0; }
  .kpi-row { grid-template-columns: repeat(2, 1fr) !important; }
  .report-controls { flex-wrap: wrap; gap: 8px; }
  .report-controls .spacer { display: none; }
  /* Gantt / charts: scroll horizontally rather than shrink to illegibility */
  .gantt-wrap, .evm-wrap, .scroll-x, #res-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .gantt-wrap svg { min-width: 820px; }
  .evm-wrap svg, .trend-svg { min-width: 620px; }
  .res-svg { min-width: 680px; }
  /* Wide data tables scroll within their panel instead of off the screen */
  table.grid-table { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  footer.foot .wrap { flex-wrap: wrap; height: auto; padding: 8px 0; }
}

/* Status form: stack each task into a card on narrow screens (the one screen that must
   work on a phone). */
@media (max-width: 640px) {
  .status-grid, .status-grid tbody, .status-grid tr, .status-grid td { display: block; width: 100%; }
  .status-grid thead { display: none; }
  .status-grid tr { border: 1px solid var(--line, #d3dae3); border-radius: 8px; margin-bottom: 10px; padding: 6px 8px; }
  .status-grid td { padding: 5px 4px; border: none; }
  .status-grid td::before { content: attr(data-label); display: block; font-size: 10px; text-transform: uppercase; letter-spacing: .05em; color: #4a5b70; margin-bottom: 2px; }
  .inp-wrap { width: 100%; }
  .inp-wrap input { width: 100%; }
}

/* Styled chart tooltips (replace native SVG <title>) */
.c-tooltip {
  position: fixed; z-index: 9999; display: none; max-width: 280px;
  background: var(--panel-2); color: var(--paper);
  border: 1px solid var(--grid); border-radius: 6px; padding: 7px 10px;
  font-size: 12px; line-height: 1.45; white-space: pre-line;
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.45); pointer-events: none;
}

/* Portfolio card internals — stop fixed-width blocks overflowing on phones */
@media (max-width: 560px) {
  .rag-pair { flex-wrap: wrap; gap: 14px !important; }
  .rag-pair .spacer { display: none; }
  .assess-gap { max-width: none !important; text-align: left !important; width: 100%; }
  .exp-row { flex-wrap: wrap; gap: 6px 10px; }
  .exp-fig { text-align: left; white-space: normal; }
  /* KPI band: health dial full-width, then CPI/SPI + completion side by side */
  .card-kpi { grid-template-columns: 1fr 1fr !important; }
  .card-kpi > :first-child { grid-column: 1 / -1; border-right: 0 !important; border-bottom: 1px solid var(--grid); }
}

/* Print: only the paper, on white */
@media print {
  body { background: #fff !important; color: #000; }
  body::before { display: none; }
  header.masthead, nav.screens, footer.foot, .report-controls, .no-print { display: none !important; }
  main { padding: 0; }
  .wrap { max-width: none; padding: 0; }
  .paper { box-shadow: none; border: none; max-width: none; margin: 0; padding: 0.5in 0.6in; border-radius: 0; }
  .paper .cursor { display: none; }
  @page { margin: 1cm; }
}

/* ---- Consolidated user menu (masthead, top-right; auth mode) ----
   Replaces the old theme-toggle + Team/Account/Log-out cluster with one dropdown
   off the user chip. Token-driven, so it themes light/dark for free. */
.usermenu { position: relative; }
.user-chip {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  background: var(--panel); border: var(--hair); border-radius: var(--radius);
  padding: 5px 10px 5px 6px; color: var(--paper); font: inherit; font-size: 12.5px;
  transition: border-color .15s;
}
.user-chip:hover, .user-chip[aria-expanded="true"] { border-color: var(--signal); }
.u-av {
  border-radius: 50%; flex: none; background: var(--signal-tint);
  border: 1px solid var(--signal); color: var(--signal);
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-weight: 600;
}
.user-chip .u-av { width: 22px; height: 22px; font-size: 11px; }
.user-chip .u-nm { font-weight: 500; max-width: 130px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-chip .u-car { color: var(--muted); font-size: 10px; transition: transform .15s; }
.user-chip[aria-expanded="true"] .u-car { transform: rotate(180deg); }

.user-menu {
  position: absolute; top: calc(100% + 8px); right: 0; width: 266px;
  background: var(--panel); border: var(--hair); border-radius: 8px;
  box-shadow: 0 16px 44px rgba(0, 0, 0, 0.42); overflow: hidden; z-index: 80;
  opacity: 0; transform: translateY(-6px); pointer-events: none;
  transition: opacity .14s, transform .14s;
}
:root[data-theme="light"] .user-menu { box-shadow: 0 16px 44px rgba(20, 40, 70, 0.2); }
.user-menu.open { opacity: 1; transform: none; pointer-events: auto; }

.um-id { display: flex; gap: 11px; align-items: center; padding: 13px 14px; border-bottom: var(--hair); }
.um-id .u-av { width: 32px; height: 32px; font-size: 13px; }
.um-id b { display: block; font-size: 13.5px; font-weight: 600; }
.um-id .u-sub { font-size: 11.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 190px; }

.um-grp { padding: 7px 0; border-bottom: var(--hair); }
.um-grp:last-child { border-bottom: 0; }
.um-h { font-size: 10px; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted); padding: 3px 14px 6px; }

.um-item {
  display: flex; align-items: center; gap: 11px; width: 100%; text-align: left;
  background: none; border: 0; cursor: pointer; font: inherit; font-size: 13px;
  color: var(--paper); padding: 7px 14px; text-decoration: none;
}
.um-item:hover { background: var(--row-hover); }
.um-item .um-ic { width: 16px; text-align: center; color: var(--muted); font-size: 13px; flex: none; }
.um-item .um-sp { flex: 1; }
.um-item.danger { color: var(--extreme); }
.um-item.danger .um-ic { color: var(--extreme); }
.um-ctx {
  font-family: var(--font-mono); font-size: 10px; color: var(--signal);
  background: var(--signal-tint); border: 1px solid var(--signal); border-radius: 4px; padding: 1px 5px;
}

.um-seg-row { padding: 0 14px 8px; }
.um-seg { display: flex; gap: 2px; background: var(--panel-2); border: var(--hair); border-radius: 7px; padding: 2px; }
.um-seg button { flex: 1; background: none; border: 0; cursor: pointer; font: inherit; font-size: 11.5px; color: var(--muted); padding: 5px 4px; border-radius: 5px; }
.um-seg button.on { background: var(--action-tint); color: var(--action); border: 1px solid var(--action); padding: 4px 3px; font-weight: 600; }

/* ---- Session control (masthead) + login page ---- */
.session { display: flex; align-items: center; gap: 10px; }
.session .who { font-size: 12px; color: var(--muted); white-space: nowrap; }
.session .logout {
  font-family: var(--font-mono); font-size: 11.5px; letter-spacing: 0.03em;
  color: var(--muted); background: var(--panel); border: var(--hair);
  border-radius: var(--radius); padding: 5px 11px; cursor: pointer;
  transition: color .15s, border-color .15s;
}
.session .logout:hover { color: var(--paper); border-color: var(--signal); }

.login-body { display: flex; min-height: 100vh; }
.login-body::before { opacity: 0.5; } /* keep the blueprint grid, softer */
.login-wrap {
  margin: auto; width: 100%; max-width: 380px; padding: 24px;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
}
.login-card {
  width: 100%; background: var(--panel); border: var(--hair);
  border-radius: 10px; padding: 30px 28px 26px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.35);
}
.login-card .wordmark { display: block; font-size: 19px; }
.login-tag { color: var(--muted); font-size: 12px; margin: 8px 0 22px; }
.login-error {
  background: var(--signal-tint); border: 1px solid var(--signal);
  color: var(--paper); font-size: 12.5px; border-radius: var(--radius);
  padding: 8px 11px; margin-bottom: 16px;
}
/* The plan a buyer picked on the pricing page, restated on the signup card. Its job is to let them
   confirm they are about to be charged the amount they chose, before they type anything — so it is
   a quiet statement of fact, not a second offer. */
.login-plan {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  background: var(--panel-2); border: 1px solid var(--grid);
  border-left: 3px solid var(--signal);
  border-radius: var(--radius); padding: 10px 12px; margin-bottom: 14px;
}
.login-plan-tier { font-size: 12.5px; color: var(--paper); font-weight: 500; }
.login-plan-price { font-family: var(--font-mono); font-size: 14px; color: var(--paper); }
.login-plan-price .muted { font-size: 11px; }

.login-field { display: block; margin-bottom: 14px; }
.login-field span { display: block; font-size: 12px; color: var(--muted); margin-bottom: 5px; }
.login-field input {
  width: 100%; box-sizing: border-box; font-size: 14px; font-family: inherit;
  color: var(--paper); background: var(--panel-2); border: var(--hair);
  border-radius: var(--radius); padding: 10px 12px; outline: none;
  transition: border-color .15s;
}
.login-field input:focus { border-color: var(--action); }
.login-btn {
  width: 100%; margin-top: 6px; font-family: var(--font-body); font-weight: 600;
  letter-spacing: 0.04em; font-size: 14px; color: var(--on-signal); background: var(--signal);
  border: none; border-radius: var(--radius); padding: 11px; cursor: pointer;
  transition: filter .15s;
}
.login-btn:hover { filter: brightness(1.08); }
.login-foot { font-size: 11px; }

/* Password Show/Hide — the wrapper and button are injected by /js/pwtoggle.js, so nothing here
   applies until that script runs. Padding on the input keeps typed text clear of the control. */
.pw-wrap { position: relative; display: block; }
.pw-wrap input { padding-right: 60px; }
.pw-toggle {
  position: absolute; top: 50%; right: 5px; transform: translateY(-50%);
  font-family: var(--font-body); font-size: 10.5px; font-weight: 600;
  letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted); background: transparent; border: none;
  border-radius: var(--radius); padding: 6px 8px; cursor: pointer;
  transition: color .15s;
}
.pw-toggle:hover { color: var(--paper); }
.pw-toggle:focus-visible { outline: 2px solid var(--action); outline-offset: 1px; color: var(--paper); }

/* Threshold meter (Portfolio settings) — a share of the book against the line that judges it.
   The track is the whole portfolio, the fill is the share assessed at that severity, and the
   marker is the threshold. Reading "22% of value is Red, the line is at 20%" off a number takes
   a moment; seeing the fill past the marker takes none. Everything derives from tokens, so the
   light theme's darker RAG trio applies without a second rule. */
.thmeter { display: block; }
.thmeter .th-track {
  position: relative; height: 26px; border-radius: var(--radius);
  background: var(--panel-2); border: var(--hair); overflow: hidden;
}
.thmeter .th-fill { position: absolute; inset: 0 auto 0 0; transition: width .18s; }
.thmeter .th-fill.red { background: var(--extreme); }
.thmeter .th-fill.amber { background: var(--caution); }
/* The marker sits ON the track, above the fill, and carries a light/dark-proof outline so it
   stays visible whether the fill has reached it or not. */
.thmeter .th-mark {
  position: absolute; top: -3px; bottom: -3px; width: 2px; margin-left: -1px;
  background: var(--paper); box-shadow: 0 0 0 1px var(--ink);
}
.thmeter .th-scale {
  position: relative; height: 15px; margin-top: 3px;
  font-size: 10.5px; color: var(--muted); font-family: var(--font-mono);
}
/* Nudged back by half its own width where there is room, so the label reads as centred on the
   marker instead of hanging off the right edge at 100%. */
.thmeter .th-scale span { position: absolute; top: 0; transform: translateX(-50%); white-space: nowrap; }
.thmeter .th-scale span.at-end { transform: translateX(-100%); }
.thmeter .th-scale span.at-start { transform: none; }

/* Saved → proposed. Two positions on the same projects, so a threshold change is chosen against
   its consequence rather than in the abstract. */
.th-compare { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; }
.th-compare .th-arrow { font-size: 20px; color: var(--muted); }

/* =====================================================================
   LIGHT THEME — "the drawing office, lights on": ink on vellum, not an
   inversion. Opt-in only via [data-theme="light"] on <html> (the demo and
   default stay dark regardless of OS). Everything re-derives from tokens;
   the ONE exception is the semantic RAG trio — high-vis orange, amber and
   green can't survive as text on white, so they are re-derived DARKER here,
   not reused. The .paper report artefact is already light and unchanged.
   ===================================================================== */
:root[data-theme="light"] {
  /* Surfaces — cool blue-grey vellum, white cards */
  --ink: #E9EEF5;        /* page ground */
  --panel: #FFFFFF;      /* cards / panels */
  --panel-2: #E4EAF2;    /* raised elements, table header rows */
  --grid: #CBD6E3;       /* hairlines, blueprint grid */
  --paper: #16222F;      /* primary text (the report ink) */
  --muted: #5A6A7E;      /* secondary text — ~5:1 on white */

  /* Semantic colours for a light ground. The first pass over-corrected into
     earth tones (olive / ochre / burnt); these are re-saturated to read as
     vivid orange / amber / red while staying legible on white (~3.5–5.5:1). */
  --signal: #D6480F;     /* critical / High / breach — vivid burnt orange */
  --extreme: #CE1A10;    /* Extreme + RAG Red — a true red, not ochre */
  --caution: #C2790A;    /* amber / Medium — bright amber-gold, not olive */
  --ok: #1E7A4B;         /* on-track / achieved — forest green */

  /* Tints stay alpha-based (they wash correctly over the light ground). */
  --signal-tint: rgba(214, 72, 15, 0.10);
  --extreme-tint: rgba(206, 26, 16, 0.10);
  --caution-tint: rgba(194, 121, 10, 0.13);
  --ok-tint: rgba(30, 122, 75, 0.12);
  /* On white, 10% burnt orange over a whole strip reads as pink. The wash drops it to a warm
     off-white that still says "something differs here" without colouring the card. */
  --signal-wash: rgba(214, 72, 15, 0.05);

  /* Same stepped ramp on the light ground — the previous values ran 0.12/0.16/0.15/0.20, where
     High was actually PALER than Medium, so the two bands were indistinguishable. */
  --heat-extreme: rgba(206, 26, 16, 0.62);
  --heat-high: rgba(214, 72, 15, 0.46);
  --heat-medium: rgba(194, 121, 10, 0.34);
  --heat-low: rgba(30, 122, 75, 0.20);
  /* Divider between risks sharing one cell — dark on the light ground. */
  --heat-divider: rgba(20, 40, 70, 0.40);

  /* Text on solid semantic fills — near-white now the fills are dark */
  --on-signal: #FFFFFF;
  --on-ok: #FFFFFF;
  --on-extreme: #FFF3F1;

  /* Structural surfaces & states — dark washes on a light ground */
  --surface-header: rgba(233, 238, 245, 0.9);
  --surface-nav: rgba(228, 234, 242, 0.7);
  --row-hover: rgba(20, 40, 70, 0.05);
  --well: rgba(20, 40, 70, 0.07);
  --select-bg: rgba(20, 40, 70, 0.06);
  --hairline-soft: rgba(20, 40, 70, 0.16);
  --hairline-strong: rgba(20, 40, 70, 0.34);
  --dot-off: rgba(20, 40, 70, 0.18);

  /* ACTION blue on a light ground — darker than the dark theme's so it holds on white.
     White-on-fill 6.70:1 (AA for all sizes); against the page ground 5.75:1. */
  --action: #1D4ED8;
  --action-hover: #1A45BE;
  --action-active: #163BA4;
  --on-action: #FFFFFF;
  --action-tint: rgba(29, 78, 216, 0.12);

  /* Submit is an action, so it follows --action rather than keeping its own green. */
  --submit-bg: var(--action); --submit-border: var(--action-active); --submit-text: var(--on-action);
  --submit-bg-hover: var(--action-hover); --submit-bg-active: var(--action-active); --submit-border-active: var(--action-active);

  color-scheme: light;
}

/* The nav step-numbers (01/02/…) are drawn in --grid — a hairline colour that vanishes on the
   light nav. Lift them to muted so they stay quiet but legible; the active step stays --action. */
:root[data-theme="light"] nav.screens a .step { color: var(--muted); }

/* Soften the big drop-shadows for the light ground (the dark values read as smudges on white) */
:root[data-theme="light"] .paper { box-shadow: 0 6px 28px rgba(20, 40, 70, 0.16); }
:root[data-theme="light"] .login-card { box-shadow: 0 14px 40px rgba(20, 40, 70, 0.16); }
:root[data-theme="light"] .ask-panel { box-shadow: -12px 0 32px rgba(20, 40, 70, 0.18); }
:root[data-theme="light"] .ask-launch { box-shadow: 0 6px 20px rgba(20, 40, 70, 0.18); }
:root[data-theme="light"] .c-tooltip { box-shadow: 0 6px 22px rgba(20, 40, 70, 0.22); }

/* --- Theme toggle control (masthead) --- */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; padding: 0; cursor: pointer;
  color: var(--muted); background: var(--panel); border: var(--hair);
  border-radius: var(--radius); font-size: 14px; line-height: 1;
  transition: color .15s, border-color .15s;
}
.theme-toggle:hover { color: var(--paper); border-color: var(--signal); }
.theme-toggle .i-sun { display: none; }
.theme-toggle .i-moon { display: inline; }
:root[data-theme="light"] .theme-toggle .i-sun { display: inline; }
:root[data-theme="light"] .theme-toggle .i-moon { display: none; }
