/* ============================================================
   MCEL JSA — Visual System
   Morgan brand: white paper, black ink, ONE red. Square corners
   everywhere. Hierarchy from weight/size, not hue — depth from
   hairline borders, never shadows or gradients.
   ============================================================ */

:root {
  /* ===== Morgan brand tokens (source: morgan-brand skill) ===== */
  --morgan-red: #E6281A;
  --morgan-black: #000000;
  --morgan-gray-dark: #4F4F4F;
  --morgan-gray-mid: #979797;
  --morgan-gray-light: #E5E5E5;

  /* Primary / action — Morgan Red. Buttons, active tab/nav, focus rings,
     progress fill: the "do this now" / "current" role per the brand's
     button and tab idioms. Press states darken, they never brighten. */
  --accent: var(--morgan-red);
  --accent-700: #b81f14;
  --accent-100: color-mix(in srgb, var(--morgan-red) 12%, #fff);
  --accent-050: color-mix(in srgb, var(--morgan-red) 6%, #fff);

  /* Risk semantics — functional only, always paired with icon/text/label,
     never color alone. High reuses Morgan Red (a hazard is legitimately
     "do this now"); Low/Med are the brand's approved amber/emerald. */
  --risk-low: #047857;
  --risk-low-bg: color-mix(in srgb, var(--risk-low) 13%, #fff);
  --risk-med: #b45309;
  --risk-med-bg: color-mix(in srgb, var(--risk-med) 14%, #fff);
  --risk-high: var(--morgan-red);
  --risk-high-bg: color-mix(in srgb, var(--risk-high) 11%, #fff);

  /* Ink + surfaces — Morgan black/grays. Four steps kept (brand defines
     two grays) so dense dashboard tables keep a legible hierarchy; -3/-4
     are tints of the one approved gray-mid, not new hues. */
  --ink: var(--morgan-black);
  --ink-2: var(--morgan-gray-dark);
  --ink-3: var(--morgan-gray-mid);
  --ink-4: color-mix(in srgb, var(--morgan-gray-mid) 70%, #fff);
  --line: var(--morgan-gray-light);
  --line-2: color-mix(in srgb, var(--morgan-gray-light) 55%, #fff);
  --surface: #ffffff;
  --surface-2: color-mix(in srgb, var(--morgan-gray-light) 40%, #fff);
  --canvas: color-mix(in srgb, var(--morgan-gray-light) 55%, #fff);

  /* Status (aliases of the tokens above, kept for call-site clarity) */
  --ok: var(--risk-low);
  --warn: var(--risk-med);
  --danger: var(--morgan-red);

  /* Zero border-radius on containers — cards, chips, buttons, inputs, tags.
     Kept as variables (not a blanket reset) so any element that legitimately
     needs to stay round — a spinner, a circular avatar — can say so explicitly
     instead of fighting a global override. */
  --radius: 0;
  --radius-sm: 0;
  --radius-lg: 0;

  /* No decorative shadows — depth is a hairline border. Kept as variables
     (rather than deleted) so nothing that references them breaks; they all
     resolve to none. */
  --shadow-sm: none;
  --shadow-md: none;
  --shadow-lg: none;

  /* Roboto (headings, bold), Montserrat (body). No separate mono face in the
     brand kit — Roboto Mono is kept only for genuinely tabular data (ids,
     dates, counters), consistent with the brand's tabular-nums guidance. */
  --font-display: "Roboto", system-ui, sans-serif;
  --font-sans: "Montserrat", system-ui, sans-serif;
  --font-mono: "Roboto Mono", ui-monospace, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  font-family: var(--font-sans);
  color: var(--ink);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button { font-family: inherit; cursor: pointer; }
input, textarea, select { font-family: inherit; }

/* ------------------------------------------------------------------------
   Below this line: an older build-free "phone / tablet mockup" harness
   (.stage, .phone*, .device-switch, .role-switch, .netbanner, .ai-*, the
   modal .scrim/.sheet, .prog/.field/.toggle/.check) — no currently-loaded
   screen (index.html) references any of these classNames or the Toggle/
   Check components ui.jsx still exports. It predates the native Expo app
   (see apps/mobile/) and is dead weight, not part of the shipped Admin
   Dashboard. Left in place (removing dead CSS is a separate cleanup, not
   a visual refactor) — the token rewrite above still cascades into it via
   var(), it is just not hand-polished shape-by-shape below.
   ------------------------------------------------------------------------ */

/* Stage holding the device/browser frames */
.stage {
  min-height: 100vh;
  width: 100%;
  background: var(--canvas);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 26px 16px 80px;
}

/* Switcher row (device + role pills) */
.switch-row { display: flex; align-items: center; gap: 10px; margin-bottom: 24px; flex: none; }
.switch-row .role-switch { margin-bottom: 0; }

/* Device switcher (links between phone / tablet versions) */
.device-switch {
  display: inline-flex;
  background: var(--surface);
  border: 1px solid var(--line);
  padding: 4px;
  gap: 2px;
}
.device-switch a, .device-switch button {
  border: 0;
  background: transparent;
  cursor: pointer;
  text-decoration: none;
  color: var(--ink-3);
  font-weight: 600;
  font-size: 13.5px;
  font-family: var(--font-sans);
  letter-spacing: .01em;
  padding: 9px 18px;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  transition: all .16s ease;
}
.device-switch a:hover, .device-switch button:hover { color: var(--ink); }
.device-switch a.on, .device-switch button.on {
  background: var(--ink);
  color: #fff;
}

/* Role switcher */
.role-switch {
  display: inline-flex;
  background: var(--surface);
  border: 1px solid var(--line);
  padding: 4px;
  gap: 2px;
  margin-bottom: 24px;
}
.role-switch button {
  border: 0;
  background: transparent;
  color: var(--ink-3);
  font-weight: 600;
  font-size: 13.5px;
  letter-spacing: .01em;
  padding: 9px 18px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition: all .16s ease;
}
.role-switch button.on {
  background: var(--ink);
  color: #fff;
}
.role-switch button .dot {
  width: 6px; height: 6px;
  background: currentColor; opacity: .55;
}

/* ---------- Phone frame ---------- */
.phone {
  width: 412px;
  height: 868px;
  background: #0c1116;
  padding: 13px;
  position: relative;
  flex: none;
}
.phone-screen {
  width: 100%;
  height: 100%;
  background: var(--surface-2);
  overflow: hidden;
  position: relative;
  display: flex;
  flex-direction: column;
}
.phone-notch {
  position: absolute;
  top: 13px; left: 50%; transform: translateX(-50%);
  width: 122px; height: 30px;
  background: #0c1116;
  z-index: 60;
}
.phone-toast {
  position: absolute; left: 50%; bottom: 30px; transform: translateX(-50%);
  z-index: 80; background: var(--ink); color: #fff;
  padding: 12px 16px; font-size: 13px; font-weight: 600;
  display: flex; align-items: center; gap: 9px; max-width: 80%;
  animation: phoneToastIn .26s ease;
}
@keyframes phoneToastIn { from { opacity: 0; transform: translate(-50%, 10px); } to { opacity: 1; transform: translate(-50%, 0); } }
.statusbar {
  flex: none;
  height: 50px;
  padding: 14px 30px 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 14px;
  color: var(--ink);
  background: var(--surface-2);
  z-index: 50;
}
.statusbar .sb-icons { display: flex; gap: 7px; align-items: center; }

/* Scroll region inside phone */
.screen-scroll {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}
.screen-scroll::-webkit-scrollbar { width: 0; }

/* App bar */
.appbar {
  position: sticky; top: 0; z-index: 30;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  padding: 14px 18px;
  display: flex; align-items: center; gap: 12px;
}
.appbar .back {
  width: 38px; height: 38px;
  border: 1px solid var(--line);
  background: var(--surface);
  display: grid; place-items: center;
  color: var(--ink-2);
  flex: none;
}
.appbar h1 {
  font-family: var(--font-display);
  font-size: 18px; font-weight: 700; margin: 0;
  letter-spacing: -.01em;
  line-height: 1.15;
}
.appbar .sub { font-size: 12px; color: var(--ink-3); margin-top: 1px; }

/* Generic */
.eyebrow {
  font-size: 11px; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-4);
}
/* Filter-bar captions. They used .eyebrow, which put a fifth uppercase run on
   the Overview - five of them side by side above the controls, which is texture
   rather than accent. Their own class so the kicker and stat-tile labels can
   keep the .eyebrow treatment while a row of form captions does not. */
.filter-label {
  font-size: 12px; font-weight: 700; letter-spacing: 0;
  text-transform: none; color: var(--ink-3);
}
.mono { font-family: var(--font-mono); }

/* Buttons — square, primary is solid Morgan Red per the brand's button
   idiom; press state darkens (brand: "press states darken"), never
   brightens. Focus ring is 2px red, inset on dark backgrounds. */
.btn {
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font-weight: 700;
  font-size: 15px;
  padding: 13px 18px;
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  transition: filter .15s ease, background .15s ease, transform .05s ease;
  min-height: 48px;
}
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn-primary { background: var(--accent); color: #fff; }
.btn-primary:hover { background: var(--accent-700); }
.btn-ghost { background: var(--surface); color: var(--ink); border-color: var(--line); }
.btn-ghost:hover { background: var(--surface-2); }
.btn-dark { background: var(--ink); color: #fff; }
.btn-dark:hover { filter: brightness(1.3); }
.btn-block { width: 100%; }
.btn-lg { min-height: 56px; font-size: 16px; }

/* Cards — white, hairline border, square. No shadow; the top-border accent
   is reserved for a page's one lead/hero card, applied per-instance
   (border-top: 3px solid var(--accent)) rather than globally here. */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

/* Risk chip — square, bold, functional color only (amber/emerald/red),
   always paired with the risk code text, never color alone. */
.risk {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono);
  font-weight: 700; font-size: 12.5px;
  padding: 4px 9px; border-radius: 0;
  letter-spacing: .02em;
}
.risk-low { background: var(--risk-low-bg); color: var(--risk-low); }
.risk-med { background: var(--risk-med-bg); color: var(--risk-med); }
.risk-high { background: var(--risk-high-bg); color: var(--risk-high); }
.risk .lvl { width: 6px; height: 6px; background: currentColor; }

/* Pills / badges — square, outlined secondary tag per the chip idiom. */
/* Chips are one of the two sanctioned uppercase roles: "square, <= 12px bold
   uppercase Roboto". They were sentence-case Montserrat, i.e. under-styled
   while the rest of the page was over-styled. */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  font-family: var(--font-display);
  padding: 4px 10px; border-radius: 0;
  background: var(--surface-2); color: var(--ink-2);
  border: 1px solid var(--line);
}

/* Progress bar */
.prog { height: 7px; background: var(--line); overflow: hidden; }
.prog > i { display: block; height: 100%; background: var(--accent); transition: width .4s ease; }
.prog.done > i { background: var(--risk-low); }

/* Inputs */
.field { display: block; }
/* Same reason as .dash-table th above: over the uppercase budget. A filter bar
   is five of these in a row, which reads as texture rather than accent. */
.field label {
  display: block; font-size: 12px; font-weight: 700; letter-spacing: 0;
  text-transform: none; color: var(--ink-3); margin-bottom: 5px;
}
.field input, .field select, .field textarea {
  width: 100%; border: 1px solid var(--line); border-radius: 0;
  padding: 11px 12px; font-size: 14.5px; color: var(--ink); background: var(--surface);
  outline: none; transition: border .15s ease, box-shadow .15s ease;
}
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-100);
}

/* Toggle — square track + square knob (brand: square corners everywhere;
   no exemption for a switch just because iOS made round ones familiar). */
.toggle {
  width: 46px; height: 26px; background: var(--line);
  border: 0; padding: 0; position: relative; flex: none; transition: background .18s ease;
}
.toggle::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 20px; height: 20px; background: #fff;
  transition: transform .18s ease;
}
.toggle.on { background: var(--risk-low); }
.toggle.on::after { transform: translateX(20px); }

/* Checkbox */
.check {
  width: 26px; height: 26px; border: 2px solid var(--line);
  background: var(--surface); display: grid; place-items: center; flex: none;
  transition: all .14s ease; color: #fff;
}
.check.on { background: var(--accent); border-color: var(--accent); }
.check svg { opacity: 0; transform: scale(.6); transition: all .14s ease; }
.check.on svg { opacity: 1; transform: scale(1); }

/* Offline banner */
.netbanner {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 16px; font-size: 13px; font-weight: 600;
  color: #fff;
}
.netbanner.off { background: var(--risk-med); }
.netbanner.on { background: var(--risk-low); }
.netbanner .ring { width: 8px; height: 8px; background: #fff; }
.netbanner.off .ring { animation: pulse 1.4s ease infinite; }
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: .35; } }
@keyframes spin { to { transform: rotate(360deg); } }

/* Desktop dashboard */
.dash {
  background: var(--canvas);
  min-height: 100vh;
  min-height: 100dvh;
  font-size: 14px;
}
.dash-shell { display: flex; min-height: 100vh; min-height: 100dvh; }
/* White paper, not black ink. The brand has no dark mode - "black is ink, not
   paper" - so this panel now reads as a sheet beside the gray canvas, and the
   only thing separating them is the hairline border the brand uses for depth.
   Kept white rather than a gray tint because the canvas behind it is already
   gray-light 55%: a tinted panel on a tinted page has no edge at all.
   Hidden entirely by the React tree (see sideOpen) rather than by a width
   transition here - a 0-width flex child still holds its padding and borders. */
.dash-side {
  width: 248px; flex: none; background: var(--surface); color: var(--ink-2);
  border-right: 1px solid var(--line);
  padding: 22px 16px; display: flex; flex-direction: column; gap: 4px;
  /* Pinned, so the nav stays reachable instead of scrolling away with the page.
     sticky rather than fixed: a sticky element stays IN FLOW, so .dash-main
     keeps getting its 248px of width automatically - a fixed panel leaves the
     main column to slide underneath it unless every page adds a manual offset.
     align-self:flex-start is load-bearing, not tidying: a flex item defaults to
     stretch, which makes this full-height, and a box already as tall as its
     container has no room to stick inside. Own scrollbar for the case where the
     nav plus the identity footer exceed a short viewport - without it those
     items would be unreachable at exactly the height that pinning is meant to
     help. dvh repeated after vh for mobile browsers whose toolbars make vh lie,
     matching .dash-shell above. */
  position: sticky; top: 0; align-self: flex-start;
  height: 100vh; height: 100dvh;
  overflow-y: auto;
}
.dash-main { flex: 1; padding: 26px 30px 60px; overflow-x: hidden; }

/* Overview's map/Needs-action pair. minmax(0, …) rather than a bare 3fr/2fr:
   a grid track's default min is auto, so one long unbroken activity name would
   push its column wider than its share and shove the map out of the viewport.
   Stacks below 1100px, where 40% of the width stops being enough for a
   contract name, an activity name and a signer list. */
.ov-split { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 16px; align-items: start; }
@media (max-width: 1100px) { .ov-split { grid-template-columns: minmax(0, 1fr); } }

/* Four columns stays the default: the AI-cost tab runs EIGHT tiles through
   this class and reads as 4+4. An earlier auto-fit version of this rule
   made the column count follow the tile count, which silently reflowed
   that tab to 5+3 (and 7+1 on a wide screen) — do not reintroduce it.
   The Overview strip opts into 5 with .kpi-grid-5 when the API is on V172+
   and returns the signatures-captured tile. */
.kpi-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 14px; }
.kpi-grid-5 { grid-template-columns: repeat(5, 1fr); }
@media (max-width: 1180px) { .kpi-grid-5 { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px)  { .kpi-grid-5 { grid-template-columns: repeat(2, 1fr); } }

/* Admin-portal adoption strip — five cumulative rollout totals, pinned above
   the portal's sub-tabs so the numbers stay put as the operator moves between
   them. Five columns (not four like .kpi-grid), reflowing on narrow screens. */
.adopt-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 14px; }
@media (max-width: 1180px) { .adopt-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 720px)  { .adopt-grid { grid-template-columns: repeat(2, 1fr); } }

.dash-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
/* Sentence case, no tracking. Uppercase + letter-spacing is an ACCENT with a
   budget of two roles per view, and the Overview was spending five: the page
   kicker, the stat-tile labels, these headers, the filter labels and the
   sidebar group label. Column headers are the largest block of the five - a
   whole row of them across two tables - so they were the texture. The budget
   now goes to the .eyebrow kicker/labels and the chips (the brand's own worked
   example is "a kicker + status chips"), with the sidebar label kept because
   the Sidebar/TOC idiom specifies it separately.
   12px, not 11px: sentence case has no tracking to hold it open, so it needs
   the size back to stay as legible as it was. */
.dash-table th {
  text-align: left; font-size: 12px; text-transform: none; letter-spacing: 0;
  color: var(--ink-3); font-weight: 700; padding: 10px 12px; border-bottom: 1px solid var(--line);
}
.dash-table td { padding: 12px; border-bottom: 1px solid var(--line-2); color: var(--ink-2); vertical-align: middle; }
.dash-table tr:last-child td { border-bottom: 0; }

/* Dense variant — the Audit Summary list runs 12 columns, and at the default
   paddings the card clipped the trailing ones. Tighter cells + smaller type
   let the whole row fit the viewport; the card's overflow-x:auto stays as the
   fallback for genuinely narrow windows (and the 50:50 sheet split). */
.dash-table--dense { font-size: 12.5px; }
.dash-table--dense th { padding: 9px 8px; font-size: 10.5px; letter-spacing: .05em; }
.dash-table--dense td { padding: 8px; }

/* Audit Summary 50:50 split — "Open sheet" docks the read-only viewer beside
   the list instead of replacing the page. The right pane is sticky and
   scrolls internally, so the auditor scrolls the list and the sheet
   independently. */
.sheets-split { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 18px; align-items: start; }
.sheets-split-left { min-width: 0; }
.sheets-split-right { position: sticky; top: 14px; height: calc(100vh - 28px); min-width: 0; }
@media (max-width: 1100px) { .sheets-split { grid-template-columns: 1fr; } .sheets-split-right { position: static; height: 70vh; } }

/* Skeleton loading placeholder — shimmer sweep over a flat bar. */
.skel {
  position: relative; overflow: hidden; display: inline-block;
  background: var(--line-2); border-radius: 0; vertical-align: middle;
}
.skel::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.6), transparent);
  animation: skel-sweep 1.3s ease-in-out infinite;
}
@keyframes skel-sweep {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(100%); }
}

