/* ============================================================================
   Dissensus — site-specific extensions to the shared design system.
   system.css is the source of truth (do not edit it here). This file adds only
   the components the flagship needs: brand mark, hero glow, mono definition
   blocks, stat grids, legal prose, and forms. Single light theme — the dark
   path was removed in Aug 2026; do not reintroduce [data-theme] selectors.
   ============================================================================ */

/* ---- nav brand + active ---------------------------------------------------- */
.nav__brand { display: flex; align-items: center; gap: 0.55rem; color: var(--text); text-transform: none; }
.nav__brand:hover { color: var(--accent); }
.nav__brand-mark { width: 20px; height: 20px; }
.nav__links a.is-active { color: var(--accent); }
/* One theme means one mark: the wine mono mark on cream. The white variant and
   its theme-swap rules are gone, which also drops a second image request from
   every page in the site. */

/* ---- hero: the subtle burgundy glow (background motif) ---------------------- */
.hero { position: relative; }
.hero::before {
  content: ""; position: absolute; inset: -25% -10% auto -10%; height: 560px; z-index: -1;
  background: radial-gradient(58% 60% at 28% 0%, rgba(128, 0, 32, 0.06), transparent 70%);
  pointer-events: none;
}
.hero__logo { width: 76px; height: 76px; margin-bottom: var(--sp-6); }
.hero .lead { font-size: 1.2rem; }

/* Editorial hero: for pages whose H1 is a sentence rather than a label. --fs-hero
   tops out at 4.25rem, which is right for "Open projects" and far too loud for a
   three-line headline — it reads as a product splash rather than a research page.
   Smaller type, a wider measure so it sets in two lines, and less bottom padding
   because the following .section already contributes 6rem. */
.hero--editorial h1 { font-size: clamp(1.8rem, 3.4vw, 2.6rem); max-width: 30ch; }
.hero--editorial { padding-bottom: var(--sp-8) !important; }

/* verbose academic tagline vs plain translation */
.hero__jargon { color: var(--text-dim); font-size: 1.05rem; max-width: 62ch; margin-top: var(--sp-6); font-style: italic; }
.hero__plain { color: var(--text); font-family: var(--font-mono); font-size: var(--fs-sm); margin-top: var(--sp-4); letter-spacing: 0.02em; }
.etymology { font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--text-dim); max-width: 64ch; margin-top: var(--sp-6); line-height: 1.7; }
.etymology .accent { color: var(--accent); }

/* hero meta strip */
.metastrip { display: flex; flex-wrap: wrap; gap: var(--sp-8); margin-top: var(--sp-8); }
.metastrip__k { font-family: var(--font-mono); font-size: var(--fs-mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--text-dim); display: block; }
.metastrip__v { color: var(--text); margin-top: var(--sp-1); }

/* ---- generic prose ---------------------------------------------------------- */
.lead { font-size: 1.15rem; color: var(--text-dim); max-width: 62ch; }
.prose > * + * { margin-top: var(--sp-4); }
.prose h3 { margin-top: var(--sp-8); color: var(--text); }
.prose ul, .prose ol { color: var(--text-dim); padding-left: 1.25rem; max-width: var(--measure); }
.prose li + li { margin-top: 0.4rem; }
.prose strong { color: var(--text); font-weight: 600; }
.prose em { color: var(--text); }
/* Generated pages write `<section class="section container">` — one element carrying
   both classes — so the descendant form never matched and every h2 on join, projects,
   tools and research sat flush against its following paragraph. Both shapes now. */
.section > .container > h2,
.section.container > h2 { margin: var(--sp-4) 0 var(--sp-6); }

