/* Design system for the QuantEcon projects dashboard.
   Forked from status-translations' style.css so the status-* family reads as one
   (design §3.5), extended with the components the v1 mock introduced: stage and
   priority chips, the Now cards, the pipeline kanban, the triage matrix and the
   project page panels.

   Theme: the light palette is the base; the dark palette applies via
   prefers-color-scheme, and an explicit data-theme attribute (set by the toggle
   in app.js, applied pre-paint by an inline script in each page's head) wins
   over the system preference in both directions.

   ---------------------------------------------------------------------------
   Colour rulings recorded here because the next reader will ask.

   1. Health is the only saturated colour in a table row. It is a STATUS scale
      (good / warning / critical / unknown) with reserved meaning, and it always
      ships as dot + word, never colour alone.

   2. The stage ramp is ORDINAL, not categorical: idea -> proposed -> active is a
      lifecycle, so it takes one hue in monotone lightness steps rather than three
      unrelated hues. The v1 mock's purple `proposed` (#8a62c9) was dropped: against
      the blue `active` it measures ΔE 3.3 under protanopia and 12.0 under normal
      vision, both below the floor — two adjacent pipeline columns a reader cannot
      separate. steady and parked leave the ramp because they are off-ramps rather
      than later stages; their hues clear all-pairs CVD against active
      (worst ΔE 8.4 protan / 17.6 normal in light, 9.0 / 18.1 in dark).

   3. --warn-mark exists because --warn (#fab219) measures 1.79:1 on the light
      surface: legible as a wash or a border, close to invisible as a 9px dot.
      Marks use --warn-mark (3.26:1 light), washes and rules keep --warn.

   4. Two light-mode tokens are darker here than in status-translations, because
      an automated audit found them failing WCAG AA for text: --ink-3 measured
      3.4:1 and --accent 4.2:1 against the page, where body text needs 4.5:1.
      They are now 4.9:1 and 4.8:1, the smallest change that clears the bar on
      all three surfaces, and the hues are unchanged. The dark palette already
      passed and is untouched. The sibling has the same defect and is worth
      fixing there too — raised on status-projects#6.

   Every stage and status colour clears 3:1 against its own surface in both
   themes. Verified 2026-08-25; re-verify with the palette validator if changed.
   --------------------------------------------------------------------------- */

:root {
  color-scheme: light;
  --plane: #f9f9f7;
  --surface: #fcfcfb;
  --ink: #0b0b0b;
  --ink-2: #52514e;
  --ink-3: #6f6d67;
  --hairline: #e1e0d9;
  --border: rgba(11, 11, 11, 0.10);
  --accent: #256ec8;
  --accent-track: #cde2fb;
  --accent-wash: rgba(42, 120, 214, 0.08);
  --good: #0ca30c;
  --good-text: #006300;
  --good-wash: rgba(12, 163, 12, 0.10);
  --warn: #fab219;
  --warn-mark: #c07f00;
  --warn-text: #7a5200;
  --warn-wash: rgba(250, 178, 25, 0.14);
  --crit: #d03b3b;
  --crit-text: #a02525;
  --crit-wash: rgba(208, 59, 59, 0.10);
  --empty-cell: #e7e6df;
  --group-wash: #f3f2ee;
  --tooltip-bg: #0b0b0b;
  --tooltip-ink: #fcfcfb;
  --stage-idea: #868d97;
  --stage-proposed: #5a86c9;
  --stage-active: #256ec8;
  --stage-steady: #1f8f6f;
  --stage-parked: #b0732a;
  --stage-done: #6f6d67;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --plane: #0d0d0d;
    --surface: #1a1a19;
    --ink: #ffffff;
    --ink-2: #c3c2b7;
    --ink-3: #898781;
    --hairline: #2c2c2a;
    --border: rgba(255, 255, 255, 0.10);
    --accent: #3987e5;
    --accent-track: #17324f;
    --accent-wash: rgba(57, 135, 229, 0.14);
    --good: #0ca30c;
    --good-text: #2fc42f;
    --good-wash: rgba(12, 163, 12, 0.16);
    --warn: #fab219;
    --warn-mark: #fab219;
    --warn-text: #fab219;
    --warn-wash: rgba(250, 178, 25, 0.14);
    --crit: #d03b3b;
    --crit-text: #e66767;
    --crit-wash: rgba(208, 59, 59, 0.16);
    --empty-cell: #30302d;
    --group-wash: #211f1e;
    --tooltip-bg: #fcfcfb;
    --tooltip-ink: #0b0b0b;
    --stage-idea: #636b79;
    --stage-proposed: #4d7dbb;
    --stage-active: #3987e5;
    --stage-steady: #3cb391;
    --stage-parked: #d1944a;
    --stage-done: #a6a49b;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --plane: #0d0d0d;
  --surface: #1a1a19;
  --ink: #ffffff;
  --ink-2: #c3c2b7;
  --ink-3: #898781;
  --hairline: #2c2c2a;
  --border: rgba(255, 255, 255, 0.10);
  --accent: #3987e5;
  --accent-track: #17324f;
  --accent-wash: rgba(57, 135, 229, 0.14);
  --good: #0ca30c;
  --good-text: #2fc42f;
  --good-wash: rgba(12, 163, 12, 0.16);
  --warn: #fab219;
  --warn-mark: #fab219;
  --warn-text: #fab219;
  --warn-wash: rgba(250, 178, 25, 0.14);
  --crit: #d03b3b;
  --crit-text: #e66767;
  --crit-wash: rgba(208, 59, 59, 0.16);
  --empty-cell: #30302d;
  --group-wash: #211f1e;
  --tooltip-bg: #fcfcfb;
  --tooltip-ink: #0b0b0b;
  --stage-idea: #636b79;
  --stage-proposed: #4d7dbb;
  --stage-active: #3987e5;
  --stage-steady: #3cb391;
  --stage-parked: #d1944a;
  --stage-done: #a6a49b;
}

