/* ============================================================
   Will: portfolio, "observatory" design
   Graphite sky, bronze instruments, celestial chapter signals.
   Hand-written CSS. No framework, no build step.
   ============================================================ */

:root {
  --paper:      oklch(15.5% 0.008 250);
  --paper-high: oklch(20.5% 0.009 250);
  --ink:        oklch(91% 0.008 235);
  --blue:       oklch(72% 0.035 220);
  --blue-deep:  oklch(60% 0.04 220);
  --bronze:     oklch(74% 0.105 70);
  --muted:      oklch(64% 0.014 240);
  --dawn:       oklch(92% 0.01 235);
  --hairline:   color-mix(in oklab, var(--ink) 16%, transparent);
  --grid-line:  color-mix(in oklab, var(--blue) 5%, transparent);
  --grid-major: color-mix(in oklab, var(--blue) 8%, transparent);

  /* Signal colours: the accent a chapter borrows from the body it orbits,
     each drawn from that body's own surface. --signal is whichever one is
     currently in play; bronze is the instrument default away from a body. */
  --signal:         var(--bronze);
  --signal-sun:     oklch(74% 0.16 48);
  --signal-mercury: oklch(79% 0.018 65);
  --signal-venus:   oklch(86% 0.07 90);
  --signal-earth:   oklch(76% 0.10 235);
  --signal-mars:    oklch(71% 0.14 42);
  --signal-jupiter: oklch(80% 0.075 72);
  --signal-saturn:  oklch(85% 0.08 92);
  --signal-uranus:  oklch(83% 0.07 195);
  --signal-neptune: oklch(72% 0.12 260);

  --font-display: "Young Serif", "Iowan Old Style", Georgia, serif;
  --font-body: "Literata", Georgia, serif;
  --font-mono: "Azeret Mono", ui-monospace, "SF Mono", monospace;

  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --wrap: 1100px;
  --gutter: clamp(1.25rem, 4vw, 3rem);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

body { overflow-x: clip; }

body {
  font-family: var(--font-body);
  font-size: clamp(1.02rem, 0.95rem + 0.3vw, 1.15rem);
  line-height: 1.55;
  color: var(--ink);
  background-color: var(--paper);
  background-image:
    radial-gradient(120% 60% at 50% 0%, color-mix(in oklab, var(--blue) 7%, transparent), transparent 70%),
    linear-gradient(to right,  var(--grid-major) 1px, transparent 1px),
    linear-gradient(to bottom, var(--grid-major) 1px, transparent 1px);
  background-size: 100% 100vh, 120px 120px, 120px 120px;
  background-repeat: no-repeat, repeat, repeat;
  -webkit-font-smoothing: antialiased;
}

::selection { background: var(--signal); color: var(--paper); }

:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }

a { color: inherit; }

strong { font-weight: 700; }

/* ---------- header ---------- */

.site-head {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.7rem var(--gutter);
  background: color-mix(in oklab, var(--paper) 86%, transparent);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--hairline);
}

.site-head__name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.15rem;
  text-decoration: none;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

section[id], figure[id], footer[id] { scroll-margin-top: 4.5rem; }

.site-head__nav {
  display: flex;
  gap: clamp(0.8rem, 2.5vw, 1.6rem);
  font-family: var(--font-mono);
  font-size: 0.78rem;
}

.site-head__nav a { text-decoration: none; color: var(--muted); }
.site-head__nav a:hover { color: var(--signal); }

/* ---------- the system is the site ---------- */

#solar-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
  touch-action: pan-y;   /* one-finger page scroll; drag, twist and pinch stay interactive */
}

main {
  position: relative;
  z-index: 1;
  pointer-events: none;  /* the open sky stays draggable between panels */
}

.hero__dot { color: var(--signal); }

/* ---------- chapters ---------- */

.chapter {
  min-height: 100vh;
  display: grid;
  align-items: center;
  max-width: var(--wrap);
  margin-inline: auto;
  padding: clamp(5rem, 14vh, 9rem) var(--gutter);
}

/* Which signal each chapter flies. The colours themselves live in :root;
   this is only the lookup from body to signal. */
