/* Layout: the page is one drawing sheet. Black ink on white paper, a thin frame, a small label per section.
   The only colour on the site is in the pictures and videos, and in the markers of a narration while it plays. */

@font-face {
  font-family: "Barlow Condensed";
  src: url("/assets/fonts/barlow-condensed-600.woff2") format("woff2");
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: "Barlow Condensed";
  src: url("/assets/fonts/barlow-condensed-700.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: "Karla";
  src: url("/assets/fonts/karla.woff2") format("woff2");
  font-weight: 200 800;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/assets/fonts/ibm-plex-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("/assets/fonts/ibm-plex-mono-500.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
}

:root {
  color-scheme: light;
  --bg: #ffffff;
  --ink: #111111;
  --muted: #5c5c5c;
  --soft: #d9d9d9;
  --surface: #f4f4f2;
  --code-bg: #111111;
  --code-fg: #f2f2f2;
  --code-muted: #a3a3a3;
  --code-line: #3a3a3a;
  --video-bg: #111111;   /* controls on top of a video: the same in both themes */
  --video-fg: #ffffff;
  /* narration markers: the four colours, only while a thought is read aloud (DESIGN.md "Narration") */
  --red: #d33a2c;
  --green: #1d8a4a;
  --blue: #2558d4;
  --yellow: #e2a900;
  --blk-red: #c62f22;   /* colour blocks behind words: white text on them is >= 4.5:1 in both themes */
  --blk-green: #16803e;
  --blk-blue: #2554d0;
  --blk-yellow: #9a6700;
  --on-blk: #ffffff;

  --display: "Barlow Condensed", "Arial Narrow", "Helvetica Neue", Arial, sans-serif;
  --body: "Karla", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --step--1: 0.72rem;
  --step-0: 1.0625rem;
  --step-1: 1.3rem;
  --step-2: clamp(1.8rem, 1.2rem + 2.2vw, 2.7rem);
  --step-3: clamp(2.6rem, 1.4rem + 5.5vw, 6rem);
  --rule: 1.5px;
  --pad: clamp(1rem, 3vw, 2.5rem);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #0e0e0e;
    --ink: #f2f2f2;
    --muted: #a3a3a3;
    --soft: #2c2c2c;
    --surface: #1a1a1a;
    --code-bg: #1a1a1a;
    --red: #ff6b5d;
    --green: #4fcf86;
    --blue: #7aa5ff;
    --yellow: #f3c64a;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0e0e0e;
  --ink: #f2f2f2;
  --muted: #a3a3a3;
  --soft: #2c2c2c;
  --surface: #1a1a1a;
  --code-bg: #1a1a1a;
  --red: #ff6b5d;
  --green: #4fcf86;
  --blue: #7aa5ff;
  --yellow: #f3c64a;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 4.5rem; background: var(--bg); }
body {
  max-width: 82rem;
  margin: clamp(.5rem, 2vw, 1.5rem) auto;
  width: calc(100% - 2 * clamp(.5rem, 2vw, 1.5rem));
  border: var(--rule) solid var(--ink);
  background: var(--bg);
  color: var(--ink);
  font-family: var(--body);
  font-size: var(--step-0);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
img, video { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 3px; }
a:hover { background: var(--ink); color: var(--bg); text-decoration-color: transparent; }
:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }
::selection { background: var(--ink); color: var(--bg); }
h1, h2, h3, h4 { font-family: var(--display); font-weight: 700; line-height: 1.05; margin: 0; text-wrap: balance; }
p { margin: 0; }
code, kbd, pre { font-family: var(--mono); font-size: .88em; }
.skip { position: absolute; left: -999px; }
.skip:focus { left: 16px; top: 16px; z-index: 50; background: var(--ink); color: var(--bg); padding: .5rem 1rem; }
.wrap { padding-left: var(--pad); padding-right: var(--pad); }

/* ---------- nav ---------- */
.nav { position: sticky; top: 0; z-index: 20; background: var(--bg); border-bottom: var(--rule) solid var(--ink); }
.nav__in { display: flex; align-items: center; gap: 1.25rem; min-height: 3.25rem; }
.brand { font-weight: 700; text-decoration: none; white-space: nowrap; }
.nav__links a { white-space: nowrap; }
.nav__links { display: flex; gap: 1.4rem; margin-left: auto; font-weight: 500; }
.nav__links a { padding: .1rem; }
.toggle { font: 500 var(--step--1)/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--ink); background: none; border: 1px solid var(--ink); padding: .5rem .65rem; cursor: pointer; }
.toggle:hover { background: var(--ink); color: var(--bg); }
@media (max-width: 480px) { .nav__links .opt3 { display: none; } }
@media (max-width: 360px) { .nav__links { gap: .6rem; font-size: .95rem; } .nav__in { gap: .5rem; } .toggle { display: none; } .hero h1 { font-size: 2.6rem; } }
@media (max-width: 560px) { .nav__links .opt, .nav__links .opt2 { display: none; } .nav__links { gap: .9rem; } .nav__in { gap: .75rem; } }

/* ---------- shared bits ---------- */
.label { font: 500 var(--step--1)/1.4 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.btn { display: inline-flex; align-items: center; gap: .5rem; font: 700 1rem/1 var(--body); padding: .8rem 1.1rem; border: var(--rule) solid var(--ink); background: var(--ink); color: var(--bg); text-decoration: none; cursor: pointer; }
.btn:hover { background: var(--bg); color: var(--ink); }
.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--bg); }
.btn-row { display: flex; flex-wrap: wrap; gap: .75rem; }
.section { padding-block: clamp(1.75rem, 4vw, 3.25rem); border-top: var(--rule) solid var(--ink); }
.section > .wrap { display: grid; gap: 1.5rem; }
.section__head { display: grid; gap: .5rem; }
.section__head h2 { font-size: var(--step-2); max-width: 26ch; }
.section__head p:not(.label) { max-width: 62ch; color: var(--muted); }

/* ---------- hero with title block ---------- */
.hero { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 19rem); }
.hero__main { padding: clamp(1.75rem, 4.5vw, 3.5rem) var(--pad); display: grid; gap: 1.1rem; align-content: start; min-width: 0;
  background-image: linear-gradient(var(--soft) 1px, transparent 1px), linear-gradient(90deg, var(--soft) 1px, transparent 1px); background-size: 48px 48px; background-position: -1px -1px; }