/* ---- mono definition / theorem / equation block ---------------------------- */
.block { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--sp-6); margin: var(--sp-6) 0; }
.block p { color: var(--text-dim); max-width: none; }
.block p + p { margin-top: var(--sp-3); }
.block ol, .block ul { color: var(--text-dim); padding-left: 1.25rem; margin-top: var(--sp-3); }
.block li + li { margin-top: 0.5rem; }
.block strong { color: var(--text); }
.block__label { font-family: var(--font-mono); font-size: var(--fs-mono); letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); display: block; margin-bottom: var(--sp-3); }
.block--accent { border-left: 3px solid var(--burgundy); }
.eq { font-family: var(--font-mono); color: var(--text); text-align: center; font-size: 1.05rem; margin: var(--sp-4) 0; line-height: 1.9; }
.eq .dim { color: var(--text-dim); font-size: 0.85em; }

/* pull quote */
blockquote { border-left: 3px solid var(--burgundy); padding: 0.2rem 0 0.2rem var(--sp-6); margin: var(--sp-6) 0; color: var(--text); font-size: 1.1rem; max-width: var(--measure); }
blockquote strong { color: var(--text); }

/* ---- cards: index number + list of paper links ----------------------------- */
.card__index { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--accent); letter-spacing: 0.15em; }
.card__links { margin-top: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); }
.card__links a { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); }
.card__links a:hover { color: var(--accent); }
.card .sym { font-family: var(--font-mono); font-size: 1.7rem; color: var(--accent); }

/* ---- publication rows (generated into research.html) ----------------------- */
.pubgroup + .pubgroup { margin-top: var(--sp-12); }
.pubgroup__blurb { color: var(--text-dim); font-size: var(--fs-sm); margin: var(--sp-2) 0 var(--sp-6); }
.research-note { margin-top: var(--sp-8); font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); }

/* The .stats grid is gone (Aug 2026). It was repeat(auto-fit, minmax(180px, 1fr)) over a
   1px-gap-on-background trick, and with five or six items it broke sentences into two-word
   columns and rendered any leftover track as a grey block. Prose content uses .deflist. */
/* ---- callout (programme intro) --------------------------------------------- */
.callout { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--sp-6); margin: var(--sp-6) 0; }
.callout__meta { font-family: var(--font-mono); font-size: var(--fs-mono); letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); }
.callout h3 { margin: var(--sp-2) 0 var(--sp-4); color: var(--text); }
.callout p { color: var(--text-dim); }
.dot { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); margin-right: 0.45rem; vertical-align: middle; }
.status-line { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); letter-spacing: 0.08em; text-transform: uppercase; margin-top: var(--sp-4); display: inline-block; }

/* ---- news banner ----------------------------------------------------------- */
.news { border-bottom: 1px solid var(--line); background: var(--surface); }
.news .container { display: flex; flex-wrap: wrap; gap: var(--sp-4) var(--sp-8); padding-block: var(--sp-4); }
.news__row { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); }
.news__row strong { color: var(--accent); font-weight: 600; }
.news__row a { color: var(--accent); }

/* ---- team ------------------------------------------------------------------ */
.person { display: grid; grid-template-columns: 88px 1fr; gap: var(--sp-6); align-items: start; }
.person + .person { margin-top: var(--sp-8); }
.person__avatar { width: 88px; height: 88px; border: 1px solid var(--line); border-radius: var(--radius); display: flex; align-items: center; justify-content: center; font-family: var(--font-mono); font-size: 1.3rem; color: var(--accent); background: var(--surface); }
.person__role { font-family: var(--font-mono); font-size: var(--fs-mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent); }
.person h3 { margin: var(--sp-2) 0; color: var(--text); }
.person__motto { font-style: italic; color: var(--text-dim); }
.person__links { margin-top: var(--sp-4); display: flex; flex-wrap: wrap; gap: var(--sp-4); }
.person__links a { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); }
.person__links a:hover { color: var(--accent); }
@media (max-width: 560px) { .person { grid-template-columns: 1fr; } }