.scrim {
  position: absolute; inset: 0; background: rgba(0,0,0,.5);
  z-index: 80; display: flex; align-items: flex-end;
  animation: fade .2s ease;
}
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
.sheet {
  background: var(--surface); width: 100%;
  max-height: 92%;
  display: flex; flex-direction: column;
  animation: slideup .26s cubic-bezier(.2,.7,.3,1);
}
@keyframes slideup { from { transform: translateY(100%); } to { transform: translateY(0); } }
.sheet-grab { width: 40px; height: 4px; background: var(--line); margin: 10px auto 4px; }

.fade-in { animation: fade .26s ease; }
@keyframes screenIn { from { transform: translateY(7px); } to { transform: translateY(0); } }
.screen-in { animation: screenIn .26s ease; }

/* ============================================================
   AI-guided JSA (Option B)
   ============================================================ */
.ai-modeseg {
  display: flex; background: var(--surface-2);
  border: 1px solid var(--line);
  padding: 3px; gap: 3px; margin-bottom: 16px;
}
.ai-modeseg button {
  flex: 1; border: 0; background: transparent;
  font-family: var(--font-sans); font-weight: 600; font-size: 13.5px; color: var(--ink-3);
  padding: 10px 12px; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  transition: all .15s ease;
}
.ai-modeseg button.on { background: var(--surface); color: var(--ink); border: 1px solid var(--line); }
.ai-modeseg button .spk { color: var(--morgan-red); }

