/* VioPO. One stylesheet for every page.
   Strict CSP: no inline styles anywhere, so everything lives here.
   Contents: fonts, tokens, base, header, links and buttons, hero, plate,
   sections, project register, pipeline figure, notes list, subjects,
   pagination, page head, article, prose, listings, tables, figures,
   footnotes, footer, privacy notice, 404, motion, responsive, print.
   Every colour is a token: the dark palette redefines the tokens only. */

/* ---------- Fonts (self-hosted, SIL Open Font Licence 1.1) ---------- */
@font-face {
  font-family: "Newsreader";
  src: url("/assets/fonts/newsreader-latin-400-600-normal.425676ef80.woff2") format("woff2");
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Newsreader";
  src: url("/assets/fonts/newsreader-latin-400-500-italic.89e76875c0.woff2") format("woff2");
  font-weight: 400 500;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "Public Sans";
  src: url("/assets/fonts/public-sans-latin-400-700-normal.25327461c4.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/assets/fonts/ibm-plex-mono-latin-400-normal.08949f728d.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
/* Metric-matched local fallbacks. They hold the same line height and close to
   the same line length as the web fonts, so the swap barely moves the page. */
@font-face {
  font-family: "Newsreader Fallback";
  src: local("Georgia");
  size-adjust: 96.07%;
  ascent-override: 76.51%;
  descent-override: 27.58%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Public Sans Fallback";
  src: local("Arial");
  size-adjust: 105.6%;
  ascent-override: 89.96%;
  descent-override: 21.31%;
  line-gap-override: 0%;
}

/* ---------- Tokens ---------- */
:root {
  --paper: #ffffff;
  --paper-2: #f7f7f5;
  --ink: #14151a;
  --ink-2: #43464f;
  --ink-3: #626570;
  --line: #dcdde2;
  --line-2: #ececef;
  --line-3: #b9bbc4;
  --line-4: #8a8d98;
  --violet: #5a3ea8;
  --violet-deep: #43297f;
  --wash: #efeaf9;
  /* the back V of the mark, text set on a violet fill, soft shading */
  --mark-back: #c9bdea;
  --on-violet: #ffffff;
  --shade: rgba(20, 21, 26, 0.1);
  --notice-shadow: 0 10px 28px -18px rgba(20, 21, 26, 0.35);
  /* highlight.js tokens, AA on --paper-2 and on --wash */
  --code-comment: #5f626d;
  --code-keyword: #5a3ea8;
  --code-string: #2a5b4c;
  --code-number: #8a4412;
  --code-title: #1d4f80;
  --code-attr: #43297f;
  --code-add: #1f5a3c;
  --code-add-bg: #e3f1e8;
  --code-del: #8c2626;
  --code-del-bg: #f9e6e4;
  /* VioPO: errors, success and warnings */
  --error: #8c2626;
  --error-text: #6d1d1d;
  --error-bg: #f9e6e4;
  --ok: #1f5a3c;
  --ok-text: #1f4a32;
  --ok-bg: #e3f1e8;
  --warn: #8a4412;
  --warn-bg: #f8ecdf;
    color-scheme: light;

  --serif: "Newsreader", "Newsreader Fallback", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --sans: "Public Sans", "Public Sans Fallback", -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --gutter: clamp(20px, 5vw, 64px);
  --wrap: 1240px;
  --no-col: 88px;
  --ease: cubic-bezier(0.22, 0.7, 0.2, 1);
  --ease-draw: cubic-bezier(0.6, 0.05, 0.25, 1);
  --header-h: 68px;
}

/* Dark: "clinical at night". A deep blue-grey ground, soft off-white ink,
   quiet hairlines, the violet lifted to pass AA as text. The same values are
   written twice: once for a choice made with the toggle (data-theme, set by
   theme.js before first paint) and once for the system setting, so dark works
   with scripts off. Keep the two blocks identical. */
:root[data-theme="dark"] {
  --paper: #121419;
  --paper-2: #181b21;
  --ink: #e7e8ec;
  --ink-2: #b9bcc5;
  --ink-3: #959aa6;
  --line: #2d313a;
  --line-2: #22262d;
  --line-3: #464b56;
  --line-4: #6d7280;
  --violet: #a593ee;
  --violet-deep: #c6b9f6;
  --wash: #2a2443;
  --mark-back: #544a86;
  --on-violet: #121419;
  --shade: rgba(0, 0, 0, 0.35);
  --notice-shadow: 0 10px 28px -18px rgba(0, 0, 0, 0.8);
  --code-comment: #959aa6;
  --code-keyword: #b4a4f2;
  --code-string: #86c6ab;
  --code-number: #e2a877;
  --code-title: #8fbbe9;
  --code-attr: #c6b9f6;
  --code-add: #9fd8b6;
  --code-add-bg: #16301f;
  --code-del: #f1aaa4;
  --code-del-bg: #3a1c1e;
  --error: #f1aaa4;
  --error-text: #f6c4bf;
  --error-bg: #3a1c1e;
  --ok: #9fd8b6;
  --ok-text: #b8e4ca;
  --ok-bg: #16301f;
  --warn: #e2a877;
  --warn-bg: #36261a;
    color-scheme: dark;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper: #121419;
    --paper-2: #181b21;
    --ink: #e7e8ec;
    --ink-2: #b9bcc5;
    --ink-3: #959aa6;
    --line: #2d313a;
    --line-2: #22262d;
    --line-3: #464b56;
    --line-4: #6d7280;
    --violet: #a593ee;
    --violet-deep: #c6b9f6;
    --wash: #2a2443;
    --mark-back: #544a86;
    --on-violet: #121419;
    --shade: rgba(0, 0, 0, 0.35);
    --notice-shadow: 0 10px 28px -18px rgba(0, 0, 0, 0.8);
    --code-comment: #959aa6;
    --code-keyword: #b4a4f2;
    --code-string: #86c6ab;
    --code-number: #e2a877;
    --code-title: #8fbbe9;
    --code-attr: #c6b9f6;
    --code-add: #9fd8b6;
    --code-add-bg: #16301f;
    --code-del: #f1aaa4;
    --code-del-bg: #3a1c1e;
    --error: #f1aaa4;
    --error-text: #f6c4bf;
    --error-bg: #3a1c1e;
    --ok: #9fd8b6;
    --ok-text: #b8e4ca;
    --ok-bg: #16301f;
    --warn: #e2a877;
    --warn-bg: #36261a;
        color-scheme: dark;
  }
}

/* ---------- Base ---------- */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: calc(var(--header-h) + 24px);
}
/* While the privacy notice is open, keyboard focus and anchor jumps stop
   short of it, and the page can scroll far enough that nothing at its foot
   stays underneath it. site.js measures the notice into --notice-h. */
html.notice-open { scroll-padding-bottom: calc(var(--notice-h, 0px) + 32px); }
html.notice-open body { padding-bottom: calc(var(--notice-h, 0px) + 16px); }
/* site.js may hand focus to <main> when the notice closes: no ring round the page. */
#main[tabindex="-1"]:focus { outline: none; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.6;
  font-feature-settings: "kern", "liga";
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

h1, h2, h3, h4, p, ol, ul, dl, dd, figure, blockquote, pre { margin: 0; }
img, svg { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
button { font: inherit; color: inherit; }

/* Lists that are layout, not prose. role="list" keeps them lists in VoiceOver. */
.plain-list,
.site-nav ul,
.footer-col ul,
.notes,
.fn,
.plate-legend,
.pipeline-steps,
.subjects ul,
.pagination ol,
.toc ol { margin: 0; padding: 0; list-style: none; }

::selection { background: var(--wash); color: var(--violet-deep); }

:focus-visible {
  outline: 2px solid var(--violet);
  outline-offset: 3px;
  border-radius: 1px;
}

.wrap {
  width: 100%;
  max-width: calc(var(--wrap) + var(--gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.skip {
  position: absolute;
  left: var(--gutter);
  top: 0;
  z-index: 100;
  padding: 10px 16px;
  background: var(--ink);
  color: var(--paper);
  font-size: 0.875rem;
  text-decoration: none;
  transform: translateY(-160%);
}
.skip:focus { transform: translateY(12px); }

/* Keeps a trailing arrow on the same line as the last word of a link. */
.nw { white-space: nowrap; }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Tracked label, used sparingly. Never below 12px. */
.label {
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ---------- Header ---------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--paper);
}
.site-header::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--line);
  opacity: 0;
  transition: opacity 0.3s ease;
}
.site-header.is-scrolled::after { opacity: 1; }

.site-header .wrap {
  display: flex;
  align-items: center;
  gap: 16px;
  height: var(--header-h);
}

.wordmark {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4em;
  font-family: var(--serif);
  font-size: 1.4375rem;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1;
  text-decoration: none;
  color: var(--ink);
  /* a taller target for touch without moving anything */
  padding-block: 6px;
  margin-block: -6px;
}
/* The mark: two offset V glyphs. It stands on the baseline of the wordmark
   and is 0.72em tall. On hover the back V slides out a little. */
.mark { width: 0.92em; height: 0.72em; flex: none; overflow: visible; }
.mark-front { fill: var(--violet); }
.mark-back { fill: var(--mark-back); transition: transform 0.45s var(--ease); }
.wordmark:hover .mark-back,
.wordmark:focus-visible .mark-back { transform: translateX(4px); }
.wordmark-text { white-space: nowrap; }

.site-nav ul { display: flex; gap: clamp(18px, 3vw, 36px); }
.site-nav a {
  position: relative;
  display: block;
  padding: 10px 0;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink-2);
  text-decoration: none;
  transition: color 0.2s ease;
}
.site-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 5px;
  height: 1px;
  background: var(--violet);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.35s var(--ease);
}
.site-nav a:hover,
.site-nav a:focus-visible,
.site-nav a[aria-current] { color: var(--ink); }
.site-nav a:hover::after,
.site-nav a:focus-visible::after,
.site-nav a[aria-current]::after { transform: scaleX(1); }

/* Theme toggle: the last item of the header. A moon in light (it will turn
   the lights down), a sun in dark. It is shown once site.js has wired it,
   and not at all without scripts; the space is kept so nothing moves. */
.site-nav { margin-left: auto; }
.theme-toggle {
  position: relative;
  display: inline-grid;
  place-items: center;
  flex: none;
  width: 36px;
  height: 36px;
  margin-right: -8px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--ink-2);
  cursor: pointer;
  visibility: hidden;
  transition: color 0.2s ease;
}
.theme-ready .theme-toggle { visibility: visible; }
@media (scripting: none) { .theme-toggle { display: none; } }
.theme-toggle:hover,
.theme-toggle:focus-visible { color: var(--violet-deep); }
.theme-toggle:focus-visible { outline-offset: 0; border-radius: 50%; }
.theme-icon { width: 20px; height: 20px; overflow: visible; fill: none; stroke: currentColor; stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.ti-sun,
.ti-moon { transform-box: view-box; transform-origin: 12px 12px; transition: transform 0.6s var(--ease), opacity 0.35s ease; }
.ti-sun { opacity: 0; transform: rotate(-90deg) scale(0.5); }
:root[data-theme="dark"] .ti-sun { opacity: 1; transform: none; }
:root[data-theme="dark"] .ti-moon { opacity: 0; transform: rotate(90deg) scale(0.5); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .ti-sun { opacity: 1; transform: none; }
  :root:not([data-theme="light"]) .ti-moon { opacity: 0; transform: rotate(90deg) scale(0.5); }
}

/* The switch itself. site.js adds .theme-switching for the frame of the
   change, so colour transitions do not run one by one; with the View
   Transitions API the new theme is revealed in a circle from the toggle
   (the clip is animated from site.js).
   The sun and moon are left out, so they still turn into each other.
   (Under reduced motion every transition is instant anyway.) */
.theme-switching *:not(.ti-sun):not(.ti-moon),
.theme-switching *::before,
.theme-switching *::after { transition: none !important; }
.theme-switching::view-transition-old(root),
.theme-switching::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
.theme-switching::view-transition-old(root) { z-index: 1; }
.theme-switching::view-transition-new(root) { z-index: 2; }

/* Reading progress, article pages only */
.progress {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  height: 2px;
  background: var(--violet);
  transform: scaleX(var(--p, 0));
  transform-origin: left center;
}

/* ---------- Links and buttons ---------- */
/* .go: an internal link with a drawn arrow. Hairline at rest, violet on hover. */
.go {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 6px 0;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  box-shadow: inset 0 -1px 0 var(--line-4);
  transition: color 0.2s ease;
}
.go::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--violet);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.45s var(--ease);
}
.go:hover,
.go:focus-visible { color: var(--violet-deep); }
.go:hover::after,
.go:focus-visible::after { transform: scaleX(1); }

