/* Plot Monitor CP — the design from the approved layout proposal.
   Tokens first: every colour below is referenced through a custom property so
   the dark theme is a token swap, never a second set of component rules. */
:root {
  --brand: #3F6455; --brand-soft: #6B9080; --brand-tint: #EDF3F0;
  --ground: #F4F7F5; --surface: #FFFFFF; --surface-2: #FAFCFB;
  --rail: #22332C; --rail-ink: #C8D8D0; --rail-ink-dim: #7E948B;
  --line: #DFE7E2; --line-2: #EDF2EF;
  --ink: #14231D; --ink-2: #46574F; --ink-3: #78897F;
  --ok: #1F7A5A; --ok-bg: #E4F2EB;
  --warn: #A8701A; --warn-bg: #FAF0DE;
  --crit: #A8433A; --crit-bg: #FBEAE7;
  --info: #38618F; --info-bg: #E7EEF7;
  --shadow: 0 1px 2px rgba(20,35,29,.05), 0 8px 24px -12px rgba(20,35,29,.18);
  --r: 10px; --r-sm: 7px;
  --ui: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
  :root {
    --brand: #7FA895; --brand-soft: #5E8574; --brand-tint: #1D2B25;
    --ground: #0D1310; --surface: #151E1A; --surface-2: #101815;
    --rail: #0A100D; --rail-ink: #B6C9C0; --rail-ink-dim: #6C8076;
    --line: #263430; --line-2: #1C2724;
    --ink: #E7EFEA; --ink-2: #A9BAB2; --ink-3: #7E9188;
    --ok: #63B994; --ok-bg: #162B22; --warn: #D6A153; --warn-bg: #2C2314;
    --crit: #E08A7F; --crit-bg: #2E1B18; --info: #8AAFD8; --info-bg: #172231;
    --shadow: 0 1px 2px rgba(0,0,0,.4), 0 10px 28px -14px rgba(0,0,0,.7);
  }
}
:root[data-theme="dark"] {
  --brand: #7FA895; --brand-soft: #5E8574; --brand-tint: #1D2B25;
  --ground: #0D1310; --surface: #151E1A; --surface-2: #101815;
  --rail: #0A100D; --rail-ink: #B6C9C0; --rail-ink-dim: #6C8076;
  --line: #263430; --line-2: #1C2724;
  --ink: #E7EFEA; --ink-2: #A9BAB2; --ink-3: #7E9188;
  --ok: #63B994; --ok-bg: #162B22; --warn: #D6A153; --warn-bg: #2C2314;
  --crit: #E08A7F; --crit-bg: #2E1B18; --info: #8AAFD8; --info-bg: #172231;
}
:root[data-theme="light"] {
  --brand: #3F6455; --brand-soft: #6B9080; --brand-tint: #EDF3F0;
  --ground: #F4F7F5; --surface: #FFFFFF; --surface-2: #FAFCFB;
  --rail: #22332C; --rail-ink: #C8D8D0; --rail-ink-dim: #7E948B;
  --line: #DFE7E2; --line-2: #EDF2EF;
  --ink: #14231D; --ink-2: #46574F; --ink-3: #78897F;
  --ok: #1F7A5A; --ok-bg: #E4F2EB; --warn: #A8701A; --warn-bg: #FAF0DE;
  --crit: #A8433A; --crit-bg: #FBEAE7; --info: #38618F; --info-bg: #E7EEF7;
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0; background: var(--ground); color: var(--ink);
  font-family: var(--ui); font-size: 15px; line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--brand); }