.chapter[data-body="sun"]     { --signal: var(--signal-sun); }
.chapter[data-body="mercury"] { --signal: var(--signal-mercury); }
.chapter[data-body="venus"]   { --signal: var(--signal-venus); }
.chapter[data-body="earth"]   { --signal: var(--signal-earth); }
.chapter[data-body="mars"]    { --signal: var(--signal-mars); }
.chapter[data-body="jupiter"] { --signal: var(--signal-jupiter); }
.chapter[data-body="saturn"]  { --signal: var(--signal-saturn); }
.chapter[data-body="uranus"]  { --signal: var(--signal-uranus); }
.chapter[data-body="neptune"] { --signal: var(--signal-neptune); }

.chapter__inner {
  pointer-events: auto;
  width: min(680px, 100%);
  padding: clamp(1.4rem, 3vw, 2.4rem);
  border: 1px solid var(--hairline);
  background: color-mix(in oklab, var(--paper) 84%, transparent);
  backdrop-filter: blur(5px);
}

.chapter[data-side="r"] .chapter__inner { margin-left: auto; }

.chapter__inner--bare {
  border: 0;
  background: none;
  backdrop-filter: none;
  padding: 0;
}

.chapter__eph {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--signal);
  margin-bottom: 1.1rem;
}

.chapter h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.7rem, 3.4vw, 2.4rem);
  letter-spacing: -0.01em;
  margin-bottom: 1rem;
  color: var(--signal);
}

.chapter__lead { max-width: 62ch; }

.chapter .demo { margin: 0; padding-top: 1.6rem; border-top: 0; }

.chapter__kicker {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--muted);
  margin-bottom: 1.4rem;
}

/* hero on the Sun */

.chapter--hero .chapter__inner { max-width: 38rem; }

.chapter--hero h1 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.5rem, 6.6vw, 4.6rem);
  line-height: 1.03;
  letter-spacing: -0.015em;
  text-wrap: balance;
  color: var(--signal);
}

.chapter__sub {
  margin-top: 1.4rem;
  max-width: 46ch;
  text-shadow: 0 1px 14px var(--paper);
}

/* hero hooks: one claim per line, each backed by something further down */

.hero-hooks {
  list-style: none;
  display: grid;
  gap: 0.5rem;
  margin-top: 1.5rem;
  max-width: 48ch;
}

.hero-hooks li {
  position: relative;
  padding-left: 1.05rem;
  text-shadow: 0 1px 14px var(--paper);
}

.hero-hooks li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--signal);
}

.hero-avail {
  margin-top: 1.4rem;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--muted);
  text-shadow: 0 1px 14px var(--paper);
}

.scroll-hint {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 2rem;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--muted);
}

.scroll-hint__arrow { animation: scroll-nudge 2.4s var(--ease) infinite; }

@keyframes scroll-nudge {
  0%, 60%, 100% { transform: translateY(0); }
  30%           { transform: translateY(3px); }
}

@media (prefers-reduced-motion: reduce) {
  .scroll-hint__arrow { animation: none; }
}

.chapter__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.7rem;
  margin-top: 1.8rem;
}

.chapter__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.1rem;
  margin-top: 2.2rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--muted);
}

.chapter__facts b { color: var(--signal); font-weight: 500; }

/* contact on Neptune */

.contact-mail {
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.4rem, 3.4vw, 2.4rem);
  letter-spacing: -0.01em;
  text-decoration: none;
  border-bottom: 3px solid color-mix(in oklab, var(--ink) 35%, transparent);
  padding-bottom: 0.12em;
  transition: border-color 0.2s var(--ease);
  overflow-wrap: anywhere;
}

.contact-mail:hover { border-color: var(--signal); }

.contact-links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.4rem;
  margin-top: 1.8rem;
  font-family: var(--font-mono);
  font-size: 0.82rem;
}

.contact-links a { text-underline-offset: 3px; }
.contact-links a:hover { color: var(--signal); }

/* colophon: how the orrery cheats, and who the imagery belongs to */

.colophon {
  margin-top: 2.4rem;
  padding-top: 1.4rem;
  border-top: 1px solid var(--hairline);
  max-width: 62ch;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  line-height: 1.65;
  color: var(--muted);
}

.colophon p + .colophon__head { margin-top: 1rem; }

.colophon__head {
  color: var(--signal);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin-bottom: 0.35rem;
}

.colophon sup { font-size: 0.8em; }

.colophon a { text-underline-offset: 3px; }
.colophon a:hover { color: var(--signal); }

/* the finale */

.chapter--system {
  align-items: start;
  justify-items: center;
  padding-top: 18vh;
  text-align: center;
}

.chapter__inner--system p { color: var(--muted); margin-top: 0.6rem; }