/* .link: a text link that is always underlined. */
.link,
.prose a,
.fn a,
.about-copy a,
.details a {
  color: var(--ink);
  text-decoration-line: underline;
  text-decoration-color: var(--violet);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}
.link:hover,
.prose a:hover,
.fn a:hover,
.about-copy a:hover,
.details a:hover { color: var(--violet-deep); text-decoration-thickness: 2px; }
.link { display: inline-flex; align-items: center; gap: 9px; font-size: 0.9375rem; font-weight: 600; }

/* .btn: the one primary outbound link of a project entry. */
.btn {
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 11px 18px 11px 20px;
  border: 1px solid var(--ink);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--ink);
  text-decoration: none;
  overflow: hidden;
  transition: color 0.25s ease 0.05s;
}
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.45s var(--ease);
}
.btn:hover,
.btn:focus-visible { color: var(--paper); }
.btn:hover::before,
.btn:focus-visible::before { transform: scaleX(1); }

/* Arrows are drawn in CSS. Only transforms change on hover. */
.arrow {
  position: relative;
  display: inline-block;
  width: 26px;
  height: 9px;
  flex: none;
}
.arrow::before {
  content: "";
  position: absolute;
  left: 0;
  top: 4px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform-origin: left center;
  transition: transform 0.45s var(--ease);
}
.arrow::after {
  content: "";
  position: absolute;
  right: 0;
  top: 1px;
  width: 7px;
  height: 7px;
  border-top: 1px solid currentColor;
  border-right: 1px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.45s var(--ease);
}
a:hover > .arrow::before,
a:focus-visible > .arrow::before,
a:hover .label > .arrow::before { transform: scaleX(1.5); }
a:hover > .arrow::after,
a:focus-visible > .arrow::after,
a:hover .label > .arrow::after { transform: translateX(13px) rotate(45deg); }
.arrow--back { transform: scaleX(-1); }

/* Outbound arrow: a square box that sits on the text baseline. */
.arrow--out {
  width: 10px;
  height: 10px;
  transition: transform 0.35s var(--ease);
}
.arrow--out::before {
  left: 0;
  top: auto;
  bottom: 0;
  width: 141.4%;
  transform: rotate(-45deg);
  transition: none;
}
.arrow--out::after {
  top: 0;
  width: 70%;
  height: 70%;
  transform: none;
  transition: none;
}
a:hover > .arrow--out::before,
a:focus-visible > .arrow--out::before { transform: rotate(-45deg); }
a:hover > .arrow--out::after,
a:focus-visible > .arrow--out::after { transform: none; }
a:hover > .arrow--out,
a:focus-visible > .arrow--out { transform: translate(2px, -2px); }

/* ---------- Hero ---------- */
.hero { padding-block: clamp(24px, 4.4vw, 56px) clamp(48px, 7vw, 96px); }
.hero-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(0, 0.88fr);
  gap: clamp(32px, 6vw, 104px);
  align-items: center;
}
.hero-copy { container-type: inline-size; min-width: 0; }

/* One roman sentence on three fixed lines. The size follows the column, so the
   breaks hold at every width from 360 to 1920. */
.hero h1 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(2.125rem, 5.2vw, 4.5rem);
  font-size: clamp(2rem, 11.2cqi, 4.75rem);
  line-height: 1.02;
  letter-spacing: -0.022em;
}
.hl {
  display: block;
  white-space: nowrap;
  overflow: clip;
  overflow-clip-margin: 0.1em;
  padding-bottom: 0.16em;
  margin-bottom: -0.16em;
}
.hl-in { display: inline-block; }
.hero-lead {
  max-width: 33em;
  margin-top: clamp(20px, 2.6vw, 32px);
  font-size: clamp(1.0625rem, 1.3vw, 1.1875rem);
  line-height: 1.6;
  color: var(--ink-2);
}

/* Footnotes to the statement */
.fn {
  position: relative;
  max-width: 36em;
  margin-top: clamp(24px, 3vw, 40px);
  padding-top: 14px;
  counter-reset: fn;
}
.fn::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 88px;
  height: 1px;
  background: var(--ink);
  transform-origin: left center;
}
.fn li {
  counter-increment: fn;
  position: relative;
  padding: 5px 0 5px 1.7em;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--ink-2);
}
.fn li::before {
  content: counter(fn);
  position: absolute;
  left: 0;
  top: 0.5em;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--violet);
  font-variant-numeric: tabular-nums;
}
.fn b { font-weight: 600; color: var(--ink); }
.fn a { white-space: nowrap; }
/* The label sits on the short rule; the list follows it. */
.fn-label {
  position: relative;
  margin-top: clamp(24px, 3vw, 40px);
  padding-top: 14px;
}
.fn-label::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 88px;
  height: 1px;
  background: var(--ink);
  transform-origin: left center;
}
.fn-label + .fn { margin-top: 4px; padding-top: 0; }
.fn-label + .fn::before { content: none; }

/* ---------- The plate ---------- */
.plate {
  position: relative;
  justify-self: end;
  width: 100%;
  max-width: 468px;
  border: 1px solid var(--line);
  background: var(--paper);
}
.plate-head,
.plate-foot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 11px 16px;
}
.plate-head { border-bottom: 1px solid var(--line); }
.plate-foot { border-top: 1px solid var(--line); align-items: center; }
.plate-name { font-family: var(--serif); font-style: italic; font-size: 1rem; line-height: 1.2; color: var(--ink-2); }
.plate > svg { width: 100%; height: auto; }

.plate-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 16px;
  padding: 0 16px 12px;
  counter-reset: part;
}
.plate-legend li {
  counter-increment: part;
  font-size: 0.75rem;
  line-height: 1.5;
  color: var(--ink-3);
}
.plate-legend li::before,
.legend-btn::before {
  content: counter(part);
  margin-right: 6px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* With scripts on, each legend item becomes a button (see site.js). */
.plate-legend li.has-btn::before { content: none; }
.legend-btn {
  display: block;
  padding: 3px 0;
  border: 0;
  background: none;
  font-size: inherit;
  line-height: inherit;
  color: inherit;
  cursor: pointer;
  transition: color 0.2s ease;
}
.legend-btn:hover,
.legend-btn.is-on,
.legend-btn[aria-pressed="true"] { color: var(--violet-deep); }
.legend-btn[aria-pressed="true"] { text-decoration: underline; text-decoration-color: var(--violet); text-underline-offset: 3px; }

.plate-caption { font-size: 0.8125rem; color: var(--ink-3); line-height: 1.4; }
.plate-caption b { font-weight: 600; color: var(--ink-2); }
.plate-caption i { font-family: var(--serif); font-size: 1.08em; }

.redraw {
  display: none;
  flex: none;
  border: 0;
  background: none;
  padding: 4px 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ink-2);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: var(--line-4);
  text-underline-offset: 4px;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}
.redraw:hover { color: var(--violet-deep); text-decoration-color: var(--violet); }
.js .redraw { display: inline-block; }
.js .redraw[hidden] { display: none; }

/* Plate drawing styles */
.p-ink { fill: none; stroke: var(--ink); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
.p-fine { fill: none; stroke: var(--ink-2); stroke-width: 1.1; stroke-linecap: round; }
.p-petal { fill: var(--wash); stroke: var(--ink); stroke-width: 1.4; stroke-linejoin: round; }
.p-leaf { fill: var(--paper); stroke: var(--ink); stroke-width: 1.4; stroke-linejoin: round; }
.p-vein { fill: none; stroke: var(--violet); stroke-width: 1; stroke-linecap: round; }
.p-eye { fill: var(--paper); stroke: var(--ink); stroke-width: 1.2; }
.p-pip { fill: var(--violet); }
.p-guide { fill: none; stroke: var(--line-3); stroke-width: 0.75; stroke-dasharray: 5 4; }
.p-axis { fill: none; stroke: var(--line-3); stroke-width: 0.75; stroke-dasharray: 14 4 2 4; }
.p-tick { fill: none; stroke: var(--line-3); stroke-width: 0.75; }
.p-tick-major { fill: none; stroke: var(--ink-3); stroke-width: 0.75; }
.p-lead { fill: none; stroke: var(--ink-3); stroke-width: 0.75; transition: stroke 0.25s ease; }
.p-num circle { fill: var(--paper); stroke: var(--ink-3); stroke-width: 0.75; transition: stroke 0.25s ease, fill 0.25s ease; }
.p-num text {
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 600;
  fill: var(--ink-2);
  text-anchor: middle;
  transition: fill 0.25s ease;
}
/* The gauge marker rests on the centre line of the flower. */
.p-mark { fill: var(--violet); transform: translateY(155px); }
.p-part { transition: stroke 0.25s ease; }
.call { cursor: default; }

.call.is-on .p-lead { stroke: var(--violet); }
.call.is-on .p-num circle { stroke: var(--violet); fill: var(--violet); }
.call.is-on .p-num text { fill: var(--on-violet); }
.p-part.is-on { stroke: var(--violet); }

/* ---------- Sections ---------- */
.section { padding-block: clamp(56px, 8vw, 112px) 0; }
.section:last-of-type { padding-bottom: clamp(64px, 9vw, 128px); }

.sec-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  column-gap: 24px;
  align-items: end;
  padding-bottom: 22px;
}
.sec-head h2 {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(2.125rem, 4.2vw, 3.5rem);
  line-height: 1.02;
  letter-spacing: -0.018em;
}
.sec-intro { max-width: 32em; color: var(--ink-2); font-size: 1rem; padding-bottom: 0.35em; }
.sec-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px 24px;
  padding-top: 22px;
  font-size: 0.875rem;
  color: var(--ink-3);
}

/* ---------- Project register ---------- */
.register { border-top: 1px solid var(--ink); }
.entry {
  position: relative;
  display: grid;
  grid-template-columns: var(--no-col) minmax(0, 0.85fr) minmax(0, 1.35fr);
  grid-template-areas:
    "no head  body"
    "no links body"
    "no fig   fig";
  grid-template-rows: auto 1fr auto;
  column-gap: 24px;
  padding-block: clamp(28px, 3.4vw, 44px);
  border-bottom: 1px solid var(--line);
}
.entry::before {
  content: "";
  position: absolute;
  left: 0;
  top: -1px;
  width: var(--no-col);
  height: 1px;
  background: var(--violet);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.5s var(--ease);
}
.entry:hover::before,
.entry:focus-within::before { transform: scaleX(1); }

.entry-no {
  grid-area: no;
  font-family: var(--serif);
  font-size: 1.125rem;
  color: var(--ink-3);
  padding-top: 0.55em;
  font-variant-numeric: tabular-nums;
  transition: color 0.3s ease;
}
.entry:hover .entry-no,
.entry:focus-within .entry-no { color: var(--violet); }

.entry-head { grid-area: head; }
.entry-title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: clamp(1.875rem, 3vw, 2.625rem);
  line-height: 1.05;
  letter-spacing: -0.015em;
}
.entry-title a {
  text-decoration-line: underline;
  text-decoration-color: var(--line-4);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.16em;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}
.entry-title a:hover,
.entry-title a:focus-visible { color: var(--violet-deep); text-decoration-color: var(--violet); }
.entry-title .arrow--out { width: 0.34em; height: 0.34em; margin-left: 0.22em; color: var(--violet); }
.entry-kind { margin-top: 10px; font-size: 0.9375rem; color: var(--ink-3); }

.entry-links {
  grid-area: links;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  padding-top: 22px;
}
.status { font-size: 0.9375rem; line-height: 1.5; color: var(--ink-2); max-width: 22em; }
.status b { font-weight: 700; color: var(--ink); }
.entry-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 24px; }

.entry-body { grid-area: body; }
.entry-body > p { color: var(--ink-2); max-width: 38em; }
.entry-facts { margin-top: 22px; border-top: 1px solid var(--line-2); max-width: 38em; }
.entry-facts div { display: grid; grid-template-columns: 104px minmax(0, 1fr); gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--line-2); font-size: 0.9375rem; }
.entry-facts dt { padding-top: 0.25em; }
.entry-facts dd { color: var(--ink); line-height: 1.5; }

.entry-fig { grid-area: fig; margin-top: clamp(28px, 3.4vw, 44px); }

/* The vacant row is shown only while the register has one project. */
.entry--vacant {
  display: grid;
  grid-template-areas: "no text";
  grid-template-columns: var(--no-col) minmax(0, 1fr);
  grid-template-rows: auto;
  align-items: baseline;
  padding-block: 22px;
  border-bottom: 0;
  color: var(--ink-3);
}
.entry--vacant::before { display: none; }
.entry--vacant .entry-no { padding-top: 0; }
.entry-vacant-text { grid-area: text; font-size: 0.9375rem; }
.register > .entry:has(+ .entry--vacant) { border-bottom-style: dashed; }