/* ------------------------------------------------------------------- shell */
.shell { display: grid; grid-template-columns: 214px 1fr; min-height: 100vh; }
.rail { background: var(--rail); color: var(--rail-ink); padding: 14px 0 20px; display: flex; flex-direction: column; }
.rail-brand { display: flex; align-items: center; gap: 9px; padding: 2px 16px 16px; }
.rail-mark {
  width: 27px; height: 27px; border-radius: 7px; flex: 0 0 27px;
  background: linear-gradient(140deg, var(--brand-soft), var(--brand));
  display: grid; place-items: center; color: #0C1512;
}
.rail-mark svg { width: 15px; height: 15px; }
.rail-name { font-size: 13px; font-weight: 640; color: #EAF2EE; letter-spacing: -.01em; }
.rail-sub { font-family: var(--mono); font-size: 9.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--rail-ink-dim); }
.rail-group { padding: 12px 0 2px; }
.rail-label { font-family: var(--mono); font-size: 9.5px; letter-spacing: .11em; text-transform: uppercase; color: var(--rail-ink-dim); padding: 0 16px 6px; }
.rail-link {
  display: flex; align-items: center; gap: 9px; padding: 7px 16px; width: 100%;
  font: inherit; font-size: 13px; color: var(--rail-ink); background: none; border: 0;
  text-align: left; cursor: pointer; text-decoration: none;
}
.rail-link:hover { background: rgba(255,255,255,.06); color: #fff; }
.rail-link svg { width: 14px; height: 14px; opacity: .75; flex: 0 0 14px; }
.rail-link .count { margin-left: auto; font-family: var(--mono); font-size: 10.5px; color: var(--rail-ink-dim); font-variant-numeric: tabular-nums; }
.rail-link .flag { margin-left: auto; font-family: var(--mono); font-size: 10px; font-weight: 600; background: var(--crit); color: #fff; border-radius: 100px; padding: 1px 6px; }
.rail-link.on { background: rgba(255,255,255,.09); color: #fff; box-shadow: inset 2px 0 0 var(--brand-soft); }
.rail-link:focus-visible { outline: 2px solid var(--brand-soft); outline-offset: -2px; }
.rail-foot { margin-top: auto; margin-inline: 12px; padding: 12px 4px 0; border-top: 1px solid rgba(255,255,255,.08); display: flex; flex-direction: column; gap: 10px; }
.rail-who { display: flex; align-items: center; gap: 8px; min-width: 0; }
.rail-avatar { flex: 0 0 22px; width: 22px; height: 22px; border-radius: 6px; display: grid; place-items: center; font-family: var(--mono); font-size: 12px; font-weight: 600; color: #0C1512; background: linear-gradient(140deg, var(--brand-soft), var(--brand)); }
.rail-email { font-size: 11.5px; color: var(--rail-ink-dim); font-family: var(--mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.rail-acts { display: flex; align-items: center; gap: 7px; }
.rail-foot form { margin: 0; }
.rail-foot .lnk { font: inherit; font-size: 11.5px; font-weight: 500; color: var(--rail-ink); background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.09); border-radius: var(--r-sm); padding: 5px 10px; cursor: pointer; text-decoration: none; white-space: nowrap; }
.rail-foot .lnk:hover { background: rgba(255,255,255,.11); color: #fff; }
.rail-foot .lnk:focus-visible { outline: 2px solid var(--brand-soft); outline-offset: 1px; }

.work { display: flex; flex-direction: column; background: var(--surface-2); min-width: 0; }

/* ------------------------------------------------------------ pipeline bar */
.pipe { display: flex; align-items: stretch; flex-wrap: wrap; background: var(--surface); border-bottom: 1px solid var(--line); padding: 0 6px; }
.pipe-cell { padding: 9px 14px; display: flex; flex-direction: column; gap: 1px; border-right: 1px solid var(--line-2); justify-content: center; }
.pipe-cell.end { border-right: 0; margin-left: auto; flex-direction: row; align-items: center; gap: 7px; }
.pipe-k { font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.pipe-v { font-size: 13.5px; font-weight: 620; font-variant-numeric: tabular-nums; letter-spacing: -.01em; display: flex; align-items: center; gap: 6px; }
.pipe-v .sub { font-weight: 460; color: var(--ink-3); font-size: 12px; }
.dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 7px; background: var(--ink-3); }
.dot.ok { background: var(--ok); } .dot.warn { background: var(--warn); } .dot.crit { background: var(--crit); }

/* ---------------------------------------------------------------- controls */
.btn {
  font: inherit; font-size: 12.5px; font-weight: 580; cursor: pointer;
  border-radius: var(--r-sm); border: 1px solid var(--line);
  background: var(--surface); color: var(--ink); padding: 6px 11px;
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
}
.btn:hover { border-color: var(--brand-soft); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.btn svg { width: 13px; height: 13px; }
.btn-primary { background: var(--brand); border-color: var(--brand); color: var(--ground); }
.btn-danger { color: var(--crit); }
.field { display: flex; flex-direction: column; gap: 4px; }
.field label { font-family: var(--mono); font-size: 9.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3); }
.field input, .field select {
  font: inherit; font-size: 13px; color: var(--ink); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 6px 9px; min-width: 132px;
}
.field.grow { flex: 1 1 220px; }
.field.grow input { width: 100%; }
.field input:focus, .field select:focus { outline: 2px solid var(--brand); outline-offset: 1px; }

/* ------------------------------------------------------------- work header */
.work-head { padding: 16px 18px 0; display: flex; align-items: flex-start; gap: 14px; flex-wrap: wrap; }
.work-head h1 { margin: 0; font-size: 19px; letter-spacing: -.02em; font-weight: 660; }
.work-head p { margin: 2px 0 0; font-size: 13px; color: var(--ink-3); }
.work-head .spacer { margin-left: auto; display: flex; gap: 7px; }
.body-pad { padding: 16px 18px 24px; display: flex; flex-direction: column; gap: 14px; }

/* ------------------------------------------------------------ queue tiles */
.queues { display: grid; grid-template-columns: repeat(auto-fit, minmax(224px, 1fr)); gap: 10px; }
.queue {
  background: var(--surface); border: 1px solid var(--line); border-left: 3px solid var(--line);
  border-radius: var(--r-sm); padding: 12px 13px; display: flex; flex-direction: column; gap: 6px;
  font: inherit; text-align: left; cursor: pointer; color: inherit;
}
.queue:hover { border-color: var(--brand-soft); }
.queue.crit { border-left-color: var(--crit); }
.queue.warn { border-left-color: var(--warn); }
.queue.info { border-left-color: var(--info); }
.queue-n { font-family: var(--mono); font-size: 23px; font-weight: 600; letter-spacing: -.03em; font-variant-numeric: tabular-nums; line-height: 1; }
.queue-t { font-size: 13px; font-weight: 620; }
.queue-d { font-size: 12px; color: var(--ink-3); line-height: 1.45; }
.queue-a { font-size: 12px; font-weight: 620; color: var(--brand); margin-top: auto; }

.split { display: grid; grid-template-columns: 1.35fr 1fr; gap: 14px; align-items: start; }
.panel { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden; }
.panel-head { display: flex; align-items: center; gap: 8px; padding: 10px 13px; border-bottom: 1px solid var(--line-2); }
.panel-head h2 { margin: 0; font-size: 12.5px; font-weight: 650; letter-spacing: -.01em; }
.panel-head .note { margin-left: auto; font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); }
.panel-pad { padding: 12px 13px; }

/* Info affordance — a detail that explains a cell without living in it.

   This used a native `title`, for a real reason: .panel is `overflow: hidden`
   for its rounded corners and .table-wrap is `overflow-x: auto`, so a bubble
   positioned inside a table cell is clipped by TWO ancestors before it is seen.
   The browser's own tooltip is never clipped.

   But it is also never quick. A native tooltip waits about a second, renders in
   the OS style, and is suppressed outright if the pointer keeps moving — so the
   one row that most needed explaining (`direct`, rejecting) looked like it had
   an icon that did nothing.

   #cptip keeps both properties: it lives on <body> and is `position: fixed`, so
   no overflow ancestor can clip it, and it is driven by JS on hover/focus so it
   appears at once. Fixed positioning is load-bearing here — moving this element
   inside the panel, or giving any ancestor a `transform`, brings the clipping
   back. */
#cptip {
  position: fixed; z-index: 9999; max-width: 340px; padding: 8px 10px;
  border-radius: var(--r-sm); background: var(--ink); color: var(--surface);
  font-size: 12px; line-height: 1.45; box-shadow: 0 6px 24px -8px rgba(0,0,0,.45);
  pointer-events: none; opacity: 0; transition: opacity .09s ease;
}
#cptip[data-show="1"] { opacity: 1; }
#cptip .k { display: block; font-family: var(--mono); font-size: 10px; letter-spacing: .06em;
  text-transform: uppercase; opacity: .7; margin-bottom: 3px; }

.info {
  display: inline-grid; place-items: center; width: 15px; height: 15px; flex: none;
  border-radius: 50%; border: 1px solid var(--line); background: var(--surface-2);
  font-family: var(--mono); font-size: 10px; font-weight: 700; line-height: 1;
  color: var(--ink-3); cursor: help; vertical-align: 1px; margin-left: 5px;
}
.info:hover, .info:focus { border-color: var(--brand-soft); color: var(--brand); outline: none; }
.info.crit { border-color: var(--crit); color: var(--crit); background: var(--crit-bg); }
.info.warn { border-color: var(--warn); color: var(--warn); background: var(--warn-bg); }

/* ------------------------------------------------------------ filter strip */
.toolbar { display: flex; gap: 8px; align-items: flex-end; flex-wrap: wrap; padding: 13px 18px; background: var(--surface); border-bottom: 1px solid var(--line); }
.chips { display: flex; gap: 6px; flex-wrap: wrap; padding: 9px 18px; background: var(--surface); border-bottom: 1px solid var(--line); align-items: center; }
.chips .lead { font-family: var(--mono); font-size: 9.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3); margin-right: 2px; }
.chip {
  font: inherit; font-size: 12px; font-weight: 560; padding: 3px 9px; border-radius: 100px;
  border: 1px solid var(--line); background: var(--surface-2); color: var(--ink-2); cursor: pointer;
}
.chip:hover { border-color: var(--brand-soft); }
.chip[aria-pressed="true"] { background: var(--brand-tint); border-color: var(--brand-soft); color: var(--brand); font-weight: 620; }
.chip .n { font-family: var(--mono); font-variant-numeric: tabular-nums; opacity: .85; }

/* ------------------------------------------------------------------ table */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
thead th {
  text-align: left; font-family: var(--mono); font-size: 9.5px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-3); font-weight: 600;
  padding: 8px 12px; border-bottom: 1px solid var(--line); background: var(--surface-2); white-space: nowrap;
}
thead th.sortable { cursor: pointer; }
thead th.sortable:hover { color: var(--ink); }
thead th[data-dir]::after { content: " ↑"; color: var(--brand); }
thead th[data-dir="desc"]::after { content: " ↓"; }
tbody td { padding: 9px 12px; border-bottom: 1px solid var(--line-2); vertical-align: middle; }
tbody td.nowrap { white-space: nowrap; }
thead th.center, tbody td.center { text-align: center; }
tbody tr:hover { background: var(--brand-tint); }
tbody tr.sel { background: var(--brand-tint); }
tbody tr.flagged td:first-child { box-shadow: inset 3px 0 0 var(--warn); }
.num { text-align: right; font-variant-numeric: tabular-nums; font-family: var(--mono); }
.strong { font-weight: 620; }
.muted { color: var(--ink-3); }
.sub-cell { font-size: 11.5px; color: var(--ink-3); font-family: var(--mono); word-break: break-all; }
.rowsel { width: 32px; }
.rowsel input { width: 14px; height: 14px; accent-color: var(--brand); cursor: pointer; }
.linkish { background: none; border: 0; font: inherit; font-weight: 620; color: var(--ink); cursor: pointer; padding: 0; text-align: left; }
.linkish:hover { color: var(--brand); text-decoration: underline; text-underline-offset: 2px; }

/* Source-page link icon (Plots list). */
th.link-col { width: 44px; }
td.link-cell { text-align: right; }
.row-link {
  display: inline-grid; place-items: center; width: 28px; height: 28px; border-radius: var(--r-sm);
  color: var(--ink-3); border: 1px solid transparent; background: none; padding: 0; cursor: pointer;
}
.row-link svg { width: 15px; height: 15px; }
.row-link:hover { color: var(--brand); background: var(--brand-tint); border-color: var(--line); }
.row-link:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }

.pill { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; font-weight: 600; padding: 2px 8px; border-radius: 100px; white-space: nowrap; }
.p-ok { background: var(--ok-bg); color: var(--ok); }
.p-warn { background: var(--warn-bg); color: var(--warn); }
.p-crit { background: var(--crit-bg); color: var(--crit); }
.p-info { background: var(--info-bg); color: var(--info); }
.p-idle { background: var(--line-2); color: var(--ink-3); }

/* Four weeks of sessions in the width of a column. Bars are drawn from a shared
   peak per row, so a heavy user and a light one are each read against
   themselves — the shape is the signal, not the absolute height. An empty week
   keeps a hairline rather than disappearing, or a gap reads as no data. */
.spark { display: inline-flex; align-items: flex-end; gap: 2px; height: 18px; vertical-align: middle; }
.spark i { display: block; width: 4px; background: var(--brand-soft); border-radius: 1px; }
.spark i.z { height: 2px; background: var(--line); }
.lock { font-family: var(--mono); font-size: 11px; color: var(--brand); }