* { box-sizing: border-box; }
body {
  margin: 0;
  padding: 0 24px 72px;
  background: var(--plane);
  color: var(--ink);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  line-height: 1.5;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.wrap { max-width: 1100px; margin: 0 auto; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
/* A link sitting inside muted prose cannot be distinguished from that prose by
   colour alone — accent against --ink-3 measures about 1.2:1 — so links in every
   prose context are underlined. Links that are their own affordance (nav tabs,
   tiles, cards, table cells) keep the underline for hover only. */
footer a, .h2-sub a, .meta a, .note-line a, .kgroup a, .notice a, .redacted a,
.error-card a, .colnote a, .crumb a, .csub a, .rail a, .lede a, details.diag a {
  text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px;
}
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
h1, h2, h3, h4 { text-wrap: balance; }
small, .sub { color: var(--ink-3); }
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 20;
  background: var(--surface); color: var(--ink); border: 1px solid var(--accent);
  border-radius: 0 0 6px 0; padding: 8px 14px; font-weight: 600;
}
.skip:focus { left: 0; }

/* clip-path as well as clip, and left:0 so the element never sits past the
   right edge of a narrow viewport and widens the page it is hidden on. */
.visually-hidden {
  position: absolute; left: 0; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------- masthead + nav ---------- */
header { padding: 44px 0 0; border-bottom: 1px solid var(--hairline); margin-bottom: 24px; }
.mast { display: flex; align-items: flex-start; gap: 16px; }
.mast .grow { flex: 1; min-width: 0; }
.eyebrow {
  font-size: 11px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--accent); margin: 0 0 8px;
}
h1 { font-size: 28px; font-weight: 650; letter-spacing: -0.01em; margin: 0 0 6px; }
.dateline { color: var(--ink-2); font-size: 13px; margin: 0; }
.dateline .sep { color: var(--ink-3); margin: 0 6px; }

.freshness {
  display: inline-block; padding: 1px 9px; border-radius: 999px;
  font-size: 12px; font-weight: 600; vertical-align: 1px; cursor: default;
}
.freshness.good { background: var(--good-wash); color: var(--good-text); }
.freshness.warn { background: var(--warn-wash); color: var(--warn-text); }
.freshness.crit { background: var(--crit-wash); color: var(--crit-text); }

.theme-toggle {
  flex: none; margin-top: 2px; padding: 5px 12px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface); color: var(--ink-2);
  font: 600 12px system-ui, sans-serif; cursor: pointer; white-space: nowrap;
}
.theme-toggle:hover { color: var(--ink); border-color: var(--ink-3); }