.ai-wrap { max-width: 560px; margin: 0 auto; padding: 26px 22px 30px; animation: aiIn .3s ease; }
@keyframes aiIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
.ai-eyebrow {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent); margin-bottom: 12px;
}
.ai-eyebrow svg { color: var(--morgan-red); }
.ai-prog { height: 4px; background: var(--line-2); overflow: hidden; margin-bottom: 22px; }
.ai-prog i { display: block; height: 100%; background: var(--accent); transition: width .35s ease; }
.ai-title {
  font-family: var(--font-display); font-size: 24px; font-weight: 700;
  letter-spacing: -.015em; line-height: 1.15; margin: 0 0 8px; color: var(--ink);
  text-wrap: pretty;
}
.ai-sub { margin: 0 0 20px; font-size: 14px; line-height: 1.5; color: var(--ink-3); }
.ai-opts { display: flex; flex-direction: column; gap: 10px; }
.ai-opt {
  display: flex; align-items: center; gap: 13px; width: 100%;
  text-align: left; cursor: pointer;
  background: var(--surface); border: 1.5px solid var(--line);
  padding: 15px 16px; font-family: var(--font-sans); font-size: 15px; font-weight: 600; color: var(--ink);
  transition: border-color .14s ease, background .14s ease, transform .1s ease;
  min-height: 54px;
}
.ai-opt:hover { border-color: var(--ink-3); }
.ai-opt:active { transform: scale(.99); }
.ai-opt.on { border-color: var(--accent); background: var(--accent-050); }
.ai-opt-ic {
  width: 38px; height: 38px; flex: none;
  display: grid; place-items: center;
  background: var(--surface-2); color: var(--ink-2);
}
.ai-opt.on .ai-opt-ic { background: var(--accent); color: #fff; }
.ai-opt-check {
  width: 22px; height: 22px; flex: none;
  display: grid; place-items: center; color: #fff;
  background: var(--accent); opacity: 0; transform: scale(.6);
  transition: all .16s ease;
}
.ai-opt.on .ai-opt-check { opacity: 1; transform: scale(1); }
.ai-foot { display: flex; align-items: center; justify-content: space-between; margin-top: 20px; min-height: 40px; }
.ai-back {
  display: inline-flex; align-items: center; gap: 6px;
  background: none; border: 0; cursor: pointer;
  font-family: var(--font-sans); font-size: 13.5px; font-weight: 600; color: var(--ink-3);
  padding: 8px 6px;
}
.ai-back:hover { color: var(--ink); }
.ai-grounding {
  display: flex; align-items: center; gap: 7px; margin-top: 22px;
  font-size: 11.5px; color: var(--ink-4); line-height: 1.4;
}

/* review */
.ai-review { display: flex; flex-direction: column; gap: 0; border: 1px solid var(--line); overflow: hidden; margin-bottom: 20px; background: var(--surface); }
.ai-review-row { display: flex; gap: 14px; padding: 12px 16px; border-bottom: 1px solid var(--line-2); }
.ai-review-row:last-child { border-bottom: 0; background: var(--surface-2); }
.ai-review-q { flex: none; width: 38%; font-size: 12px; font-weight: 700; color: var(--ink-4); text-transform: uppercase; letter-spacing: .03em; line-height: 1.35; padding-top: 1px; }
.ai-review-a { flex: 1; font-size: 13.5px; font-weight: 600; color: var(--ink); line-height: 1.4; }

/* build animation */
.ai-build { max-width: 480px; margin: 0 auto; padding: 44px 24px; text-align: center; animation: aiIn .3s ease; }
.ai-build-mark {
  width: 76px; height: 76px; margin: 0 auto 8px;
  display: grid; place-items: center;
  background: var(--ink); color: #fff;
  position: relative; animation: aiMarkPulse 1.6s ease-in-out infinite;
}
.ai-build-mark.ready { background: var(--risk-low); animation: none; }
@keyframes aiMarkPulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(0,0,0,.18); }
  50% { box-shadow: 0 0 0 14px rgba(0,0,0,0); }
}
.ai-build-refs { display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; margin: 18px 0 6px; min-height: 30px; }
.ai-refchip {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--font-mono); font-size: 11.5px; font-weight: 600; color: var(--ink-2);
  background: var(--surface); border: 1px solid var(--line);
  padding: 6px 12px; opacity: 0;
  animation: aiChipIn .4s ease forwards;
}
.ai-refchip b { color: var(--accent); font-weight: 700; }
@keyframes aiChipIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
.ai-build-steps { display: flex; flex-direction: column; gap: 12px; margin: 22px auto 24px; max-width: 400px; text-align: left; }
.ai-build-step {
  display: flex; align-items: flex-start; gap: 11px;
  font-size: 13.5px; line-height: 1.4; color: var(--ink-4); font-weight: 500;
  transition: color .25s ease;
}
.ai-build-step.now { color: var(--ink); font-weight: 600; }
.ai-build-step.done { color: var(--ink-2); }
.ai-step-dot {
  width: 19px; height: 19px; border-radius: 50%; flex: none; margin-top: 1px;
  display: grid; place-items: center;
  border: 2px solid var(--line); color: #fff;
  transition: all .25s ease;
}
.ai-build-step.now .ai-step-dot { border-color: var(--accent); animation: aiSpin 1s linear infinite; border-top-color: transparent; }
.ai-build-step.done .ai-step-dot { background: var(--risk-low); border-color: var(--risk-low); }
@keyframes aiSpin { to { transform: rotate(360deg); } }
.ai-build-bar { height: 5px; background: var(--line-2); overflow: hidden; max-width: 400px; margin: 0 auto; }
.ai-build-bar i { display: block; height: 100%; background: var(--accent); transition: width .9s ease; }