.bulkbar { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; padding: 9px 18px; background: var(--brand-tint); border-bottom: 1px solid var(--line); font-size: 12.5px; color: var(--ink-2); }
.bulkbar .count { font-weight: 650; color: var(--ink); font-family: var(--mono); }
.bulkbar .spacer { margin-left: auto; display: flex; gap: 6px; flex-wrap: wrap; }

.foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; padding: 11px 18px; font-size: 12.5px; color: var(--ink-3); border-top: 1px solid var(--line); background: var(--surface); }
.foot .pages { margin-left: auto; display: flex; gap: 4px; align-items: center; }
.pg { font: inherit; font-size: 12px; font-family: var(--mono); padding: 3px 8px; border-radius: var(--r-sm); border: 1px solid var(--line); background: var(--surface); color: var(--ink-2); cursor: pointer; }
.pg:disabled { opacity: .45; cursor: not-allowed; }
.pg.on { background: var(--brand); border-color: var(--brand); color: var(--ground); }

/* ----------------------------------------------------------------- drawer */
.stage { position: relative; flex: 1; display: flex; flex-direction: column; min-height: 0; }
.scrim { position: fixed; inset: 0; background: rgba(12,20,17,.34); z-index: 40; }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(460px, 92vw); z-index: 41;
  background: var(--surface); border-left: 1px solid var(--line);
  display: flex; flex-direction: column; box-shadow: -18px 0 40px -24px rgba(0,0,0,.5);
}
.drawer-head { padding: 14px 16px; border-bottom: 1px solid var(--line); display: flex; gap: 10px; align-items: flex-start; }
.drawer-head h2 { margin: 0; font-size: 16px; letter-spacing: -.02em; }
.drawer-head .x { margin-left: auto; font: inherit; font-size: 16px; color: var(--ink-3); cursor: pointer; background: none; border: 0; line-height: 1; }
.drawer-body { padding: 14px 16px; display: flex; flex-direction: column; gap: 14px; overflow-y: auto; }

/* Drawer tabs — the three read-only panels. The decision form is NOT one of
   them: it sits below, always visible, because approving is what this drawer is
   for. The strip carries the panel's own bottom rule so the selected tab reads
   as attached to what is under it. */