/* demos inside panels */

.chapter .nn-net { display: none; }
.chapter .demo__stage--nn { grid-template-columns: auto minmax(200px, 1fr); }
.chapter .demo__stage--chess { grid-template-columns: minmax(230px, 300px) minmax(200px, 1fr); }
.chapter .demo__stage--maze { grid-template-columns: 1fr; }
.chapter .ledger__row { grid-template-columns: 110px minmax(0, 1fr); padding: 1.2rem 0; }
.chapter .ctf { grid-template-columns: minmax(0, 1fr) auto; column-gap: 1.5rem; }
.chapter .stamp { width: 126px; }
.chapter .spec__row { grid-template-columns: 110px 1fr; }

/* ---------- HUD ---------- */

.hud {
  position: fixed;
  z-index: 6;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem 1.4rem;
  padding: 0.55rem var(--gutter);
  font-family: var(--font-mono);
  font-size: 0.76rem;
  color: var(--muted);
  border-top: 1px solid var(--hairline);
  background: color-mix(in oklab, var(--paper) 80%, transparent);
  backdrop-filter: blur(5px);
}

.orrery__clock { color: var(--ink); min-width: 11ch; }

.orrery__speeds { display: flex; flex-wrap: wrap; gap: 0.15rem; }

.orrery__zoom {
  display: flex;
  flex: 0 0 auto;
  gap: 0.3rem;
  margin-left: auto;
}

.hud button {
  appearance: none;
  border: 0;
  background: none;
  font: inherit;
  color: var(--muted);
  padding: 0.3em 0.55em;
  cursor: pointer;
}

.hud button:hover { color: var(--signal); }

.hud button.is-active { color: var(--signal); box-shadow: inset 0 -2px 0 var(--signal); }

.hud .orrery__zoom button {
  display: grid;
  width: 2rem;
  height: 2rem;
  padding: 0;
  place-items: center;
  color: var(--ink);
  border: 1px solid var(--hairline);
}

.hud .orrery__zoom button:hover {
  color: var(--paper);
  border-color: var(--signal);
  background: var(--signal);
}

.orrery__zoom svg {
  width: 1.1rem;
  height: 1.1rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.45;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------- buttons ---------- */

.btn {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink);
  background: color-mix(in oklab, var(--paper-high) 72%, transparent);
  border: 1px solid var(--hairline);
  padding: 0.6em 1.1em;
  cursor: pointer;
  transition: background 0.18s var(--ease), color 0.18s var(--ease),
              border-color 0.18s var(--ease), transform 0.18s var(--ease);
}

.btn:hover { background: var(--signal); border-color: var(--signal); color: var(--paper); transform: translateY(-1px); }

.btn--primary { background: var(--signal); border-color: var(--signal); color: var(--paper); }
.btn--primary:hover { background: var(--ink); border-color: var(--ink); }

.btn--small { font-size: 0.72rem; padding: 0.5em 0.9em; }

.btn.is-active { background: var(--blue); border-color: var(--blue); color: var(--paper); }

/* ---------- demo figures ---------- */

.demo {
  position: relative;
  margin: 0 0 clamp(4rem, 9vh, 6.5rem);
  padding-top: 2.2rem;
  border-top: 1px solid var(--hairline);
}

.demo__header { max-width: 62ch; }

.demo__header h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.4rem, 2.6vw, 1.9rem);
  margin-bottom: 0.7rem;
}

.demo__stage {
  margin-top: 2rem;
  display: grid;
  gap: clamp(1.4rem, 3.5vw, 2.6rem);
  align-items: start;
}

.demo figcaption {
  margin-top: 1.4rem;
  font-style: italic;
  font-size: 0.92rem;
  color: var(--muted);
  max-width: 68ch;
}

.fig-label { font-style: normal; font-weight: 700; color: var(--signal); }

.annotation {
  position: absolute;
  font-family: var(--font-mono);
  font-size: 0.76rem;
  color: var(--signal);
  transform: rotate(-2deg);
  max-width: 15ch;
  line-height: 1.4;
}

.annotation svg { display: block; width: 56px; }

.annotation svg path, .margin-arrow path {
  stroke: var(--signal);
  stroke-width: 2.4;
  fill: none;
}

/* ---------- Fig 1: neural net ---------- */

.demo__stage--nn { grid-template-columns: auto auto minmax(220px, 1fr); }

