:root {
  color-scheme: light;

  /* Surfaces & ink */
  --page:        #f9f9f7;
  --surface:     #fcfcfb;
  --surface-2:   #f2f2ef;
  --ink:         #0b0b0b;
  --ink-2:       #52514e;
  --muted:       #898781;
  --grid:        #e1e0d9;
  --axis:        #c3c2b7;
  --border:      rgba(11, 11, 11, 0.10);

  /* Data colours — validated set, see README */
  --series-1:    #2a78d6;   /* blue   */
  --series-2:    #eb6834;   /* orange */
  --flow-in:     #2a78d6;
  --flow-out:    #e34948;
  --stage-1:     #184f95;   /* Actual   */
  --stage-2:     #2a78d6;   /* Signed   */
  --stage-3:     #5598e7;   /* Estimate */
  --stage-4:     #86b6ef;   /* Scoping  */

  /* Status */
  --good:        #0ca30c;
  --good-text:   #006300;
  --warning:     #fab219;
  --critical:    #d03b3b;

  --radius: 10px;
  --shadow: 0 1px 2px rgba(11, 11, 11, .04), 0 1px 8px rgba(11, 11, 11, .03);
  --font: system-ui, -apple-system, "Segoe UI", sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.45;
  -webkit-font-smoothing: antialiased;
}