/* Count-aware compact form. On the home page, as soon as there is more than
   one project, each entry drops to a single row: number, name, summary and
   status, links. The full entry stays on /projects/. */
.register--home > article.entry:not(:only-of-type) {
  grid-template-columns: var(--no-col) minmax(0, 0.8fr) minmax(0, 1.4fr) minmax(0, 0.8fr);
  grid-template-areas: "no head body links";
  grid-template-rows: auto;
  padding-block: clamp(22px, 2.6vw, 32px);
}
.register--home > article.entry:not(:only-of-type) .entry-title { font-size: clamp(1.5rem, 2.2vw, 1.875rem); }
.register--home > article.entry:not(:only-of-type) .entry-kind { margin-top: 6px; }
.register--home > article.entry:not(:only-of-type) .entry-facts,
.register--home > article.entry:not(:only-of-type) .entry-fig { display: none; }
.register--home > article.entry:not(:only-of-type) .entry-links { padding-top: 0.3em; gap: 12px; }
.register--home > article.entry:not(:only-of-type) .status { font-size: 0.875rem; }
.register--home > article.entry:not(:only-of-type) .btn { padding: 8px 14px 8px 16px; font-size: 0.875rem; }
.register--home > article.entry:not(:only-of-type) .link { font-size: 0.875rem; }
.register--home > article.entry:not(:only-of-type) .entry-body > p { font-size: 0.9688rem; }

/* ---------- Pipeline figure (a named figure partial for a project) ---------- */
.pipeline-steps {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  column-gap: 24px;
  counter-reset: step;
}
.step {
  position: relative;
  counter-increment: step;
  display: grid;
  grid-template-rows: 56px 25px auto auto;
  row-gap: 0;
  align-content: start;
}
.step-glyph { width: 112px; height: 56px; }
/* the track: a numbered node and a hairline to the next station */
.step-node {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  width: 25px;
  height: 25px;
  border: 1px solid var(--ink-3);
  border-radius: 50%;
  background: var(--paper);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  transition: background-color 0.25s ease, border-color 0.25s ease, color 0.25s ease;
}
.step-node::before { content: counter(step); }
.step:hover .step-node { background: var(--violet); border-color: var(--violet); color: var(--on-violet); }
.step::before {
  content: "";
  position: absolute;
  left: 25px;
  right: -19px;
  top: 68px;
  height: 1px;
  background: var(--ink-3);
  transform-origin: left center;
}
.step:last-child::before { display: none; }
.step::after {
  content: "";
  position: absolute;
  right: -19px;
  top: 65px;
  width: 7px;
  height: 7px;
  border-top: 1px solid var(--ink-3);
  border-right: 1px solid var(--ink-3);
  transform: translateX(-1px) rotate(45deg);
}
.step:last-child::after { display: none; }
.step-title { margin-top: 14px; font-size: 1rem; font-weight: 600; line-height: 1.3; color: var(--ink); }
.step-text { margin-top: 4px; padding-right: 8px; font-size: 0.875rem; line-height: 1.5; color: var(--ink-2); max-width: 22em; }
.pipeline figcaption,
.caption { margin-top: 20px; font-family: var(--sans); font-size: 0.8125rem; line-height: 1.5; color: var(--ink-3); }
.pipeline figcaption b,
.caption b { font-weight: 600; color: var(--ink-2); }

/* Shared figure strokes (pipeline glyphs and article diagrams) */
.f-cell { fill: none; stroke: var(--ink-3); stroke-width: 0.75; }
.f-cell--on { fill: var(--ink); stroke: var(--ink); }
.f-line { fill: none; stroke: var(--ink); stroke-width: 1.4; stroke-linecap: round; }
.f-line--v { stroke: var(--violet); }
.f-line--soft { stroke: var(--line-3); }
.f-hair { fill: none; stroke: var(--ink-3); stroke-width: 0.75; }
.f-gate { fill: var(--paper); stroke: var(--violet); stroke-width: 1.1; }
.f-box { fill: var(--paper); stroke: var(--ink); stroke-width: 1.2; }
.f-box--v { stroke: var(--violet); }
.f-dot { fill: var(--violet); }
.f-label { font-family: var(--sans); font-size: 12px; font-weight: 500; fill: var(--ink); text-anchor: middle; }
.f-label--sm { font-size: 11px; fill: var(--ink-3); font-weight: 400; }
.f-head { fill: var(--ink); }
.f-head--v { fill: var(--violet); }

/* ---------- Notes list ---------- */
.notes { border-top: 1px solid var(--ink); }
.note {
  position: relative;
  display: grid;
  grid-template-columns: var(--no-col) minmax(0, 0.8fr) minmax(0, 2.2fr) 7.5em;
  column-gap: 24px;
  align-items: baseline;
  padding-block: clamp(22px, 2.6vw, 32px);
  border-bottom: 1px solid var(--line);
}
.note::before {
  content: "";
  position: absolute;
  left: 0;
  bottom: -1px;
  width: 100%;
  height: 1px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.6s var(--ease);
}
.note:hover::before,
.note:focus-within::before { transform: scaleX(1); }
.note-no { font-family: var(--serif); font-size: 1.125rem; color: var(--ink-3); font-variant-numeric: tabular-nums; transition: color 0.3s ease; }
.note:hover .note-no,
.note:focus-within .note-no { color: var(--violet); }
.note-meta { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; font-size: 0.875rem; color: var(--ink-3); }
.note-meta time { color: var(--ink-2); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Subject links sit above the stretched row link. */
.tag {
  position: relative;
  z-index: 1;
  /* at least 24px tall to touch; the negative margin keeps the row where it was */
  display: inline-block;
  padding-block: 2px;
  margin-block: -2px;
  color: var(--ink-3);
  text-decoration-line: underline;
  text-decoration-color: var(--line-4);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.22em;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}
.tag:hover,
.tag:focus-visible { color: var(--violet-deep); text-decoration-color: var(--violet); }
.note-title { font-family: var(--serif); font-weight: 400; font-size: clamp(1.4375rem, 2.2vw, 1.875rem); line-height: 1.14; letter-spacing: -0.01em; }
/* The link stretches over the whole row. Nothing between the link and .note
   may carry a transform, or the stretched area collapses: the hover shift is
   on the inner span. */
.note-title a { text-decoration: none; transition: color 0.2s ease; }
.note-title a::after { content: ""; position: absolute; inset: 0; }
.note-title-in { display: block; transition: transform 0.45s var(--ease); }
.note:hover .note-title-in,
.note-title a:focus-visible .note-title-in { transform: translateX(10px); }
.note:hover .note-title a,
.note-title a:focus-visible { color: var(--violet-deep); }
.note-title a:focus-visible { outline: none; }
.note-title a:focus-visible::after { outline: 2px solid var(--violet); outline-offset: -2px; }
.note-sum { margin-top: 8px; color: var(--ink-2); font-size: 0.9688rem; max-width: 40em; }
.note-time { font-size: 0.875rem; color: var(--ink-3); white-space: nowrap; font-variant-numeric: tabular-nums; text-align: right; }

/* A plain list in the same register: the subjects at /blog/tag/ and the
   index pages at /blog/page/. Two columns: a count, then the name. */
.notes--list > .note { grid-template-columns: 9em minmax(0, 1fr); }
.notes--list .note-no { font-family: var(--sans); font-size: 0.875rem; }

/* Preview builds only (npm run dev): marks a draft or a scheduled note.
   Production output never contains it. */
.note-preview { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--violet-deep); background: var(--wash); padding: 1px 6px; }

/* Count-aware: when a list holds exactly one note (the launch state), the row
   is set larger so it reads as a lead item. On the index this applies only
   when the whole page has one note, not to a year that happens to have one. */
.notes:not(.notes--index) > .note:only-child,
.index-body > section:only-of-type .note:only-child { padding-block: clamp(28px, 3.4vw, 44px); }
.notes:not(.notes--index) > .note:only-child .note-title,
.index-body > section:only-of-type .note:only-child .note-title { font-size: clamp(1.75rem, 3vw, 2.625rem); line-height: 1.08; letter-spacing: -0.015em; }
.notes:not(.notes--index) > .note:only-child .note-sum,
.index-body > section:only-of-type .note:only-child .note-sum { margin-top: 12px; font-size: 1.0625rem; }

/* Empty state: an honest vacant row in the same register. */
.note--vacant { color: var(--ink-3); align-items: baseline; }
.note--vacant::before { display: none; }
.note-vacant-text { grid-column: 2 / -1; font-size: 0.9375rem; max-width: 40em; }
.note-vacant-text b { display: block; margin-bottom: 6px; font-family: var(--serif); font-weight: 400; font-size: clamp(1.4375rem, 2.2vw, 1.875rem); line-height: 1.14; letter-spacing: -0.01em; color: var(--ink); }
.notes > .note:has(+ .note--vacant) { border-bottom-style: dashed; }

/* ---------- Subject list and pagination ---------- */
.subjects {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 28px;
  padding-block: 14px;
  border-top: 1px solid var(--ink);
}
.subjects ul { display: flex; flex-wrap: wrap; gap: 2px 28px; }
.subjects a {
  position: relative;
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  padding: 6px 0;
  font-size: 0.9375rem;
  font-weight: 500;
  color: var(--ink-2);
  text-decoration: none;
  transition: color 0.2s ease;
}
.subjects a::after { content: ""; position: absolute; left: 0; right: 0; bottom: 2px; height: 1px; background: var(--line-4); }
.subjects a::before { content: ""; position: absolute; z-index: 1; left: 0; right: 0; bottom: 2px; height: 1px; background: var(--violet); transform: scaleX(0); transform-origin: left center; transition: transform 0.35s var(--ease); }
.subjects a:hover,
.subjects a:focus-visible,
.subjects a[aria-current] { color: var(--ink); }
.subjects a:hover::before,
.subjects a:focus-visible::before,
.subjects a[aria-current]::before { transform: scaleX(1); }
.count { font-size: 0.75rem; font-weight: 600; color: var(--ink-3); font-variant-numeric: tabular-nums; }

.year { display: grid; grid-template-columns: var(--no-col) minmax(0, 1fr); column-gap: 24px; align-items: baseline; padding-block: 14px; border-top: 1px solid var(--line); }
.year h2 { grid-column: 1 / -1; font-family: var(--serif); font-weight: 500; font-size: 1.125rem; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.notes--index { border-top-color: var(--line); }

.pagination {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 12px 24px;
  margin-top: clamp(28px, 4vw, 48px);
  padding-block: 14px;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--line);
}
.pagination ol { display: flex; gap: 4px; }
.page {
  position: relative;
  display: grid;
  place-items: center;
  min-width: 44px;
  height: 44px;
  font-family: var(--serif);
  font-size: 1.125rem;
  color: var(--ink-2);
  text-decoration: none;
  font-variant-numeric: tabular-nums;
  transition: color 0.2s ease;
}
.page::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 6px;
  height: 1px;
  background: var(--violet);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.35s var(--ease);
}
a.page:hover,
a.page:focus-visible { color: var(--violet-deep); }
a.page:hover::after,
a.page:focus-visible::after,
.page[aria-current]::after { transform: scaleX(1); }
.page[aria-current] { color: var(--ink); font-weight: 500; }
.pagination-step { justify-self: start; }
.pagination-step + ol + .pagination-step,
.pagination-step:last-child { justify-self: end; }
.pagination-step.is-disabled { box-shadow: none; color: var(--ink-3); font-weight: 500; cursor: default; }
.pagination-step.is-disabled::after { display: none; }
.pagination-step.is-disabled .arrow { opacity: 0.5; }
.pagination-status { margin-top: 14px; font-size: 0.875rem; color: var(--ink-3); }

/* ---------- Page head (notes index, projects, about, tag, 404) ---------- */
.page-head { padding-block: clamp(36px, 6vw, 88px) clamp(28px, 4vw, 48px); }
.page-head-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); column-gap: 24px; align-items: end; }
.page-head h1 { font-family: var(--serif); font-weight: 400; font-size: clamp(2.75rem, 6.4vw, 5.5rem); line-height: 1; letter-spacing: -0.022em; }
.page-head .sec-intro { font-size: 1.0625rem; padding-bottom: 0.7em; }
.page-head .crumbs { grid-column: 1 / -1; }
.index-body { padding-bottom: clamp(64px, 9vw, 128px); }