.hero__main > * { background: var(--bg); justify-self: start; box-shadow: 0 0 0 .5rem var(--bg); }
.hero h1 { font-size: clamp(3rem, 9.5vw, 7.5rem); line-height: .9; }
.hero .lede { font-size: clamp(1.15rem, 2vw, 1.4rem); line-height: 1.45; max-width: 36ch; }
.tb { margin: 0; border-left: var(--rule) solid var(--ink); display: grid; align-content: stretch; }
.tb div { padding: .75rem 1rem; border-bottom: 1px solid var(--ink); display: grid; gap: .15rem; align-content: center; }
.tb div:last-child { border-bottom: 0; }
.tb dt { font: 500 .68rem/1.4 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.tb dd { margin: 0; font-weight: 700; overflow-wrap: anywhere; }
.tb .mono { font: 500 .82rem/1.5 var(--mono); }
@media (max-width: 860px) { .hero { grid-template-columns: minmax(0, 1fr); } .tb { border-left: 0; border-top: var(--rule) solid var(--ink); grid-template-columns: repeat(2, minmax(0, 1fr)); } .tb .wide { grid-column: 1 / -1; } .tb div:nth-child(odd):not(.wide) { border-right: 1px solid var(--ink); } }

/* ---------- research ---------- */
.facts { margin: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 2rem; border-top: 1px solid var(--ink); }
.facts div { padding: .7rem 0; border-bottom: 1px solid var(--soft); display: grid; gap: .1rem; align-content: start; }
.facts dt { font: 500 .68rem/1.4 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.facts dd { margin: 0; overflow-wrap: anywhere; }
@media (max-width: 860px) { .facts { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .facts { grid-template-columns: minmax(0, 1fr); } }
.adv__id { display: flex; flex-wrap: wrap; gap: .5rem; font: 500 var(--step--1)/1 var(--mono); letter-spacing: .06em; }
.adv__id span { padding: .4rem .55rem; border: 1px solid var(--ink); }
.adv__id .hot { background: var(--ink); color: var(--bg); }

/* ---------- code ---------- */
.code { background: var(--code-bg); color: var(--code-fg); border: 1px solid var(--code-line); min-width: 0; }
.code__bar { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: .35rem .35rem .35rem .9rem; border-bottom: 1px solid var(--code-line); font: 500 .75rem/1.3 var(--mono); color: var(--code-muted); }
.code__bar span { overflow-wrap: anywhere; min-width: 0; }
.copy { font: 500 .75rem/1 var(--mono); background: none; color: var(--code-fg); border: 1px solid var(--code-line); padding: .45rem .6rem; cursor: pointer; flex: none; }
.copy:hover, .copy[data-done] { background: var(--code-fg); color: var(--code-bg); border-color: var(--code-fg); }
.code pre { margin: 0; padding: .9rem; overflow-x: auto; font-size: .8438rem; line-height: 1.65; tab-size: 2; }
.code pre.ln { counter-reset: ln; }
.code .l { display: block; }
.code pre.ln .l::before { counter-increment: ln; content: counter(ln); display: inline-block; width: 3ch; margin-right: 1.25ch; text-align: right; color: var(--code-muted); user-select: none; }
.code pre.ln-233 { counter-reset: ln 232; }
.k { font-weight: 500; } .s { color: var(--code-muted); } .c { color: var(--code-muted); }
.hl { background: var(--code-fg); color: var(--code-bg); }

/* ---------- verify ---------- */
.verify { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: clamp(1.5rem, 4vw, 3rem); align-items: start; }
@media (max-width: 860px) { .verify { grid-template-columns: minmax(0, 1fr); } }
.fpr { display: grid; gap: 1.1rem; min-width: 0; }
.fpr__hex { font: 500 clamp(1.1rem, .8rem + 1.5vw, 1.6rem)/1.4 var(--mono); display: grid; grid-template-columns: repeat(5, max-content); gap: 0 .7em; font-variant-numeric: tabular-nums; }
.fpr__meta { display: flex; flex-wrap: wrap; gap: .4rem 1.5rem; font: 500 var(--step--1)/1.4 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
@media (max-width: 400px) { .fpr__hex { gap: 0 .45em; font-size: 1rem; } }

/* ---------- projects ---------- */
.projects { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(1.25rem, 3vw, 2.25rem); }
@media (max-width: 700px) { .projects { grid-template-columns: minmax(0, 1fr); } }
.proj { display: grid; gap: 1rem; align-content: start; padding: clamp(1rem, 2.5vw, 1.5rem); border: var(--rule) solid var(--ink); text-decoration: none; }
.proj:hover { background: var(--bg); color: var(--ink); outline: 3px solid var(--ink); outline-offset: -1px; }
.proj h3 { font-size: var(--step-2); }
.proj img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border: 1px solid var(--ink); background: var(--surface); }
.proj p { color: var(--muted); max-width: 46ch; }
.proj .dg { aspect-ratio: 16 / 9; border-width: 1px; }
.dg .t-l, .dg .t-h.t-l { font-size: 22px; }
.proj__more { font-weight: 700; text-decoration: underline; text-decoration-thickness: 1.5px; text-underline-offset: 3px; }
.reel { margin: 0; border: var(--rule) solid var(--ink); background: var(--code-bg); }
.reel video { width: 100%; aspect-ratio: 16 / 9; display: block; }
/* the player: a silent loop with one button and a thin progress line */
.player { position: relative; display: grid; border: var(--rule) solid var(--ink); background: var(--code-bg); }
.player video { width: 100%; height: auto; display: block; border: 0; cursor: pointer; }
.player__btn { position: absolute; left: .75rem; bottom: .9rem; width: 2.5rem; height: 2.5rem; padding: 0; border: 0; background: var(--video-bg); color: var(--video-fg); cursor: pointer; display: grid; place-items: center; transition: opacity .2s; }
.player__btn::before { content: ""; display: block; width: .8rem; height: .9rem; background: currentColor; }
.player[data-state="playing"] .player__btn::before { background: linear-gradient(90deg, currentColor 0 34%, transparent 34% 66%, currentColor 66%); }
.player[data-state="paused"] .player__btn::before { clip-path: polygon(0 0, 100% 50%, 0 100%); margin-left: .15rem; }
.player__btn:hover { background: var(--video-fg); color: var(--video-bg); }
.player__btn:focus-visible { outline: 2px solid var(--video-fg); outline-offset: 2px; }
/* while it plays, the button steps back until the pointer or the keyboard comes near */
@media (hover: hover) { .player[data-state="playing"] .player__btn { opacity: 0; } .player:hover .player__btn, .player .player__btn:focus-visible { opacity: 1; } }
@media (hover: none) { .player[data-state="playing"] .player__btn { opacity: .75; } }
.player__bar { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--video-bg); pointer-events: none; }
.player__bar i { display: block; height: 100%; width: 0; background: var(--video-fg); }
.product > .reel { border-width: 0; border-top: var(--rule) solid var(--ink); background: none; }
.product { display: grid; }
.product > * { padding: clamp(1.75rem, 4vw, 3.25rem) var(--pad); border-top: var(--rule) solid var(--ink); }
.product__about { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 4fr); gap: clamp(2rem, 5vw, 4rem); align-items: start; }
@media (max-width: 860px) { .product__about { grid-template-columns: minmax(0, 1fr); } }
.product__about .prose p { max-width: 60ch; }
.feats { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--ink); }
.feats li { padding: .7rem 0; border-bottom: 1px solid var(--soft); display: grid; gap: .1rem; }
.feats b { font: 600 1.3rem/1.2 var(--display); }
.feats span { color: var(--muted); font-size: .95rem; line-height: 1.45; }
.shots { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem; }
.shots figure { margin: 0; }
.shots img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border: var(--rule) solid var(--ink); }
@media (max-width: 560px) { .shots { grid-template-columns: minmax(0, 1fr); } }
.changes h2 { font-size: var(--step-2); margin-bottom: .6rem; }
.changes__intro, .changes__note { max-width: 60ch; color: var(--muted); }
.changes__note { font: 500 var(--step--1)/1.5 var(--mono); letter-spacing: .04em; margin: 0; padding-top: 1.25rem; border-top: 1px solid var(--soft); }
.tl { --tl-x: .55rem; list-style: none; margin: 1.75rem 0 0; padding: 0; position: relative; }
.tl::before { content: ""; position: absolute; left: var(--tl-x); top: .4rem; bottom: 0; width: var(--rule); margin-left: calc(var(--rule) / -2); background: var(--ink); }
.tl > li { position: relative; display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 5fr); gap: clamp(1.25rem, 3vw, 2.5rem); align-items: start; padding: 0 0 2.25rem calc(var(--tl-x) * 2 + 1.25rem); }
.tl > li::before { content: ""; position: absolute; left: var(--tl-x); top: .3rem; width: .8rem; height: .8rem; margin-left: -.4rem; border-radius: 50%; background: var(--bg); border: var(--rule) solid var(--ink); box-sizing: border-box; }
.tl > li:first-child::before { background: var(--ink); }
.tl__text { order: -1; display: grid; gap: .45rem; }
.tl__text h3 { font-size: var(--step-1); }
.tl__text p { margin: 0; max-width: 52ch; }
.tl__also { margin: .2rem 0 0; padding-left: 1.1rem; color: var(--muted); font-size: .95rem; line-height: 1.45; }
@media (max-width: 760px) { .tl > li { grid-template-columns: minmax(0, 1fr); } }