nav.tabs { display: flex; gap: 2px; margin-top: 18px; flex-wrap: wrap; }
nav.tabs a {
  padding: 7px 14px 8px; font-size: 13px; font-weight: 600; color: var(--ink-2);
  border: 1px solid transparent; border-bottom: none; border-radius: 6px 6px 0 0;
}
nav.tabs a:hover { color: var(--ink); text-decoration: none; }
nav.tabs a.active {
  color: var(--ink); background: var(--surface); border-color: var(--hairline);
  position: relative; top: 1px;
}

/* The maintainer's group. Pushed to the right-hand end and drawn recessively so
   it reads as "how this site is built" rather than as a third dashboard. It is
   still a real tab: reachable, focusable, and it goes active like the others. */
/* `nav.tabs a` is (0,1,2), so these have to be at least as specific or the
   recessive treatment silently does nothing — which it did on first attempt. */
nav.tabs .tabs-dev {
  margin-left: auto; display: flex; align-items: center; gap: 8px;
  padding-left: 14px; border-left: 1px solid var(--hairline); align-self: center;
}
nav.tabs .tabs-dev .dev-label {
  font-size: 10px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-3); border: 1px solid var(--border); border-radius: 3px; padding: 1px 5px;
}
nav.tabs .tabs-dev a {
  color: var(--ink-3); font-weight: 500; font-size: 12px; padding: 5px 10px 6px;
}
nav.tabs .tabs-dev a:hover { color: var(--ink); }
nav.tabs .tabs-dev a.active {
  color: var(--ink-2); background: var(--group-wash); border-color: var(--border);
}

/* ---------- section headings ---------- */
h2 { font-size: 16px; font-weight: 650; margin: 40px 0 2px; letter-spacing: -0.005em; }
section:first-child h2 { margin-top: 8px; }
.h2-sub { color: var(--ink-2); font-size: 13px; margin: 0 0 14px; max-width: 78ch; }

.error-card {
  background: var(--crit-wash); border: 1px solid var(--border); border-radius: 6px;
  padding: 16px 18px; margin-top: 24px; color: var(--ink); font-size: 14px;
}
.error-card b { display: block; margin-bottom: 4px; }

/* Run diagnostics — a degraded collection must be visible, never silent. */
.notice {
  border: 1px solid var(--border); border-left: 3px solid var(--warn);
  background: var(--warn-wash); border-radius: 6px; padding: 11px 14px;
  margin-top: 20px; font-size: 13px; color: var(--ink);
}
.notice.crit { border-left-color: var(--crit); background: var(--crit-wash); }
.notice b { font-weight: 650; }
.notice ul { margin: 6px 0 0; padding-left: 20px; }
.notice li { margin: 2px 0; }
.notice .where { color: var(--ink-2); }

/* ---------- stat tiles ---------- */
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 12px; margin-top: 20px; }
.tile {
  background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
  padding: 14px 16px 13px; display: flex; flex-direction: column; gap: 2px;
  color: inherit; text-align: left;
}
a.tile:hover { border-color: var(--accent); text-decoration: none; }
.tile .label { font-size: 12px; color: var(--ink-2); }
.tile .value { font-size: 27px; font-weight: 650; line-height: 1.15; }
.tile .value small { font-size: 15px; font-weight: 500; color: var(--ink-3); }
.tile .note { font-size: 12px; color: var(--ink-3); }
.tile .note b { color: var(--ink-2); font-weight: 600; }
.meter { margin-top: 8px; height: 8px; border-radius: 4px; background: var(--accent-track); overflow: hidden; }
.meter > i { display: block; height: 100%; background: var(--accent); border-radius: 0 4px 4px 0; }

/* ---------- chips: stage, priority, health, flags ---------- */
.chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 1px 9px;
  border-radius: 999px; font-size: 11.5px; font-weight: 600; line-height: 1.7;
  white-space: nowrap; border: 1px solid transparent;
}
.chip.stage { color: var(--ink-2); border-color: var(--border); background: var(--surface); }
.chip.stage::before { content: ""; width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--stage-c, var(--ink-3)); }
.s-idea { --stage-c: var(--stage-idea); }
.s-proposed { --stage-c: var(--stage-proposed); }
.s-active { --stage-c: var(--stage-active); }
.s-steady { --stage-c: var(--stage-steady); }
.s-parked { --stage-c: var(--stage-parked); }
.s-done, .s-dropped { --stage-c: var(--stage-done); }