.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: clamp(18px, 2.4vw, 28px); }
.crumbs a { display: inline-block; padding-block: 3px; margin-block: -3px; color: var(--ink-3); text-decoration-line: underline; text-decoration-color: var(--line-4); text-decoration-thickness: 1px; text-underline-offset: 0.3em; transition: color 0.2s ease, text-decoration-color 0.2s ease; }
.crumbs a:hover,
.crumbs a:focus-visible { color: var(--violet); text-decoration-color: var(--violet); }
.crumbs span[aria-hidden] { width: 18px; height: 1px; background: var(--line-3); }

/* ---------- About ---------- */
.about-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  column-gap: clamp(32px, 6vw, 104px);
  row-gap: 28px;
  padding-top: clamp(28px, 3.4vw, 44px);
  border-top: 1px solid var(--ink);
}
.about-statement {
  font-family: var(--serif);
  font-size: clamp(1.625rem, 2.9vw, 2.375rem);
  line-height: 1.18;
  letter-spacing: -0.012em;
  max-width: 19em;
  text-wrap: balance;
}
.about-copy { display: grid; gap: 1em; align-content: start; justify-items: start; color: var(--ink-2); }
.about-copy .go { margin-top: 0.4em; }

/* Labelled details: company record on the about page and in the footer. */
.details { border-top: 1px solid var(--ink); }
.details div {
  display: grid;
  grid-template-columns: 11em minmax(0, 1fr);
  column-gap: 16px;
  align-items: baseline;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.details dt { line-height: 1.5; }
.details dd { color: var(--ink); line-height: 1.5; }
/* The company details on the about page sit inside .prose, so the heading is
   set and drawn like the other section headings. The list itself is sans. */
.details-block .details { margin-top: 0.8em; font-family: var(--sans); font-size: 1rem; }

/* ---------- Footer ---------- */
.site-footer { position: relative; border-top: 1px solid var(--ink); padding-block: clamp(36px, 4vw, 56px) 40px; font-size: 0.9375rem; }
.footer-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr) minmax(0, 0.6fr) minmax(0, 0.7fr); gap: 32px clamp(24px, 4vw, 56px); }
/* On the about page the company column is left out (the page body has it). */
.footer-grid--brief { grid-template-columns: minmax(0, 2.5fr) minmax(0, 0.6fr) minmax(0, 0.7fr); }
.footer-brand p { margin-top: 14px; color: var(--ink-2); max-width: 22em; }
.footer-label { margin-bottom: 12px; }
.footer-col .details { border-top-color: var(--line); }
.footer-col .details div { grid-template-columns: 10.5em minmax(0, 1fr); padding: 7px 0; }
.footer-col .details dd { color: var(--ink-2); font-size: 0.9375rem; }
.footer-col li + li { margin-top: 2px; }
.footer-col li a {
  position: relative;
  display: inline-block;
  padding: 4px 0;
  color: var(--ink-2);
  text-decoration: none;
  transition: color 0.2s ease;
}
.footer-col li a::after { content: ""; position: absolute; left: 0; right: 0; bottom: 3px; height: 1px; background: var(--violet); transform: scaleX(0); transform-origin: left center; transition: transform 0.4s var(--ease); }
.footer-col li a:hover,
.footer-col li a:focus-visible { color: var(--ink); }
.footer-col li a:hover::after,
.footer-col li a:focus-visible::after { transform: scaleX(1); }
.footer-base { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px 24px; margin-top: clamp(36px, 5vw, 64px); padding-top: 18px; border-top: 1px solid var(--line); font-size: 0.8125rem; color: var(--ink-3); }

/* ---------- Article ---------- */
.article-head { padding-block: clamp(32px, 5vw, 72px) clamp(24px, 3vw, 40px); }
.article-head-grid,
.article-grid { display: grid; grid-template-columns: 220px minmax(0, 1fr); column-gap: clamp(40px, 5vw, 72px); }
.article-head-grid { align-items: start; }
.article-head-inner { min-width: 0; max-width: 940px; }
.article-no { font-family: var(--serif); font-size: 1.125rem; line-height: 1.2; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.crumb-no { display: none; }
.article-head h1 { font-family: var(--serif); font-weight: 400; font-size: clamp(2.25rem, 5.4vw, 4.375rem); line-height: 1.03; letter-spacing: -0.022em; text-wrap: balance; }
.article-meta { display: flex; flex-wrap: wrap; margin-top: clamp(24px, 3vw, 40px); border-top: 1px solid var(--ink); border-bottom: 1px solid var(--line); }
.article-meta div { padding: 12px 28px 13px 0; margin-right: 28px; border-right: 1px solid var(--line); }
.article-meta div:last-child { border-right: 0; margin-right: 0; padding-right: 0; }
.article-meta dt { margin-bottom: 3px; }
.article-meta dd { font-size: 0.9375rem; color: var(--ink); font-variant-numeric: tabular-nums; }
.article-meta dd a { display: inline-block; padding-block: 4px; margin-block: -4px; text-decoration-line: underline; text-decoration-color: var(--violet); text-decoration-thickness: 1px; text-underline-offset: 0.22em; transition: color 0.2s ease; }
.article-meta dd a:hover,
.article-meta dd a:focus-visible { color: var(--violet-deep); text-decoration-thickness: 2px; }
.article-meta .arrow--out { width: 8px; height: 8px; margin-left: 5px; color: var(--violet); }

.article-grid { align-items: start; padding-bottom: clamp(48px, 7vw, 96px); }

.toc { position: sticky; top: calc(var(--header-h) + 32px); max-height: calc(100vh - var(--header-h) - 64px); overflow-y: auto; }
.toc-title { margin-bottom: 14px; }
.toc-box > summary { display: block; list-style: none; }
.toc-box > summary::-webkit-details-marker { display: none; }
/* Beside the text the list is always open: its label is only a label. */
@media (min-width: 1081px) { .toc-box > summary { pointer-events: none; } }
.toc ol { position: relative; border-left: 1px solid var(--line); }
.toc ol a {
  position: relative;
  display: block;
  padding: 6px 0 6px 16px;
  font-size: 0.875rem;
  line-height: 1.35;
  color: var(--ink-3);
  text-decoration: none;
  transition: color 0.25s ease;
}
.toc ol a::before {
  content: "";
  position: absolute;
  left: -1px;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--violet);
  transform: scaleY(0);
  transform-origin: center top;
  transition: transform 0.35s var(--ease);
}
.toc ol a span { display: block; transition: transform 0.35s var(--ease); }
.toc ol a:hover,
.toc ol a:focus-visible { color: var(--ink); }
.toc ol a.is-current { color: var(--ink); }
.toc ol a.is-current span { transform: translateX(3px); }
.toc ol a.is-current::before { transform: scaleY(1); }
.toc-back { margin-top: 28px; }
.toc-back .go { font-size: 0.875rem; }

/* ---------- Prose (the target of the markdown renderer) ---------- */
.prose {
  font-family: var(--serif);
  font-size: clamp(1.1875rem, 1.2vw + 0.95rem, 1.3125rem);
  line-height: 1.62;
  color: var(--ink);
  min-width: 0;
  max-width: 720px;
  counter-reset: h2 fig;
}
.prose > * + * { margin-top: 1.15em; }
.prose .lead,
.prose > p:first-child { font-size: 1.24em; line-height: 1.42; letter-spacing: -0.006em; color: var(--ink); }
.prose .lead + *,
.prose > p:first-child + * { margin-top: 1.5em; }
.prose h2 {
  position: relative;
  margin-top: 2.2em;
  padding-top: 1.1em;
  font-weight: 500;
  font-size: 1.62em;
  line-height: 1.12;
  letter-spacing: -0.014em;
  border-top: 1px solid var(--line);
  counter-increment: h2;
}
.prose h2::before {
  content: counter(h2);
  display: block;
  margin-bottom: 0.4em;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 0.42em;
  color: var(--violet);
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
}
.prose--plain h2::before { content: none; }
.prose h3 { margin-top: 1.9em; font-family: var(--serif); font-size: 1.18em; font-weight: 500; letter-spacing: -0.008em; line-height: 1.25; }
.prose h4 { margin-top: 1.7em; font-family: var(--sans); font-size: 0.84em; font-weight: 700; line-height: 1.3; }
.prose h3 + *,
.prose h4 + * { margin-top: 0.5em; }
.prose h2 + * { margin-top: 0.8em; }
/* Optional heading anchor: <a class="anchor" href="#id" aria-label="..."></a> */
.anchor {
  display: inline-block;
  min-width: 24px;
  margin-left: 0.1em;
  text-align: center;
  font-family: var(--sans);
  font-size: 0.7em;
  font-weight: 400;
  text-decoration: none;
  opacity: 0;
  transition: opacity 0.2s ease;
}
.prose .anchor { color: var(--violet); text-decoration: none; }
.anchor::before { content: "#"; }
h2:hover > .anchor,
h3:hover > .anchor,
.anchor:focus-visible { opacity: 1; }
/* No hover on touch screens: the mark is always shown, at full strength so it passes contrast. */
@media (hover: none) { .anchor { opacity: 1; } }

.prose strong { font-weight: 600; }
.prose code { font-family: var(--mono); font-size: 0.8em; padding: 0.1em 0.32em; background: var(--paper-2); border: 1px solid var(--line-2); overflow-wrap: anywhere; }
.prose ul,
.prose ol { padding-left: 1.5em; }
.prose ul { list-style: square; }
.prose ol { list-style: decimal; }
.prose li { padding-left: 0.3em; }
.prose li + li { margin-top: 0.5em; }
.prose li > ul,
.prose li > ol { margin-top: 0.5em; }
.prose li::marker { color: var(--violet); }
.prose ol > li::marker { font-family: var(--sans); font-size: 0.72em; font-weight: 600; font-variant-numeric: tabular-nums; }
.prose hr { height: 1px; margin-block: 2.2em; border: 0; background: var(--line); }

.prose blockquote {
  position: relative;
  margin-block: 1.9em;
  padding: 0.1em 0 0.1em 1.2em;
  font-style: italic;
  font-size: 1.24em;
  line-height: 1.34;
  letter-spacing: -0.008em;
  color: var(--ink);
}
.prose blockquote::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  background: var(--violet);
  transform-origin: center top;
}
.prose blockquote > * + * { margin-top: 0.6em; }
.prose blockquote cite { display: block; font-family: var(--sans); font-style: normal; font-size: 0.6em; letter-spacing: 0; color: var(--ink-3); }

/* Listings: fenced code. The header is optional. */
.listing { margin-block: 1.9em; border: 1px solid var(--line); background: var(--paper-2); font-family: var(--sans); }
.listing-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; padding: 9px 16px; border-bottom: 1px solid var(--line); background: var(--paper); }
.listing-name { min-width: 0; font-family: var(--mono); font-size: 0.8125rem; color: var(--ink); overflow-wrap: break-word; }
.listing pre {
  --scroll-bg: var(--paper-2);
  margin: 0;
  padding: 16px 0;
  overflow-x: auto;
  font-family: var(--mono);
  font-size: 0.875rem;
  line-height: 1.7;
  color: var(--ink);
  counter-reset: ln;
  tab-size: 4;
}
.listing pre:focus-visible { outline-offset: -2px; }
.listing pre code { display: block; min-width: max-content; padding: 0 16px; font: inherit; background: none; border: 0; overflow-wrap: normal; }
/* Numbered lines: each line is wrapped in <span class="ln">. */
.listing pre code:has(.ln) { padding: 0; }
.ln { display: inline-block; min-width: 100%; counter-increment: ln; padding-right: 20px; }
.ln::before {
  content: counter(ln);
  display: inline-block;
  width: 2.6em;
  margin-right: 1.1em;
  padding-right: 0.7em;
  text-align: right;
  color: var(--ink-3);
  border-right: 1px solid var(--line);
  user-select: none;
  -webkit-user-select: none;
}
.ln--mark { background: var(--wash); }
.ln--mark::before { color: var(--violet-deep); border-right-color: var(--violet); }

/* highlight.js tokens. Restrained, AA on the listing background in both themes. */
.hljs-comment,
.hljs-quote { color: var(--code-comment); }
.hljs-keyword,
.hljs-selector-tag,
.hljs-meta,
.hljs-doctag,
.hljs-section { color: var(--code-keyword); }
.hljs-string,
.hljs-regexp,
.hljs-symbol,
.hljs-bullet { color: var(--code-string); }
.hljs-number,
.hljs-literal { color: var(--code-number); }
.hljs-title,
.hljs-title.function_,
.hljs-title.class_,
.hljs-type,
.hljs-built_in,
.hljs-selector-class,
.hljs-selector-id { color: var(--code-title); }
.hljs-attr,
.hljs-attribute,
.hljs-name,
.hljs-tag { color: var(--code-attr); }
.hljs-params,
.hljs-variable,
.hljs-template-variable,
.hljs-property,
.hljs-punctuation,
.hljs-operator,
.hljs-subst { color: var(--ink); }
.hljs-addition { color: var(--code-add); background: var(--code-add-bg); }
.hljs-deletion { color: var(--code-del); background: var(--code-del-bg); }
.hljs-emphasis { font-style: italic; }
.hljs-strong { font-weight: 700; }