/* ---------------------------------------------------------------- Login */
.login-wrap {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 24px;
}
.login-card {
  width: 100%;
  max-width: 360px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 32px;
}
.login-card h1 { margin: 0 0 4px; font-size: 19px; letter-spacing: -0.01em; }
.login-card p  { margin: 0 0 22px; color: var(--muted); font-size: 13px; }
.login-card label { display: block; font-size: 12px; color: var(--ink-2); margin-bottom: 6px; font-weight: 600; }
.login-card input {
  width: 100%; padding: 10px 12px; font: inherit;
  border: 1px solid var(--axis); border-radius: 8px; background: #fff; color: var(--ink);
}
.login-card input:focus { outline: 2px solid var(--series-1); outline-offset: -1px; border-color: transparent; }
.login-card button {
  width: 100%; margin-top: 14px; padding: 10px 12px;
  font: inherit; font-weight: 600; color: #fff;
  background: var(--ink); border: 0; border-radius: 8px; cursor: pointer;
}
.login-card button:hover { background: #2b2b2b; }
.login-err {
  margin: 0 0 16px; padding: 9px 11px; border-radius: 8px; font-size: 13px;
  background: #fdecec; color: #8f2323; border: 1px solid #f3c9c9;
}
.login-note {
  margin: 0 0 16px; padding: 9px 11px; border-radius: 8px; font-size: 13px;
  background: #eef4fc; color: #1c4a80; border: 1px solid #cfe0f5;
}

/* --------------------------------------------------------------- Layout */
.topbar {
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 12px 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 20;
}
.brand { font-weight: 700; letter-spacing: -0.01em; font-size: 15px; }
.brand span { color: var(--muted); font-weight: 500; }
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.source-note { font-size: 12px; color: var(--muted); text-align: right; line-height: 1.3; min-width: 0; overflow-wrap: anywhere; }

@media (max-width: 700px) {
  .topbar { gap: 10px; padding: 10px 14px; position: static; }
  .topbar-right { margin-left: 0; width: 100%; gap: 8px; }
  .source-note { text-align: left; margin-right: auto; }
}

.btn {
  font: inherit; font-size: 13px; font-weight: 600;
  padding: 7px 13px; border-radius: 8px; cursor: pointer;
  border: 1px solid var(--axis); background: var(--surface); color: var(--ink);
}
.btn:hover { background: var(--surface-2); }
.btn-primary { background: var(--ink); border-color: var(--ink); color: #fff; }
.btn-primary:hover { background: #2b2b2b; }
.btn[disabled] { opacity: .5; cursor: default; }

.shell { display: grid; grid-template-columns: 244px minmax(0, 1fr); gap: 18px; padding: 18px 20px 40px; align-items: start; }
@media (max-width: 980px) { .shell { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 700px) { .shell { padding: 14px 12px 32px; gap: 14px; } }

/* ----------------------------------------------------------------- Rail */
/* minmax(0, 1fr) rather than the implicit `auto` track: an auto track refuses to
 * shrink below its widest child's min-content width, which let the transactions
 * table (nowrap headers) set a ~650px floor on the whole page at phone widths. */
.rail { position: sticky; top: 70px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
@media (max-width: 980px) { .rail { position: static; } }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px 18px;
}
.card h2 {
  margin: 0 0 2px; font-size: 14px; font-weight: 700; letter-spacing: -0.01em;
}
.card .sub { margin: 0 0 14px; font-size: 12px; color: var(--muted); }
.rail .card { padding: 14px 15px; }
.rail h3 {
  margin: 0 0 9px; font-size: 11px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--muted);
}
.rail .group + .group { margin-top: 16px; padding-top: 15px; border-top: 1px solid var(--grid); }

.seg { display: flex; flex-wrap: wrap; gap: 4px; }
.seg button {
  font: inherit; font-size: 12px; font-weight: 600; padding: 5px 10px;
  border: 1px solid var(--axis); background: var(--surface); color: var(--ink-2);
  border-radius: 7px; cursor: pointer;
}
.seg button[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: #fff; }

.check { display: flex; align-items: center; gap: 8px; padding: 4px 0; font-size: 13px; cursor: pointer; }
.check input { accent-color: var(--series-1); width: 15px; height: 15px; margin: 0; }
.swatch { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.check .cnt { margin-left: auto; font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }

.field { display: block; margin-bottom: 10px; }
.field span { display: block; font-size: 12px; color: var(--ink-2); margin-bottom: 4px; font-weight: 600; }
.field input, .field textarea, .field select {
  width: 100%; font: inherit; font-size: 13px; padding: 7px 9px;
  border: 1px solid var(--axis); border-radius: 7px; background: #fff; color: var(--ink);
}
.field input { font-variant-numeric: tabular-nums; }
.field textarea { min-height: 76px; resize: vertical; line-height: 1.4; }
.field input:focus, .field textarea:focus, .field select:focus { outline: 2px solid var(--series-1); outline-offset: -1px; }

/* Per-field save status and "someone else is editing this" state.
   The label row holds the field name on the left and its status on the right,
   so the status never reflows the input below it. */
.field-top {
  display: flex !important;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  /* Let a long status drop to its own line rather than squeezing the field
     name into a two-line wrap. */
  flex-wrap: wrap;
}
.field-top > .field-state { flex: 0 1 auto; white-space: nowrap; }
.field-state {
  font-style: normal;
  font-weight: 500;
  font-size: 11px;
  color: var(--muted);
  text-align: right;
  /* Reserve the line so a status appearing never nudges the layout. */
  min-height: 1em;
  transition: color .15s ease;
}
.field-state.is-saving { color: var(--ink-2); }
.field-state.is-saved  { color: var(--good, #1a7f4b); }
.field-state.is-error  { color: var(--bad, #b3261e); font-weight: 600; }
.field-state.is-locked { color: var(--warn, #8a5a00); font-weight: 600; }

/* A field held by another editor: visibly not yours to type in. */
.field.is-locked input, .field.is-locked textarea {
  background: var(--surface-2, #f4f4f5);
  color: var(--muted);
  cursor: not-allowed;
  border-style: dashed;
}
/* Value changed by someone else — brief flash so it isn't a silent swap. */
@keyframes fieldFlash {
  from { background: var(--series-1); }
  to   { background: transparent; }
}
.field.just-updated input, .field.just-updated textarea {
  animation: fieldFlash 1.2s ease-out;
}
@media (prefers-reduced-motion: reduce) {
  .field.just-updated input, .field.just-updated textarea { animation: none; }
}

.event-filter { max-height: 240px; overflow-y: auto; border: 1px solid var(--grid); border-radius: 8px; padding: 6px 8px; }
.event-search { margin-bottom: 7px; }

/* View-only pickers over the events list */
.view-filters { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; margin-bottom: 8px; }
.mini { display: block; min-width: 0; }
.mini > span { display: block; font-size: 11px; color: var(--muted); font-weight: 600; margin-bottom: 3px; }
.mini select {
  width: 100%; font: inherit; font-size: 12px; padding: 5px 6px;
  border: 1px solid var(--axis); border-radius: 7px; background: #fff; color: var(--ink);
}
.mini select:focus { outline: 2px solid var(--series-1); outline-offset: -1px; }

/* Event rows: tick to count it, click the name to trace it */
.ev { display: flex; align-items: center; gap: 8px; padding: 3px 0; font-size: 13px; }
.ev input { accent-color: var(--series-1); width: 15px; height: 15px; margin: 0; flex: none; cursor: pointer; }
.ev-name {
  flex: 1 1 auto; min-width: 0; text-align: left; font: inherit; font-size: 13px;
  background: none; border: 0; padding: 2px 5px; margin: 0 -5px; border-radius: 5px;
  color: var(--ink); cursor: pointer;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ev-name:hover { background: var(--surface-2); }
.ev-name:focus-visible { outline: 2px solid var(--series-1); outline-offset: -1px; }
.ev.is-focus .ev-name { background: var(--series-2); color: #fff; font-weight: 600; }
.ev-amt { flex: none; font-size: 11px; font-variant-numeric: tabular-nums; color: var(--ink-2); }
.ev-amt.neg { color: var(--critical); }
.ev-amt.settled { color: var(--muted); font-style: italic; }

.link-btn {
  font: inherit; font-size: 11px; font-weight: 600; padding: 0;
  background: none; border: 0; color: var(--series-1); cursor: pointer; text-decoration: underline;
}

/* ----------------------------------------------------------------- Main */
.main { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; min-width: 0; }
.card { min-width: 0; }

.tiles { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 1500px) { .tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 700px)  { .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.tile {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 13px 15px 14px;
}
.tile .label {
  font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 7px; display: block;
}
.tile .value { font-size: 25px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.05; }
.tile .value.sm { font-size: 20px; }
.tile .foot { margin-top: 5px; font-size: 12px; color: var(--ink-2); }
.tile .foot.good { color: var(--good-text); font-weight: 600; }
.tile .foot.bad  { color: var(--critical); font-weight: 600; }

.chart-box { position: relative; }
.legend { display: flex; flex-wrap: wrap; gap: 14px; margin: 0 0 10px; font-size: 12px; color: var(--ink-2); }
.legend .item { display: flex; align-items: center; gap: 6px; }
.legend .key { width: 12px; height: 3px; border-radius: 2px; flex: none; }
.legend .key.sq { height: 10px; width: 10px; border-radius: 3px; }
.legend .key.dash { background: repeating-linear-gradient(90deg, currentColor 0 5px, transparent 5px 9px); }

.grid-2 { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; }
@media (max-width: 1150px) { .grid-2 { grid-template-columns: 1fr; } }

.card-head { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 12px; }
.card-head .titles { min-width: 0; }
.card-head .actions { margin-left: auto; flex: none; }

/* ------------------------------------------------- Collapsible sections */
/* One pattern for every titled block: the header is the toggle, the body is a
 * 1fr → 0fr grid row so it animates without anyone having to measure it. The
 * inner wrapper is what actually clips, which is why it must stay. */
.sec-head { cursor: pointer; user-select: none; -webkit-user-select: none; }
.sec-head:focus-visible { outline: 2px solid var(--series-1); outline-offset: 3px; border-radius: 6px; }
.card > .sec-head { transition: margin-bottom .22s ease; }
.card .sec-head .sub { transition: margin-bottom .22s ease; }
/* Collapsed: drop the spacing the open body used to sit under. */
.sec.is-collapsed > .sec-head { margin-bottom: 0; }
.sec.is-collapsed > .sec-head .sub { margin-bottom: 0; }

h3.sec-head { display: flex; align-items: center; gap: 7px; }

.chev {
  flex: none; width: 12px; height: 12px; margin-top: 4px;
  display: flex; align-items: center; justify-content: center;
  color: var(--muted);
}
h3.sec-head .chev { margin-top: 0; }
.chev::before {
  content: ''; display: block; width: 6px; height: 6px; margin-top: -3px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  border-radius: 1px;
  transform: rotate(45deg);
  transition: transform .22s ease;
}
.sec.is-collapsed > .sec-head .chev::before { transform: rotate(-45deg); margin: 0 0 0 -2px; }
.sec-head:hover .chev { color: var(--ink-2); }

.sec-body {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows .22s ease;
}
.sec.is-collapsed > .sec-body { grid-template-rows: 0fr; }
.sec-inner { min-height: 0; overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .sec-body, .chev::before, .card > .sec-head, .card .sec-head .sub { transition: none; }
}
/* Suppress the opening animation while the saved layout is applied on load. */
body.no-anim .sec-body,
body.no-anim .chev::before,
body.no-anim .sec-head,
body.no-anim .sec-head .sub { transition: none !important; }

/* The topbar is sticky, so scrolled-to sections need to clear it. */
.sec { scroll-margin-top: 66px; }

/* Side-by-side panels stretch to match each other, which is right while both
 * are open and leaves a tall empty box the moment one is closed. */
.grid-2 > .sec.is-collapsed { align-self: start; }

/* A first child pulled upwards by a negative margin (the sidebar hints) would
 * have its top few pixels clipped by the body's overflow. */
.sec-inner > .hint:first-child { margin-top: 0 !important; }

/* --------------------------------------------------------------- Tables */
.table-scroll { overflow-x: auto; max-height: 430px; overflow-y: auto; border: 1px solid var(--grid); border-radius: 8px; }
table { border-collapse: collapse; width: 100%; font-size: 13px; }
thead th {
  position: sticky; top: 0; background: var(--surface-2); z-index: 1;
  text-align: left; font-size: 11px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-2);
  padding: 8px 10px; border-bottom: 1px solid var(--grid); white-space: nowrap;
}
tbody td { padding: 7px 10px; border-bottom: 1px solid var(--grid); vertical-align: top; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: #f6f7f9; }
/* Where the list parks itself when it opens: the row closest to today. Subtle
   on purpose — it explains the scroll position, it isn't a selection. */
tbody tr.is-anchor td { background: #eef4fc; }
tbody tr.is-anchor:hover td { background: #e6eefa; }
tbody tr.is-anchor td:first-child { box-shadow: inset 2px 0 0 var(--series-1); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
td.neg { color: var(--critical); }
td.desc { max-width: 380px; color: var(--ink-2); }
.pill {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  font-size: 11px; font-weight: 700; color: #fff; white-space: nowrap;
}

/* Stage breakdown list */
.stage-rows { display: grid; gap: 10px; }
.stage-row .top { display: flex; align-items: baseline; gap: 8px; font-size: 13px; }
.stage-row .top .name { font-weight: 600; display: flex; align-items: center; gap: 7px; }
.stage-row .top .amt { margin-left: auto; font-weight: 700; font-variant-numeric: tabular-nums; }
.stage-row .top .pct { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
.bar-track { height: 9px; background: var(--surface-2); border-radius: 5px; overflow: hidden; margin-top: 5px; }
.bar-fill { height: 100%; border-radius: 5px; }
.stage-row .events { margin-top: 6px; font-size: 12px; color: var(--muted); }

/* ------------------------------------------------------------ First load */
/* The page waits on a live read of the sheet before it paints, so the wait
   needs to read as working. Same card surface as everything else, so the
   dashboard resolves into place rather than replacing a foreign-looking box. */
.boot {
  display: flex; align-items: center; gap: 11px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 18px 20px; font-size: 13px; color: var(--ink-2);
  /* Held off screen for a moment. A reading reused from the last minute — or
     no sheet configured at all — lands in tens of milliseconds, and an
     indicator that paints for one frame reads as a stutter rather than as
     work. Holding it back in CSS rather than in script keeps the point of
     putting it in index.html: it still needs no JavaScript to appear.
     Written as an animation off the element's own styles, so a browser that
     ignores it falls back to showing the indicator straight away.
     app.js keeps it up for a beat once it is on screen — the two timings are
     paired there, and BOOT_HOLD_MS must match the duration below. */
  animation: bootHold 260ms step-end both;
}
/* Nothing actually moves during the hold — the from-state is simply held for
   the duration and then dropped — so this is left alone under reduced motion. */
@keyframes bootHold {
  from { visibility: hidden; height: 0; padding: 0; border-width: 0; box-shadow: none; }
}
.spinner {
  flex: none; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid var(--grid); border-top-color: var(--series-1);
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
/* No animation available: a still ring reads as broken, so fall back to a
   pulsing bar that says the same thing without spinning. */
@media (prefers-reduced-motion: reduce) {
  .spinner {
    width: 46px; height: 4px; border: 0; border-radius: 3px;
    background: var(--series-1); animation: bootPulse 1.4s ease-in-out infinite;
  }
  @keyframes bootPulse { 0%, 100% { opacity: .28; } 50% { opacity: 1; } }
}

/* --------------------------------------------------------------- Notices */
.notice {
  display: flex; gap: 10px; align-items: flex-start;
  padding: 10px 13px; border-radius: 8px; font-size: 13px;
  border: 1px solid; margin-bottom: 0;
}
.notice.warn     { background: #fff8e6; border-color: #f0dca8; color: #6b5410; }
.notice.err      { background: #fdecec; border-color: #f3c9c9; color: #8f2323; }
.notice.info     { background: #eef4fc; border-color: #cfe0f5; color: #1c4a80; }
.notice b { font-weight: 700; }
.notice .ico { font-weight: 700; flex: none; }
.notice > div { min-width: 0; overflow-wrap: anywhere; }
.notice .quiet { opacity: .72; }

/* More than one notice can stack, and the hidden-count line sits under them. */
#notices { display: grid; gap: 10px; }

/* Acknowledge: present but quiet. It borrows the notice's own colour so it
   reads as part of the warn/info block rather than a call to action. */
.notice-ack {
  flex: none; margin-left: auto; align-self: flex-start;
  font: inherit; font-size: 12px; font-weight: 600; color: inherit;
  background: transparent; border: 1px solid currentColor; border-radius: 6px;
  padding: 3px 9px; opacity: .62; cursor: pointer;
  transition: opacity .15s ease;
}
.notice-ack:hover { opacity: 1; }
.notice-ack:focus-visible { opacity: 1; outline: 2px solid currentColor; outline-offset: 2px; }

.notice-hidden {
  margin: 0; font-size: 12px; color: var(--muted);
  display: flex; flex-wrap: wrap; gap: 7px; align-items: baseline;
}
.linkish {
  font: inherit; font-size: inherit; font-weight: 600; color: var(--ink-2);
  background: none; border: 0; border-bottom: 1px solid var(--border);
  padding: 0; cursor: pointer;
}
.linkish:hover { color: var(--ink); border-bottom-color: currentColor; }
.linkish:focus-visible { outline: 2px solid var(--ink-2); outline-offset: 2px; }

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

.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%);
  background: var(--ink); color: #fff; padding: 10px 18px; border-radius: 9px;
  font-size: 13px; font-weight: 600; box-shadow: 0 6px 24px rgba(0,0,0,.22);
  opacity: 0; pointer-events: none; transition: opacity .18s ease; z-index: 60;
}
.toast.show { opacity: 1; }

.hint { font-size: 12px; color: var(--muted); margin: 8px 0 0; }
.empty { padding: 26px; text-align: center; color: var(--muted); font-size: 13px; }

/* ------------------------------------------------- What changed since… */
/* Prose first, figures second. This panel is orientation, so it reads as a
 * short written answer with a few numbers in it rather than as a report. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* The window picker sits in the section header, where its label would push the
   header taller than every other panel's. The select carries its own name. */
.changes-window { margin-top: -2px; }
.changes-window select { min-width: 168px; }

.chg-baseline { margin: 0 0 12px; font-size: 13px; color: var(--ink-2); }
/* Not an error and not decoration: the baseline is not the one that was asked
   for, and that has to be visible without shouting. */
.chg-baseline.warnish {
  color: #6b5410; background: #fff8e6; border: 1px solid #f0dca8;
  border-radius: 8px; padding: 8px 11px;
}
.chg-state { margin: 0; font-size: 13px; color: var(--ink-2); max-width: 72ch; }
.chg-state + .chg-block { margin-top: 14px; }

.chg-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }
.chg-chip {
  display: flex; flex-direction: column; gap: 1px;
  padding: 6px 11px; border: 1px solid var(--grid); border-radius: 8px;
  background: var(--surface-2); font-size: 12px;
}
.chg-chip b { font-weight: 700; color: var(--ink); }
.chg-chip em { font-style: normal; color: var(--muted); font-variant-numeric: tabular-nums; }

.chg-headline {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px;
  margin-bottom: 4px;
}
@media (max-width: 760px) { .chg-headline { grid-template-columns: 1fr; } }
.chg-figure {
  border: 1px solid var(--grid); border-radius: 8px; padding: 10px 12px;
  background: var(--surface);
}
.chg-figure .label {
  display: block; font-size: 11px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted); margin-bottom: 5px;
}
.chg-figure .pair { font-size: 15px; font-variant-numeric: tabular-nums; color: var(--ink-2); }
.chg-figure .pair b { color: var(--ink); font-weight: 700; }
.chg-figure .foot { margin-top: 3px; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.chg-figure .foot.good { color: var(--good-text); font-weight: 600; }
.chg-figure .foot.bad  { color: var(--critical); font-weight: 600; }
.arr { color: var(--muted); padding: 0 2px; }

.chg-block { margin-top: 16px; }
.chg-block h4 {
  margin: 0 0 7px; font-size: 11px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted);
}
.chg-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 6px; }
.chg-list li {
  font-size: 13px; color: var(--ink-2); line-height: 1.45;
  padding-left: 12px; position: relative; overflow-wrap: anywhere;
}
.chg-list li::before {
  content: ''; position: absolute; left: 0; top: 8px;
  width: 4px; height: 4px; border-radius: 50%; background: var(--axis);
}
.chg-list b { color: var(--ink); font-weight: 700; }
.chg-list .quiet { color: var(--muted); }
.chg-list .good { color: var(--good-text); font-weight: 600; }
.chg-list .bad  { color: var(--critical); font-weight: 600; }
