/* The portfolio stylesheet. One file, no framework, no build step, shared by peterparker.ca
   and every project site, so each project reads as part of one body of work.

   The two fonts are copied beside the page rather than linked: the page makes no off-origin
   request, and a font is a request. Both are SIL Open Font License; fonts/LICENSE.txt says
   where they came from.

   Colours live here and never in app.js, so one palette follows the page into dark mode.
   Everything below the "project" marker at the end is this project's own; everything above
   it is the shared base and should change only for all sites at once. */

@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url(fonts/newsreader-latin.woff2) format("woff2");
}

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url(fonts/inter-latin.woff2) format("woff2");
}

:root {
  color-scheme: light dark;
  --paper: #f5f3ee;
  --paper-soft: #fdfcf9;
  --ink: #16181d;
  --ink-soft: #3c4048;
  --ink-faint: #6b7079;
  --line: #e3dfd6;
  --line-2: #cfc9bd;
  --line-soft: #eeebe4;
  --accent: #0f5c6e;
  --accent-ink: #0b4653;
  --accent-soft: #e4eff1;
  --warn: #c0392b;
  --good: #1e7a4c;
  --sim: #6d3f9e;
  --alt: #6d3f9e;
  /* An ordered set (levels, depths, years) is one hue in steps, never several hues. */
  --seq0: #0b4653;
  --seq1: #2f8294;
  --seq2: #7bb3c0;
  --serif: "Newsreader", Georgia, "Times New Roman", serif;
  --sans: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", Consolas, "SF Mono", Menlo, monospace;
  --radius: 10px;
  --shadow: 0 6px 24px -18px rgba(0, 0, 0, 0.35);
  --column: 66rem;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #0e1013;
    --paper-soft: #15181d;
    --ink: #ece9e2;
    --ink-soft: #c9c6bf;
    --ink-faint: #969ba5;
    --line: #262a31;
    --line-2: #363b44;
    --line-soft: #1c2026;
    --accent: #7cc7d6;
    --accent-ink: #a9dde7;
    --accent-soft: #14262b;
    --warn: #f0736a;
    --good: #58c286;
    --sim: #b191e0;
    --alt: #b191e0;
    --seq0: #cbeaf2;
    --seq1: #7cc7d6;
    --seq2: #3d8ea1;
    --shadow: 0 6px 24px -14px rgba(0, 0, 0, 0.6);
  }
}

* { box-sizing: border-box; }

html { font-size: 18px; -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.72;
  border-top: 3px solid var(--accent);
  overflow-x: clip;
  font-feature-settings: "cv11", "ss01";
}

main {
  max-width: var(--column);
  margin: 0 auto;
  padding: 0 1.5rem 5rem;
}

h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 500;
  letter-spacing: -0.012em;
}

h1 { font-size: clamp(2.1rem, 4.6vw, 3rem); line-height: 1.1; margin: 0 0 1rem; }
h2 { font-size: clamp(1.55rem, 2.6vw, 2rem); line-height: 1.2; margin: 0 0 0.7rem; }
h3 { font-size: 1.2rem; line-height: 1.25; margin: 0 0 0.45rem; }
p { margin: 0 0 0.85rem; }

a { color: var(--accent); text-decoration: none; text-underline-offset: 0.15em; }
a:hover, a:focus-visible { text-decoration: underline; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

code { font-family: var(--mono); font-size: 0.9em; }

strong { font-weight: 600; }

/* ---------------------------------------------------------------- the way back */

.top { border-bottom: 1px solid var(--line); background: var(--paper); }

.top-inner {
  max-width: var(--column);
  margin: 0 auto;
  padding: 0 1.5rem;
  height: 4rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  color: var(--ink);
  font-weight: 600;
  letter-spacing: -0.01em;
}

.brand:hover { text-decoration: none; color: var(--accent-ink); }

.mono-mark {
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 6px;
  background: var(--accent);
  color: #fdfcf9;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.15rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

@media (prefers-color-scheme: dark) {
  .mono-mark { color: #0e1013; }
}

.top-nav { font-size: 0.92rem; color: var(--ink-soft); text-align: right; margin: 0; }
.top-nav a { color: var(--ink-soft); }
.top-nav a:hover { color: var(--accent-ink); }

/* ---------------------------------------------------------------- hero */

.hero { position: relative; padding: 2rem 0 2.25rem; border-bottom: 1px solid var(--line); }
/* The first screen as project 03 (gate.peterparker.ca) has it: a wash of the accent behind it,
   full width and fading into the page, with a violet glow in the top right corner. */
.hero::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 100vw;
  margin-left: -50vw;
  background:
    radial-gradient(60rem 22rem at 85% 0%, color-mix(in srgb, var(--sim) 14%, transparent), transparent 70%),
    linear-gradient(180deg, var(--accent-soft), var(--paper) 85%);
}
.hero h1 .hl { color: var(--accent); }
.hero .eyebrow { color: var(--accent-ink); }

.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--ink-faint);
  margin: 0 0 0.6rem;
}