.prose figure { margin-block: 1.9em; }
.prose figcaption { margin-top: 0.9em; font-family: var(--sans); font-size: 0.8125rem; line-height: 1.5; color: var(--ink-3); }
.prose figcaption b { font-weight: 600; color: var(--ink-2); }
/* Figures in an article number themselves. */
.prose figure { counter-increment: fig; }
.prose figcaption::before { content: "Fig. " counter(fig) ". "; font-weight: 600; color: var(--ink-2); }
.prose figure > img { width: 100%; border: 1px solid var(--line); }
.figure-frame { border: 1px solid var(--line); padding: clamp(12px, 3vw, 28px); }
.figure-frame svg { width: 100%; max-width: 430px; height: auto; margin-inline: auto; }

/* Tables: the wrapper scrolls, and is a focusable region. */
.table-wrap { margin-block: 1.9em; overflow-x: auto; font-family: var(--sans); --scroll-bg: var(--paper); }
/* Scroll cue for tables and listings that are wider than the column: a
   hairline and a faint shade on whichever edge has more to show. The first
   two layers move with the content and cover the cue at each end; the last
   four stay with the box. Nothing here is animated. */
.table-wrap,
.listing pre {
  background:
    linear-gradient(var(--scroll-bg), var(--scroll-bg)) left / 14px 100% no-repeat local,
    linear-gradient(var(--scroll-bg), var(--scroll-bg)) right / 14px 100% no-repeat local,
    linear-gradient(var(--line-4), var(--line-4)) left / 1px 100% no-repeat scroll,
    linear-gradient(var(--line-4), var(--line-4)) right / 1px 100% no-repeat scroll,
    linear-gradient(to right, var(--shade), transparent) left / 12px 100% no-repeat scroll,
    linear-gradient(to left, var(--shade), transparent) right / 12px 100% no-repeat scroll;
}
.table-wrap:focus-visible { outline-offset: 4px; }
.prose table { width: 100%; min-width: 520px; border-collapse: collapse; font-family: var(--sans); font-size: 0.9375rem; line-height: 1.45; }
.prose caption { caption-side: top; text-align: left; padding-bottom: 0.9em; font-size: 0.8125rem; color: var(--ink-3); }
.prose caption b { font-weight: 600; color: var(--ink-2); }
.prose th,
.prose td { text-align: left; vertical-align: top; padding: 11px 16px 11px 0; border-bottom: 1px solid var(--line); }
.prose thead th { border-top: 1px solid var(--ink); border-bottom: 1px solid var(--ink); font-size: 0.75rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-3); }
.prose tbody th { font-weight: 600; white-space: nowrap; }
.prose .align-center { text-align: center; }
.prose .align-right { text-align: right; }
.prose td code,
.prose th code { font-size: 0.86em; }
.prose tbody tr { transition: background-color 0.2s ease; }
.prose tbody tr:hover { background: var(--paper-2); }

/* Footnotes and small print */
.fn-ref { font-family: var(--sans); font-size: 0.62em; font-weight: 600; line-height: 0; vertical-align: super; }
.prose .fn-ref a { padding: 0 0.15em; color: var(--violet); text-decoration: none; }
.prose .fn-ref a:hover { text-decoration: underline; }
.footnotes { margin-top: 2.6em; padding-top: 1.2em; border-top: 1px solid var(--ink); font-family: var(--sans); font-size: 0.9375rem; line-height: 1.6; color: var(--ink-2); }
.footnotes ol { padding-left: 1.4em; }
.footnotes li + li { margin-top: 0.5em; }
.footnotes li:target { background: var(--wash); box-shadow: 0 0 0 6px var(--wash); }
.fn-back { margin-left: 0.4em; font-size: 0.8125rem; font-weight: 600; white-space: nowrap; }
.endnote { max-width: 720px; margin-top: 2.6em; padding-top: 1.2em; border-top: 1px solid var(--line); font-family: var(--sans); font-size: 0.9375rem; line-height: 1.6; color: var(--ink-2); }
.footnotes + .endnote { margin-top: 1.4em; }

/* Previous and next */
/* Related notes, above the pager on an article. */
.related { margin-top: clamp(56px, 8vw, 104px); margin-bottom: clamp(40px, 6vw, 72px); }
.related-heading { margin: 0 0 clamp(16px, 2vw, 24px); font-family: var(--serif); font-weight: 400; font-size: clamp(1.5rem, 2.6vw, 2rem); line-height: 1.15; letter-spacing: -0.01em; }
.pager { margin-bottom: clamp(64px, 9vw, 128px); display: grid; grid-template-columns: 1fr 1fr; border-top: 1px solid var(--ink); border-bottom: 1px solid var(--line); }
.pager a { position: relative; display: block; padding: clamp(22px, 3vw, 36px) 0; text-decoration: none; }
.pager a[rel="next"] { grid-column: 2; padding-left: clamp(20px, 3vw, 40px); border-left: 1px solid var(--line); text-align: right; }
.pager a[rel="prev"] { grid-column: 1; padding-right: clamp(20px, 3vw, 40px); }
.pager .label { display: flex; align-items: center; gap: 12px; margin-bottom: 10px; transition: color 0.2s ease; }
.pager a[rel="next"] .label { justify-content: flex-end; }
.pager-title { display: block; font-family: var(--serif); font-size: clamp(1.25rem, 2.2vw, 1.75rem); line-height: 1.15; letter-spacing: -0.01em; transition: color 0.2s ease; }
.pager a:hover .pager-title,
.pager a:focus-visible .pager-title { color: var(--violet-deep); }
.pager a:hover .label,
.pager a:focus-visible .label { color: var(--violet); }
.pager a:focus-visible .label > .arrow::before { transform: scaleX(1.5); }
.pager a:focus-visible .label > .arrow::after { transform: translateX(13px) rotate(45deg); }

/* ---------- Privacy notice ----------
   Not a consent banner: there is nothing to consent to. In every page with
   the hidden attribute; site.js shows it until it is closed. Fixed at the
   bottom left, clear of the skip link, never a modal. */
.notice {
  position: fixed;
  left: 16px;
  bottom: 16px;
  z-index: 40;
  width: calc(100% - 32px);
  max-width: 34rem;
  padding: 16px 18px 12px;
  border: 1px solid var(--line-3);
  background: var(--paper);
  color: var(--ink-2);
  box-shadow: var(--notice-shadow);
  font-size: 0.875rem;
  line-height: 1.5;
}
.notice[hidden] { display: none; }
.notice-label { margin-bottom: 6px; }
.notice-actions { display: flex; align-items: center; justify-content: space-between; gap: 8px 20px; margin-top: 8px; }
.notice-actions .link { font-size: 0.875rem; padding-block: 4px; }
.notice-close {
  min-width: 44px;
  min-height: 32px;
  margin-right: -6px;
  padding: 4px 10px;
  border: 1px solid var(--line-3);
  background: none;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.2;
  color: var(--ink);
  cursor: pointer;
  transition: color 0.2s ease, border-color 0.2s ease;
}
.notice-close:hover,
.notice-close:focus-visible { color: var(--violet-deep); border-color: var(--violet); }
.notice.is-out { animation: none; opacity: 0; transform: translateY(12px); transition: opacity 0.3s ease, transform 0.35s var(--ease); }
/* On pages with a contents column, the notice lines up with the text column,
   so it never sits over the contents list or the All notes link. */
@media (min-width: 1081px) {
  body:has(.article-grid .toc) .notice {
    left: max(16px, calc((100vw - var(--wrap)) / 2 + 220px + clamp(40px, 5vw, 72px)), calc(var(--gutter) + 220px + clamp(40px, 5vw, 72px)));
  }
}
/* On a very short screen (a laptop at 400% zoom) the notice keeps to one
   short row: the label and the text give way to the link and the button. */
@media (max-height: 420px) {
  .notice { padding: 6px 12px; font-size: 0.8125rem; }
  .notice-label,
  .notice-text { display: none; }
  .notice-actions { margin-top: 0; }
}

/* ---------- 404 ---------- */
.lost { padding-block: clamp(48px, 9vw, 128px); }
.lost h1 { font-family: var(--serif); font-weight: 400; font-size: clamp(2.75rem, 6.4vw, 5.5rem); line-height: 1; letter-spacing: -0.022em; }
.lost-lead { max-width: 30em; margin-top: clamp(20px, 2.6vw, 32px); font-size: 1.125rem; color: var(--ink-2); }
.lost .register { margin-top: clamp(32px, 5vw, 56px); }
.lost .entry-no { white-space: nowrap; }
.lost-links { display: flex; flex-wrap: wrap; gap: 14px 40px; margin-top: 8px; }

/* ---------- Motion ----------
   Rules of the house:
   1. Every rule that hides content before animating it sits inside
      (prefers-reduced-motion: no-preference).
   2. Anything that waits for a script to reveal it also needs the .js class,
      which site.js sets as its first statement and removes again on error.
   3. Load animations (hero, plate, page titles) are pure CSS and run with
      scripts off.
   4. Only transform, opacity and SVG stroke or fill are animated. Nothing
      loops: every animation has an end state. */
/* Paths carry pathLength="1000". The dash pattern is dropped at the very end
   so a finished line is a plain solid stroke at every zoom level. */