/* ---- reading list rows ----------------------------------------------------- */
.refgroup + .refgroup { margin-top: var(--sp-12); }
.refgroup__title { font-family: var(--font-mono); font-size: var(--fs-mono); letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); padding-bottom: var(--sp-3); border-bottom: 1px solid var(--line); }
.ref { padding: var(--sp-4) 0; border-bottom: 1px solid var(--line); }
.ref__cite { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); letter-spacing: 0.08em; }
.ref h4 { color: var(--text); font-size: 1rem; margin: var(--sp-2) 0; font-weight: 600; }
.ref p { font-size: var(--fs-sm); }

/* ---- legal doc ------------------------------------------------------------- */
.legal { max-width: 74ch; }
.legal h2 { margin-top: var(--sp-8); font-size: 1.3rem; }
.legal h3 { margin-top: var(--sp-6); color: var(--text); font-size: 1.05rem; }
.legal p { color: var(--text-dim); margin-top: var(--sp-3); }
.legal ul { padding-left: 1.25rem; margin-top: var(--sp-3); color: var(--text-dim); }
.legal li + li { margin-top: 0.4rem; }
.legal strong { color: var(--text); }

/* ---- forms ----------------------------------------------------------------- */
.form { display: flex; flex-direction: column; gap: var(--sp-6); max-width: 640px; }
.form__row { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-4); }
.label { font-family: var(--font-mono); font-size: var(--fs-mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-dim); display: block; margin-bottom: var(--sp-2); }
.input, .select, .textarea {
  width: 100%; padding: var(--sp-3) var(--sp-4); background: var(--surface); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--radius);
  font-family: var(--font-mono); font-size: var(--fs-sm);
}
.input:focus, .select:focus, .textarea:focus { outline: none; border-color: var(--accent); }
.textarea { resize: vertical; line-height: 1.6; }

/* Element-scoped twin of the rules above, for generated forms (join.html) whose
   controls are wrapped in a bare <label> and carry no .input/.select/.textarea class.
   Without this they rendered completely unstyled. `min-width: 0` is load-bearing: a
   <select> sizes to its widest <option>, and the project titles are long enough to push
   the form ~190px past a 320px viewport. */
.form label { display: flex; flex-direction: column; gap: var(--sp-2);
  font-family: var(--font-mono); font-size: var(--fs-mono); letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-dim); min-width: 0; }
.form input, .form select, .form textarea {
  width: 100%; max-width: 100%; min-width: 0; padding: var(--sp-3) var(--sp-4);
  background: var(--surface); color: var(--text);
  border: 1px solid var(--line); border-radius: var(--radius);
  font-family: var(--font-mono); font-size: var(--fs-sm);
  text-transform: none; letter-spacing: normal;
}
.form input:focus, .form select:focus, .form textarea:focus { outline: none; border-color: var(--accent); }
.form textarea { resize: vertical; line-height: 1.6; min-height: 9rem; }
.form__hint { font-family: var(--font-mono); font-size: 0.7rem; color: var(--text-dim);
  text-transform: none; letter-spacing: 0.02em; }
.form button { align-self: flex-start; }
.radios { display: flex; flex-wrap: wrap; gap: var(--sp-4); }
.radios label { display: flex; align-items: center; gap: var(--sp-2); color: var(--text-dim); font-size: var(--fs-sm); cursor: pointer; }
.radios input { accent-color: var(--accent); }
.form-note { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); }

/* ---- copyable text card (press) -------------------------------------------- */
.copybox { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--sp-6); margin-top: var(--sp-4); }
.copybox p { color: var(--text); }
.mini-btn { font-family: var(--font-mono); font-size: var(--fs-mono); background: transparent; color: var(--text-dim); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--sp-1) var(--sp-3); cursor: pointer; margin-top: var(--sp-4); letter-spacing: 0.08em; }
.mini-btn:hover { color: var(--accent); border-color: var(--accent); }

/* logo swatch (press) */
.swatch { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--sp-6); text-align: center; }
.swatch__stage { border-radius: var(--radius); padding: var(--sp-8); margin-bottom: var(--sp-4); display: flex; align-items: center; justify-content: center; min-height: 130px; }
.swatch__stage img { max-width: 84px; }