/* ---------- Live AI flow (ai-jsa-live.jsx) ---------- */
.ai-live { display: flex; flex-direction: column; height: 100%; }
.ai-live-bar { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px; border-bottom: 1px solid var(--line); flex: none; }
.ai-live-close { width: 32px; height: 32px; display: grid; place-items: center; border: 1px solid var(--line); background: var(--surface); color: var(--ink-2); cursor: pointer; }
.ai-live-close:hover { border-color: var(--ink-3); }
.ai-live-tag { display: inline-flex; align-items: center; gap: 5px; font-family: var(--font-mono); font-size: 10.5px; font-weight: 700; letter-spacing: .08em; color: #fff; background: var(--risk-high); padding: 3px 8px; }
.ai-live .ai-wrap, .ai-live .ai-build { flex: 1; overflow-y: auto; }

.ai-bar-indet { width: 40%; animation: aiIndet 1.1s ease-in-out infinite; }
@keyframes aiIndet { 0% { margin-left: -40%; } 100% { margin-left: 100%; } }

/* Indented intake-question groups */
.ai-qgroup { margin-bottom: 16px; }
.ai-qgroup-label { font-size: 11.5px; font-weight: 800; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-4); margin: 0 2px 8px; }

/* Inputs on the connect screen */
.ai-field-label { display: block; font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--ink-4); margin: 14px 2px 5px; }
.ai-input { width: 100%; border: 1px solid var(--line); padding: 11px 13px; font-family: var(--font-mono); font-size: 12.5px; color: var(--ink); background: var(--surface); box-sizing: border-box; }
.ai-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-100); }