@keyframes draw {
  from { stroke-dasharray: 1000 1000; stroke-dashoffset: 1000; }
  99.9% { stroke-dasharray: 1000 1000; stroke-dashoffset: 0; }
  to { stroke-dasharray: none; stroke-dashoffset: 0; }
}
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes wash { from { fill: var(--paper); } to { fill: var(--wash); } }
@keyframes rise { from { transform: translateY(110%); } to { transform: translateY(0); } }
@keyframes rise-soft { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: translateY(0); } }
@keyframes grow-x { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes gauge { from { transform: translateY(0); } to { transform: translateY(155px); } }
@keyframes pop { from { opacity: 0; transform: scale(0.6); } to { opacity: 1; transform: scale(1); } }
@keyframes progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* Delay steps used by the drawings: .dN is N tenths of a second. */
.d1 { --d: 0.1s; } .d2 { --d: 0.2s; } .d3 { --d: 0.3s; } .d4 { --d: 0.4s; } .d5 { --d: 0.5s; }
.d6 { --d: 0.6s; } .d7 { --d: 0.7s; } .d8 { --d: 0.8s; } .d9 { --d: 0.9s; } .d10 { --d: 1s; }
.d11 { --d: 1.1s; } .d12 { --d: 1.2s; } .d13 { --d: 1.3s; } .d14 { --d: 1.4s; } .d15 { --d: 1.5s; }
.d16 { --d: 1.6s; } .d17 { --d: 1.7s; } .d18 { --d: 1.8s; } .d19 { --d: 1.9s; } .d20 { --d: 2s; }
.d21 { --d: 2.1s; } .d22 { --d: 2.2s; } .d23 { --d: 2.3s; } .d24 { --d: 2.4s; } .d25 { --d: 2.5s; }
.d26 { --d: 2.6s; } .d27 { --d: 2.7s; } .d28 { --d: 2.8s; } .d29 { --d: 2.9s; } .d30 { --d: 3s; }
.d31 { --d: 3.1s; } .d32 { --d: 3.2s; } .d33 { --d: 3.3s; } .d34 { --d: 3.4s; } .d35 { --d: 3.5s; }
.d36 { --d: 3.6s; } .d37 { --d: 3.7s; } .d38 { --d: 3.8s; } .d39 { --d: 3.9s; } .d40 { --d: 4s; }

@supports (animation-timeline: scroll()) {
  .progress { animation: progress linear both; animation-timeline: scroll(root block); }
}

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }

  /* The privacy notice rises in once site.js shows it. */
  .notice { animation: rise-soft 0.8s var(--ease) both; }

  /* Hero plate: pure CSS, runs with or without scripts, once. */
  .plate .dr { animation: draw var(--t, 1.2s) var(--ease-draw) var(--d, 0s) both; }
  .plate .p-petal.dr { animation: draw var(--t, 1.3s) var(--ease-draw) var(--d, 0s) both, wash 1.6s ease 2.9s both; }
  .plate .fd { animation: fade 0.9s ease var(--d, 0s) both; }
  .plate .pp { transform-box: fill-box; transform-origin: center; animation: pop 0.5s var(--ease) var(--d, 0s) both; }
  .plate .p-vein { --t: 0.7s; }
  .plate .p-lead { --t: 0.6s; }
  .plate .p-mark { animation: fade 0.9s ease 0.4s both, gauge 3.4s var(--ease-draw) 0.9s both; }
  .plate.is-reset .dr,
  .plate.is-reset .fd,
  .plate.is-reset .pp,
  .plate.is-reset .p-mark { animation: none; }
  .plate.is-reset .dr { stroke-dasharray: 1000 1000; stroke-dashoffset: 1000; }
  .plate.is-reset .fd,
  .plate.is-reset .pp { opacity: 0; }
  .plate.is-reset .p-petal { fill: var(--paper); }
  .plate.is-reset .p-mark { opacity: 0; transform: none; }
  .plate { animation: fade 0.8s ease 0.1s both; }
  .plate-legend li { animation: fade 0.7s ease both; animation-delay: calc(3.3s + var(--n, 0) * 0.1s); }
  .plate-legend li:nth-child(2) { --n: 1; }
  .plate-legend li:nth-child(3) { --n: 2; }
  .plate-legend li:nth-child(4) { --n: 3; }
  .plate-legend li:nth-child(5) { --n: 4; }
  .plate-legend li:nth-child(6) { --n: 5; }

  /* Hero copy: the sentence sets itself line by line, then the notes follow. */
  .hl-in { animation: rise 1s var(--ease) both; animation-delay: calc(var(--l, 0) * 140ms + 150ms); }
  .hl:nth-child(2) .hl-in { --l: 1; }
  .hl:nth-child(3) .hl-in { --l: 2; }
  .hero-lead { animation: rise-soft 0.9s var(--ease) 0.75s both; }
  .fn::before { animation: grow-x 0.9s var(--ease-draw) 1.05s both; }
  .fn-label::before { animation: grow-x 0.9s var(--ease-draw) 1.05s both; }
  .fn-label { animation: rise-soft 0.8s var(--ease) 1.1s both; }
  .fn li { animation: rise-soft 0.8s var(--ease) both; animation-delay: calc(1.2s + var(--n, 0) * 0.12s); }
  .fn li:nth-child(2) { --n: 1; }
  .fn li:nth-child(3) { --n: 2; }

  /* Page titles: words are wrapped at build time (.w > .wi) and rise in
     reading order. Pure CSS. Words after the fourteenth share one delay. */
  .w { display: inline-block; overflow: clip; overflow-clip-margin: 0.08em; vertical-align: top; padding-bottom: 0.16em; margin-bottom: -0.16em; }
  .wi { display: inline-block; }
  .title-set .wi { animation: rise 0.95s var(--ease) both; animation-delay: calc(var(--k, 13) * 45ms + 120ms); }
  .title-set .w:nth-child(1) .wi { --k: 0; }
  .title-set .w:nth-child(2) .wi { --k: 1; }
  .title-set .w:nth-child(3) .wi { --k: 2; }
  .title-set .w:nth-child(4) .wi { --k: 3; }
  .title-set .w:nth-child(5) .wi { --k: 4; }
  .title-set .w:nth-child(6) .wi { --k: 5; }
  .title-set .w:nth-child(7) .wi { --k: 6; }
  .title-set .w:nth-child(8) .wi { --k: 7; }
  .title-set .w:nth-child(9) .wi { --k: 8; }
  .title-set .w:nth-child(10) .wi { --k: 9; }
  .title-set .w:nth-child(11) .wi { --k: 10; }
  .title-set .w:nth-child(12) .wi { --k: 11; }
  .title-set .w:nth-child(13) .wi { --k: 12; }
  .page-head .sec-intro,
  .page-head .crumbs,
  .article-head .crumbs,
  .lost-lead { animation: rise-soft 0.9s var(--ease) 0.45s both; }
  .page-head .crumbs,
  .article-head .crumbs { animation-delay: 0.05s; }
  .article-no { animation: fade 0.9s ease 0.3s both; }
  .article-meta { animation: rise-soft 0.9s var(--ease) 0.55s both; }

  /* Statements below the fold: site.js splits them into lines once the fonts
     are in, and they set line by line when they scroll into view. */
  .js .set-lines:not(.is-split) { visibility: hidden; }
  .js .set-lines.is-split .wi { transform: translateY(110%); }
  .js .set-lines.is-split.is-in .wi { animation: rise 0.95s var(--ease) both; animation-delay: calc(var(--l, 0) * 130ms + var(--k, 0) * 22ms + 80ms); }

  /* Scroll reveals */
  .js [data-reveal] { opacity: 0; transform: translateY(16px); transition: opacity 0.8s ease, transform 0.9s var(--ease); transition-delay: calc(var(--i, 0) * 90ms); }
  .js [data-reveal].is-in { opacity: 1; transform: none; }

  /* Top borders that draw: the border is replaced by a pseudo rule. */
  .js .draws-top { position: relative; border-top-color: transparent; }
  .js .draws-top::after { content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 1px; background: var(--ink); transform: scaleX(0); transform-origin: left center; transition: transform 1.3s var(--ease-draw); }
  .js .draws-top.is-in::after { transform: scaleX(1); }

  /* Inline SVG figures that ink in when they enter the viewport. */
  .js .figure-draw .dr { stroke-dasharray: 1000 1000; stroke-dashoffset: 1000; }
  .js .figure-draw .fd,
  .js .figure-draw .pp { opacity: 0; }
  .js .figure-draw.is-in .dr { animation: draw var(--t, 0.9s) var(--ease-draw) calc(var(--s, 0s) + var(--d, 0s)) both; }
  .js .figure-draw.is-in .fd { animation: fade 0.7s ease calc(var(--s, 0s) + var(--d, 0s)) both; }
  .js .figure-draw.is-in .pp { transform-box: fill-box; transform-origin: center; animation: pop 0.5s var(--ease) calc(var(--s, 0s) + var(--d, 0s)) both; }

  /* Pipeline: stations appear in order, the track draws between them. */
  .step:nth-child(2) { --s: 0.45s; }
  .step:nth-child(3) { --s: 0.9s; }
  .step:nth-child(4) { --s: 1.35s; }
  .step:nth-child(5) { --s: 1.8s; }
  .step:nth-child(n + 6) { --s: 2.25s; }
  .js .pipeline .step-node,
  .js .pipeline .step-title,
  .js .pipeline .step-text,
  .js .pipeline figcaption,
  .js .pipeline .step::after { opacity: 0; }
  .js .pipeline .step::before { transform: scaleX(0); }
  .js .pipeline.is-in .step-node { animation: pop 0.5s var(--ease) var(--s, 0s) both; }
  .js .pipeline.is-in .step::before { animation: grow-x 0.6s var(--ease-draw) calc(var(--s, 0s) + 0.2s) both; }
  .js .pipeline.is-in .step::after { animation: fade 0.3s ease calc(var(--s, 0s) + 0.7s) both; }
  .js .pipeline.is-in .step-title { animation: rise-soft 0.7s var(--ease) calc(var(--s, 0s) + 0.1s) both; }
  .js .pipeline.is-in .step-text { animation: rise-soft 0.7s var(--ease) calc(var(--s, 0s) + 0.2s) both; }
  .js .pipeline.is-in figcaption { animation: fade 0.8s ease 2s both; }

  .js .prose blockquote::before { transform: scaleY(0); transition: transform 1s var(--ease-draw) 0.15s; }
  .js .prose blockquote.is-in::before { transform: scaleY(1); }

  .js .prose h2 { border-top-color: transparent; }
  .js .prose h2::after { content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 1px; background: var(--line); transform: scaleX(0); transform-origin: left center; transition: transform 1.1s var(--ease-draw); }
  .js .prose h2.is-in::after { transform: scaleX(1); }

  .js .site-footer { border-top-color: transparent; }
  .js .site-footer::before { content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 1px; background: var(--ink); transform: scaleX(0); transform-origin: left center; transition: transform 1.3s var(--ease-draw); }
  .js .site-footer.is-in::before { transform: scaleX(1); }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
}

/* ---------- Responsive ---------- */
@media (max-width: 1080px) {
  /* Not the vacant row: it has two cells of its own ("no text") and this
     rule, coming later with the same weight, would give it four empty rows. */
  .entry:not(.entry--vacant) {
    grid-template-columns: var(--no-col) minmax(0, 1fr);
    grid-template-areas:
      "no head"
      "no body"
      "no links"
      "no fig";
    grid-template-rows: none;
    row-gap: 22px;
  }
  .entry-links { padding-top: 0; }
  .entry-fig { margin-top: 12px; }
  .register--home > article.entry:not(:only-of-type) {
    grid-template-columns: var(--no-col) minmax(0, 1fr);
    grid-template-areas:
      "no head"
      "no body"
      "no links";
    row-gap: 12px;
  }
  .pipeline-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 32px; }
  .step:nth-child(2n)::before,
  .step:nth-child(2n)::after { display: none; }
  .article-grid,
  .article-head-grid { grid-template-columns: minmax(0, 720px); justify-content: center; }
  .article-no { display: none; }
  .crumb-no { display: inline; }
  .crumbs span.crumb-no[aria-hidden] { display: block; }
  .toc { position: static; max-height: none; margin-bottom: 40px; padding-bottom: 24px; border-bottom: 1px solid var(--line); }
  /* Above the text the list folds away behind its label. */
  .toc:has(.toc-box) { padding-bottom: 0; }
  .toc-box > summary { position: relative; margin: 0; padding: 12px 28px 12px 0; cursor: pointer; border-top: 1px solid var(--line); }
  .toc-box > summary::after { content: ""; position: absolute; right: 6px; top: 50%; width: 7px; height: 7px; margin-top: -6px; border-right: 1.5px solid var(--ink-2); border-bottom: 1.5px solid var(--ink-2); transform: rotate(45deg); transition: transform 0.25s var(--ease); }
  .toc-box[open] > summary::after { margin-top: -2px; transform: rotate(-135deg); }
  .toc-box > summary:hover { color: var(--ink); }
  .toc-box[open] > ol { margin-bottom: 20px; }
  .toc-back { display: none; }
  .footer-grid,
  .footer-grid--brief { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .footer-brand,
  .footer-col--company { grid-column: 1 / -1; }
  .footer-col--company { max-width: 560px; }
}