#nn-canvas {
  display: block;
  width: min(280px, 76vw);
  aspect-ratio: 1;
  height: auto;
  background: var(--paper-high);
  border: 1px solid var(--hairline);
  touch-action: none;
  cursor: crosshair;
}

.nn-draw__tools {
  display: flex;
  align-items: center;
  gap: 0.8rem;
  margin-top: 0.7rem;
}

.nn-draw__hint { font-family: var(--font-mono); font-size: 0.74rem; color: var(--muted); }

.nn-net {
  display: flex;
  gap: 2.1rem;
  padding-top: 0.4rem;
}

.nn-net__layer {
  display: grid;
  gap: 6px;
  align-content: start;
  position: relative;
  padding-bottom: 1.6rem;
}

.nn-net__layer::after {
  content: attr(data-label);
  position: absolute;
  bottom: 0;
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: 0.64rem;
  color: var(--muted);
  white-space: nowrap;
}

.nn-net__dot {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1px solid var(--signal);
  background: var(--signal);
  transition: opacity 0.12s linear;
}

.nn-out__guess {
  display: flex;
  align-items: baseline;
  gap: 0.9rem;
  margin-bottom: 1rem;
}

.nn-out__digit {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(3.4rem, 6vw, 5rem);
  line-height: 1;
  color: var(--signal);
  min-width: 1.2ch;
}

.nn-out__conf { font-family: var(--font-mono); font-size: 0.8rem; color: var(--muted); }

.nn-bars { list-style: none; display: grid; gap: 5px; max-width: 340px; }

.nn-bars li {
  display: grid;
  grid-template-columns: 1.4ch 1fr 4.5ch;
  align-items: center;
  gap: 0.6rem;
  font-family: var(--font-mono);
  font-size: 0.76rem;
  color: var(--muted);
}

.nn-bars .bar { height: 12px; background: color-mix(in oklab, var(--blue) 14%, var(--paper)); position: relative; }

.nn-bars .bar i {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0%;
  background: var(--blue);
  transition: width 0.25s var(--ease);
}

.nn-bars li.is-top .bar i { background: var(--signal); }
.nn-bars li.is-top { color: var(--ink); font-weight: 500; }
.nn-bars li span:last-child { text-align: right; }

/* ---------- Fig 2: chess ---------- */

.demo__stage--chess { grid-template-columns: minmax(280px, 400px) minmax(240px, 320px); }

.chess-board {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: repeat(5, 1fr);
  width: 100%;
  aspect-ratio: 1;
  border: 1px solid var(--hairline);
  background: var(--paper-high);
}

.chess-board button {
  appearance: none;
  border: 0;
  padding: 0;
  font-family: var(--font-body);
  font-size: clamp(1.7rem, 6vw, 2.7rem);
  line-height: 1;
  display: grid;
  place-items: center;
  cursor: pointer;
  background: var(--paper-high);
  color: var(--ink);
  position: relative;
}

.chess-board button.sq-dark { background: color-mix(in oklab, var(--blue) 13%, var(--paper-high)); }
.chess-board button.sq-last { box-shadow: inset 0 0 0 3px color-mix(in oklab, var(--signal) 45%, transparent); }
.chess-board button.sq-selected { box-shadow: inset 0 0 0 3px var(--signal); }
.chess-board button.sq-move::after {
  content: "";
  position: absolute;
  width: 22%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: color-mix(in oklab, var(--signal) 55%, transparent);
}
.chess-board button.sq-capture::after {
  content: "";
  position: absolute;
  inset: 6%;
  width: auto;
  aspect-ratio: auto;
  border-radius: 50%;
  background: none;
  border: 3px solid color-mix(in oklab, var(--signal) 55%, transparent);
}

.chess-status {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  margin-bottom: 1.1rem;
  min-height: 1.4em;
}

.engine-readout { display: grid; gap: 0; font-family: var(--font-mono); font-size: 0.8rem; }

.engine-readout > div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.42em 0;
  border-bottom: 1px solid var(--hairline);
}

.engine-readout dt { color: var(--muted); }
.engine-readout dd { text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.chess-tools, .maze-tools { display: flex; gap: 0.6rem; margin-top: 1.2rem; }

/* ---------- Fig 3: maze ---------- */

.demo__stage--maze { grid-template-columns: minmax(0, 1fr) minmax(220px, 260px); }

#maze-canvas {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--hairline);
  /* matches COL.bg in js/maze.js: the canvas is blank until the maze scrolls
     into view, and a mismatch here reads as a flash when it first paints */
  background: #C0E1EF;
}