.lead { font-size: 1.05rem; color: var(--ink-soft); }

.hero-points {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: 0.9rem;
  margin: 1.75rem 0 1.1rem;
}

.point {
  background: var(--paper-soft);
  border: 1px solid var(--line);
  border-top: 3px solid var(--accent);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  box-shadow: var(--shadow);
}
.point.good { border-top-color: var(--good); }
.point.violet { border-top-color: var(--sim); }
.point .point-figure { color: var(--accent-ink); }
.point.good .point-figure { color: var(--good); }
.point.violet .point-figure { color: var(--sim); }

.point-figure {
  display: block;
  font-family: var(--serif);
  font-size: 1.9rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--ink);
}

.point-figure.up { color: var(--good); }
.point-figure.down { color: var(--warn); }

.point-unit {
  display: block;
  margin-top: 0.2rem;
  font-size: 0.84rem;
  font-weight: 600;
  color: var(--ink-soft);
  line-height: 1.35;
}

.point-label {
  display: block;
  margin-top: 0.4rem;
  padding-top: 0.4rem;
  border-top: 1px solid var(--line);
  font-size: 0.82rem;
  color: var(--ink-faint);
  line-height: 1.4;
}

.point-extra {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.8rem;
  color: var(--ink-faint);
  line-height: 1.35;
  font-variant-numeric: tabular-nums;
}

/* The one way straight to the thing to use, for a reader who came for that and not the method. */
.hero-cta { margin: 0 0 0.7rem; }

.button {
  display: inline-block;
  padding: 0.6rem 1.1rem;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--paper);
  font-weight: 600;
  text-decoration: none;
}
.button:hover, .button:focus-visible { background: var(--accent-ink); color: var(--paper); }
section[id] { scroll-margin-top: 1rem; }

/* A technical term that explains itself. The bubble hangs from the paragraph rather than
   from the word, because the paragraph is the one box that is always inside the page: a
   bubble anchored to a name at the end of a line would run off the right edge. It opens on
   focus as well as hover, so a keyboard reaches it and a tap on a phone opens it. */
.term {
  border-bottom: 1px dotted var(--ink-faint);
  cursor: help;
}

.term:hover, .term:focus { color: var(--accent-ink); border-bottom-color: var(--accent); }

.term::after {
  content: attr(data-note);
  position: absolute;
  left: 0;
  top: calc(100% + 0.4rem);
  width: min(32rem, 100%);
  padding: 0.7rem 0.85rem;
  background: var(--paper-soft);
  color: var(--ink-soft);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  font-size: 0.84rem;
  font-weight: 400;
  line-height: 1.5;
  z-index: 10;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.12s ease;
}

.term:hover::after, .term:focus::after { opacity: 1; visibility: visible; }

/* Read by a screen reader, drawn for nobody: the notes the bubbles show, as descriptions. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.hero-note { font-size: 0.88rem; color: var(--ink-faint); margin: 0; }

/* ---------------------------------------------------------------- sections */

.section { padding: 2.75rem 0; border-bottom: 1px solid var(--line); }
.section:last-of-type { border-bottom: 0; }
.section-lead { color: var(--ink-soft); }
.note { font-size: 0.86rem; color: var(--ink-faint); }
/* A note that explains the table above it, rather than the one below. */
.table-wrap + .note { margin-top: 1.1rem; }

.warning {
  max-width: var(--column);
  margin: 1.25rem auto;
  padding: 0.9rem 1.1rem;
  border-left: 3px solid var(--warn);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: color-mix(in srgb, var(--warn) 9%, transparent);
}