@media (max-width: 900px) {
  :root { --no-col: 56px; }
  .hero-grid { grid-template-columns: minmax(0, 1fr); }
  .plate { justify-self: start; max-width: 460px; }
  .sec-head,
  .page-head-grid { grid-template-columns: minmax(0, 1fr); row-gap: 14px; }
  .note { grid-template-columns: var(--no-col) minmax(0, 1fr); row-gap: 8px; }
  .note-meta { grid-column: 2; flex-direction: row; flex-wrap: wrap; gap: 4px 14px; order: -1; }
  .note-no { order: -2; }
  .note-body { grid-column: 2; }
  .note-time { grid-column: 2; text-align: left; }
  .about-grid { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 680px) {
  :root { --no-col: 0px; --header-h: 60px; }
  body { font-size: 1rem; }
  .wordmark { font-size: 1.3125rem; }
  .note,
  .year,
  .entry--vacant { grid-template-columns: minmax(0, 1fr); column-gap: 0; }
  .note-meta,
  .note-body,
  .note-time,
  .note-vacant-text { grid-column: 1; }
  .note-no { font-size: 0.9375rem; }
  .notes--list > .note { grid-template-columns: minmax(0, 1fr); }
  .notes--list .note-no,
  .notes--list .note-body { grid-column: 1; }
  /* Callout numerals in the plate: larger, so they can be read at this size. */
  .p-num circle { r: 14px; }
  .p-num text { font-size: 15px; transform: translateY(1.6px); }
  /* Short dates on phones: "30 Sep 2026". The tail of the month is wrapped. */
  .mo { display: none; }
  /* Must be at least as specific as .entry:not(.entry--vacant) in the 1080px block. */
  .entry:not(.entry--vacant),
  .register--home > article.entry:not(:only-of-type) {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      "no"
      "head"
      "body"
      "links"
      "fig";
    column-gap: 0;
    row-gap: 16px;
  }
  .register--home > article.entry:not(:only-of-type) { grid-template-areas: "no" "head" "body" "links"; row-gap: 10px; }
  .entry--vacant { grid-template-areas: "no" "text"; row-gap: 4px; }
  .entry-no { padding-top: 0; font-size: 0.9375rem; }
  .entry::before { width: 56px; }
  .entry-facts div { grid-template-columns: 92px minmax(0, 1fr); }
  /* Pipeline turns vertical: node and track on the left, text on the right. */
  .pipeline-steps { grid-template-columns: minmax(0, 1fr); row-gap: 0; }
  .step {
    grid-template-columns: 25px minmax(0, 1fr) 84px;
    grid-template-rows: auto auto;
    column-gap: 16px;
    padding-bottom: 22px;
  }
  .step:last-child { padding-bottom: 0; }
  .step-node { grid-column: 1; grid-row: 1; }
  .step-title { grid-column: 2; grid-row: 1; margin-top: 1px; }
  .step-text { grid-column: 2; grid-row: 2; padding-right: 0; }
  .step-glyph { grid-column: 3; grid-row: 1 / span 2; width: 84px; height: 42px; }
  .step::before,
  .step:nth-child(2n)::before {
    display: block;
    left: 12px;
    right: auto;
    top: 25px;
    bottom: 0;
    width: 1px;
    height: auto;
    transform-origin: center top;
  }
  .step:last-child::before { display: none; }
  .step::after { display: none; }
  .subjects { gap: 2px 20px; }
  .subjects ul { gap: 0 20px; }
  .pagination { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .pagination ol { grid-column: 1 / -1; grid-row: 1; justify-content: center; }
  .footer-grid { grid-template-columns: minmax(0, 1fr); }
  .details div,
  .footer-col .details div { grid-template-columns: minmax(0, 1fr); row-gap: 1px; }
  .pager { grid-template-columns: 1fr; }
  .pager a[rel="next"] { grid-column: 1; padding-left: 0; border-left: 0; text-align: left; }
  .pager a[rel="prev"] + a[rel="next"] { border-top: 1px solid var(--line); }
  .pager a[rel="next"] .label { justify-content: flex-start; }
  .article-meta { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: 20px; }
  .article-meta div { padding: 10px 0 11px; margin-right: 0; border-right: 0; border-bottom: 1px solid var(--line-2); }
  .article-meta div:last-child:nth-child(odd) { grid-column: 1 / -1; border-bottom: 0; }
  .prose .lead,
  .prose > p:first-child { font-size: 1.1em; line-height: 1.5; }
  .prose blockquote { font-size: 1.14em; }
  .prose ul,
  .prose ol { padding-left: 1.25em; }
  .ln::before { width: 2em; margin-right: 0.8em; }
  .listing pre { font-size: 0.8125rem; }
  .footer-grid,
  .footer-grid--brief { grid-template-columns: minmax(0, 1fr); }
  /* The notice stays compact on a phone: the label is for screen readers. */
  .notice { left: 12px; bottom: 12px; width: calc(100% - 24px); padding: 12px 14px 8px; font-size: 0.8125rem; }
  .notice-label { display: none; }
  .notice-actions { margin-top: 4px; }
}

/* Between phone and desktop the hero is one column. The plate takes its full
   width there, with the legend beside the drawing, so that no part of the
   column is left empty next to it. */
@media (min-width: 681px) and (max-width: 900px) {
  .plate {
    display: grid;
    grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
    max-width: none;
  }
  .plate-head,
  .plate-foot { grid-column: 1 / -1; }
  .plate > svg { grid-column: 1; }
  .plate-legend {
    grid-column: 2;
    flex-direction: column;
    flex-wrap: nowrap;
    justify-content: center;
    gap: 6px;
    padding: 16px 20px;
    border-left: 1px solid var(--line);
  }
  .plate-legend li { font-size: 0.875rem; }
}

@media (prefers-reduced-motion: no-preference) and (max-width: 680px) {
  .js .pipeline .step::before { transform: scaleY(0); }
  .js .pipeline.is-in .step::before { animation-name: grow-y; }
}
@keyframes grow-y { from { transform: scaleY(0); } to { transform: scaleY(1); } }

@media (max-width: 420px) {
  .prose table { min-width: 440px; }
  /* Wordmark, three links and the toggle on one line down to 360px. */
  .site-nav ul { gap: 12px; }
  .site-nav a { font-size: 0.875rem; }
  .site-header .wrap { gap: 8px; }
  .theme-toggle { width: 32px; height: 32px; margin-right: -6px; }
  .step { grid-template-columns: 25px minmax(0, 1fr) 64px; column-gap: 12px; }
  .step-glyph { width: 64px; height: 32px; }
}

@media (max-width: 359px) {
  .wordmark { font-size: 1.1875rem; }
  .site-nav ul { gap: 10px; }
}

/* ---------- Print ---------- */
@media print {
  .site-header, .skip, .toc, .redraw, .subjects, .pagination, .pager, .progress, .notice { display: none !important; }
  /* Paper is white whatever the screen shows. */
  :root:root,
  :root:root[data-theme] {
    --paper: #ffffff;
    --paper-2: #f7f7f5;
    --ink: #14151a;
    --ink-2: #43464f;
    --ink-3: #626570;
    --line: #dcdde2;
    --line-2: #ececef;
    --line-3: #b9bbc4;
    --line-4: #8a8d98;
    --violet: #5a3ea8;
    --violet-deep: #43297f;
    --wash: #efeaf9;
    --mark-back: #c9bdea;
    --on-violet: #ffffff;
    --shade: rgba(20, 21, 26, 0.1);
    --code-comment: #5f626d;
    --code-keyword: #5a3ea8;
    --code-string: #2a5b4c;
    --code-number: #8a4412;
    --code-title: #1d4f80;
    --code-attr: #43297f;
    --code-add: #1f5a3c;
    --code-add-bg: #e3f1e8;
    --code-del: #8c2626;
    --code-del-bg: #f9e6e4;
    --error: #8c2626;
    --error-text: #6d1d1d;
    --error-bg: #f9e6e4;
    --ok: #1f5a3c;
    --ok-text: #1f4a32;
    --ok-bg: #e3f1e8;
    --warn: #8a4412;
    --warn-bg: #f8ecdf;
        color-scheme: light;
  }
  *,
  *::before,
  *::after { animation: none !important; transition: none !important; }
  .js [data-reveal],
  .js .set-lines,
  .js .set-lines .wi,
  .js .pipeline .step-node,
  .js .pipeline .step-title,
  .js .pipeline .step-text,
  .js .pipeline figcaption,
  .js .pipeline .step::after,
  .js .figure-draw .fd,
  .js .figure-draw .pp { opacity: 1 !important; transform: none !important; visibility: visible !important; }
  .js .figure-draw .dr { stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
  .js .draws-top::after,
  .js .prose h2::after,
  .js .site-footer::before,
  .js .pipeline .step::before { transform: none !important; }
  .js .prose blockquote::before { transform: none !important; }
  /* A plate that was still held undrawn (see site.js) prints finished. */
  .plate.is-reset .dr { stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
  .plate.is-reset .fd,
  .plate.is-reset .pp,
  .plate.is-reset .p-mark { opacity: 1 !important; }
  .plate.is-reset .p-mark { transform: translateY(155px) !important; }
  .plate.is-reset .p-petal { fill: var(--wash) !important; }
  body { font-size: 11pt; }
  .prose { font-size: 11.5pt; max-width: none; }
  .article-grid,
  .article-head-grid { display: block; }
  .prose a[href^="http"]::after { content: " (" attr(href) ")"; font-family: var(--sans); font-size: 0.8em; color: var(--ink-3); }
  .listing, .prose figure, .table-wrap, .entry, .note { break-inside: avoid; }
  .listing pre { white-space: pre-wrap; }
  .listing pre code { min-width: 0; }
}

/* ======================================================================
   VioPO. Everything below is specific to this site: the waitlist button in
   the header, the status line, the examples panel, plans and the waitlist
   form. Same rules
   as above: hairlines, one violet accent, no inline styles.
   ====================================================================== */

/* The hidden attribute always wins over a display set in this file. */
[hidden] { display: none !important; }

/* ---------- Header waitlist button ---------- */
/* Wordmark, nav, the theme toggle, then the one waitlist button. */
.site-header .wrap { gap: clamp(16px, 3vw, 40px); }
.site-header .theme-toggle { margin-inline: -6px; }
.site-account { display: flex; align-items: center; gap: 20px; flex: none; }
.btn--sm { padding: 7px 14px; font-size: 0.875rem; }
.btn--quiet { border-color: var(--line-3); }
button.btn { background: none; cursor: pointer; font-family: inherit; }
button.btn:disabled { opacity: 0.5; cursor: wait; }
.link-button {
  border: 0;
  background: none;
  padding: 4px 0;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ink-2);
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: var(--line-4);
  text-underline-offset: 4px;
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}
.link-button:hover { color: var(--violet-deep); text-decoration-color: var(--violet); }

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

/* ---------- Hero additions ---------- */
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 16px 28px; margin-top: clamp(24px, 3vw, 36px); }
.plate-legend li,
.legend-btn { font-family: var(--mono); font-size: 0.75rem; }
.p-txt { font-family: var(--sans); font-size: 10px; font-weight: 600; letter-spacing: 0.14em; fill: var(--ink); }
@media (prefers-reduced-motion: no-preference) {
  .hero-actions { animation: rise-soft 0.9s var(--ease) 0.9s both; }
}

/* ---------- Try panel ---------- */
.try {
  display: grid;
  grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.6fr);
  gap: clamp(24px, 4vw, 56px);
  padding-top: clamp(24px, 3vw, 36px);
  border-top: 1px solid var(--ink);
}
.try-label { margin-bottom: 10px; }
.try-label:not(:first-child) { margin-top: 28px; }
.try-samples { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--line); }
.try-sample {
  position: relative;
  display: grid;
  gap: 2px;
  padding: 12px 0 12px 16px;
  border-bottom: 1px solid var(--line);
}
.try-sample::before {
  content: "";
  position: absolute;
  left: 0;
  top: 12px;
  bottom: 12px;
  width: 2px;
  background: var(--violet);
  transform: scaleY(0);
  transition: transform 0.3s var(--ease);
}
.try-sample.is-current::before,
.try-sample[data-current]::before { transform: scaleY(1); }
.try-sample-name { font-weight: 600; font-size: 0.9375rem; }
.try-sample-detail { font-size: 0.8125rem; color: var(--ink-3); }
.try-sample-file { justify-self: start; display: inline-flex; align-items: center; min-height: 32px; font-size: 0.8125rem; color: var(--ink-2); text-underline-offset: 3px; text-decoration-color: var(--line-4); }
.try-sample-pick {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  margin-top: 2px;
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-weight: 600;
  font-size: 0.875rem;
  color: var(--violet-deep);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.try-sample.is-current .try-sample-pick { color: var(--ink-3); text-decoration: none; cursor: default; }
.try-hint { margin-top: 10px; font-size: 0.8125rem; line-height: 1.5; color: var(--ink-3); }
.try-hint a { color: inherit; text-underline-offset: 3px; }

.try-out { min-width: 0; scroll-margin-top: calc(var(--header-h) + 16px); }
.try-out-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 20px; padding-bottom: 10px; border-bottom: 1px solid var(--line); }
.try-out-head .label span { color: var(--ink); letter-spacing: 0.04em; text-transform: none; font-weight: 600; }
.try-tabs { display: flex; gap: 4px; }
.try-tabs button {
  border: 1px solid transparent;
  background: none;
  padding: 5px 12px;
  font: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ink-3);
  cursor: pointer;
}
.try-tabs button[aria-selected="true"] { color: var(--ink); border-color: var(--line-3); }
.try-actions { display: flex; gap: 16px; }
.try-status { min-height: 1.5em; margin-top: 12px; font-size: 0.875rem; color: var(--ink-2); }
.try-status.is-error { color: var(--error); }
.try-json .listing { margin-block: 12px 0; }
.try-json pre { max-height: 560px; overflow: auto; }
.try-after { margin-top: 18px; font-size: 0.9375rem; color: var(--ink-2); display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }

/* The summary view of a result */
.try-summary { margin-top: 12px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 22px; }
.try-summary > * { min-width: 0; }
.sum-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 0 24px; border-top: 1px solid var(--ink); }
.sum-grid div { padding: 9px 0; border-bottom: 1px solid var(--line-2); }
.sum-grid dt { margin-bottom: 2px; }
.sum-grid dd { font-size: 0.9375rem; overflow-wrap: anywhere; }
.sum-grid dd.is-null { color: var(--ink-3); }
.sum-title { font-family: var(--serif); font-size: 1.25rem; font-weight: 400; margin-bottom: 8px; }
.sum-addresses { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 16px 24px; }
.sum-addresses address { overflow-wrap: anywhere; font-style: normal; font-size: 0.9375rem; line-height: 1.5; color: var(--ink-2); }
.sum-addresses .label { display: block; margin-bottom: 4px; }
.try-summary .table-wrap { margin-block: 0; }
.sum-lines { width: 100%; min-width: 560px; border-collapse: collapse; font-size: 0.875rem; }
.sum-lines th,
.sum-lines td { text-align: left; vertical-align: top; padding: 8px 12px 8px 0; border-bottom: 1px solid var(--line); }
.sum-lines thead th { border-top: 1px solid var(--ink); font-size: 0.6875rem; font-weight: 600; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-3); }
.sum-lines .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Part numbers such as NJ-1104 never break at the hyphen; the table scrolls instead. */
.sum-lines td:nth-child(2) { white-space: nowrap; }
/* The totals: a short list under the lines, outside the table's scrolling
   box, so on a phone they never sit in columns scrolled out of view. */