.ai-opt-meta { display: block; font-size: 11.5px; color: var(--ink-4); margin-top: 2px; line-height: 1.35; }

.ai-empty { display: flex; gap: 9px; align-items: flex-start; padding: 13px 15px; border: 1px dashed var(--line); color: var(--ink-3); font-size: 13px; line-height: 1.45; background: var(--surface-2); }
.ai-empty.err { border-color: var(--risk-high); color: var(--risk-high); background: var(--risk-high-bg); border-style: solid; }

/* ============================================================
   Official JSA sheet — the full-sheet view (JsaDetailView) rendered to
   match the Morgan JSA form (header block, critical questions, the 8-column
   hazard table grouped by section, per-section sign-off, footer). Same markup
   prints to PDF via Export (see print rules below).
   ============================================================ */
.jsa-sheet { font-size: 12px; color: var(--ink); -webkit-print-color-adjust: exact; print-color-adjust: exact; }
.jsa-meta { width: 100%; border-collapse: collapse; margin-bottom: 12px; table-layout: fixed; }
.jsa-meta td { border: 1px solid var(--line); padding: 6px 9px; vertical-align: top; width: 33.33%; }
/* 10px is the brand's floor - nothing smaller. Was 9.5px. */
.jsa-meta .lbl, .jsa-crit .lbl, .jsa-foot .lbl { display: block; font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-4); margin-bottom: 2px; }
.jsa-meta .val { font-size: 13px; font-weight: 600; }
.jsa-crit { border: 1px solid var(--line); padding: 8px 10px; margin-bottom: 14px; }
.jsa-crit ul { margin: 4px 0 0; padding: 0; list-style: none; display: grid; grid-template-columns: 1fr 1fr; gap: 2px 18px; font-size: 12px; }
.jsa-form { width: 100%; border-collapse: collapse; table-layout: fixed; }
.jsa-form th, .jsa-form td { border: 1px solid var(--line); padding: 5px 7px; vertical-align: top; text-align: left; font-size: 11.5px; line-height: 1.35; overflow-wrap: anywhere; }
.jsa-form th { background: var(--surface-2); font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .03em; color: var(--ink-2); }
.jsa-form tr.jsa-secrow td { background: var(--surface-2); font-size: 12.5px; font-weight: 700; }
.jsa-form tr.jsa-signrow td { background: var(--surface-2); }
.jsa-signhead { display: flex; align-items: center; gap: 7px; font-size: 10px; font-weight: 800; text-transform: uppercase; letter-spacing: .03em; color: var(--ink-3); margin-bottom: 8px; }
.jsa-signhead .cnt { margin-left: 6px; font-weight: 700; color: var(--ink-4); text-transform: none; letter-spacing: 0; }
.jsa-signnote { color: var(--ink-3); font-size: 12px; }
.jsa-sigrow { display: flex; flex-wrap: wrap; gap: 10px; }
.jsa-foot { margin-top: 16px; display: grid; gap: 12px; }
.jsa-foot-block { border: 1px solid var(--line); padding: 9px 11px; }
.jsa-foot-block p { margin: 4px 0 0; font-size: 12px; line-height: 1.5; }