.maze-algos { display: flex; gap: 0.5rem; margin-bottom: 1.1rem; }

/* ---------- experience ledger ---------- */

.ledger { list-style: none; }

.ledger__row {
  display: grid;
  grid-template-columns: 130px minmax(0, 62ch);
  column-gap: clamp(1.5rem, 4vw, 3rem);
  padding: 1.6rem 0;
  border-top: 1px solid var(--hairline);
}

.ledger__when { font-family: var(--font-mono); font-size: 0.78rem; color: var(--muted); line-height: 1.8; }

.ledger__what h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.25rem;
  margin-bottom: 0.5rem;
}

.ledger__what h3 span {
  font-family: var(--font-body);
  font-style: italic;
  font-weight: 400;
  font-size: 0.95rem;
  color: var(--muted);
  margin-left: 0.6rem;
}

.ledger--lab .ledger__row { padding: 1.1rem 0; }

.ledger--lab .ledger__what h3 {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 0.95rem;
  letter-spacing: 0;
  margin-bottom: 0.25rem;
  color: var(--blue);
}

.ledger--lab .ledger__what h3 a { text-decoration: none; border-bottom: 1px solid var(--hairline); }
.ledger--lab .ledger__what h3 a:hover { color: var(--signal); border-color: var(--signal); }

.right-mark {
  font-style: normal;
  font-family: var(--font-mono);
  color: var(--signal);
  font-size: 0.6em;
  vertical-align: super;
  margin-left: 0.05em;
}

.chess-board .right-mark {
  position: absolute;
  top: 6%;
  right: 10%;
  font-size: 0.85rem;
  margin: 0;
}

.annotation--nn {
  position: static;
  display: flex;
  gap: 7px;
  align-items: flex-start;
  margin-top: 1rem;
  max-width: 26ch;
  transform: rotate(-1.5deg);
}

.annotation--nn svg { width: 16px; flex-shrink: 0; margin-top: -4px; }

/* ---------- CTF ---------- */

.ctf {
  display: grid;
  grid-template-columns: minmax(0, 62ch) auto;
  align-items: center;
  column-gap: clamp(2rem, 6vw, 5rem);
}

.ctf__body p + p { margin-top: 0.9rem; }

.ctf__flags {
  margin-top: 1rem;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--muted);
}

.stamp {
  width: 148px;
  aspect-ratio: 1;
  border: 3px double var(--signal);
  border-radius: 50%;
  display: grid;
  place-content: center;
  text-align: center;
  color: var(--signal);
  transform: rotate(-8deg);
  opacity: 0.9;
}

.stamp span {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.7rem;
  line-height: 0.95;
  text-transform: uppercase;
}

.stamp em {
  display: block;
  font-family: var(--font-mono);
  font-style: normal;
  font-size: 0.58rem;
  letter-spacing: 0.14em;
  margin-top: 0.5rem;
}

/* ---------- skills spec ---------- */

.spec { max-width: 760px; }

.spec__row {
  display: grid;
  grid-template-columns: 130px 1fr;
  column-gap: clamp(1.5rem, 4vw, 3rem);
  padding: 0.9rem 0;
  border-top: 1px solid var(--hairline);
}

.spec__row dt {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  padding-top: 0.25em;
}

/* ---------- footer: dawn ---------- */

.footer {
  margin-top: clamp(5rem, 12vh, 9rem);
  background: var(--dawn);
  color: var(--paper);
}

.footer__inner {
  max-width: var(--wrap);
  margin-inline: auto;
  padding: clamp(3.5rem, 9vh, 6rem) var(--gutter) clamp(2.5rem, 6vh, 4rem);
}

.footer__kicker { font-family: var(--font-mono); font-size: 0.82rem; opacity: 0.75; margin-bottom: 1rem; }

.footer__mail {
  display: inline-block;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.5rem, 4.6vw, 3.4rem);
  letter-spacing: -0.01em;
  text-decoration: none;
  border-bottom: 3px solid color-mix(in oklab, var(--paper) 35%, transparent);
  padding-bottom: 0.15em;
  transition: border-color 0.2s var(--ease);
  overflow-wrap: anywhere;
}

.footer__mail:hover { border-color: var(--paper); }