/* ---- paper detail (generated) ---------------------------------------------- */
.paper__back { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); display: inline-block; margin-bottom: var(--sp-8); }
.paper__back:hover { color: var(--accent); }
.paper__meta { display: flex; flex-wrap: wrap; gap: var(--sp-3); align-items: center; font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); letter-spacing: 0.08em; text-transform: uppercase; }
.paper__title { margin: var(--sp-4) 0 var(--sp-3); max-width: 24ch; }
.paper__subtitle { color: var(--text-dim); font-size: 1.15rem; margin-bottom: var(--sp-3); }
.paper__authors { font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--text); }
.paper__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin: var(--sp-8) 0; padding-bottom: var(--sp-8); border-bottom: 1px solid var(--line); }
.paper__section { margin-top: var(--sp-8); }
.paper__section h2 { font-size: 1.3rem; margin-bottom: var(--sp-4); }
.paper__abstract p { color: var(--text-dim); max-width: var(--measure); }
.paper__cite { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--sp-6); color: var(--text-dim); font-size: var(--fs-sm); }
.paper__cite em { color: var(--text); }
.taglist { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.tag { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); border: 1px solid var(--line); border-radius: 100px; padding: 2px var(--sp-3); letter-spacing: 0.06em; }

/* ---- open-project cards (projects.html, generated) ---------------------- */
.proj__k { display: block; font-family: var(--font-mono); font-size: var(--fs-mono);
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-dim); margin-top: var(--sp-6); }
.proj__gaps { list-style: none; margin: var(--sp-3) 0; padding: 0; }
.proj__gaps li { color: var(--text-dim); font-size: var(--fs-sm); padding-left: 1.1rem; position: relative; line-height: 1.55; }
.proj__gaps li + li { margin-top: 0.35rem; }
/* the gaps list is deliberately marked differently from the features list — these
   are the unflattering bits and should not read as selling points */
.proj__gaps li::before { content: "\2715"; position: absolute; left: 0; color: var(--text-dim); opacity: 0.7; font-size: 0.75em; top: 0.3em; }
.proj__ask { border-left: 3px solid var(--burgundy); background: var(--surface-2);
  border-radius: var(--radius); padding: var(--sp-4) var(--sp-6); margin-top: var(--sp-6); }
.proj__ask .proj__k { margin-top: 0; color: var(--accent); }
.proj__ask p { font-size: var(--fs-sm); margin-top: var(--sp-2); }

/* ---- category legend (tools catalogue, open projects) ---------------------- */
.legend { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: var(--sp-4) var(--sp-6);
  border-top: 1px solid var(--line); padding-top: var(--sp-4); margin-top: var(--sp-6); }
.legend__item { display: flex; flex-direction: column; gap: 0.3rem; }
.legend__k { font-family: var(--font-mono); font-size: var(--fs-mono); letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text); }
.legend__n { color: var(--accent); }
.legend__v { color: var(--text-dim); font-size: var(--fs-sm); line-height: 1.5; }

/* ---- tool cards (generated) ------------------------------------------------ */
.tool__head { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--sp-3); }
.tool__head .card__meta { line-height: 1.4; }
.tool__tagline { color: var(--text); font-size: var(--fs-sm); margin-top: var(--sp-2); }
.tool__install { display: block; font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--accent); background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius); padding: var(--sp-2) var(--sp-3); margin: var(--sp-4) 0; overflow-x: auto; }
.tool__features { list-style: none; margin: var(--sp-3) 0; padding: 0; }
.tool__features li { color: var(--text-dim); font-size: var(--fs-sm); padding-left: 1.1rem; position: relative; }
.tool__features li + li { margin-top: 0.3rem; }
.tool__features li::before { content: "→"; position: absolute; left: 0; color: var(--accent); }
.badges { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-top: var(--sp-4); }
.badge { font-family: var(--font-mono); font-size: var(--fs-mono); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; display: inline-flex; }
.badge__k { padding: 2px var(--sp-2); color: var(--text-dim); background: var(--surface-2); }
.badge__v { padding: 2px var(--sp-2); color: var(--text); }