.pri {
  display: inline-block; font-size: 11px; font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase; padding: 1px 7px; border-radius: 4px; white-space: nowrap;
}
.pri.now { background: var(--ink); color: var(--plane); }
.pri.next { background: var(--group-wash); color: var(--ink-2); border: 1px solid var(--border); }
.pri.later { color: var(--ink-3); border: 1px solid var(--border); }
.pri.unset { color: var(--ink-3); border: 1px dashed var(--border); font-weight: 600; letter-spacing: 0; text-transform: none; }

.health { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; white-space: nowrap; font-weight: 600; }
.health i { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.health.h-current { color: var(--good-text); } .health.h-current i { background: var(--good); }
.health.h-aging { color: var(--warn-text); } .health.h-aging i { background: var(--warn-mark); }
.health.h-stale { color: var(--crit-text); } .health.h-stale i { background: var(--crit); }
.health.h-unknown { color: var(--ink-3); } .health.h-unknown i { background: transparent; border: 2px solid var(--ink-3); }
.health .age { font-weight: 500; color: var(--ink-2); }

.lock { color: var(--ink-3); font-size: 11px; position: relative; }

.flag {
  display: inline-flex; align-items: center; gap: 5px; font-size: 11.5px; font-weight: 600;
  color: var(--crit-text); background: var(--crit-wash); border-radius: 4px; padding: 1px 7px;
}
.flag.soft { color: var(--warn-text); background: var(--warn-wash); }
.flag-row { display: flex; flex-wrap: wrap; gap: 6px; }
/* A flag is a whole sentence, so inside a narrow card it stacks and wraps as
   prose rather than trying to behave like a pill. */
.card .flag-row { flex-direction: column; align-items: stretch; }
.card .flag { display: block; white-space: normal; padding: 4px 8px; line-height: 1.45; }

.badge {
  display: inline-block; padding: 1px 8px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; border: 1px solid var(--border); color: var(--ink-2);
}
.badge.warn { background: var(--warn-wash); color: var(--warn-text); border-color: transparent; }
.badge.crit { background: var(--crit-wash); color: var(--crit-text); border-color: transparent; }
.badge.good { background: var(--good-wash); color: var(--good-text); border-color: transparent; }

/* ---------- progress bar ---------- */
.bar { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; }
.bar b { height: 8px; width: 82px; background: var(--accent-track); border-radius: 4px; overflow: hidden; display: block; flex: none; }
.bar b > i { display: block; height: 100%; background: var(--accent); border-radius: 0 4px 4px 0; }
.bar .n { font-size: 12.5px; color: var(--ink); }
.bar.unmeasured .n { color: var(--ink-3); font-style: italic; }

/* ---------- Now cards ---------- */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(255px, 1fr)); gap: 12px; }
.card {
  background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
  padding: 12px 14px; display: grid; gap: 6px; align-content: start; color: inherit;
}
a.card:hover { border-color: var(--accent); text-decoration: none; }
.card .top { display: flex; justify-content: space-between; align-items: center; gap: 8px; }
.card .prog { font-size: 11px; color: var(--ink-3); text-transform: uppercase; letter-spacing: 0.08em; font-weight: 600; }
.card .namerow { display: flex; align-items: baseline; gap: 5px; }
.card .name { font-weight: 650; font-size: 14.5px; color: var(--ink); }
.card .sum { color: var(--ink-2); font-size: 12.5px; }
.card .foot { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; }
.empty-note { color: var(--ink-3); font-size: 13px; padding: 14px 0; }

/* ---------- programme table ---------- */
.table-scroll { overflow-x: auto; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; }
table { border-collapse: collapse; width: 100%; min-width: 860px; }
th {
  text-align: left; font-size: 11px; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-3); padding: 12px 12px 9px; border-bottom: 1px solid var(--hairline); white-space: nowrap;
}
th button {
  background: none; border: none; padding: 0; font: inherit; color: inherit;
  letter-spacing: inherit; text-transform: inherit; cursor: pointer;
}
th button:hover { color: var(--ink); }
th[aria-sort] button { color: var(--ink); }
th button .dir { margin-left: 4px; }
td { padding: 10px 12px; border-bottom: 1px solid var(--hairline); vertical-align: middle; }
tbody tr:last-child td { border-bottom: none; }