/* ---- Static reference appendix (1:1 with the paper form) ---- */
.jsa-appx { margin-top: 16px; display: grid; gap: 14px; }
.jsa-appx > section { border: 1px solid var(--line); padding: 10px 12px; }
.jsa-appx h3 { margin: 0 0 8px; font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; color: var(--ink-2); }
.jsa-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 3px 16px; font-size: 11.5px; }
.jsa-defs { display: grid; gap: 6px; font-size: 11.5px; line-height: 1.45; }
.jsa-defs b { color: var(--ink); }
.jsa-defs .ex { color: var(--ink-3); }
.jsa-matrix { width: 100%; border-collapse: collapse; font-size: 10.5px; table-layout: fixed; margin-bottom: 8px; }
.jsa-matrix th, .jsa-matrix td { border: 1px solid var(--line); padding: 4px 5px; text-align: center; vertical-align: middle; }
.jsa-matrix th { background: var(--surface-2); font-weight: 700; }
.jsa-matrix th.cons { text-align: left; font-weight: 600; }
.jsa-matrix td.low  { background: var(--risk-low-bg);  color: var(--risk-low);  font-weight: 700; }
.jsa-matrix td.med  { background: var(--risk-med-bg);  color: var(--risk-med);  font-weight: 700; }
.jsa-matrix td.high { background: var(--risk-high-bg); color: var(--risk-high); font-weight: 700; }
.jsa-refs { width: 100%; border-collapse: collapse; font-size: 11.5px; table-layout: fixed; }
.jsa-refs th, .jsa-refs td { border: 1px solid var(--line); padding: 6px 8px; text-align: left; }
.jsa-refs th { background: var(--surface-2); font-weight: 700; }