/* ---- news: index rows + post pages ------------------------------------------ */
.news-item { display: block; padding: var(--sp-6) 0; border-bottom: 1px solid var(--line); }
.news-item:first-of-type { border-top: 1px solid var(--line); }
.news-item__date { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); letter-spacing: 0.08em; text-transform: uppercase; }
.news-item h3 { color: var(--text); margin: var(--sp-2) 0 var(--sp-2); font-size: 1.25rem; }
.news-item p { font-size: var(--fs-sm); }
.news-item:hover h3 { color: var(--accent); }

.post-meta { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); letter-spacing: 0.08em; text-transform: uppercase; }
.post-title { margin: var(--sp-4) 0 var(--sp-3); max-width: 26ch; }
.post-dek { color: var(--text-dim); font-size: 1.15rem; max-width: 62ch; margin-bottom: var(--sp-8); padding-bottom: var(--sp-8); border-bottom: 1px solid var(--line); }
.post-body { max-width: var(--measure); }
.post-body p { color: var(--text-dim); }
.post-body p + p { margin-top: var(--sp-4); }
.post-body h2 { font-size: 1.35rem; margin: var(--sp-12) 0 var(--sp-4); }
.post-body em { color: var(--text); }
.post-body b, .post-body strong { color: var(--text); }
.post-foot { margin-top: var(--sp-12); padding-top: var(--sp-6); border-top: 1px solid var(--line); font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--text-dim); }

/* homepage latest-news strip */
.newsband { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--surface); }
.newsband .container { padding-block: var(--sp-8); }
.newsband__lbl { font-family: var(--font-mono); font-size: 0.68rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--accent); margin-bottom: var(--sp-4); display: block; }
.newsband__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-6); }
.newsband__item { display: block; }
.newsband__item .news-item__date { font-size: 0.68rem; }
.newsband__item h3 { color: var(--text); font-size: 1.02rem; margin: var(--sp-2) 0; }
.newsband__item:hover h3 { color: var(--accent); }
.newsband__item p { font-size: var(--fs-sm); color: var(--text-dim); }
@media (max-width: 720px) { .newsband__grid { grid-template-columns: 1fr; } }

/* social links row */
.social-row { display: flex; flex-wrap: wrap; gap: var(--sp-6); align-items: center; }
.social-row a { display: inline-flex; align-items: center; gap: var(--sp-2); font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--text-dim); letter-spacing: 0.04em; }
.social-row a:hover { color: var(--accent); }
.social-row svg { width: 18px; height: 18px; fill: currentColor; }

/* research agendas */
.agenda-entry { border-left: 3px solid var(--burgundy); padding: var(--sp-2) 0 var(--sp-2) var(--sp-6); margin-top: var(--sp-8); }
.agenda-entry h3 { color: var(--text); margin-bottom: var(--sp-3); }
.agenda-entry p { color: var(--text-dim); max-width: var(--measure); }
.agenda-entry b { color: var(--text); }

/* ---- 404 ------------------------------------------------------------------- */
.error { min-height: 68vh; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; }
.error__code { font-family: var(--font-mono); font-size: clamp(5rem, 18vw, 11rem); font-weight: 600; color: var(--accent-dim); line-height: 1; }
.error__eq { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--accent); margin-top: var(--sp-8); }

/* ---- misc ------------------------------------------------------------------ */
.btn-row { display: flex; gap: var(--sp-4); flex-wrap: wrap; margin-top: var(--sp-6); min-width: 0; }
/* Button labels carry full identifiers ("Zenodo 10.5281/zenodo.17614725"); without
   this the token is one unbreakable word and sets the card's minimum width. */