tr.group td { background: var(--group-wash); padding: 9px 12px; border-top: 1px solid var(--hairline); }
tr.group .group-line { display: flex; align-items: baseline; gap: 6px 12px; flex-wrap: wrap; }
tr.group .pname { font-weight: 650; font-size: 13.5px; }
tr.group .meta { color: var(--ink-2); font-size: 12.5px; }
tr.group .roll { margin-left: auto; color: var(--ink-2); font-size: 12px; display: flex; gap: 12px; white-space: nowrap; }

tr.proj:hover td { background: var(--accent-wash); }
tr.proj:focus-within td { background: var(--accent-wash); }
td.name { min-width: 250px; overflow-wrap: anywhere; }
td.name .n { font-weight: 600; color: var(--ink); }
td.name .n:hover { text-decoration: underline; }
td.name .s { display: block; color: var(--ink-3); font-size: 12px; }
td.num { text-align: right; white-space: nowrap; }
td.links { white-space: nowrap; font-size: 12.5px; }
td.links a { white-space: nowrap; }
td.links a + a::before { content: "·"; color: var(--ink-3); margin: 0 6px; text-decoration: none; }
tr.flags-row td { padding-top: 0; border-top: none; }
tr.done-toggle td { padding: 6px 12px; background: var(--surface); }
tr.done-toggle button { background: none; border: none; color: var(--ink-3); font: inherit; font-size: 12.5px; cursor: pointer; padding: 2px 0; }
tr.done-toggle button:hover { color: var(--ink-2); }
tr.done-row td { color: var(--ink-3); }

/* ---------- pipeline ---------- */
.cols { display: grid; grid-template-columns: repeat(5, minmax(180px, 1fr)); gap: 12px; }
.col {
  background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
  padding: 10px; display: flex; flex-direction: column; gap: 8px; min-height: 180px; min-width: 0;
  border-top: 3px solid var(--stage-c, var(--hairline));
}
.col h3 {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-2);
  display: flex; justify-content: space-between; margin: 0 0 2px; font-weight: 600;
}
.col h3 .n { color: var(--ink-3); font-weight: 500; }
.kcard {
  border: 1px solid var(--hairline); border-radius: 6px; padding: 8px 10px; background: var(--plane);
  display: grid; gap: 4px; border-left: 3px solid var(--h-c, var(--hairline)); color: inherit;
}
a.kcard:hover { border-color: var(--accent); text-decoration: none; }
.kcard .kp { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-3); font-weight: 600; }
.kcard .kn { font-weight: 600; font-size: 13px; line-height: 1.35; color: var(--ink); overflow-wrap: anywhere; }
.kcard .kf { display: flex; justify-content: space-between; align-items: center; gap: 6px; flex-wrap: wrap; }
.kcard.h-current { --h-c: var(--good); }
.kcard.h-aging { --h-c: var(--warn-mark); }
.kcard.h-stale { --h-c: var(--crit); }
.kcard.h-unknown { --h-c: var(--ink-3); }
.kgroup { border: 1px dashed var(--border); border-radius: 6px; padding: 8px 10px; color: var(--ink-2); font-size: 12.5px; }
.kgroup b { color: var(--ink); }
.col .none { color: var(--ink-3); font-size: 12.5px; padding: 4px 2px; }

.rail {
  margin-top: 12px; border: 1px solid var(--border); background: var(--surface); border-radius: 6px;
  padding: 10px 12px; display: flex; gap: 8px 18px; flex-wrap: wrap; align-items: center;
  color: var(--ink-2); font-size: 12.5px;
}
.rail .kn { color: var(--ink); font-weight: 600; }

/* minmax(0, 1fr), not 1fr: a grid track's default min-width is `auto`, so a long
   project name would refuse to shrink and push the matrix past the viewport. */
.matrix { display: grid; grid-template-columns: 92px repeat(3, minmax(0, 1fr)); gap: 6px; }
/* The rows exist so the grid can carry role="row" and satisfy the table role it
   claims; display:contents keeps their cells as direct grid items. */