.dtabs { display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin: -2px -16px 0; padding: 0 16px; }
.dtabs button {
  appearance: none; border: 0; background: none; font: inherit; font-size: 12.5px; font-weight: 620;
  color: var(--ink-3); padding: 8px 12px; border-radius: var(--r-sm) var(--r-sm) 0 0; cursor: pointer;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.dtabs button:hover { color: var(--ink); background: var(--brand-tint); }
.dtabs button.on { color: var(--brand); border-bottom-color: var(--brand); background: var(--brand-tint); }
.dtabs button:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.dpanel { display: none; }
.dpanel.on { display: block; }
.kv { display: grid; grid-template-columns: 118px 1fr; gap: 7px 12px; font-size: 13px; align-items: baseline; margin: 0; }
.kv dt { color: var(--ink-3); font-size: 12px; }
.kv dd { margin: 0; }
.kv dd.mono { font-family: var(--mono); font-size: 12px; word-break: break-all; }
.inline-edit { display: flex; gap: 7px; align-items: center; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 7px 9px; }
.inline-edit input { font: inherit; font-size: 13.5px; font-weight: 600; border: 0; background: transparent; color: var(--ink); flex: 1; min-width: 0; }
.inline-edit input:focus { outline: none; }
.toggle { display: inline-flex; align-items: center; gap: 7px; font-size: 12.5px; color: var(--ink-2); cursor: pointer; }
.toggle input { width: 15px; height: 15px; accent-color: var(--brand); }
.tl-row { display: grid; grid-template-columns: 78px 1fr; gap: 10px; padding: 7px 0; border-bottom: 1px solid var(--line-2); font-size: 12.5px; }
.tl-row:last-child { border-bottom: 0; }
.tl-when { font-family: var(--mono); font-size: 11px; color: var(--ink-3); }

/* ------------------------------------------------------------- misc states */
.empty { padding: 40px 20px; text-align: center; color: var(--ink-3); }
.empty h3 { margin: 0 0 6px; color: var(--ink); font-size: 15px; }
.screen { display: none; flex-direction: column; flex: 1; min-height: 0; }
.screen.on { display: flex; }
.toast {
  position: fixed; right: 16px; bottom: 16px; z-index: 60; max-width: 380px;
  background: var(--ink); color: var(--ground); padding: 10px 14px; border-radius: var(--r-sm);
  font-size: 13px; box-shadow: var(--shadow);
}
.toast.err { background: var(--crit); color: #fff; }

/* ------------------------------------------------------------------ login */
.login-wrap { min-height: 100vh; display: grid; place-items: center; padding: 24px; }
.login-card { width: min(390px, 100%); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow); padding: 26px; }
.login-card h1 { margin: 0 0 4px; font-size: 20px; letter-spacing: -.02em; }
.login-card p.sub { margin: 0 0 18px; font-size: 13px; color: var(--ink-3); }
.login-card form { display: flex; flex-direction: column; gap: 12px; }
.login-card .field input { width: 100%; }
.login-err { background: var(--crit-bg); color: var(--crit); font-size: 13px; padding: 8px 11px; border-radius: var(--r-sm); margin-bottom: 14px; }

@media (max-width: 900px) {
  .shell { grid-template-columns: 1fr; }
  .rail { flex-direction: row; flex-wrap: wrap; align-items: center; padding: 8px 10px; gap: 4px; }
  .rail-group { padding: 0; display: flex; gap: 2px; }
  .rail-label, .rail-foot, .rail-brand .rail-sub { display: none; }
  .split { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }

/* ---------------------------------------------- PW-E · approvals + settings */
/* Two screens the generic resource engine cannot express: a decision needs a
   reason box and a pair of committing buttons, and a settings row needs the
   control beside the explanation rather than under it. */
.field textarea {
  font: inherit; font-size: 13px; color: var(--ink); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 7px 9px; width: 100%; resize: vertical;
}
.field textarea:focus { outline: 2px solid var(--brand); outline-offset: 1px; }
.field .help { font-size: 11.5px; color: var(--ink-3); line-height: 1.45; }
/* An override with no stated reason is refused by the server; the label says so
   before the click, not after it. */
.field .req { color: var(--crit); font-weight: 650; }
/* .field input sets min-width:132px for text inputs — a checkbox inherits it and
   renders as a 132px box with the label shoved to the right. */
.field .toggle input[type="checkbox"] { min-width: 0; width: 15px; flex: none; padding: 0; }
.drawer-actions { display: flex; gap: 8px; flex-wrap: wrap; padding-top: 2px; }
.set-row { display: flex; gap: 14px; align-items: flex-start; padding: 11px 0; border-bottom: 1px solid var(--line-2); }
.set-row:last-child { border-bottom: 0; }
.set-lbl { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.set-lbl strong { font-family: var(--mono); font-size: 12px; font-weight: 600; color: var(--ink); }
.set-lbl .help { font-size: 11.5px; color: var(--ink-3); line-height: 1.45; }
/* Control column: fixed width on the right, its help text STACKED beneath the
   input/select (it used to run inline off the right edge). */
.set-ctl { flex: 0 0 auto; display: flex; flex-direction: column; align-items: stretch; gap: 5px; width: 340px; max-width: 44%; }
.set-ctl > input, .set-ctl > select {
  font: inherit; font-size: 13px; color: var(--ink); background: var(--surface-2);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 6px 9px; width: 100%; box-sizing: border-box;
}
.set-ctl .help { font-size: 11.5px; color: var(--ink-3); line-height: 1.45; }
.set-ctl .toggle { align-self: flex-start; }
.mono { font-family: var(--mono); font-size: 12px; }

/* Settings / Days-on-market: give stacked panels air, and let a section's blurb
   be a proper left-aligned subtitle rather than a cramped right-edge mono note. */
#set-body > .panel + .panel,
#dom-body > .panel + .panel { margin-top: 14px; }
.panel-head.stacked { align-items: flex-start; }
.set-hd { display: flex; flex-direction: column; gap: 2px; }
.set-hd h2 { line-height: 1.2; }
.set-hd .set-sub { font-family: var(--sans); font-size: 11.5px; font-weight: 400;
  letter-spacing: 0; text-transform: none; color: var(--ink-3); line-height: 1.45; max-width: 70ch; }

/* ------------------------------------------------------------- dashboard */
/* Period selector — segmented control living in the work-head spacer. */
.period { display: inline-flex; background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 2px; gap: 2px; }
.period button { appearance: none; border: 0; background: transparent; font: inherit; font-size: 12.5px; font-weight: 580; color: var(--ink-3); padding: 6px 12px; border-radius: 6px; cursor: pointer; white-space: nowrap; }
.period button:hover { color: var(--ink); }
.period button.on { background: var(--brand); color: var(--ground); }

.range-bar { display: flex; align-items: flex-end; gap: 12px; padding: 0 18px; flex-wrap: wrap; }
.range-bar[hidden] { display: none; }   /* display:flex above would otherwise defeat the hidden attribute */
.range-bar label { display: flex; flex-direction: column; gap: 4px; font-family: var(--mono); font-size: 9.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3); }
.range-bar input { font: inherit; font-size: 13px; color: var(--ink); background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 6px 9px; }

/* Band headings that group the two zones (activity / needs attention). */
.band-head { display: flex; align-items: baseline; gap: 10px; margin: 4px 0 0; }
.band-head + .act, .band-head + .split { margin-top: 2px; }
.band-head h2 { margin: 0; font-size: 14px; font-weight: 700; letter-spacing: -.01em; }
.band-head h2 span { color: var(--ink-3); font-weight: 600; }
.band-head .band-note { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--ink-3); }

/* Activity tiles — the "what changed in this period" headline numbers. */
.act { display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; }
.stat { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 13px 15px; }
.stat .k { font-size: 11.5px; color: var(--ink-3); font-weight: 600; }
.stat .v { font-size: 25px; font-weight: 750; letter-spacing: -.02em; color: var(--ink); line-height: 1; margin-top: 8px; font-variant-numeric: tabular-nums; }
.stat .sub { font-size: 11.5px; margin-top: 7px; line-height: 1.4; }
.stat .g { color: var(--ok); font-weight: 600; }
.stat .r { color: var(--crit); font-weight: 600; }
.stat .muted { color: var(--ink-3); }
@media (max-width: 1040px) { .act { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 620px) { .act { grid-template-columns: repeat(2, 1fr); } }

/* -------------------------------------------------------------- API usage */
.prov-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 12px; }
.prov { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); box-shadow: var(--shadow); padding: 14px 16px; }
.prov-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.prov-name { font-size: 13.5px; font-weight: 650; }
.prov-head .pill { margin-left: auto; }
.prov-nums { display: flex; align-items: baseline; gap: 4px; font-size: 22px; font-weight: 750; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.prov-nums .muted { font-size: 12.5px; font-weight: 500; }
.prov-pct { margin-left: auto; font-size: 12.5px; font-weight: 650; }
.prov-bar { height: 7px; border-radius: 100px; background: var(--line-2); overflow: hidden; margin: 9px 0 7px; }
.prov-fill { display: block; height: 100%; border-radius: 100px; background: var(--ok); }
.prov-fill.warn { background: var(--warn); } .prov-fill.crit { background: var(--crit); }
.prov-meta { font-size: 12px; }
.prov-note { font-size: 11px; margin-top: 6px; }
.prov .ok { color: var(--ok); font-weight: 600; } .prov .warn { color: var(--warn); font-weight: 600; } .prov .crit { color: var(--crit); font-weight: 600; }
.issue-list { display: flex; flex-direction: column; gap: 8px; }
.issue { display: flex; align-items: center; gap: 10px; font-size: 12.5px; color: var(--ink-2); }
.issue .pill { flex: 0 0 auto; }
.issue b { color: var(--ink); }

/* ------------------------------------------------------------ activity log */
.feed { display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden; background: var(--surface); }
.feed-row { display: flex; align-items: center; gap: 12px; padding: 11px 14px; border-bottom: 1px solid var(--line-2); }
.feed-row:last-child { border-bottom: 0; }
.feed-row:hover { background: var(--surface-2); }
.feed-row .pill { flex: 0 0 124px; justify-content: center; }
.feed-main { flex: 1; min-width: 0; }
.feed-head { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.feed-who { font-size: 12px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.feed-meta { flex: 0 0 auto; text-align: right; }
.feed-detail { font-size: 13px; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.feed-time { font-size: 10.5px; color: var(--ink-3); font-family: var(--mono); display: flex; align-items: center; gap: 6px; justify-content: flex-end; margin-top: 2px; }
.feed-src { color: var(--ink-3); text-decoration: none; font-size: 13px; }
.feed-src:hover { color: var(--brand); }
.feed-plotlink { color: inherit; text-decoration: none; border-bottom: 1px solid var(--line-2); }
.feed-plotlink:hover { color: var(--brand); border-bottom-color: var(--brand); }
.feed .cut { color: var(--crit); } .feed .rise { color: var(--ok); }
@media (max-width: 720px) { .feed-row .pill { flex-basis: auto; } .feed-detail { font-size: 12px; } }

/* ---------------------------------------------------------- data quality */
.q-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
.q-card { border: 1px solid var(--line, #e4e9e6); border-radius: 10px; padding: 12px 13px; }
.q-card-k { font-size: 12px; font-weight: 600; color: var(--ink-3, #6b7a72); }
.q-card-v { font-size: 24px; font-weight: 700; line-height: 1.2; margin: 2px 0 8px; font-variant-numeric: tabular-nums; }
.q-card-s { font-size: 11.5px; color: var(--ink-3, #6b7a72); margin-top: 7px; }
.q-bar { display: block; height: 6px; border-radius: 100px; background: var(--line-2, #eef2f0); overflow: hidden; }
.q-bar-fill { display: block; height: 100%; border-radius: 100px; }
.q-ok { background: #2f9e63; } .q-warn { background: #d99b28; } .q-bad { background: #cc4b3c; }
.q-note { font-size: 12.5px; color: var(--ink-3, #6b7a72); margin: 14px 0 0; }
.q-list { margin: 0; padding-left: 18px; font-size: 13px; }
.q-list li { margin: 4px 0; }
/* The AI panel is visually distinct on purpose: everything inside it is
   generated prose, everything outside it is measured. */
.q-ai { font-size: 13.5px; line-height: 1.6; }
.q-ai p { margin: 0 0 10px; }
.q-ai ul { margin: 0 0 12px; padding-left: 20px; }
.q-ai li { margin: 4px 0; }
.q-ai strong { font-weight: 650; }

/* ------------------------------------------------------ builder analysis */
/* The gate has always been a sequence, so the screen is a stepper rather than
   a page of cards: what is done, what is now, what is still ahead. */
.steps { display: flex; align-items: flex-start; flex-wrap: wrap; gap: 0; margin: 0 0 16px; }
.stp { display: flex; align-items: center; gap: 9px; padding-right: 8px; }
.stp .dot { width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  font-size: 11.5px; font-weight: 700; flex: none; border: 1.5px solid var(--line);
  background: var(--surface); color: var(--ink-3); }
.stp.done .dot { background: var(--ok); border-color: var(--ok); color: #fff; }
/* Waiting on you: the same tick as the rest of the rail, distinguished only by
   its colour — the darker brand green against the completion green.
   
   It has been through a "4", a hollow ring and a pulse, and each of those made
   it the odd one out in a row of five. The label under it already says "needs
   your tick"; the rail does not need to wave as well. The one thing on this
   screen that blinks is the LADDER TESTED pill, which is the state actually
   worth catching from across a desk. */
.stp.now .dot { background: var(--brand); border-color: var(--brand); color: #fff; }
.stp .txt { display: flex; flex-direction: column; line-height: 1.25; white-space: nowrap; }
.stp .txt b { font-size: 12.5px; font-weight: 650; }
.stp.todo .txt b { color: var(--ink-3); font-weight: 600; }
.stp .txt em { font-style: normal; font-size: 10.5px; color: var(--ink-3); font-family: var(--mono); }
.stp .bar { width: 26px; height: 1.5px; background: var(--line); margin: 0 4px; }
.stp.done .bar { background: var(--ok); }
@media (max-width: 1100px) { .stp .bar { display: none } .steps { gap: 14px } }

.ba-n { width: 21px; height: 21px; border-radius: 5px; background: var(--brand); color: #fff;
  display: inline-grid; place-items: center; font-size: 11px; font-weight: 700; margin-right: 8px; vertical-align: -4px; }
.panel.ba-todo { opacity: .72 }
.panel.ba-todo .ba-n { background: var(--line); color: var(--ink-3) }
.panel.ba-now { box-shadow: 0 0 0 2px color-mix(in srgb, var(--brand) 22%, transparent), var(--shadow) }

.ba-fields { display: grid; grid-template-columns: 150px 1fr; gap: 9px 14px; align-items: center; font-size: 13px; }
.ba-fields label { font-size: 10.5px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); }
.ba-fields input { width: 100%; padding: 7px 10px; border: 1px solid var(--line); border-radius: var(--r-sm);
  font-family: var(--mono); font-size: 11.5px; background: var(--surface-2); color: var(--ink); }

.mtx { width: 100%; border-collapse: collapse; font-size: 13px; }
.mtx th { font-size: 9.5px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
  padding: 9px 6px; border-bottom: 1px solid var(--line); text-align: center; background: var(--surface-2); }
.mtx th:first-child { text-align: left; padding-left: 16px; }
.mtx th.rt { font-family: var(--mono); text-transform: none; letter-spacing: 0; font-size: 10.5px; }
.mtx td { padding: 9px 6px; border-bottom: 1px solid var(--line-2); text-align: center; }
.mtx tr:last-child td { border-bottom: 0; }
/* FIXED width, not min-width: the level column used to grow to whatever the
   longest URL needed, which squeezed the route squares — the thing the screen
   exists to show — and made the grid jump as each row's URL appeared. */
.mtx td.lv { text-align: left; padding-left: 16px; line-height: 1.35; width: 400px; }
.mtx td.lv .lv-h { display: flex; align-items: center; gap: 7px; }
.mtx td.lv .lv-h b { font-size: 13px; }
.mtx td.lv .lv-none { display: block; margin-top: 3px; font-family: var(--mono); font-size: 10px;
  color: var(--ink-3); font-style: italic; }
/* The URL is a LINK, carries data-tip with the whole thing, and is split into
   host / middle / tail so only the MIDDLE is ever cut.
     bloorhomes.com  /new-homes/staffordshire/burton-on-trent  /plot-222
     └─ which site     └─ the only part nobody reads             └─ which page
   Trimming from the left instead loses the tail, and on a deep path that makes
   the development row and the plot row read identically — exactly when you need
   to tell them apart. The middle absorbs the overflow; host and tail never
   shrink, and the tail is capped so a long query string (Cameron's region level
   is /homes-for-sale?location=&lat=&lng=) cannot push the grid sideways. Full
   URL on hover regardless — see the #cptip controller.

   max-width is 100%, not a pixel figure: it was 300px against a 320px cell, so
   the URL was clipped 20px before the cell ended and would not have followed the
   column when it was widened. Tied to the cell, one width to change, not two. */
.mtx td.lv .lv-split { display: flex; align-items: baseline; margin-top: 3px; max-width: 100%;
  font-family: var(--mono); font-size: 10px; text-decoration: none; cursor: help; }
.mtx td.lv .lv-split .host { flex: 0 0 auto; white-space: nowrap; color: var(--ink-3); opacity: .72; }
/* SHRINK but never GROW. `flex: 1 1 auto` let the middle expand into whatever
   space was spare, which pushed the tail to the far edge of the cell and left a
   gap in the middle of a URL — newhomes.lovell.co.uk/developments   /swinfen-vale
   read as two things rather than one address. `0 1 auto` still absorbs the
   overflow when the URL is too long, which is the only job it has. */
.mtx td.lv .lv-split .mid { flex: 0 1 auto; min-width: 0; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; color: var(--ink-3); opacity: .5; }
.mtx td.lv .lv-split .tail { flex: 0 0 auto; max-width: 62%; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; color: var(--ink-2); font-weight: 600; }
.mtx td.lv .lv-split:hover .host, .mtx td.lv .lv-split:focus-visible .host,
.mtx td.lv .lv-split:hover .mid, .mtx td.lv .lv-split:focus-visible .mid { opacity: .85; }
.mtx td.lv .lv-split:hover .tail, .mtx td.lv .lv-split:focus-visible .tail { color: var(--brand); }
/* Per-row re-probe. Always PRESENT, deliberately quiet: hidden-until-hover is
   the classic way to ship a feature nobody finds, and this one exists precisely
   for the moment a row fails and you want to retest it without paying for the
   whole matrix. Low contrast keeps four of them from competing with the grid;
   the row hover brings it up to full. */
/* Spacing and alignment come from .lv-h's flex gap now, not a margin and a
   vertical-align nudge — those were compensating for an inline layout the cell
   no longer uses, and left as they were they double the gap. */
.mtx td.lv .lv-re { flex: 0 0 auto; width: 19px; height: 19px; padding: 0;
  border: 1px solid var(--line); border-radius: 5px; background: var(--surface-2); color: var(--ink-3);
  font-size: 11px; line-height: 1; cursor: pointer; opacity: .45; transition: opacity .12s ease; }
@media (prefers-reduced-motion: reduce) { .mtx td.lv .lv-re { transition: none; } }
.mtx tr:hover .lv-re, .mtx .lv-re:focus { opacity: 1; }
.mtx td.lv .lv-re:hover { border-color: var(--brand); color: var(--brand); }
.mtx td.lv .lv-re:disabled { cursor: default; opacity: .35; }
.mtx td.c { font-weight: 800; font-size: 14px; cursor: help; }
.mtx td.c em { display: block; font-style: normal; font-weight: 500; font-size: 9.5px; color: var(--ink-3); }
.mtx td.c.ok { color: var(--ok); background: var(--ok-bg); }
.mtx td.c.no { color: var(--crit); background: var(--crit-bg); }

.ba-res { display: grid; grid-template-columns: repeat(4, 1fr); border-top: 1px solid var(--line-2); }
.ba-res > div { padding: 11px 16px; border-right: 1px solid var(--line-2); }
.ba-res > div:last-child { border-right: 0; }
.ba-res .k { font-size: 9.5px; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3); }
.ba-res .v { font-size: 18px; font-weight: 700; margin-top: 2px; }
.ba-res .x { font-size: 11px; color: var(--ink-3); }
.ba-pre { background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 11px 13px; font-family: var(--mono); font-size: 11px; line-height: 1.65; overflow-x: auto;
  margin: 0; color: var(--ink-2); white-space: pre; }
.ba-hint { font-size: 12px; color: var(--ink-3); margin: 9px 0 0; }
.ba-row { display: flex; gap: 9px; align-items: center; flex-wrap: wrap; margin-top: 10px; }

/* ── Builder analysis · layout ──────────────────────────────────────────────
   The screen's own sections have to carry the same 18px gutter as .work-head,
   or the stepper and panels sit flush against the rail while the title above
   them is inset. */
#ba-steps, #ba-body, #ba-newbuilder { padding: 0 18px; }
#ba-steps { padding-top: 12px; padding-bottom: 4px; }
#ba-body > .panel + .panel { margin-top: 12px; }

/* A URL is about 90 characters. Left to stretch, these fields ran the full
   1,500px of a wide screen, which reads as a form that has lost its shape and
   makes the label column look detached from what it labels. */
.ba-fields { max-width: 1080px; align-items: center; }
.ba-fields input { max-width: 760px; }
.ba-fields label { padding-top: 0; }

/* The note beside a button is a hint, not body copy. At 13px inline it competed
   with the button it was explaining. */
.ba-row .note { font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); }

/* Builder picker: a name plus a short suffix, not an essay. */
#ba-builder { max-width: 260px; }

/* The stepper is navigation, so its items are buttons. A step you have not
   reached is not clickable — opening step 4 early just shows an empty panel. */
.stp { background: none; border: 0; font-family: inherit; cursor: pointer; text-align: left; padding: 4px 8px 4px 0; }
.stp[disabled] { cursor: default; }
.stp:not([disabled]):hover .txt b { color: var(--brand); }
.stp.open .txt b { color: var(--brand); }
.stp.open .dot { box-shadow: 0 0 0 4px color-mix(in srgb, var(--brand) 18%, transparent); }
.stp.locked { opacity: .55; }
/* Back and Next belong together, with the counter beside them. Spreading them
   to opposite edges of a 1,700px screen left "Step 1 of 6" marooned in the
   middle and put Next a screen-width from Back. */
.ba-nav { display: flex; align-items: center; justify-content: flex-end; gap: 10px;
  margin: 12px 0 0; padding: 11px 13px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--r-sm); }
.ba-nav .count { margin-right: auto; font-family: var(--mono); font-size: 11px; color: var(--ink-3); }
.ba-nav .btn[disabled] { opacity: .45; cursor: default; }

/* "Switch to <builder>" — the picker is for changing which builder you are on,
   not for identifying it. The one being worked on is the page title. */
.ba-switch { display: inline-flex; align-items: center; gap: 6px; font-family: var(--mono);
  font-size: 10.5px; color: var(--ink-3); text-transform: uppercase; letter-spacing: .06em; }
.ba-switch select { text-transform: none; letter-spacing: 0; font-family: var(--ui); font-size: 12.5px; }

/* Choosing a builder lives in step 1, because step 1 is "Define the builder"
   and which builder is the first thing that defines it. */
.ba-chosen { display: flex; align-items: center; gap: 10px; padding: 0 0 12px;
  margin-bottom: 12px; border-bottom: 1px solid var(--line-2); }
.ba-chosen .k { font-size: 10.5px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--ink-3); width: 150px; flex: none; }
.ba-chosen .v { font-size: 14px; font-weight: 650; }
.ba-chosen .m { font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); }
.ba-chosen .btn { margin-left: auto; }

.ba-pick-tabs { display: inline-flex; background: var(--surface-2); border: 1px solid var(--line);
  border-radius: 100px; padding: 2px; gap: 2px; margin-bottom: 12px; }
.ba-tab { border: 0; background: none; font-family: inherit; font-size: 12px; font-weight: 600;
  color: var(--ink-3); padding: 5px 13px; border-radius: 100px; cursor: pointer; line-height: 1; }
.ba-tab:hover { color: var(--ink-2); }
.ba-tab.on { background: var(--brand); color: #fff; }

.ba-search { width: 100%; max-width: 420px; padding: 7px 10px; border: 1px solid var(--line);
  border-radius: var(--r-sm); font: inherit; font-size: 13px; background: var(--surface-2);
  color: var(--ink); margin-bottom: 10px; }
/* The list takes the window it is given. A fixed 300px was set when there were
   26 builders and it scrolled a little; at 34 it scrolled a lot while half the
   screen below sat empty, so the picker was a letterbox onto a list that would
   have fitted. It still scrolls on a short window — the floor is 260px — and it
   costs the rest of the flow nothing, because choosing a builder replaces this
   whole block with the one-line summary.

   align-content:start matters: a grid stretches its rows to fill spare height
   by default, so a search narrowed to two builders would otherwise draw two
   cards half a screen tall. */
.ba-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 6px; max-height: max(260px, calc(100vh - 330px)); overflow-y: auto; padding-right: 4px;
  align-content: start; }
.ba-item { display: flex; flex-direction: column; gap: 2px; text-align: left; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm);
  padding: 8px 11px; font-family: inherit; }
.ba-item:hover { border-color: var(--brand); background: var(--brand-tint); }
.ba-item.on { border-color: var(--brand); box-shadow: inset 2px 0 0 var(--brand); }
.ba-item .nm { font-size: 13px; font-weight: 600; color: var(--ink); }
.ba-item .mt { font-family: var(--mono); font-size: 10.5px; color: var(--ink-3); }

/* Live probe: the grid is the same one the finished matrix uses, so the panel
   does not rearrange itself when the run ends — cells stop being pending. */
.ba-prog { height: 3px; background: var(--line-2); overflow: hidden; }
.ba-prog-bar { height: 100%; background: var(--brand); transition: width .4s ease; }
.mtx td.c.wait { color: var(--ink-3); background: var(--surface-2); font-weight: 400; }
.mtx td.c.busy { background: var(--brand-tint); }
.spin { display: inline-block; width: 12px; height: 12px; border: 2px solid var(--brand);
  border-right-color: transparent; border-radius: 50%; animation: ba-spin .7s linear infinite; }
@keyframes ba-spin { to { transform: rotate(360deg) } }
@media (prefers-reduced-motion: reduce) { .spin { animation: none } }

/* Step 3 phases. Not a matrix — a short sequence — so it reads as a list, with
   the detail line carrying what each phase actually found: the route and page
   size, the model and its proposal, the count it parsed. */
.ba-job-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 10px; }
.ba-phases { list-style: none; margin: 0; padding: 0; }
.ba-phases .ph { display: grid; grid-template-columns: 18px 1fr auto; gap: 4px 8px;
  align-items: baseline; padding: 7px 0; border-top: 1px solid var(--line-2); }
.ba-phases .ph:first-child { border-top: 0; }
.ba-phases .ph-t { font-size: 13px; color: var(--ink); }
.ba-phases .ph.wait .ph-t { color: var(--ink-3); }
.ba-phases .ph-d { grid-column: 2 / -1; font-family: var(--mono); font-size: 11px; color: var(--ink-3); }
.ba-phases .ph-ms { font-family: var(--mono); font-size: 11px; color: var(--ink-3); }
.ba-phases .ok { color: var(--ok); }
.ba-phases .bad { color: var(--crit); }
.ba-phases .wait { color: var(--ink-3); }

/* ------------------------------------------------------- page gutter fix --
   Every chrome element uses an 18px gutter — .work-head, .toolbar, .chips,
   .bulkbar, .foot, .body-pad. Table cells used 12px and .table-wrap adds none,
   so every table sat 6px left of its own heading and hard against the rail.
   Measured: heading text at 232px, table text at 226px.

   Fixed on the OUTER cells only, so the gutter matches the rest of the page
   without touching the spacing between columns.

   #screen-analysis is excluded deliberately — Builder Analysis is being built
   in a parallel session and was asked to be left alone. */
/* Superseded by .screen-body below: every table now sits inside a panel that
   already carries the gutter, so widening the outer cells would double it. A
   table inside a card is legitimately inset from the card edge. */

/* Screens that render their panels straight into a bare <div id="…-body"> had
   no gutter at all — the card sat on 214px, flush against the rail.
   Matched by SHAPE rather than by id: Settings and Data quality were fixed by
   name, then Days on market arrived a day later with exactly the same markup
   and exactly the same bug. Anything following the convention now inherits the
   gutter instead of waiting to be noticed.
   #ba-body is excluded outright rather than left to specificity: its own rule
   sets padding but not display, so this one would still have imposed flex and a
   14px gap on top of its `.panel + .panel { margin-top: 12px }`, quietly
   changing a screen that was asked to be left alone. */
.screen > div[id$="-body"]:not(#ba-body) { padding: 16px 18px 24px; display: flex; flex-direction: column; gap: 14px; }

/* A screen body that renders raw content rather than panels still needs the
   card, or the gutter alone leaves a table floating on the canvas. */
.screen > div[id$="-body"]:not(#ba-body) > .table-wrap,
.screen > div[id$="-body"]:not(#ba-body) > table {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-sm); overflow: hidden;
}

/* ------------------------------------------- screen body: card in a gutter --
   The Builder Analysis layout, applied to every screen that had a full-bleed
   toolbar and table running edge to edge into the rail. Controls, table and
   footer are now one bordered card inset by the page gutter, so a screen reads
   as an object on the canvas rather than as content poured into the window.

   The card is a plain .panel, which already carries the border, radius and
   overflow:hidden that clips the toolbar and footer corners — so the parts keep
   their own dividers and need no special casing. */
.screen-body { padding: 14px 18px 24px; }

/* Inside the card these are internal dividers, not page-width rules, so they
   lose the edge-to-edge look they had when they were the page. */
.screen-body .toolbar,
.screen-body .chips,
.screen-body .bulkbar { border-bottom: 1px solid var(--line-2); }
.screen-body .foot { border-top: 1px solid var(--line-2); }

/* A table filling the card needs no bottom rule on its last row — the card edge
   or the footer border already provides one. */
.screen-body .table-wrap tbody tr:last-child td { border-bottom: 0; }

/* ---------------------------------------------- step 3: the data it returned
   Two shapes, because the pages are two shapes: the development page is a list
   (a row per house type or per plot) and the plot page is a set of fields. */
.ba-sub { display: flex; align-items: baseline; gap: 10px; margin: 0 0 8px; }
.ba-sub.mt { margin-top: 22px; }
.ba-sub h3 { margin: 0; font-size: 14px; font-weight: 640; letter-spacing: -.01em; }
.ba-shape { margin: 0 0 10px; font-size: 12.5px; color: var(--ink-2); }
.ba-warn { margin: 8px 0 0; font-size: 12.5px; color: var(--warn); }
.ba-data td, .ba-data th { font-size: 12.5px; }
.ba-data td.nm { font-weight: 600; }
/* A row that matched the marker but carries no plot value. Greyed rather than
   dropped: on a region page a name-only row can be a real development, so the
   table keeps it and the note under the table says how many there are. */
.ba-data tr.no-val td { color: var(--ink-3); background: var(--surface-2); }
.ba-data tr.no-val td.nm { font-weight: 400; font-style: italic; }
.ba-data td.n, .ba-data th.n { text-align: right; font-variant-numeric: tabular-nums; }
.dash { color: var(--ink-3); }
/* Plot numbers are the join between a house type and its plots, so they are
   shown in full rather than truncated — that list IS the finding. */
.ba-plots { display: flex; flex-wrap: wrap; gap: 3px; max-width: 360px; }
.ba-plots i { font-style: normal; font-family: var(--mono); font-size: 10.5px;
  background: var(--surface-2); border: 1px solid var(--line-2); border-radius: 4px; padding: 0 4px; }
.ba-kv td { font-size: 12.5px; }
.ba-kv td.k { width: 150px; font-family: var(--mono); font-size: 11px;
  color: var(--ink-3); text-transform: uppercase; letter-spacing: .06em; }
.ba-fallback { margin-top: 18px; padding: 12px 14px; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: var(--surface-2); font-size: 12.5px; color: var(--ink-2); }

/* The route picker sits with the button, not above it: choosing a provider and
   reading with it are one action. */
.ba-readrow { flex-wrap: wrap; }
.ba-routepick { display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--mono); font-size: 11px; color: var(--ink-3); }
.ba-routepick select { font: inherit; font-family: var(--ui); font-size: 12.5px; color: var(--ink);
  background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm); padding: 5px 8px; }
.ba-routepick select:focus { outline: 2px solid var(--brand); outline-offset: 1px; }

/* A re-run inside a day is usually a mis-click and costs ~28 live fetches.
   Warned in place, not in a dialog: the modal was removed from this screen
   deliberately, and the honest answer is sometimes "yes, run it again". */
/* 12px top and nothing below — the same rhythm .ba-nav uses, so panel, warning
   and nav are evenly spaced instead of the warning sitting hard against the
   frame above it. The gap below comes from .ba-nav's own top margin. */
.ba-recent { margin: 12px 0 0; padding: 10px 13px; border-radius: var(--r-sm);
  border: 1px solid var(--warn); background: var(--warn-bg); color: var(--ink-2); font-size: 12.5px; }
.ba-recent b { color: var(--ink); }
/* The note that carries an empty step 3 forward. Full width and three rows
   deep because what goes in it is a sentence about where the plot list is, not
   a label — a one-line input invited "n/a". */
.ba-note { display: block; width: 100%; margin: 9px 0 0; padding: 8px 10px; box-sizing: border-box;
  border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface-2);
  color: var(--ink); font-family: inherit; font-size: 12.5px; line-height: 1.5; resize: vertical; }
.ba-note:focus { outline: 2px solid var(--brand); outline-offset: 1px; }
/* The same note once it is saved, read back rather than re-offered for editing. */
.ba-quote { margin: 9px 0 0; padding: 8px 11px; border-left: 2px solid var(--warn);
  background: var(--surface-2); color: var(--ink); font-size: 12.5px; line-height: 1.5; }
.btn-warn { background: var(--warn); border-color: var(--warn); color: #fff; }
.btn-warn:hover { border-color: var(--warn); filter: brightness(1.05); }

/* Derived, not observed. Marked in place rather than in a footnote: this
   builder answers an invented plot number with HTTP 200 and the house-type
   page, so a wrong guess looks exactly like a right one. */
.ba-data .drv { font-style: normal; color: var(--warn); font-weight: 700; margin-left: 3px; cursor: help; }
.ba-derived { margin: 9px 0 0; font-size: 12px; color: var(--ink-2); line-height: 1.55; }
.ba-derived b { color: var(--ink); }

/* The same external-link button the customer-facing app puts on every plot row
   (PlotWatchApp assets/app.css .plot-link), so a plot reads the same in both
   places. Status uses the CP's own pill tokens with the product's vocabulary:
   reserved, sold and withdrawn are ONE "Reserved or Sold". */
.plot-link { display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 7px; color: var(--ink-3);
  transition: background .12s, color .12s; }
.plot-link:hover { background: var(--brand-tint); color: var(--brand); }
.ba-data td.lk { width: 60px; text-align: center; padding-left: 4px; padding-right: 4px; }

/* A row the data says needs attention. Its own token rather than --crit-bg:
   that colour is tuned for a pill a few characters wide, and filling whole rows
   with it makes a list of 114 look like a list of failures. This is a wash you
   can scan past on the rows that are fine.

   The tint survives :hover deliberately — with only the default hover rule, the
   one row you are pointing at is the one row that stops looking wrong. */
:root { --stall-bg: #FDF6F4; }
@media (prefers-color-scheme: dark) { :root { --stall-bg: #1F1614; } }
:root[data-theme="dark"] { --stall-bg: #1F1614; }
:root[data-theme="light"] { --stall-bg: #FDF6F4; }
tr.row-stalled td, tr.row-stalled:hover td { background: var(--stall-bg); }

/* ── Generate PDF Deck ─────────────────────────────────────────────────────
   The screen follows the same skeleton as Developments — screen-body > panel >
   toolbar > chips > body > foot — and the controls reuse .field, .toggle and
   the saved-views .chip. Only three things here are genuinely new: the stat
   strip, the caveat box, and the preview frame. Everything else the panel
   already knew how to draw, and inventing a parallel set of control styles is
   what made this screen look like a different product. */

/* ── The builder bar ──────────────────────────────────────────────────────
   The CP's own surfaces are near-white on a near-white ground, which is right
   for screens you read and wrong for the one screen you OPERATE. These controls
   wear the forest the deck itself is printed in, so they carry weight on the
   page and look like what they make.

   The colour is FIXED, not --rail. Against the light ground either would work,
   but in dark mode --rail (#0A100D) is a shade off --ground (#0D1310) and the
   bar disappeared completely — the exact fault this was built to fix. #22332C
   is darker than the light ground and lighter than the dark one, so it lifts
   off both. Everything inside it is therefore fixed too: theme tokens over a
   constant background would put near-black text on it in light mode. This is
   the only place in the panel that leaves the palette on purpose. */
.deck-bar {
  background: #22332C; border-radius: var(--r); overflow: hidden;
  box-shadow: var(--shadow); margin-bottom: 14px;
}
/* ── The three sections ───────────────────────────────────────────────────
   Housebuilder, Regions, Generate — all exactly the same height.

   That height comes from REGIONS' worst case: a builder trading in all twelve
   wraps to two lines of chips, which needs ~124px with the header and padding.
   Sizing every section to that means the bar is a constant height whatever
   builder is chosen, so Generate never walks up and down the page under the
   cursor between one builder and the next.

   `grid-auto-rows: 1fr` does the equalising rather than a min-height on each,
   so if a narrow window ever wraps the chips to a third line all three sections
   grow together and stay level. */
.deck-bar.dk-rows { --dk-h: 124px; display: grid; grid-auto-rows: 1fr; min-height: calc(var(--dk-h) * 3); }
.dk-sect { display: flex; flex-direction: column; gap: 9px; padding: 14px 18px; }
.dk-sect + .dk-sect { border-top: 1px solid rgba(255, 255, 255, .09); }
.dk-sect-h { display: flex; align-items: center; gap: 9px; font-size: 12.5px; font-weight: 650; color: #EAF2EE; }
.dk-n {
  display: grid; place-items: center; width: 19px; height: 19px; border-radius: 50%;
  background: rgba(255, 255, 255, .13); color: #C8D8D0;
  font-family: var(--mono); font-size: 10.5px; font-weight: 650; flex: none;
}
.dk-note {
  margin-left: auto; font-family: var(--mono); font-size: 11px;
  font-weight: 400; letter-spacing: .04em; color: #8FA79B;
}
.dk-sect-b { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; flex: 1; }
.dk-go { margin-left: auto; }

/* ── The builder combobox ─────────────────────────────────────────────────
   28 builders today and more coming, so the picker has to be typed into. */
.dk-search { position: relative; width: 340px; max-width: 100%; }
.dk-mag {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  width: 15px; height: 15px; color: #8FA79B; pointer-events: none;
}
.dk-input {
  width: 100%; padding: 9px 32px 9px 33px; border-radius: var(--r-sm);
  font: inherit; font-size: 13px;
  background: rgba(255, 255, 255, .07); border: 1px solid rgba(255, 255, 255, .18); color: #EAF2EE;
}
.dk-input::placeholder { color: #7E948B; }
.dk-input:focus { outline: 2px solid var(--brand-soft); outline-offset: 1px; }
.dk-clear {
  position: absolute; right: 7px; top: 50%; transform: translateY(-50%);
  width: 20px; height: 20px; border: 0; border-radius: 50%; cursor: pointer;
  background: rgba(255, 255, 255, .12); color: #C8D8D0; font-size: 14px; line-height: 1;
}
.dk-clear:hover { background: rgba(255, 255, 255, .2); color: #fff; }
.dk-drop {
  position: absolute; left: 0; right: 0; top: calc(100% + 5px); z-index: 20;
  background: #18251F; border: 1px solid rgba(255, 255, 255, .16); border-radius: var(--r-sm);
  box-shadow: 0 12px 30px -10px rgba(0, 0, 0, .6); overflow: auto; max-height: 260px;
}
.dk-opt { display: flex; align-items: baseline; gap: 9px; padding: 8px 12px; font-size: 13px; color: #C8D8D0; cursor: pointer; }
.dk-opt.on, .dk-opt:hover { background: rgba(127, 168, 149, .2); color: #fff; }
.dk-opt b { font-weight: 560; }
.dk-opt u { text-decoration: none; background: rgba(127, 168, 149, .35); border-radius: 2px; padding: 0 1px; }
.dk-opt span { margin-left: auto; font-family: var(--mono); font-size: 11px; color: #8FA79B; }
.dk-empty { padding: 10px 12px; font-size: 12.5px; color: #8FA79B; }

.deck-bar .toolbar { background: transparent; border-bottom-color: rgba(255, 255, 255, .09); }
.deck-bar .chips { background: transparent; border-bottom: 0; padding: 0; }
.deck-bar .field label, .deck-bar .lead, .deck-bar .muted { color: #8FA79B; }
.deck-bar .field select {
  background: rgba(255, 255, 255, .07); border-color: rgba(255, 255, 255, .18); color: #EAF2EE;
}
.deck-bar .field select:focus { outline-color: var(--brand-soft); }
/* Specific enough to beat `.toolbar .field .toggle` below, which sets --ink-2
   and was painting near-black text onto the dark bar. */
.deck-bar .toolbar .field .toggle { color: #C8D8D0; }
.deck-bar .chip {
  background: rgba(255, 255, 255, .06); border-color: rgba(255, 255, 255, .17); color: #C8D8D0;
}
.deck-bar .chip:hover { border-color: #7FA895; }
.deck-bar .chip-tick input { accent-color: #7FA895; }
.deck-bar .chip-tick.on { background: rgba(127, 168, 149, .22); border-color: #7FA895; color: #EAF2EE; }
/* The primary button has to lift off a dark ground, not sink into it. */
.deck-bar .btn-primary { background: #4E7A66; border-color: #4E7A66; color: #fff; }
.deck-bar .btn-primary:hover:not(:disabled) { background: #5B8C76; border-color: #5B8C76; }
.deck-bar .btn:disabled { background: rgba(255, 255, 255, .09); border-color: rgba(255, 255, 255, .14); color: #8FA79B; }

/* Where the deck lands. An empty white expanse read as a broken screen; three
   slide shapes and a sentence say the space is waiting, not failed. */
.deck-stage {
  border: 1.5px dashed var(--line); border-radius: var(--r); background: var(--surface-2);
  min-height: 260px; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 8px; text-align: center; padding: 24px;
}
.deck-stage b { font-size: 15px; font-weight: 640; }
.deck-stage span { font-size: 12.5px; color: var(--ink-3); }
.deck-stage-slides { display: flex; gap: 9px; margin-bottom: 4px; }
.deck-stage-slides i { width: 74px; height: 42px; border-radius: 4px; background: var(--surface); border: 1px solid var(--line); }
/* Matched to the bar, for the same reason — against the dark ground a --rail
   thumbnail was invisible. */
.deck-stage-slides i:first-child { background: #22332C; border-color: #22332C; }
/* The foot is no longer inside a panel, so it must not draw a panel's edge. */
#screen-deck .foot { background: transparent; border-top: 0; padding: 12px 2px 0; }

/* `.field label` is mono/uppercase for the field's own caption, and it matches
   ANY label inside — including the toggle, whose sentence was being shouted in
   9.5px small caps. Put the sentence back into UI type. */
.toolbar .field .toggle {
  font-family: var(--ui); font-size: 12.5px; letter-spacing: 0;
  text-transform: none; color: var(--ink-2);
}

/* A region chip carries a REAL checkbox. Which regions a deck covers is the one
   choice here that changes what the customer ends up reading, and a chip that
   differs only by tint is too easy to misread at a glance. The chip shape is
   kept so the row still matches the saved-views row it sits in the place of.
   `.on` is set from JS rather than with :has(), to stay in step with how the
   rest of the panel tracks selection. */
.chips .chip-tick { display: inline-flex; align-items: center; gap: 7px; }
.chips .chip-tick input { width: 14px; height: 14px; margin: 0; accent-color: var(--brand); flex: none; }
.chips .chip-tick.on { background: var(--brand-tint); border-color: var(--brand-soft); color: var(--brand); font-weight: 620; }
.chips .deck-all { font-family: var(--mono); font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; }

.deck-summary { display: flex; flex-wrap: wrap; gap: 26px; padding: 2px 0 16px; }
.deck-stat { display: flex; flex-direction: column-reverse; gap: 3px; }
.deck-stat span, .deck-stat { font-family: var(--mono); font-size: 9.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3); }
.deck-stat b {
  font-family: var(--ui); font-size: 23px; font-weight: 680; color: var(--ink);
  letter-spacing: -.025em; text-transform: none; font-variant-numeric: tabular-nums;
}
.deck-stat-warn b { color: var(--crit); }

.deck-warn {
  border: 1px solid var(--line); background: var(--warn-bg); border-radius: var(--r-sm);
  padding: 11px 14px; margin-bottom: 14px; font-size: 12.5px; color: var(--ink-2);
}
.deck-warn b { display: block; margin-bottom: 4px; color: var(--warn); }
.deck-warn ul { margin: 0; padding-left: 17px; }

/* The stage a slide sits on. The deck is a light document whatever the panel is
   wearing — it is going to a printer — so this ground is the deck's own page
   colour, not a theme token. A whole 16:9 slide is fitted inside it, so the
   margin around it is deliberate staging, as in any presentation app. */
.deck-preview {
  border: 1px solid var(--line); border-radius: var(--r-sm); overflow: hidden;
  background: #dfe6e2; height: 560px;   /* replaced on render from the slide size */
}
/* Width and zoom are set on render from the container's real width, so a slide
   always fits whatever the window is doing. These are the pre-measure state.
   `zoom` is display-only — print reads the document's own layout — so nothing
   here can change what comes out of the printer. */
.deck-preview iframe { width: 1280px; border: 0; display: block; margin: 0 auto; zoom: .5; }

/* ── Sign-in activity (approvals drawer) ───────────────────────────────────
   A compact three-column list: when, from where, on what. Deliberately not a
   full table — twenty rows in a drawer is a list, and a table's furniture would
   cost more room than the data. */
.lite-list { margin-top: 9px; border-top: 1px solid var(--line-2); }
.row-lite {
  display: grid; grid-template-columns: 1fr auto 1fr; gap: 12px; align-items: baseline;
  padding: 6px 0; border-bottom: 1px solid var(--line-2); font-size: 12.5px;
}
.row-lite:last-child { border-bottom: 0; }
.row-lite .mono { font-family: var(--mono); font-size: 11.5px; color: var(--ink-2); }
.row-lite span:last-child { text-align: right; }

/* One visit, openable. Collapsed by default because the question is almost
   always "what did they just do" — the older sessions are context, not the
   answer, and a drawer that opens six timelines at once answers nothing. */
.act-session .act-body { display: none; padding: 4px 0 8px 0; }
.act-session.open .act-body { display: block; }
.act-head { cursor: pointer; }
.act-head:hover { background: var(--brand-tint); }
.act-ev { display: grid; grid-template-columns: 44px 1fr; gap: 10px; align-items: baseline;
  font-size: 12.5px; padding: 3px 0; border-left: 1px solid var(--line); margin-left: 18px; padding-left: 12px; }
.act-ev .mono { font-family: var(--mono); font-size: 11px; color: var(--ink-3); }

/* ── "Ladder tested" — all five analysis steps pass ────────────────────────
   One reading, two places: the rail on a builder's own page and the card in the
   browse list. The verdict is computed on the server (fiveGreen in cp/router.js)
   so the two can never disagree.

   It blinks because it is the one thing on that screen worth spotting without
   reading it — but a blink is motion, and motion is not free for everyone, so
   prefers-reduced-motion gets a steady dot with the same colour and meaning. */
.blip {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: var(--ok); flex: none;
  box-shadow: 0 0 0 0 color-mix(in srgb, var(--ok) 60%, transparent);
  animation: blip 1.6s ease-out infinite;
}
@keyframes blip {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--ok) 55%, transparent); opacity: 1; }
  70%  { box-shadow: 0 0 0 6px color-mix(in srgb, var(--ok) 0%, transparent); opacity: .55; }
  100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--ok) 0%, transparent); opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .blip { animation: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 20%, transparent); }
}

.ba-live {
  display: inline-flex; align-items: center; gap: 7px; margin-left: 10px;
  padding: 5px 11px; border-radius: 100px; white-space: nowrap;
  background: var(--ok-bg); color: var(--ok); border: 1px solid color-mix(in srgb, var(--ok) 30%, transparent);
  font-family: var(--mono); font-size: 11px; letter-spacing: .05em; text-transform: uppercase; font-weight: 600;
}
.ba-item .nm { display: inline-flex; align-items: center; gap: 7px; }
.ba-item.verified { border-color: color-mix(in srgb, var(--ok) 35%, var(--line)); }