.btn-row .btn { max-width: 100%; overflow-wrap: anywhere; }
.center { text-align: center; }

/* ============================================================================
   motion layer — shared scroll polish (drives public/js/motion.js)
   Reuses system.css tokens. Elements opt in per-element with [data-reveal]; the
   #progress bar and .count count-ups stay inert until motion.js + the matching
   markup are present, so linking motion.js on a page with none of these is a
   no-op. On prefers-reduced-motion, reveals show immediately (see below).
   ============================================================================ */

/* ---- roles ladder (join.html) ---------------------------------------------- */
/* Tier cards carry a commitment line that must read before the prose, so the
   commitment sits directly under the heading in mono rather than inside the body. */
.tier__commit { display: block; font-family: var(--font-mono); font-size: var(--fs-mono);
  color: var(--accent); letter-spacing: 0.06em; margin: var(--sp-2) 0 var(--sp-4); }
.tier__enter { border-left: 3px solid var(--burgundy); background: var(--surface-2);
  padding: var(--sp-3) var(--sp-4); margin-top: var(--sp-4); border-radius: 0 var(--radius) var(--radius) 0; }
.tier__enter p { font-size: var(--fs-sm); margin: 0; }

/* ---- entry tasks ------------------------------------------------------------ */
/* The recruiting argument is that these asks are small, so the effort figure is
   the first thing in the row and gets its own column on wide screens. Single
   column below 46rem — a two-column grid puts the badge above the task, which
   reads fine, but the wide layout is what makes the list scannable. */
.tasks { list-style: none; padding: 0; margin-top: var(--sp-8);
  border-top: 1px solid var(--line); }
.task { display: grid; grid-template-columns: 1fr; gap: var(--sp-2);
  padding: var(--sp-6) 0; border-bottom: 1px solid var(--line); }
@media (min-width: 46rem) {
  .task { grid-template-columns: 13rem 1fr; gap: var(--sp-6); }
}
.task__effort { font-family: var(--font-mono); font-size: var(--fs-mono);
  color: var(--accent); letter-spacing: 0.06em; line-height: 1.5; }
.task__effort span { display: block; color: var(--text-dim); text-transform: uppercase;
  letter-spacing: 0.14em; font-size: 0.7rem; margin-bottom: var(--sp-1); }
.task__body { min-width: 0; }
.task__body h3 { color: var(--text); font-size: 1.05rem; }
/* The grid column is already the measure here; the inherited 68ch from the base p
   rule wrapped these two lines short of the column edge and left a ragged trail. */
.task__body p { font-size: var(--fs-sm); margin-top: var(--sp-2); max-width: none; }
.task__meta { font-family: var(--font-mono); font-size: var(--fs-mono);
  color: var(--text-dim); margin-top: var(--sp-3); display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.task__meta a { color: var(--accent); }
.task__note { font-size: var(--fs-sm); color: var(--text); border-left: 2px solid var(--line);
  padding-left: var(--sp-4); margin-top: var(--sp-3); }

/* ---- "not offering" list ---------------------------------------------------- */
/* Deliberately styled as plainly as the commitments it negates — no warning
   colour, no icon. It is information, not an apology. */
.plainlist { list-style: none; padding: 0; margin-top: var(--sp-6); max-width: var(--measure); }
.plainlist li { color: var(--text-dim); font-size: var(--fs-sm); padding-left: 1.4rem;
  position: relative; line-height: 1.6; }
.plainlist li + li { margin-top: var(--sp-3); }
.plainlist li::before { content: "\2014"; position: absolute; left: 0; color: var(--accent); }

/* scroll progress bar */
#progress {
  position: fixed; top: 0; left: 0; height: 2px; width: 0%;
  background: var(--accent); z-index: 100;
  box-shadow: 0 0 8px color-mix(in srgb, var(--accent) 60%, transparent);
}