/* ---- Print / PDF export: strip app chrome, keep rows off page breaks ---- */
.print-only { display: none; }
@media print {
  .no-print { display: none !important; }
  .print-only { display: block !important; }
  .jsa-detail-scroll { height: auto !important; overflow: visible !important; border: 0 !important; }
  .jsa-sheet-wrap { padding: 0 !important; max-width: none !important; }
  body, .dash-app-root { background: #fff !important; }
  @page { size: landscape; margin: 10mm; }
  .jsa-secrow, .jsa-signrow, .jsa-sig, tr, .jsa-appx > section, .jsa-matrix { break-inside: avoid; }
  .jsa-form th, .jsa-matrix th, .jsa-refs th, .jsa-matrix td.low, .jsa-matrix td.med, .jsa-matrix td.high { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  /* 50:50 sheet split: Export PDF prints ONLY the docked sheet — the sidebar,
     the page header and the list half are chrome here, not the document. */
  .dash--sheet-split .dash-side { display: none !important; }
  .dash--sheet-split .dash-main > *:not(.sheets-split) { display: none !important; }
  .dash--sheet-split .sheets-split { display: block !important; }
  .dash--sheet-split .sheets-split-left { display: none !important; }
  .dash--sheet-split .sheets-split-right { position: static !important; height: auto !important; }
  .dash--sheet-split .dash-main { padding: 0 !important; overflow: visible !important; }
  .dash--sheet-split .dash-shell { display: block !important; }
}

/* ---- Leaflet overrides: strip the library's own rounded/shadowed chrome so
   the activity map's UI (not the base tiles — those stay OpenStreetMap's own
   colors) matches the brand's square, hairline-border, no-shadow system. ---- */
.leaflet-container { font-family: var(--font-sans); }
.leaflet-tooltip {
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: 0;
  box-shadow: none; font-size: 12.5px; line-height: 1.4; padding: 8px 10px;
}
.leaflet-tooltip:before { display: none; }
/* Zoom and locate share one rule set so the locate button cannot drift from
   the +/- bar it docks under - square corners, no shadow, brand ink on paper. */
.leaflet-control-zoom,
.leaflet-control-locate { border: 1px solid var(--line) !important; border-radius: 0 !important; box-shadow: none !important; }
.leaflet-control-zoom a,
.leaflet-control-locate a { border-radius: 0 !important; color: var(--ink) !important; background: var(--surface) !important; }
.leaflet-control-zoom a:hover,
.leaflet-control-locate a:hover { background: var(--surface-2) !important; }
/* Leaflet centres its own text glyphs with line-height; an inline SVG needs to
   be blocked and margin-centred instead or it sits high in the 26px box. */
.leaflet-control-locate a svg { display: block; margin: 5px auto; }
.leaflet-control-attribution { background: rgba(255, 255, 255, .82) !important; font-size: 10px; }