.mrow { display: contents; }
.matrix .hd {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-3);
  font-weight: 600; align-self: end; padding: 0 6px 4px;
}
.matrix .rh { font-size: 12px; font-weight: 700; padding: 10px 6px; text-transform: uppercase; letter-spacing: 0.05em; }
.mcell {
  background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
  padding: 8px 10px; min-height: 66px; display: flex; flex-direction: column; gap: 4px;
}
.mcell .mtag {
  align-self: flex-start; font-size: 10.5px; font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; border-radius: 3px; padding: 0 5px;
}
.mcell.hot { background: var(--crit-wash); border-color: var(--crit); }
.mcell.hot .mtag { background: var(--crit-wash); color: var(--crit-text); }
.mcell.warm { background: var(--warn-wash); }
.mcell.warm .mtag { background: var(--warn-wash); color: var(--warn-text); }
.mcell a { font-size: 12.5px; color: var(--ink); overflow-wrap: anywhere; }
.mcell .none { color: var(--ink-3); font-size: 12px; }

/* ---------- project page ---------- */
.crumb { color: var(--ink-3); font-size: 12.5px; margin: 0 0 8px; }
.crumb a { color: var(--ink-2); }
.phead { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.phead h2 { margin: 0; font-size: 24px; letter-spacing: -0.015em; }
.pmeta { display: flex; gap: 8px 20px; flex-wrap: wrap; color: var(--ink-2); font-size: 13px; margin-top: 10px; }
.pmeta b { color: var(--ink); font-weight: 600; }
.pmeta .unset { color: var(--ink-3); font-weight: 500; font-style: italic; }
.pgrid { display: grid; grid-template-columns: 1.6fr 1fr; gap: 16px; margin-top: 22px; align-items: start; }
.pcol { display: grid; gap: 16px; align-content: start; }
.panel { background: var(--surface); border: 1px solid var(--border); border-radius: 6px; padding: 14px 16px; }
.panel h3 {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--ink-3);
  font-weight: 600; margin: 0 0 10px; display: flex; justify-content: space-between; gap: 10px;
}
.panel h3 span { font-weight: 500; text-transform: none; letter-spacing: 0; }
.panel p { margin: 0; max-width: 65ch; }
.note-line { display: block; margin-top: 8px; color: var(--ink-2); font-size: 13px; }
.kv .note-line { margin-top: 4px; font-size: 12px; color: var(--ink-3); }
.kv { display: grid; grid-template-columns: 116px 1fr; gap: 7px 12px; font-size: 13px; margin: 12px 0 0; }
.kv dt { color: var(--ink-3); }
.kv dd { margin: 0; overflow-wrap: anywhere; }
.items { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.items li { display: flex; gap: 10px; align-items: baseline; font-size: 13px; }
.items .dot { width: 9px; height: 9px; border-radius: 50%; border: 2px solid var(--stage-active); flex: none; position: relative; top: 1px; }
.items .dot.closed { background: var(--good); border-color: var(--good); }
.items .t { flex: 1; min-width: 0; }
.items .ref { color: var(--ink-3); font-size: 12px; white-space: nowrap; }
.redacted {
  color: var(--ink-2); font-size: 13px; padding: 10px 12px;
  border: 1px dashed var(--border); border-radius: 6px;
}
.flags { display: grid; gap: 7px; }
.flags div { font-size: 13px; padding: 8px 10px; border-radius: 6px; background: var(--crit-wash); color: var(--crit-text); }
.flags div.soft { background: var(--warn-wash); color: var(--warn-text); }
.flags div.ok { background: var(--good-wash); color: var(--good-text); }
.flags div.info { background: var(--group-wash); color: var(--ink-2); }
.spark-empty { color: var(--ink-3); font-size: 12.5px; }

/* ---------- Now card link row ---------- */
.card .cardlinks { font-size: 12.5px; }
.card .cardlinks a + a::before { content: "·"; color: var(--ink-3); margin: 0 6px; }

/* ---------- pipeline: programme grouping, candidates, rail ---------- */
.kgrp { display: grid; gap: 6px; }
.kgrp + .kgrp { margin-top: 4px; padding-top: 8px; border-top: 1px dashed var(--border); }
.kgrp-h { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-3); font-weight: 700; }
.kcard .ksub { font-size: 11.5px; color: var(--ink-2); }
.kcard .health { font-size: 11.5px; }
.colnote { margin: 0 0 2px; font-size: 11.5px; color: var(--ink-3); }
.clist { list-style: none; margin: 8px 0 0; padding: 0; display: grid; gap: 6px; }
.clist li { font-size: 12.5px; }
.csub { display: block; color: var(--ink-3); font-size: 11.5px; }