.sum-totals { width: min(100%, 320px); margin: 10px 0 0 auto; font-size: 0.875rem; font-variant-numeric: tabular-nums; }
.sum-totals div { display: flex; justify-content: space-between; gap: 16px; padding: 6px 0; border-bottom: 1px solid var(--line-2); }
.sum-totals dt { color: var(--ink-2); }
.sum-totals dd { text-align: right; white-space: nowrap; }
.sum-totals .is-total { border-bottom: 0; border-top: 1px solid var(--ink); font-weight: 600; }
.sum-totals .is-total dt { color: var(--ink); }
@media (max-width: 680px) {
  .sum-totals { width: 100%; }
}
.sum-checks { margin: 0; padding: 0; list-style: none; display: grid; gap: 6px; font-size: 0.875rem; }
.sum-checks li { position: relative; padding-left: 22px; color: var(--ink-2); }
.sum-checks li::before { content: ""; position: absolute; left: 2px; top: 0.45em; width: 9px; height: 5px; border-left: 1.5px solid var(--ok); border-bottom: 1.5px solid var(--ok); transform: rotate(-45deg); }
.sum-checks li.is-fail::before { width: 10px; height: 10px; top: 0.35em; border: 0; transform: none; background: linear-gradient(45deg, transparent 45%, var(--error) 45%, var(--error) 55%, transparent 55%), linear-gradient(-45deg, transparent 45%, var(--error) 45%, var(--error) 55%, transparent 55%); }
.sum-checks li.is-warn::before { width: 6px; height: 6px; top: 0.55em; left: 3px; border: 0; transform: none; border-radius: 50%; background: var(--warn); }

/* ---------- What comes back ---------- */
.output-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); gap: clamp(28px, 5vw, 72px); padding-top: clamp(24px, 3vw, 36px); border-top: 1px solid var(--ink); }
.fields div { display: grid; grid-template-columns: 9.5em minmax(0, 1fr); gap: 16px; padding: 11px 0; border-bottom: 1px solid var(--line); }
.fields dt code { font-size: 0.8125rem; color: var(--violet-deep); }
.fields dd { font-size: 0.9375rem; color: var(--ink-2); line-height: 1.5; }
.output-code .label { margin-bottom: 8px; }
.output-code .listing { margin-block: 0 22px; }
.listing--tall pre { max-height: 440px; overflow: auto; }
.how { padding-top: clamp(28px, 3.4vw, 44px); }

/* ---------- Plans ---------- */
.plans { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0; margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--ink); }
.plan { display: flex; flex-direction: column; padding: clamp(22px, 2.6vw, 32px) clamp(18px, 2.4vw, 32px) clamp(24px, 3vw, 36px); border-bottom: 1px solid var(--line); }
.plan + .plan { border-left: 1px solid var(--line); }
.plan--starter { background: var(--paper-2); }
.plan-name { font-family: var(--serif); font-weight: 400; font-size: clamp(1.75rem, 2.6vw, 2.25rem); line-height: 1.05; }
.plan-summary { margin-top: 8px; font-size: 0.9375rem; line-height: 1.6; color: var(--ink-2); min-height: 3.2em; }
.plan-price { margin-top: 18px; display: flex; align-items: baseline; gap: 8px; }
.plan-amount { font-family: var(--serif); font-size: clamp(2.5rem, 4vw, 3.25rem); line-height: 1; letter-spacing: -0.02em; font-variant-numeric: lining-nums; }
.plan-per { font-size: 0.9375rem; color: var(--ink-3); }
.plan-facts { margin-top: 20px; border-top: 1px solid var(--line); }
.plan-facts div { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--line-2); }
.plan-facts dd { font-weight: 600; font-variant-numeric: tabular-nums; }
.plan-features { margin: 16px 0 0; padding: 0; list-style: none; display: grid; gap: 6px; font-size: 0.9375rem; color: var(--ink-2); }
.plan-features li { position: relative; padding-left: 20px; }
.plan-features li::before { content: ""; position: absolute; left: 1px; top: 0.5em; width: 8px; height: 4px; border-left: 1.5px solid var(--violet); border-bottom: 1.5px solid var(--violet); transform: rotate(-45deg); }
.plan-cta { margin-top: auto; padding-top: 24px; }

.ticks { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 32px; border-top: 1px solid var(--ink); }
.ticks li { position: relative; padding: 12px 0 12px 24px; border-bottom: 1px solid var(--line); color: var(--ink-2); }
.ticks li::before { content: ""; position: absolute; left: 2px; top: 1.25em; width: 9px; height: 4.5px; border-left: 1.5px solid var(--violet); border-bottom: 1.5px solid var(--violet); transform: rotate(-45deg); }

.faq { border-top: 1px solid var(--ink); max-width: 980px; }
.faq div { display: grid; grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); gap: 8px 32px; padding: 18px 0; border-bottom: 1px solid var(--line); }
.faq dt { font-family: var(--serif); font-size: 1.25rem; line-height: 1.3; }
.faq dd { color: var(--ink-2); }

/* ---------- Article call to action ---------- */
.cta-box { max-width: 720px; margin-top: 2.6em; padding: 22px 24px 24px; border: 1px solid var(--line); border-top: 2px solid var(--violet); background: var(--paper-2); }
.cta-title { font-family: var(--serif); font-size: 1.375rem; line-height: 1.2; }
.cta-box p + p { margin-top: 10px; color: var(--ink-2); }
.cta-box .btn { margin-top: 6px; }

/* ---------- Forms ---------- */
.page-head--narrow h1 { font-size: clamp(2.5rem, 5vw, 4rem); }
.form { max-width: 480px; display: grid; gap: 18px; padding-top: 24px; border-top: 1px solid var(--ink); }
.form--inline { max-width: none; grid-template-columns: minmax(0, 320px) auto; align-items: end; border-top: 0; padding-top: 12px; }
.form--inline .form-error { grid-column: 1 / -1; }
.field { display: grid; gap: 6px; }
.field label { font-size: 0.875rem; font-weight: 600; }
.field input[type="email"],
.field input[type="password"],
.field input[type="text"] {
  width: 100%;
  padding: 11px 12px;
  border: 1px solid var(--line-3);
  border-radius: 0;
  background: var(--paper);
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  transition: border-color 0.2s ease;
}
.field input:not([type="checkbox"]):focus { outline: none; border-color: var(--violet); box-shadow: 0 0 0 1px var(--violet); }
.field input:not([type="checkbox"])[aria-invalid="true"]:focus { border-color: var(--error); box-shadow: 0 0 0 1px var(--error); }
/* Browser autofill paints its own light fill: keep the page colours. */
.field input:-webkit-autofill {
  -webkit-text-fill-color: var(--ink);
  caret-color: var(--ink);
  box-shadow: 0 0 0 100px var(--paper) inset;
}
.field input:-webkit-autofill:focus { box-shadow: 0 0 0 100px var(--paper) inset, 0 0 0 1px var(--violet); }
.field input::placeholder { color: var(--ink-3); opacity: 1; }
.field-hint { font-size: 0.8125rem; color: var(--ink-3); }
.field--check { grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: 10px; }
.field--check input { margin-top: 4px; width: 16px; height: 16px; accent-color: var(--violet); }
.field--check label { font-weight: 400; font-size: 0.9375rem; color: var(--ink-2); }
.field--check a { color: var(--ink); text-decoration-color: var(--violet); text-underline-offset: 3px; }
.form-actions { padding-top: 4px; }
.form-error { padding: 10px 12px; border-left: 2px solid var(--error); background: var(--error-bg); color: var(--error-text); font-size: 0.9375rem; }
.form-note { font-size: 0.9375rem; color: var(--ink-2); }
.form-note a { color: var(--ink); text-decoration-color: var(--violet); text-underline-offset: 3px; }
.form-status { font-size: 1.0625rem; }
.form-done { padding: 10px 12px; border-left: 2px solid var(--ok); background: var(--ok-bg); color: var(--ok-text); font-size: 0.9375rem; }
.form-done:focus { outline: none; }
.form-done:focus-visible { outline: 2px solid var(--violet); outline-offset: 3px; }
.field input[aria-invalid="true"] { border-color: var(--error); }
.field--check input[aria-invalid="true"] { outline: 2px solid var(--error); outline-offset: 2px; }

/* ---------- Status line and waitlist ---------- */
/* One calm line: VioPO is not open yet. A small violet mark, then the text. */
.prerelease { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 12px; max-width: 46em; margin-bottom: clamp(20px, 2.6vw, 30px); padding: 10px 14px; border-left: 2px solid var(--violet); background: var(--wash); font-size: 0.9375rem; line-height: 1.5; color: var(--ink); }
.prerelease-label { font-size: 0.75rem; font-weight: 700; letter-spacing: 0.12em; text-transform: uppercase; color: var(--violet-deep); }
.prerelease-text { flex: 1 1 18em; min-width: 0; }
.prerelease .go { font-size: 0.9375rem; }
.hero-copy .prerelease { margin-bottom: clamp(22px, 3vw, 36px); }

/* The waitlist block: the words on the left, the form on the right. */
.join { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(28px, 4vw, 64px); align-items: start; padding-top: clamp(24px, 3vw, 36px); border-top: 1px solid var(--ink); }
.join-copy > * + * { margin-top: 14px; }
.join-title { font-family: var(--serif); font-weight: 400; font-size: clamp(1.625rem, 2.4vw, 2rem); line-height: 1.1; margin-bottom: 14px; }
.join--single { grid-template-columns: minmax(0, 1fr); }
.join .ticks { border-top: 0; }
.waitlist { max-width: 520px; border-top: 0; padding-top: 0; gap: 16px; }
.waitlist .btn { justify-content: center; }
.waitlist-trap { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
.waitlist.is-done { gap: 0; }
.waitlist--compact .field-hint { display: none; }
.ticks--single { grid-template-columns: minmax(0, 1fr); }
.ticks--single a { color: var(--ink); text-decoration-color: var(--violet); text-underline-offset: 3px; }
.cta-box .waitlist { margin-top: 18px; }
.cta-box .go { white-space: nowrap; }

/* Copy buttons that app.js adds to code listings. */
.listing-copy { flex: none; margin-left: auto; padding: 2px 0; min-height: 24px; font-size: 0.8125rem; }
.listing-head .listing-lang { margin-left: auto; }
.listing-head .listing-lang + .listing-copy { margin-left: 0; }
.listing-head--bare { justify-content: flex-end; padding-block: 5px; }
/* ---------- Responsive (VioPO) ---------- */
@media (max-width: 1080px) {
  .plans { grid-template-columns: minmax(0, 1fr); }
  .plan + .plan { border-left: 0; }
  .plan-summary { min-height: 0; }
  .output-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 900px) {
  .try { grid-template-columns: minmax(0, 1fr); }
  .join { grid-template-columns: minmax(0, 1fr); }
  /* One column: the form first, so "Join the waitlist" lands on the field. */
  .join > .waitlist { order: -1; }
  .faq div { grid-template-columns: minmax(0, 1fr); }
  .ticks { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 760px) {
  :root { --header-h: 104px; }
  .site-header .wrap { flex-wrap: wrap; height: auto; padding-block: 12px 4px; row-gap: 4px; }
  .site-nav { order: 3; width: 100%; margin-left: 0; overflow-x: auto; }
  .site-nav ul { gap: 22px; }
  /* First row: the wordmark on the left, the toggle and the waitlist button
     on the right (the wordmark's auto margin holds them there, with or
     without the toggle). The nav takes the second row. */
  .wordmark { margin-right: auto; }
  .site-header .theme-toggle { margin-inline: 0 -4px; }
  .site-account { gap: 14px; }
}
/* The first row holds the wordmark, the toggle and the button. */
@media (max-width: 380px) {
  .site-header .wrap { column-gap: 10px; }
  .site-account { gap: 10px; }
  .site-account .btn--sm { padding-inline: 10px; }
}
@media (max-width: 345px) {
  .start-lead { display: none; }
  .fields div { grid-template-columns: minmax(0, 1fr); gap: 4px; }
  .form--inline { grid-template-columns: minmax(0, 1fr); }
}