/* The callout a section's finding goes in, and the one an assumption goes in. Same shape,
   different weight: a finding is the point of the section, an assumption is the fine print
   that stops the finding being overread. */
.verdict {
  margin: 1.1rem 0 1.6rem;
  padding: 1rem 1.1rem;
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  font-size: 0.98rem;
}

.verdict p:last-child { margin-bottom: 0; }

.assumption {
  margin: 1.1rem 0 0;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-2);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--paper-soft);
  font-size: 0.88rem;
  color: var(--ink-soft);
}

.assumption p:last-child { margin-bottom: 0; }

/* ---------------------------------------------------------------- controls */

.controls {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 1rem;
  margin: 1.25rem 0;
  padding: 1rem;
  background: var(--paper-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.control { display: flex; flex-direction: column; gap: 0.4rem; min-width: 0; }
.control.wide { grid-column: 1 / -1; }

label { font-size: 0.85rem; font-weight: 600; color: var(--ink-soft); }

.hint {
  display: block;
  font-weight: 400;
  font-size: 0.78rem;
  color: var(--ink-faint);
  margin-top: 0.1rem;
}

select, input[type="range"] { width: 100%; font: inherit; accent-color: var(--accent); }

select {
  padding: 0.5rem 0.6rem;
  border: 1px solid var(--line-2);
  border-radius: 8px;
  background: var(--paper-soft);
  color: var(--ink);
  font-size: 0.9rem;
}

input[type="range"] { height: 1.6rem; }

output { font-variant-numeric: tabular-nums; color: var(--accent-ink); font-weight: 600; }

/* ---------------------------------------------------------------- charts */

.chart-figure { margin: 1.1rem 0; }
.chart { width: 100%; }
.chart svg { width: 100%; height: auto; display: block; touch-action: pan-y; }

/* A chart whose labels are words rather than ticks cannot be shrunk to a phone's width and
   still be read, so it keeps its size and scrolls sideways instead. */
.wide-chart { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.wide-chart svg { min-width: 40rem; }

figcaption { font-size: 0.83rem; color: var(--ink-faint); margin-top: 0.5rem; }

.gridline { stroke: var(--line); stroke-width: 1; }
.axis-line { stroke: var(--line-2); stroke-width: 1; }
.tick { fill: var(--ink-faint); font-size: 11px; }
.axis-title { fill: var(--ink-faint); font-size: 11px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
.series { fill: none; stroke-linejoin: round; stroke-linecap: round; stroke-width: 1.5; }
.band { fill: var(--accent); stroke: none; }

/* Series colours and the swatch that names each one. Set here rather than on the element so
   that both follow the palette into dark mode. Add a project's series below the marker. */
.s0 { stroke: var(--accent); }
.s1 { stroke: var(--warn); }
.s2 { stroke: var(--alt); }
.dot.s0 { fill: var(--accent); }
.dot.s1 { fill: var(--warn); }
.dot.s2 { fill: var(--alt); }
.sw-s0 { background: var(--accent); }
.sw-s1 { background: var(--warn); }
.sw-s2 { background: var(--alt); }
.bar.seq0 { fill: var(--seq0); }
.bar.seq1 { fill: var(--seq1); }
.bar.seq2 { fill: var(--seq2); }
.sw-seq0 { background: var(--seq0); }
.sw-seq1 { background: var(--seq1); }
.sw-seq2 { background: var(--seq2); }

.sw-ink { background: var(--ink); }
.sw-accent { background: var(--accent); }
.sw-band { background: var(--accent); }
.sw-warn { background: var(--warn); color: var(--warn); }
.sw-faint { background: var(--ink-faint); color: var(--ink-faint); }
.nominal { stroke: var(--ink-faint); stroke-width: 1; stroke-dasharray: 5 4; fill: none; }
.actual-line { fill: none; stroke: var(--ink); stroke-width: 1.5; stroke-linejoin: round; }
.median { fill: none; stroke: var(--accent); stroke-width: 1.75; stroke-linejoin: round; }
/* A dense series (hundreds of points in the same width) gets the thin variant. */
.actual-line.thin, .median.thin { stroke-width: 0.8; }

.cursor { stroke: var(--ink-faint); stroke-width: 1; stroke-dasharray: 3 3; }
.dot { stroke: var(--paper-soft); stroke-width: 1.5; fill: var(--ink); }

.catcher { cursor: crosshair; }

/* A bar is a length, so it gets a fill and no outline; the interval is
   a hairline through it, in ink rather than in the series colour, because it is not a
   fourth series. */
.bar { stroke: none; }

.bar.own { fill-opacity: 0.7; stroke: var(--ink-faint); stroke-width: 1; stroke-dasharray: 3 2; }

.whisker { stroke: var(--ink-soft); stroke-width: 1; }
.zero { stroke: var(--ink-faint); stroke-width: 1.25; }
.zero-label { fill: var(--ink-faint); font-size: 10.5px; }
.bar-value { fill: var(--ink-soft); font-size: 11px; font-variant-numeric: tabular-nums; }
.row-label { fill: var(--ink); font-size: 12px; font-weight: 600; }
.row-label.faint { fill: var(--ink-soft); font-weight: 500; }
.row-note { fill: var(--ink-faint); font-size: 10.5px; }
.divider { stroke: var(--line-2); stroke-width: 1; stroke-dasharray: 4 3; }

/* A label a line runs through gets a halo in the page colour, so it stays readable. */
.halo { paint-order: stroke; stroke: var(--paper); stroke-width: 4px; stroke-linejoin: round; }

.divider-label { fill: var(--ink-faint); font-size: 10.5px; letter-spacing: 0.04em; text-transform: uppercase; }

.legend { display: flex; flex-wrap: wrap; gap: 0.45rem; margin: 0.25rem 0 0.5rem; }

.legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.82rem;
  padding: 0.3rem 0.7rem;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: var(--paper-soft);
  color: var(--ink-soft);
}

.swatch { width: 14px; height: 3px; border-radius: 2px; display: inline-block; flex: none; }
.swatch.dashed { background: repeating-linear-gradient(90deg, currentColor 0 4px, transparent 4px 7px); }
.swatch.block { height: 11px; border-radius: 3px; opacity: 0.3; }
/* A bar's swatch is the bar's colour at full strength: it names a series, not a band. */
.swatch.solid { height: 11px; border-radius: 3px; }

/* The hover readout. One row per series, values right-aligned so they line up as a column. */
.readout {
  min-height: 1.6rem;
  margin: 0.3rem 0 0;
  font-size: 0.84rem;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

.readout .when { font-weight: 600; color: var(--ink); margin-right: 0.6rem; }
.readout .pair { margin-right: 0.9rem; white-space: nowrap; }
.readout .key { color: var(--ink-faint); }

/* ---------------------------------------------------------------- tables */

.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }

table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }

th, td {
  text-align: left;
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

th {
  font-weight: 600;
  color: var(--ink);
  font-size: 0.82rem;
  background: var(--line-soft);
  border-bottom-color: var(--line-2);
  vertical-align: bottom;
}

tbody th { background: transparent; font-size: 0.9rem; }
/* A row label that carries its window as well as its name is the one cell allowed to wrap,
   so that one long label does not push the whole table out of its column. */
tbody th.wrap { white-space: normal; max-width: 14rem; }

td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }

/* A wide table of estimates and intervals gets narrower gutters before it gets a scrollbar.
   It still scrolls on a narrow screen, like every other table. */
.tight th, .tight td { padding-left: 0.55rem; padding-right: 0.55rem; }

caption { caption-side: bottom; text-align: left; color: var(--ink-faint); font-size: 0.83rem; padding-top: 0.6rem; }

tbody tr.reference { background: var(--accent-soft); }

.interval { color: var(--ink-faint); font-size: 0.82em; }

.better { color: var(--good); font-weight: 600; }
.worse { color: var(--warn); font-weight: 600; }

/* ---------------------------------------------------------------- headline stats */

.headline {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.9rem;
  margin: 1.25rem 0;
}

.stat {
  background: var(--paper-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
}

.figure {
  display: block;
  font-family: var(--serif);
  font-size: 1.75rem;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  line-height: 1.15;
}

.stat.up .figure { color: var(--good); }
.stat.down .figure { color: var(--warn); }

.caption { display: block; margin-top: 0.3rem; font-size: 0.82rem; color: var(--ink-faint); line-height: 1.4; }

.range { display: block; font-size: 0.78rem; color: var(--ink-faint); font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------- disclosure */

.disclose {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 1.1rem;
  margin: 1.1rem 0;
  background: var(--paper-soft);
}

.disclose summary {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  cursor: pointer;
  padding: 0.8rem 0 0.8rem 0.25rem;
  font-weight: 600;
  font-size: 0.94rem;
  list-style: none;
}

.disclose summary::-webkit-details-marker { display: none; }

.disclose summary::before {
  content: "\203A";
  flex: none;
  width: 0.6em;
  text-align: center;
  font-size: 1.2em;
  line-height: 1;
  color: var(--ink-faint);
  transform: rotate(90deg);
  transition: transform 0.12s ease;
}

.disclose[open] summary::before { transform: rotate(270deg); }
.disclose summary:hover { color: var(--accent-ink); }
.disclose[open] summary { border-bottom: 1px solid var(--line); margin-bottom: 0.75rem; }
.disclose > *:last-child { margin-bottom: 0.85rem; }

@media (prefers-reduced-motion: reduce) {
  .disclose summary::before { transition: none; }
  .term::after { transition: none; }
}

/* ---------------------------------------------------------------- footer */

.foot {
  border-top: 1px solid var(--line);
  background: var(--paper-soft);
  margin-top: 2rem;
}

.foot-inner {
  max-width: var(--column);
  margin: 0 auto;
  padding: 2rem 1.5rem 2.5rem;
  font-size: 0.88rem;
  color: var(--ink-faint);
}

.foot-inner p { margin: 0 0 0.5rem; }

.foot-inner ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; }

@media (max-width: 34rem) {
  html { font-size: 17px; }
  main { padding: 0 1rem 3rem; }
  .top-inner { padding: 0 1rem; height: auto; min-height: 4rem; flex-wrap: wrap; gap: 0.25rem 1rem; padding-top: 0.6rem; padding-bottom: 0.6rem; }
  .top-nav { text-align: left; }
  .controls { padding: 0.85rem; }
  .foot-inner { padding: 1.5rem 1rem 2rem; }
}

/* ------------------------------------------------------------- on this page */

.toc { padding: 1.5rem 0 1.75rem; border-bottom: 1px solid var(--line); }
.toc ol {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: toc;
  columns: 2 16rem;
  column-gap: 2rem;
}
.toc li { counter-increment: toc; margin: 0 0 0.3rem; break-inside: avoid; font-size: 0.93rem; }
.toc li::before {
  content: counter(toc, decimal-leading-zero);
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
  font-size: 0.78rem;
  margin-right: 0.6rem;
}

.part { padding: 3.5rem 0 0.5rem; }
.part-title { font-size: clamp(1.75rem, 3.4vw, 2.4rem); line-height: 1.15; margin-bottom: 0.9rem; }

.two-col { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); gap: 1.25rem 2rem; margin: 1rem 0; }

/* ------------------------------------------------------------- the picture */

.pipeline {
  list-style: none;
  margin: 1.5rem 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(var(--steps, 7), minmax(0, 1fr));
  gap: 0.6rem;
}
.pipeline.steps-4 { --steps: 4; }
.pipeline.steps-5 { --steps: 5; }
.pipeline.steps-6 { --steps: 6; }
.pipeline.steps-7 { --steps: 7; }
.pipeline.steps-8 { --steps: 8; }
@media (max-width: 60rem) {
  .pipeline { grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); }
}
.pipeline li {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.8rem 0.75rem 0.9rem;
  background: var(--paper-soft);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: 0.82rem;
  color: var(--ink-soft);
  line-height: 1.45;
}
.pipeline li strong { font-family: var(--serif); font-size: 1.15rem; font-weight: 500; color: var(--ink); }
.pipeline li.key { border-color: var(--accent); background: var(--accent-soft); }
.step {
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  background: var(--accent);
  color: var(--paper-soft);
  font-size: 0.8rem;
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 0.2rem;
}

/* ------------------------------------------------------------- how it works */

table.example { margin-top: 0.5rem; }

pre.formula {
  font-family: var(--mono);
  font-size: 0.8rem;
  line-height: 1.55;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0.9rem 1rem;
  overflow-x: auto;
  margin: 0.4rem 0 0.9rem;
}

.cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.9rem; margin: 1.25rem 0; }
@media (max-width: 50rem) {
  .cards { grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
}

.card-note { padding: 1rem 1.1rem; background: var(--paper-soft); border: 1px solid var(--line); border-top: 3px solid var(--warn); border-radius: var(--radius); }
.card-note h3 { font-size: 1.08rem; }
.card-note p { font-size: 0.9rem; color: var(--ink-soft); margin: 0; }

.checks { list-style: none; padding: 0; margin: 1rem 0; display: grid; gap: 0.7rem; }
.checks li { padding-left: 1.7rem; position: relative; }
.checks li::before { content: "\2713"; position: absolute; left: 0; top: 0; color: var(--good); font-weight: 700; }

.chips { list-style: none; padding: 0; margin: 1.25rem 0; display: flex; flex-wrap: wrap; gap: 0.45rem; }
.chips li { padding: 0.25rem 0.75rem; border: 1px solid var(--line-2); border-radius: 999px; font-size: 0.82rem; background: var(--paper-soft); color: var(--ink-soft); }

.glossary { margin: 0 0 0.9rem; }
.glossary dt { font-weight: 600; margin-top: 0.7rem; }
.glossary dd { margin: 0.15rem 0 0; color: var(--ink-soft); font-size: 0.92rem; }

.disclose ul { padding-left: 1.2rem; }
.disclose li { margin-bottom: 0.5rem; }

@media (max-width: 34rem) {
  .toc ol { columns: 1; }
}

section > h3 { margin-top: 2rem; }

/* ---------------------------------------------------------------- the menu */

/* The page's main sections and the architecture page, as pills, as on the other project
   pages. The numbered list below the hero stays the full table of contents. */
.tabs { border-bottom: 1px solid var(--line); background: var(--paper-soft); }

.tabs-inner {
  max-width: var(--column);
  margin: 0 auto;
  padding: 0.55rem 1.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem;
}

.tabs a {
  font-size: 0.83rem;
  padding: 0.2rem 0.55rem;
  border-radius: 999px;
  border: 1px solid transparent;
  color: var(--ink-soft);
}

.tabs a:hover { text-decoration: none; border-color: var(--line-2); color: var(--accent-ink); }

.tabs a[aria-current] {
  border-color: var(--accent);
  background: var(--accent-soft);
  color: var(--ink);
  font-weight: 600;
}

@media (max-width: 46rem) {
  /* One row that scrolls sideways, rather than rows of pills above the page. */
  .tabs-inner { padding: 0.5rem 1.1rem; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .tabs a { flex: none; }
}

/* ---------------------------------------------------------------- the architecture page */

/* The diagrams are white-ground SVGs generated from a specification, so they sit on their own
   card in both themes, and each opens full size for narrow screens. */
.arch-figure { margin: 1.1rem 0 1.4rem; }
.arch-figure a { display: block; }
.arch-figure img {
  display: block;
  width: 100%;
  height: auto;
  background: #ffffff;
  border: 1px solid var(--line);
  border-radius: 8px;
}
.prose .where { font-size: 0.86rem; color: var(--ink-faint); }
.arch-back { margin: 0; font-size: 0.95rem; }

/* ---------------------------------------------------------------- reading on paper */

@media print {
  .top, .tabs, .toc, .hero::before, .button, .controls { display: none; }
  body { border-top: 0; }
  .disclose { border: 0; padding: 0; }
}

/* ====================================================================== project */

/* This project's own components and series colours go here, each with a comment saying what
   it shows and why it looks the way it does. */

/* The warning figure in the hero: the confidently-wrong rate, which missed its target. */
.point.warnline { border-top-color: var(--warn); }
.hero .point.warnline .point-figure { color: var(--warn); }

/* Bars in the warning colour: a fix that failed, or a reviewer's false alarm. */
.bar.warnbar { fill: var(--warn); fill-opacity: 0.8; }
.sw-warnbar { background: var(--warn); }

/* An invisible strip over each bar row, so the whole row answers the pointer and the keyboard,
   not only the bar, which can be a few pixels wide. */
.hit { fill: transparent; cursor: pointer; }
.hit:focus { outline: none; fill: var(--accent-soft); fill-opacity: 0.45; }

/* The walk-through of one failure: numbered step buttons over one panel. */
.stepper { display: flex; flex-wrap: wrap; gap: 0.45rem; margin: 1.2rem 0 0.8rem; }
.stepper button {
  display: inline-flex; align-items: center; gap: 0.45rem;
  font: inherit; font-size: 0.9rem; color: var(--ink-soft);
  background: var(--paper-soft); border: 1px solid var(--line-2); border-radius: 999px;
  padding: 0.3rem 0.85rem 0.3rem 0.35rem; cursor: pointer;
  transition: border-color 0.12s, background 0.12s;
}
.stepper button .step { width: 1.5rem; height: 1.5rem; font-size: 0.8rem; margin: 0; }
.stepper button:hover { border-color: var(--accent); color: var(--accent-ink); }
.stepper button[aria-selected="true"] { background: var(--accent-soft); border-color: var(--accent); color: var(--ink); font-weight: 600; }
.step-panel {
  background: var(--paper-soft); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.1rem 1.25rem 0.6rem; min-height: 18rem;
}
.step-panel h3 { margin-top: 0; }
.step-nav { display: flex; justify-content: space-between; gap: 0.6rem; flex-wrap: wrap; margin-top: 1rem; }
.step-move {
  font: inherit; font-size: 0.88rem; color: var(--accent-ink); background: none;
  border: 1px solid var(--line-2); border-radius: 6px; padding: 0.3rem 0.75rem; cursor: pointer;
}
.step-move.next { margin-left: auto; }
.step-move:hover { border-color: var(--accent); }
@media (prefers-reduced-motion: reduce) { .stepper button { transition: none; } }

/* Code from the run's record: the test, the sandbox output and the diff. */
pre.code {
  font-family: var(--mono); font-size: 0.78rem; line-height: 1.55;
  background: var(--paper); border: 1px solid var(--line); border-radius: 6px;
  padding: 0.75rem 0.9rem; overflow-x: auto; margin: 0.5rem 0 1rem; color: var(--ink);
}
pre.code span { white-space: pre; }
pre.diff .add { color: var(--good); }
pre.diff .del { color: var(--warn); }
ul.plain { padding-left: 1.1rem; margin: 0.3rem 0 1rem; }
ul.plain li { margin-bottom: 0.2rem; }
ul.compact li { font-size: 0.86rem; word-break: break-word; }

/* The tickets: one row each, a pip per failure, the biggest first and marked. */
.tickets { display: grid; gap: 0.45rem; margin: 0.6rem 0 1rem; }
.ticket { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; gap: 0.8rem; align-items: center; font-size: 0.88rem; }
.ticket-name { font-family: var(--mono); font-size: 0.8rem; overflow-wrap: anywhere; color: var(--ink-soft); }
.ticket.first .ticket-name { color: var(--ink); font-weight: 600; }
.ticket-track { display: inline-flex; gap: 3px; }
.pip { width: 0.8rem; height: 0.8rem; border-radius: 3px; background: var(--line); }
.pip.on { background: var(--seq2); }
.ticket.first .pip.on { background: var(--accent); }
.ticket-size { font-size: 0.8rem; color: var(--ink-faint); min-width: 5.5rem; text-align: right; font-variant-numeric: tabular-nums; }
@media (max-width: 34rem) {
  .ticket { grid-template-columns: minmax(0, 1fr) auto; }
  .ticket-track { display: none; }
}

/* The live runs and the five cases are tables of words as well as numbers. */
#cases-rows td { white-space: normal; vertical-align: top; }
#cases-rows td:last-child { min-width: 18rem; font-size: 0.88rem; }
#cases-rows code { font-size: 0.8rem; white-space: nowrap; }

/* The limits are not promises kept, so they get a plain marker rather than the tick. */
.checks.limits li::before { content: "\2022"; color: var(--ink-faint); }

/* The film: rendered by video/render.py, dark in both themes like the other project films. */
.demo-video { display: block; width: 100%; max-width: 52rem; aspect-ratio: 1; margin: 1rem auto 0; border-radius: var(--radius); background: #0a111c; box-shadow: var(--shadow); }
.demo-video-note { max-width: 52rem; margin: 0.6rem auto 0; font-size: 0.9rem; color: var(--ink-faint); text-align: center; }

/* The note under the hero figures that carries the missed target. */
.hero-caveat { margin-bottom: 0.6rem; color: var(--ink-soft); }
.hero-caveat strong { color: var(--warn); }