.rail-wrap { margin-top: 12px; }
.rail-wrap > summary { cursor: pointer; font-size: 12.5px; color: var(--ink-2); padding: 4px 0; display: flex; gap: 8px; align-items: center; }
.rail-wrap > summary::marker { color: var(--ink-3); }
.railitem { display: inline-flex; align-items: baseline; gap: 6px; }

/* ---------- project page extras ---------- */
.tracker-title { margin: 8px 0 0; color: var(--ink-2); font-size: 13px; }
.workbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 12px; }
.milestone { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--hairline); }
.milestone h4 { margin: 0 0 6px; font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; color: var(--ink-3); font-weight: 600; }
.milestone p { margin: 0 0 8px; font-size: 13px; }
.nf { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 16px; margin: 18px 0; }
.nf-group h3 { font-size: 12px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--ink-3); margin: 0 0 6px; font-weight: 600; }
.nf-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; font-size: 13px; }

/* ---------- footer + legend ---------- */
footer { margin-top: 44px; padding-top: 16px; border-top: 1px solid var(--hairline); color: var(--ink-3); font-size: 12.5px; }
footer p { margin: 0 0 8px; max-width: 90ch; }
footer b { color: var(--ink-2); font-weight: 600; }
.legend-block { margin-bottom: 16px; }
.legend-block .lg { max-width: 90ch; margin: 0 0 6px; display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: center; }
details.diag { margin: 0 0 14px; border: 1px solid var(--border); border-radius: 6px; background: var(--surface); padding: 8px 12px; }
details.diag > summary { cursor: pointer; color: var(--ink-2); }
details.diag ul { margin: 8px 0 2px; padding-left: 20px; }
details.diag li { margin: 4px 0; }
details.diag .where { color: var(--ink-3); }

/* The sibling's rich tooltip is deliberately not carried across. It renders the
   trigger's data-tip attribute as innerHTML, and this document carries free
   prose up to 500 characters from other people's issue bodies; --tooltip-bg and
   --tooltip-ink stay in the palette so the token set still diffs cleanly against
   status-translations. Facts here live in the page text, not in a hover. */

/* ---------- responsive ----------
   Reviewed at 320, 375 and 414 px (the phone range) and at 200% zoom, which is
   the same reflow test in a different disguise (WCAG 1.4.10). */
@media (max-width: 900px) {
  .cols { grid-template-columns: repeat(2, 1fr); }
  .pgrid { grid-template-columns: 1fr; }
}

/* Below 700px the eight-column table stops being a table and becomes one card
   per project. A horizontally-scrolled strip would satisfy "no horizontal page
   scroll" while making the Overview's main artefact unreadable — the column
   headings would be off-screen for every column but the first. The table markup
   carries explicit ARIA roles so that changing `display` here does not take the
   table semantics away from a screen reader, and each cell carries its heading
   in `data-label`. */
@media (max-width: 700px) {
  .table-scroll { overflow: visible; border: none; background: none; border-radius: 0; }
  /* The table box itself must leave table layout too, or it shrink-to-fits its
     widest cell's content and overflows a narrow viewport. */
  table, thead, tbody, tr, td { display: block; width: 100%; min-width: 0; }
  thead { display: none; }
  tbody tr:last-child td { border-bottom: none; }

  tr.group td, tr.done-toggle td { border-bottom: none; border-radius: 6px; }
  tr.group { margin: 18px 0 8px; }

  tr.proj {
    background: var(--surface); border: 1px solid var(--border); border-radius: 6px;
    margin-bottom: 10px; padding: 6px 0;
  }
  tr.proj:hover td, tr.proj:focus-within td { background: none; }
  tr.proj td {
    border-bottom: none; padding: 3px 12px; display: flex; gap: 4px 10px;
    align-items: baseline; flex-wrap: wrap;
  }
  /* The links cell is nowrap on a wide screen so a row stays on one line; on a
     phone it has to be allowed to wrap, while each individual link stays whole. */
  tr.proj td.links, tr.done-row td.links { white-space: normal; }
  tr.proj td:empty { display: none; }
  tr.proj td::before {
    content: attr(data-label); flex: none; width: 78px; color: var(--ink-3);
    font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 600;
    position: relative; top: -1px;
  }
  tr.proj td.name { display: block; padding: 8px 12px 6px; }
  tr.proj td.name::before { content: none; }
  tr.proj td.num { text-align: left; }
  tr.flags-row { margin: -8px 0 10px; padding: 0 12px 8px; }
  tr.flags-row td { padding: 0; }
  tr.done-row { border: 1px dashed var(--border); border-radius: 6px; margin-bottom: 8px; padding: 6px 0; }
  tr.done-row td { border-bottom: none; padding: 3px 12px; }
}