.footer__links {
  display: flex;
  flex-wrap: wrap;
  gap: 1.6rem;
  margin-top: 2.2rem;
  font-family: var(--font-mono);
  font-size: 0.82rem;
}

.footer__links a { color: var(--paper); text-underline-offset: 3px; }

.footer ::selection { background: var(--paper); color: var(--dawn); }

/* ---------- writing / blog ---------- */

.post {
  /* main is pointer-events: none so the orrery stays draggable between the
     chapter panels, and each .chapter__inner opts back in. The blog has no
     orrery and no chapters, so it has to opt in here or every link in the
     post body is unclickable. */
  pointer-events: auto;

  /* The same panel the chapters use, sized to hug the reading column rather
     than the full wrap: long-form text sat directly on the 120px grid, with
     gridlines running through the paragraphs. Behind glass the grid reads as
     texture instead of interference. */
  width: min(72ch, 100%);
  margin: clamp(2rem, 6vh, 4rem) auto clamp(3rem, 8vh, 5rem);
  padding: clamp(1.75rem, 4vw, 3rem);
  border: 1px solid var(--hairline);
  background: color-mix(in oklab, var(--paper) 84%, transparent);
  backdrop-filter: blur(5px);
}

.post__back {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  text-decoration: none;
  color: var(--muted);
}

.post__back:hover { color: var(--signal); }

.post__kicker {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--muted);
  margin: 2.1rem 0 0.9rem;
}

.post > h1 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2rem, 5vw, 3.3rem);
  line-height: 1.05;
  letter-spacing: -0.015em;
  max-width: 26ch;
}

.post__body { margin-top: 2.4rem; max-width: 62ch; }

.post__body p + p { margin-top: 1rem; }

/* Section headings have to win against a 1.15rem serif body. At 1.4rem in
   the same colour they were only a fifth larger than the text they were
   meant to be breaking, so they read as emphasis rather than as a new
   section. Size, the signal colour, and a clear step of space do the work.

   The divider is back now that .post is a panel: the grid sits behind
   glass, so a rule no longer has the background's own horizontals to be
   mistaken against. It matches the ledger and spec rows elsewhere. */
.post__body h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.6rem, 2.5vw, 1.95rem);
  line-height: 1.15;
  color: var(--signal);
  border-top: 1px solid var(--hairline);
  padding-top: 1.6rem;
  margin: 3.2rem 0 0.9rem;
}

.post__body a { text-underline-offset: 3px; }
.post__body a:hover { color: var(--signal); }

.post__body code {
  font-family: var(--font-mono);
  font-size: 0.85em;
  background: var(--paper-high);
  border: 1px solid var(--hairline);
  padding: 0.08em 0.35em;
}

.post__body pre {
  margin: 1.2rem 0;
  padding: 1rem 1.2rem;
  background: var(--paper-high);
  border: 1px solid var(--hairline);
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 0.82rem;
  line-height: 1.6;
}

.post__body pre code { border: 0; background: none; padding: 0; font-size: inherit; }

.post__body ul, .post__body ol { margin: 1rem 0 1rem 1.2rem; }
.post__body li + li { margin-top: 0.35rem; }

.writing-intro { max-width: 62ch; margin: 1.2rem 0 clamp(2rem, 5vh, 3rem); }

/* ---------- reveal motion ---------- */

.reveal { opacity: 0; transform: translateY(22px); }

.is-visible {
  opacity: 1;
  transform: none;
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; }
  .is-visible { transition: none; }
}

/* ---------- responsive ---------- */

@media (max-width: 780px) {
  .chapter { align-items: end; }
  .chapter__inner { margin-top: 42vh; }
  .chapter--system { align-items: start; }
  .chapter--system .chapter__inner { margin-top: 0; }
  .chapter .demo__stage--chess,
  .chapter .demo__stage--nn { grid-template-columns: 1fr; }
  .chess-board { max-width: 340px; }
  .chapter .ctf { grid-template-columns: 1fr; row-gap: 1.6rem; }
  .chapter .stamp { justify-self: end; }
}

@media (max-width: 560px) {
  .site-head__nav { font-size: 0.72rem; gap: 0.9rem; }
  .site-head__nav a:nth-child(3),
  .site-head__nav a:nth-child(4) { display: none; }
  .ledger__row { grid-template-columns: 1fr; row-gap: 0.5rem; }
  .ledger__when { line-height: 1.4; }
  .spec__row { grid-template-columns: 1fr; row-gap: 0.3rem; }
}