/* reveal-on-scroll (motion.js adds .in when the element enters the viewport).
   Gated on html.js (set synchronously by theme.js) so JS-off visitors and
   render bots never see content stuck at opacity:0. */
html.js [data-reveal] {
  opacity: 0; transform: translateY(22px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
  will-change: opacity, transform;
}
html.js [data-reveal="left"]  { transform: translateX(-28px); }
html.js [data-reveal="right"] { transform: translateX(28px); }
html.js [data-reveal="scale"] { transform: scale(0.96); }
html.js [data-reveal].in { opacity: 1; transform: none; }

/* system.css already kills transitions under reduced-motion; force reveals
   visible so nothing is left stuck at opacity:0 (motion.js also adds .in). */
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1 !important; transform: none !important; }
}


/* a11y: visible keyboard focus */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.input:focus-visible, .select:focus-visible, .textarea:focus-visible { box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 40%, transparent); }

/* ---- research record: linear stage groups ----------------------------------- */
/* Replaced a five-category grid of boxed cards. On an archive the useful axis is how
   finished a thing is, not which internal category it was filed under, and twenty
   equal-weight cards read as twenty products. Rows separated by hairlines, no boxes. */
.stagegroup + .stagegroup { margin-top: var(--sp-16); }
.stagegroup__h {
  display: flex; align-items: baseline; gap: var(--sp-3); flex-wrap: wrap;
  font-family: var(--font-serif); font-size: 1.35rem; color: var(--text);
  padding-bottom: var(--sp-3); border-bottom: 2px solid var(--burgundy);
}
.stagegroup__n { font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--accent); letter-spacing: 0.12em; }
.stagegroup__c {
  font-family: var(--font-mono); font-size: 0.7rem; color: var(--text-dim);
  border: 1px solid var(--line); border-radius: 100px; padding: 1px var(--sp-2); margin-left: auto;
}
.stagegroup__blurb { color: var(--text-dim); font-size: var(--fs-sm); margin: var(--sp-4) 0 var(--sp-2); max-width: var(--measure); }

.pubrow { padding: var(--sp-6) 0; border-bottom: 1px solid var(--line); }
.pubrow__meta {
  display: block; font-family: var(--font-mono); font-size: var(--fs-mono);
  color: var(--accent); letter-spacing: 0.08em; margin-bottom: var(--sp-2);
}
.pubrow h4 { font-family: var(--font-serif); font-size: 1.12rem; font-weight: 600; line-height: 1.35; }
.pubrow h4 a { color: var(--text); }
.pubrow h4 a:hover { color: var(--accent); }
.pubrow__sub { color: var(--text-dim); font-size: var(--fs-sm); margin-top: var(--sp-2); max-width: var(--measure); }
.pubrow__links {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin-top: var(--sp-3); font-family: var(--font-mono); font-size: var(--fs-mono);
}
.pubrow__links .sep { color: var(--line); }
.pubrow__open { color: var(--accent); }

/* A tool sits under the paper it came out of, indented so it reads as belonging to it
   rather than as the next item in the list. */
.pubtool {
  margin-top: var(--sp-4); padding: var(--sp-4) var(--sp-6);
  border-left: 2px solid var(--line); background: var(--surface-2);
  border-radius: 0 var(--radius) var(--radius) 0;
}
.pubtool__k {
  font-family: var(--font-mono); font-size: 0.66rem; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--accent); display: block; margin-bottom: var(--sp-1);
}
.pubtool__name { font-family: var(--font-mono); font-size: 0.92rem; color: var(--text); font-weight: 500; }
.pubtool__ver { color: var(--text-dim); font-weight: 400; }
.pubtool__desc { font-size: var(--fs-sm); color: var(--text-dim); margin-top: var(--sp-1); max-width: var(--measure); }
.pubtool__install {
  display: block; font-family: var(--font-mono); font-size: var(--fs-mono); color: var(--accent);
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--sp-2) var(--sp-3); margin-top: var(--sp-3); overflow-x: auto;
}
.pubtool__links {
  display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center;
  margin-top: var(--sp-3); font-family: var(--font-mono); font-size: var(--fs-mono);
}
.pubtool__links .sep { color: var(--line); }