@media (max-width: 600px) {
  body { padding: 0 14px 56px; }
  header { padding-top: 28px; }
  h1 { font-size: 23px; }
  .mast { flex-wrap: wrap; }
  .cols { grid-template-columns: 1fr; }
  .cards { grid-template-columns: 1fr; }
  .tiles { grid-template-columns: 1fr; }
  .matrix { grid-template-columns: 56px repeat(3, minmax(0, 1fr)); gap: 4px; }
  .matrix .rh { padding: 8px 2px; font-size: 11px; }
  .matrix .hd { padding: 0 2px 4px; font-size: 10px; }
  .mcell { padding: 6px 7px; min-height: 54px; }
  .kv { grid-template-columns: 1fr; gap: 2px 0; }
  .kv dt { margin-top: 8px; }
  tr.group .roll { margin-left: 0; width: 100%; }
  .nf { grid-template-columns: 1fr; }
}

/* Tap targets: WCAG 2.5.5 asks for 44px. Rows and cards are large already; these
   are the small controls. */
@media (pointer: coarse) {
  nav.tabs a, .theme-toggle, th button, tr.done-toggle button,
  details.diag > summary, .rail-wrap > summary { min-height: 44px; display: inline-flex; align-items: center; }
}

@media (prefers-reduced-motion: no-preference) {
  .meter > i, .bar b > i { transition: width 0.5s ease-out; }
  .tile, .card, .kcard, tr.proj td { transition: border-color 0.12s, background-color 0.12s; }
}

/* ---------- print ----------
   A portfolio page gets taken into a meeting, so printing is a real use. The
   palette is forced back to the light tokens: without this a reader who chose
   the dark theme prints white text on white paper. */
@media print {
  :root, :root[data-theme="dark"], :root[data-theme="light"] {
    color-scheme: light;
    --plane: #ffffff; --surface: #ffffff; --ink: #000000; --ink-2: #333333; --ink-3: #595959;
    --hairline: #cccccc; --border: rgba(0, 0, 0, 0.28);
    --accent: #12467f; --accent-track: #dddddd; --accent-wash: transparent;
    --good: #006300; --good-text: #006300; --good-wash: transparent;
    --warn: #7a5200; --warn-mark: #7a5200; --warn-text: #7a5200; --warn-wash: transparent;
    --crit: #a02525; --crit-text: #a02525; --crit-wash: transparent;
    --empty-cell: #eeeeee; --group-wash: #f0f0f0;
    --stage-idea: #595959; --stage-proposed: #333333; --stage-active: #000000;
    --stage-steady: #333333; --stage-parked: #595959; --stage-done: #767676;
  }
  body { padding: 0; background: #fff; }
  .theme-toggle, nav.tabs, .skip { display: none; }
  .table-scroll { overflow: visible; border: none; }
  table { min-width: 0; }
  thead { display: table-header-group; }
  .tile, .card, .panel, .col, .kcard, tr { break-inside: avoid; }
  details { display: block; }
  details > summary { list-style: none; }
  details:not([open]) > *:not(summary) { display: revert; }
  /* Washes carry meaning in the triage matrix, and greyscale printing flattens
     them, so the marked cells get a border as well. */
  .mcell.hot { border: 2px solid var(--crit); }
  .mcell.warm { border: 1px dashed var(--warn-text); }
  /* Meters and bars print empty without this. */
  .meter, .meter > i, .bar b, .bar b > i { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  /* A printed page whose links are invisible is half a document. */
  main a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 10px; color: var(--ink-3); word-break: break-all; }
  footer a[href^="http"]::after { content: none; }
}