/* ---------- live demo in a phone ---------- */
.demo { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.25rem; justify-items: center; }
.demo--side { grid-template-columns: minmax(0, auto) minmax(0, 1fr); gap: clamp(2rem, 6vw, 5rem); align-items: center; justify-items: start; }
@media (max-width: 860px) { .demo--side { grid-template-columns: minmax(0, 1fr); justify-items: center; } }
.demo__text { display: grid; gap: .9rem; max-width: 34rem; }
.demo__text h2 { font-size: var(--step-2); }
.demo__text p { color: var(--muted); }
.demo__note { font: 500 var(--step--1)/1.5 var(--mono); letter-spacing: .04em; color: var(--muted); max-width: 60ch; }
.phone { background: #111111; border: var(--rule) solid var(--ink); border-radius: 2.6rem; padding: .8rem; max-width: 100%; }
.phone--portrait { width: 22.5rem; }
.phone--landscape { width: 56rem; border-radius: 2.2rem; }
.phone__screen { position: relative; overflow: hidden; border-radius: 1.9rem; background: #111111; display: grid; }
.phone--portrait .phone__screen { aspect-ratio: 1 / 2; }
.phone--landscape .phone__screen { aspect-ratio: 874 / 402; border-radius: 1.5rem; }
.phone__screen > * { grid-area: 1 / 1; }
.phone__screen img, .phone__screen iframe { width: 100%; height: 100%; object-fit: cover; border: 0; display: block; }
.phone__play { align-self: center; justify-self: center; z-index: 1; background: #ffffff; color: #111111; border-color: #111111; }
.phone__play:hover { background: #111111; color: #ffffff; border-color: #ffffff; }
@media (max-width: 700px) { .phone--landscape { border-radius: 1.2rem; padding: .4rem; } .phone--landscape .phone__screen { border-radius: .9rem; } }

/* ---------- footer ---------- */
.foot { border-top: var(--rule) solid var(--ink); font: 500 var(--step--1)/1.5 var(--mono); letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.foot .wrap { display: flex; flex-wrap: wrap; justify-content: space-between; gap: .5rem 2rem; padding-block: 1rem; }

/* ---------- article ---------- */
.post-head { padding-block: clamp(1.75rem, 4.5vw, 3.5rem); display: grid; gap: 1rem; }
.post-head h1 { font-size: var(--step-3); line-height: .95; max-width: 16ch; }
.post-head .sub { font-size: var(--step-1); color: var(--muted); max-width: 52ch; line-height: 1.45; }
.crumb { font: 500 var(--step--1)/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; justify-self: start; }
.post { display: grid; grid-template-columns: 13rem minmax(0, 44rem); gap: clamp(2rem, 6vw, 5rem); padding-block: clamp(1.75rem, 4vw, 3.25rem) clamp(3rem, 7vw, 5rem); border-top: var(--rule) solid var(--ink); }
.toc { position: sticky; top: 4.75rem; align-self: start; display: grid; gap: .8rem; }
.toc ol { list-style: none; margin: 0; padding: 0; display: grid; gap: .1rem; font-size: .9688rem; }
.toc a { display: block; padding: .3rem .6rem; text-decoration: none; border-left: 2px solid var(--soft); color: var(--muted); }
.toc a:hover { color: var(--bg); }
.toc a[aria-current="true"] { border-left-color: var(--ink); color: var(--ink); font-weight: 700; }
.toc a[aria-current="true"]:hover { color: var(--bg); }
@media (max-width: 860px) { .post { grid-template-columns: minmax(0, 1fr); } .toc { position: static; } }
.prose { display: grid; gap: 1.1rem; min-width: 0; }
.prose > * { min-width: 0; }
.prose h2 { font-size: var(--step-2); margin-top: 2rem; padding-top: 1.4rem; border-top: 1px solid var(--ink); }
.prose h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.prose ul, .prose ol { margin: 0; padding-left: 1.3rem; display: grid; gap: .4rem; }
.prose li::marker { font-family: var(--mono); font-size: .85em; color: var(--muted); }
.prose :not(pre) > code { background: var(--surface); border: 1px solid var(--soft); padding: .08em .35em; overflow-wrap: anywhere; }
.prose a { overflow-wrap: anywhere; }
.tbl { overflow-x: auto; min-width: 0; }
.tbl table { border-collapse: collapse; width: 100%; font-size: var(--step--1); }
.tbl th, .tbl td { border: 1px solid var(--soft); padding: .4rem .6rem; text-align: left; vertical-align: top; }
.tbl th { border-bottom: var(--rule) solid var(--ink); font-family: var(--mono); font-weight: 500; }
.note { border: var(--rule) solid var(--ink); background: var(--surface); padding: 1rem 1.15rem; display: grid; gap: .4rem; }
.payload { background: var(--code-bg); color: var(--code-fg); border: 1px solid var(--code-line); }
.payload dl { margin: 0; display: grid; }
.payload div { display: grid; gap: .3rem; padding: .8rem .9rem; border-bottom: 1px solid var(--code-line); }
.payload div:last-child { border-bottom: 0; }
.payload dt { font: 500 .6875rem/1.3 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--code-muted); }
.payload dd { margin: 0; font: 500 .875rem/1.5 var(--mono); overflow-wrap: anywhere; }
figure { margin: .5rem 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: .6rem; }
.prose figure a { border: var(--rule) solid var(--ink); display: block; background: var(--surface); }
.prose figure a:hover { background: var(--surface); outline: 3px solid var(--ink); outline-offset: 3px; }
.prose figcaption a { display: inline; border: 0; background: none; }
.prose figcaption a:hover { background: var(--ink); color: var(--bg); outline: 0; }
figure video { width: 100%; }
figcaption { overflow-wrap: anywhere; font: 500 var(--step--1)/1.4 var(--mono); letter-spacing: .04em; color: var(--muted); }
blockquote { margin: 0; padding: .2rem 0 .2rem 1.2rem; border-left: 3px solid var(--ink); color: var(--muted); }
.dates { list-style: none !important; padding: 0 !important; }
.dates li { display: grid; grid-template-columns: 6.5rem minmax(0, 1fr); gap: 1rem; padding: .55rem 0; border-bottom: 1px solid var(--soft); }
.dates time { font: 500 .875rem/1.8 var(--mono); color: var(--muted); }
.post-end { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.5rem; }
.product > .post-end { margin-top: 0; }

/* ---------- blog ---------- */
.posts { list-style: none; margin: 1.5rem 0 1.25rem; padding: 0; border-top: 1px solid var(--ink); }
.posts li { border-bottom: 1px solid var(--soft); }
.posts a { display: grid; gap: .35rem; padding: 1rem 0; text-decoration: none; color: var(--ink); }
.posts__title { font: 600 var(--step-1)/1.2 var(--display); text-decoration: underline; text-underline-offset: .18em; text-decoration-thickness: 1px; }
.posts__sum { color: var(--muted); max-width: 62ch; }
.posts a:hover { background: var(--bg); color: var(--ink); }
.posts a:hover .posts__title { text-decoration-thickness: 2.5px; }
.posts a:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }

.blog-list { padding-bottom: clamp(3rem, 7vw, 5rem); border-top: var(--rule) solid var(--ink); }
.blog-list .posts { margin-top: 0; border-top: 0; }
.refs { font-size: .9375rem; color: var(--muted); }
.refs li:target { color: var(--ink); }

/* diagrams: inline SVG drawn with the colour tokens, so they follow the theme */
.dg { width: 100%; height: auto; display: block; border: var(--rule) solid var(--ink); background: var(--bg); }
.dg text { font: 500 13px/1 var(--mono); fill: var(--ink); letter-spacing: .02em; }
.dg .t-s { font-size: 11px; fill: var(--muted); }
.dg .t-h { font: 600 15px/1 var(--display); letter-spacing: .03em; text-transform: uppercase; }
.dg .t-m { fill: var(--muted); }
.dg .t-inv { fill: var(--bg); }
.dg .ln { fill: none; stroke: var(--ink); stroke-width: 1.5; }
.dg .ln-s { fill: none; stroke: var(--muted); stroke-width: 1; stroke-dasharray: 4 4; }
.dg .ln-t { fill: none; stroke: var(--ink); stroke-width: 3; }
.dg .bx { fill: var(--bg); stroke: var(--ink); stroke-width: 1.5; }
.dg .bx-s { fill: var(--surface); stroke: var(--ink); stroke-width: 1; }
.dg .bx-i { fill: var(--ink); stroke: var(--ink); stroke-width: 1.5; }
.dg .bx-d { fill: none; stroke: var(--ink); stroke-width: 1; stroke-dasharray: 5 4; }
.dg .gap { fill: url(#d3h); stroke: var(--ink); stroke-width: 1; stroke-dasharray: 5 4; }
.dg .hatch-p { stroke: var(--muted); stroke-width: 1; }
.dg .qr-w { fill: var(--bg); stroke: none; }
.dg .dot { fill: var(--ink); }
.dg .arr { fill: var(--ink); }
.fig-wide { overflow-x: auto; }
/* diagrams with steps (site.js): a box under the diagram holds the step, its text and the buttons.
   Without the script the box holds the whole numbered list. */
.steps__panel { margin-top: calc(var(--rule) * -1 - .6rem); border: var(--rule) solid var(--ink); background: var(--surface); padding: .9rem 1rem 1rem; display: grid; gap: .55rem; position: sticky; left: 0; }
.steps__list { margin: 0; padding-left: 1.3rem; display: grid; gap: .3rem; font-size: .9688rem; line-height: 1.5; }
.steps--on .steps__list { list-style: none; padding-left: 0; }
.steps--on .steps__list li { display: none; }
.steps--on .steps__list li.is-now { display: block; }
.steps--on .steps__list:not(:has(.is-now)) { display: none; }
.steps__at { margin: 0; }
.steps__hint { margin: 0; font-size: .9688rem; line-height: 1.5; color: var(--muted); }
.steps__bar { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-top: .25rem; }
.btn--s { padding: .4rem .75rem; font-size: .875rem; }
.btn:disabled { opacity: .35; cursor: default; }
.btn--ghost:disabled:hover { background: none; color: var(--ink); }
.dg [data-step] { transition: opacity .45s ease; }
.dg .is-past { opacity: .4; }
.dg .is-later { opacity: .07; }
@media (prefers-reduced-motion: reduce) { .dg [data-step] { transition: none; } }
.fig-wide .dg { min-width: 34rem; }

/* ---------- thoughts: status, dates, revisions ---------- */
.tmeta { margin: 0; display: flex; flex-wrap: wrap; gap: .5rem 2rem; padding-top: .9rem; border-top: 1px solid var(--soft); }
.tmeta div { display: grid; gap: .15rem; }
.tmeta dt { font: 500 .68rem/1.4 var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.tmeta dd { margin: 0; font: 500 .875rem/1.5 var(--mono); }
.status { display: inline-block; font: 500 var(--step--1)/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; padding: .3rem .45rem; border: 1px solid var(--ink); color: var(--ink); }
.posts__meta { display: flex; flex-wrap: wrap; gap: .5rem 1rem; align-items: center; }
.code pre.wrap-lines { white-space: pre-wrap; overflow-wrap: anywhere; }

/* ---------- animated diagrams (site.js): figure.anim
   site.js adds .anim--ready, then .is-in when the figure comes on screen: .draw lines draw, .grow / .grow-l bars grow, .pop parts appear (.d1-.d8 delay them).
   data-state="a" / "b" from the switch buttons: .w-a shows in state a, .w-b in state b, .hi-a / .hi-b stay strong, the rest fades.
   [data-pick] parts are buttons: they show their item of .pick__list. A visitor who asked for less motion gets the end state. */
.anim--ready .draw { stroke-dasharray: 1; stroke-dashoffset: 1; transition: stroke-dashoffset 1.4s cubic-bezier(.6,0,.2,1); }
.anim--ready .grow, .anim--ready .grow-l { transform: scaleX(0); transform-box: fill-box; transform-origin: left center; transition: transform 1.1s cubic-bezier(.3,0,.1,1); }
.anim .grow-l { transform-origin: right center; transform-box: fill-box; }
.anim--ready .pop { opacity: 0; transform: scale(.6); transform-box: fill-box; transform-origin: center; transition: opacity .5s ease, transform .6s cubic-bezier(.3,1.4,.5,1); }
.anim--ready.is-in .draw { stroke-dashoffset: 0; }
.anim--ready.is-in .grow, .anim--ready.is-in .grow-l, .anim--ready.is-in .pop { transform: none; opacity: 1; }
.anim .d1 { transition-delay: .15s; } .anim .d2 { transition-delay: .3s; } .anim .d3 { transition-delay: .45s; } .anim .d4 { transition-delay: .6s; }
.anim .d5 { transition-delay: .75s; } .anim .d6 { transition-delay: .9s; } .anim .d7 { transition-delay: 1.05s; } .anim .d8 { transition-delay: 1.2s; }
.anim .w-a, .anim .w-b, .anim .fade { transition: opacity .5s ease; }
.anim[data-state="a"] .w-b, .anim[data-state="b"] .w-a, .anim:not([data-state]) .w-b { opacity: 0; pointer-events: none; }
.anim[data-state="a"] .hi-b, .anim[data-state="b"] .hi-a { opacity: .2; }
.anim[data-state="b"] .off-b { opacity: .22; }
.anim .lvl { transform-box: fill-box; transform-origin: left center; transition: transform .9s cubic-bezier(.3,0,.1,1); }
.anim .lvl.s20 { transform: scaleX(.2); } .anim .lvl.s30 { transform: scaleX(.3); } .anim .lvl.s100 { transform: scaleX(1); }
.anim[data-state="b"] .lvl.b100 { transform: scaleX(1); } .anim[data-state="b"] .lvl.b10 { transform: scaleX(.1); }
.anim [data-pick] { cursor: pointer; pointer-events: bounding-box; }
.anim [data-pick] .bx, .anim [data-pick] text { transition: fill .25s ease; }
.anim [data-pick]:hover .bx, .anim [data-pick].is-on .bx { fill: var(--ink); }
.anim [data-pick]:hover text, .anim [data-pick].is-on text { fill: var(--bg); }
.anim [data-pick]:focus { outline: none; }
.anim [data-pick]:focus-visible .bx { stroke-width: 4; }
.anim .dot-pick { transition: r .25s ease; }
.anim [data-pick]:hover .dot-pick, .anim [data-pick].is-on .dot-pick { r: 13; }
.anim [data-pick]:hover .t-pick, .anim [data-pick].is-on .t-pick { fill: var(--ink); font-weight: 700; }
.anim__bar { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.anim__bar .btn[aria-pressed="true"] { background: var(--ink); color: var(--bg); }
.pick__panel { border: var(--rule) solid var(--ink); background: var(--surface); padding: .9rem 1rem 1rem; display: grid; gap: .55rem; margin-top: calc(var(--rule) * -1 - .6rem); }
.pick__list { margin: 0; padding-left: 1.3rem; display: grid; gap: .3rem; font-size: .9688rem; line-height: 1.5; }
.pick--on .pick__list { list-style: none; padding-left: 0; }
.pick--on .pick__list li { display: none; }
.pick--on .pick__list li.is-now { display: block; }
.pick__list b { font-family: var(--display); font-size: 1.15rem; font-weight: 600; }
.prose .pick__list a { display: inline; border: 0; background: none; }
.prose .pick__list a:hover { background: var(--ink); color: var(--bg); outline: 0; }
.pick__hint { margin: 0; font-size: .9688rem; color: var(--muted); }
.pick__hint[hidden] { display: none; }
/* a figure can hold a wide drawing (.dg-w) and a narrow one for phones (.dg-n) */
figure .dg-n { display: none; }
@media (max-width: 600px) { figure:has(.dg-n) .dg-w { display: none; } figure .dg-n { display: block; } .fig-wide:has(.dg-n) { overflow-x: visible; } .fig-wide .dg-n { min-width: 0; } }
@media (prefers-reduced-motion: reduce) {
  .anim .draw, .anim .grow, .anim .grow-l, .anim .pop, .anim .w-a, .anim .w-b, .anim .fade, .anim .lvl { transition: none; }
}

/* ---------- 404 ---------- */
.lost { min-height: 60vh; display: grid; align-content: center; gap: 1.25rem; padding-block: 3rem; }
.lost h1 { font-size: clamp(5rem, 22vw, 14rem); line-height: .85; }
.lost p { font-size: var(--step-1); max-width: 40ch; }
.lost code { overflow-wrap: anywhere; }
.lost__sealed[hidden] { display: none; }

/* ---------- login of an encrypted site below /sealed/ (the theme "t7d" of sealed) ---------- */
.sealed { min-height: 60vh; display: grid; align-content: center; gap: 1rem; padding-block: 3rem; max-width: 34rem; }
.sealed h1 { font-size: var(--step-3); line-height: .95; overflow-wrap: anywhere; }
.sealed__hint { margin: 0; font-size: var(--step-1); color: var(--muted); max-width: 40ch; line-height: 1.45; }
.sealed__form { display: grid; gap: .5rem; margin-top: .5rem; padding-top: 1rem; border-top: 1px solid var(--ink); }
.sealed__form .label { margin-top: .5rem; }
.sealed__form input { min-width: 0; font: inherit; color: var(--ink); background: var(--bg); border: var(--rule) solid var(--ink); border-radius: 0; padding: .7rem .8rem; }
.sealed__form .btn-row { margin-top: 1rem; }
.sealed__form .btn:disabled { opacity: .6; cursor: wait; }
.sealed__msg { min-height: 1.5em; margin: 0; font: 500 var(--step--1)/1.5 var(--mono); letter-spacing: .04em; color: var(--muted); overflow-wrap: anywhere; }
.sealed__msg.bad { color: var(--ink); font-weight: 700; }

/* ---- Narration (narration.js): the page follows a voice. Nothing here shows until the reader presses Listen. ---- */
[data-c=red] { --c: var(--red); --b: var(--blk-red); }
[data-c=green] { --c: var(--green); --b: var(--blk-green); }
[data-c=blue] { --c: var(--blue); --b: var(--blk-blue); }
[data-c=yellow] { --c: var(--yellow); --b: var(--blk-yellow); }
/* spoken parts: text that only the voice says, folded until the voice reaches it */
.say { display: none; }
.narr-on .say, .narr-all .say { display: grid; grid-template-rows: 0fr; opacity: 0; margin-block: -.55rem; transition: grid-template-rows .55s cubic-bezier(.3,.7,.2,1), opacity .45s ease, margin .55s; }
.say > * { overflow: hidden; min-height: 0; }
.say.open { grid-template-rows: 1fr; opacity: 1; margin-block: 0; }
.say p { color: var(--muted); font-size: .9688rem; }
.say p + p { margin-top: .6rem; }   /* a spoken part with several paragraphs keeps them in one wrapper, so it folds as one row */
.say .w.rd { color: var(--ink); }
.say-k { font: 500 var(--step--1) var(--mono); letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-right: .5rem; white-space: nowrap; }
.say-k::before { content: ""; display: inline-block; width: 6px; height: 6px; background: currentColor; border-radius: 50%; margin-right: .4rem; vertical-align: 1px; }
.prose figure .say { margin-block: 0; }
.prose figure .say:not(.open) { display: none; }   /* in the figure grid even an empty row adds a gap */
.prose figure .say.open { margin-top: .3rem; }
/* the block that the voice reads: a bar on the left; the other blocks dim by text colour, never by opacity,
   so a colour block keeps its contrast */
.narr-seg { position: relative; transition: color .45s ease; }
.narr-on .narr-seg.cur::before { content: ""; position: absolute; left: -.9rem; top: .25em; bottom: .25em; width: 2px; background: var(--ink); }
.narr-playing .narr-seg:not(.cur) { color: color-mix(in srgb, var(--ink) 36%, var(--bg)); }
.narr-playing .say .narr-seg:not(.cur) { color: color-mix(in srgb, var(--ink) 30%, var(--bg)); }
.narr-playing .prose figure:not(.cur) svg, .narr-playing .prose figure:not(.cur) figcaption { opacity: .34; transition: opacity .45s; }
.narr-on .narr-seg.cur .w:not(.rd) { opacity: .5; }
.narr-on .say .w:not(.rd) { opacity: 1; }
.w { position: relative; z-index: 1; transition: opacity .25s ease; }
.narr-on .prose .narr-seg code { background: transparent; border: 0; padding: 0; }
.narr-on .narr-seg { cursor: pointer; }
.narr-on .prose figure.fig-wide.cur:not(:has(.dg-n)) { overflow-x: visible; }   /* no narrow drawing: fit the wide one while the voice explains it */
.narr-on .prose figure.fig-wide.cur:not(:has(.dg-n)) .dg { min-width: 0; }
.narr-on li.narr-seg.cur::before { left: -2.2rem; }   /* in a list, the bar sits left of the number */
/* figures with voice steps: a plain numbered list under the drawing; the voice brings in the parts of each step */
.prose .fig-steps { margin: .9rem 0 0; padding-left: 1.6rem; font-size: .9688rem; line-height: 1.5; }
.narr-playing .prose figure.cur .say:not(:has(.cur)), .narr-playing .prose figure.cur .say .narr-seg:not(.cur),
.narr-playing .prose figure.cur .fig-steps .narr-seg:not(.cur) { display: none; }   /* under a figure, only the paragraph that the voice reads now */
.narr-playing .prose figure.cur figcaption { display: none; }   /* the voice explains the figure; the caption returns afterwards */
/* the phrase marker: a grey tint over the phrase that the voice reads */
.narr-on #main { position: relative; }
.narr-hl { position: absolute; left: 0; top: 0; z-index: 0; pointer-events: none; opacity: 0; background: color-mix(in srgb, var(--ink) 16%, transparent);
  transition: transform .32s cubic-bezier(.25,.8,.25,1), width .32s cubic-bezier(.25,.8,.25,1), height .2s, opacity .35s ease; }
.narr-hl.show { opacity: 1; }
.narr-hl.jump { transition: opacity .35s ease; }
/* marked terms: a colour block with white text once the voice says them; plain text otherwise */
.mk { transition: background-color .4s ease, color .4s ease; }
.mk.on { background: var(--b); color: var(--on-blk); padding: 0 .12em; margin: 0 -.12em; }
.mk.on .w { color: var(--on-blk); opacity: 1; }
.mk.on code { color: inherit; }
/* figure cues: the part that the voice describes stands out, the rest of the figure steps back */
.dg [class^="cue-"] { transition: opacity .35s ease; }
.dg:has(.hot) [class^="cue-"]:not(.hot) { opacity: .3; }
.dg .hot .t-s { fill: var(--ink); }
.dg [data-c] { transition: fill .5s ease, stroke .5s ease; }
.dg [data-c].on { fill: var(--c); stroke: var(--c); }
/* the listen row and the player strip */
.narr-listen { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1rem; padding-block: .75rem; border-block: 1px solid var(--soft); }
.narr-go { display: inline-flex; align-items: center; gap: .55rem; }
.narr-go svg, .narr-play svg { width: 1.25rem; height: 1.25rem; fill: currentColor; }
.i-pause { display: none; } .narr-playing .i-play { display: none; } .narr-playing .i-pause { display: block; }
.narr-note { margin: 0; flex: 1 1 16rem; color: var(--muted); font-size: .9375rem; line-height: 1.4; }
.narr-again[hidden] { display: none; }   /* .btn sets display, which would win over [hidden] */
.narr-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 30; background: var(--bg); border-top: var(--rule) solid var(--ink); padding-bottom: env(safe-area-inset-bottom, 0px); display: none; }
.narr-on .narr-bar { display: block; }
.narr-on { padding-bottom: 4.5rem; }
.narr-scrub { position: relative; height: 16px; margin-top: -9px; cursor: pointer; touch-action: none; }
.narr-rail, .narr-fill { position: absolute; left: 0; top: 7px; height: 2px; }
.narr-rail { right: 0; background: var(--soft); }
.narr-fill { width: 0; background: var(--ink); }
.narr-tick { position: absolute; top: 5px; width: 1.5px; height: 6px; background: var(--muted); }
.narr-knob { position: absolute; top: 3px; width: 10px; height: 10px; margin-left: -5px; border-radius: 50%; background: var(--ink); opacity: 0; transition: opacity .2s; }
.narr-scrub:hover .narr-knob, .narr-scrub.drag .narr-knob { opacity: 1; }
.narr-row { display: flex; align-items: center; gap: .25rem; max-width: 82rem; margin: 0 auto; padding: 0 var(--pad) .35rem; }
.narr-row button { border: 0; background: none; color: var(--ink); cursor: pointer; min-width: 44px; min-height: 44px; display: grid; place-items: center; font: inherit; }
.narr-row .narr-play { background: var(--ink); color: var(--bg); }
.narr-skip { position: relative; }
.narr-skip svg { width: 1.6rem; height: 1.6rem; }
.narr-skip span { position: absolute; inset: 0; display: grid; place-items: center; padding-top: 2px; font: 500 .66rem var(--mono); }
.narr-row .narr-chap { flex: 1; min-width: 0; display: grid; justify-items: start; text-align: left; padding-inline: .5rem; }
.narr-chap span { font-weight: 700; font-size: .9375rem; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.narr-chap small { font: 400 .75rem var(--mono); color: var(--muted); font-variant-numeric: tabular-nums; }
.narr-row .narr-speed { font: 500 .8rem var(--mono); border: 1px solid var(--soft); min-width: 3.2rem; }
.narr-sheet { position: fixed; left: 50%; transform: translateX(-50%); bottom: calc(4.1rem + env(safe-area-inset-bottom, 0px)); z-index: 40; width: min(26rem, calc(100% - 2rem)); background: var(--bg); border: var(--rule) solid var(--ink); padding: .7rem 1rem; display: none; }
.narr-sheet.open { display: block; }
.narr-sheet ol { list-style: none; margin: .4rem 0 .6rem; padding: 0; display: grid; }
.narr-sheet button { width: 100%; display: flex; justify-content: space-between; gap: 1rem; border: 0; border-top: 1px solid var(--soft); background: none; color: var(--ink); padding: .55rem .1rem; cursor: pointer; text-align: left; font: inherit; font-size: .9375rem; }
.narr-sheet .is-now button { font-weight: 700; }
.narr-t { font: 400 .75rem var(--mono); color: var(--muted); }
.narr-opt { display: flex; gap: .5rem; align-items: center; font-size: .875rem; color: var(--muted); }
.narr-follow { position: fixed; left: 50%; transform: translateX(-50%); bottom: calc(4.6rem + env(safe-area-inset-bottom, 0px)); z-index: 31; display: none; border: 0; background: var(--ink); color: var(--bg); padding: .5rem .9rem; font: 500 var(--step--1) var(--mono); letter-spacing: .06em; text-transform: uppercase; cursor: pointer; }
.narr-playing.narr-lost .narr-follow { display: block; }
@media (prefers-reduced-motion: reduce) { .say, .narr-hl, .narr-seg, .mk, .w { transition: none !important; } }

@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }
@media print { .nav, .toc, .copy, .toggle, .demo, .narr-bar, .narr-listen { display: none !important; } body { border: 0; } }