/* ---- linear records: projects + join rungs ---------------------------------- */
/* Both pages used a two-column card grid. A dossier that names what is missing reads
   as a document; a ladder reads as a sequence. Neither is a product tile, and side-by-side
   boxes forced both into short columns that scrolled badly on a phone. */
.projlist, .runglist { margin-top: var(--sp-8); border-top: 1px solid var(--line); }
.projrow, .rung { padding: var(--sp-12) 0; border-bottom: 1px solid var(--line); }
.projrow > * + *, .rung > * + * { margin-top: var(--sp-4); }

.projrow__head, .rung__head {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-3);
  font-family: var(--font-mono); font-size: var(--fs-mono);
}
.projrow__n, .rung__n { color: var(--accent); letter-spacing: 0.12em; }
.projrow__domain { color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.12em; }
.projrow__head .pill, .rung__head .pill { margin-left: auto; }
.projrow h3, .rung h3 { font-size: 1.3rem; margin: 0; }
.rung__head h3 { flex: 0 1 auto; }
.projrow__one { font-size: 1.08rem; color: var(--text); max-width: var(--measure); }
.projrow__state, .rung__what { color: var(--text-dim); max-width: var(--measure); }

.rung__commit {
  display: block; font-family: var(--font-mono); font-size: var(--fs-mono);
  color: var(--accent); letter-spacing: 0.06em;
}
.rung__get { max-width: var(--measure); }
.rung__enter {
  border-left: 3px solid var(--burgundy); background: var(--surface-2);
  padding: var(--sp-3) var(--sp-4); border-radius: 0 var(--radius) var(--radius) 0;
  font-size: var(--fs-sm); max-width: var(--measure);
}

.projrow__links {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  font-family: var(--font-mono); font-size: var(--fs-mono);
}
.projrow__links .sep { color: var(--line); }

/* ---- definition rows -------------------------------------------------------- */
/* Replaces the `.stats` grid for prose content. That grid was
   `repeat(auto-fit, minmax(180px, 1fr))` over a 1px-gap-on-background trick, which had
   two failure modes with more than four items: 180px tracks broke sentences into
   two-word lines, and any leftover track rendered the container's line colour as a
   grey block beside the last cell (visible with five and six items).
   These are rows: a narrow key column, a body column capped at the measure, hairline
   separators, no boxes and no empty tracks to leak. Stacks below 52rem. */
.deflist { margin-top: var(--sp-6); border-top: 1px solid var(--line); }
.defrow { display: grid; gap: var(--sp-2); padding: var(--sp-6) 0; border-bottom: 1px solid var(--line); }
@media (min-width: 52rem) {
  .defrow { grid-template-columns: minmax(0, 13rem) minmax(0, 1fr); gap: var(--sp-8); align-items: baseline; }
}
/* Numeric keys need a narrow gutter, not the 13rem text-key column — a two-digit
   number followed by 11rem of whitespace reads as a layout mistake. */
@media (min-width: 52rem) {
  .deflist--tight .defrow { grid-template-columns: minmax(0, 3.25rem) minmax(0, 1fr); gap: var(--sp-6); }
}
.defrow__k {
  font-family: var(--font-mono); font-size: var(--fs-mono); letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--text); line-height: 1.6;
}
.defrow__n { color: var(--accent); }
.defrow__v { color: var(--text-dim); max-width: var(--measure); }
.defrow__v b { color: var(--text); font-weight: 600; }
.defrow__promise {
  display: block; font-family: var(--font-serif); font-size: 1.12rem; font-weight: 600;
  color: var(--text); margin-bottom: var(--sp-2); letter-spacing: -0.01em;
}
.defrow__fail { color: var(--accent); font-weight: 500; }
