/* Fonts (SIL OFL, served from /fonts). Default: Barlow for text, Barlow Condensed for the name and the labels.
   Archivo and Saira are the alternatives on /options/fonts/; they are only downloaded when chosen. */
@font-face { font-family: "Barlow"; font-style: normal; font-display: swap; font-weight: 400; src: url(../fonts/barlow-latin-400-normal.woff2) format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2199, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Barlow"; font-style: normal; font-display: swap; font-weight: 400; src: url(../fonts/barlow-latin-ext-400-normal.woff2) format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Barlow"; font-style: normal; font-display: swap; font-weight: 500; src: url(../fonts/barlow-latin-500-normal.woff2) format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2199, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Barlow"; font-style: normal; font-display: swap; font-weight: 500; src: url(../fonts/barlow-latin-ext-500-normal.woff2) format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Barlow"; font-style: normal; font-display: swap; font-weight: 600; src: url(../fonts/barlow-latin-600-normal.woff2) format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2199, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Barlow"; font-style: normal; font-display: swap; font-weight: 600; src: url(../fonts/barlow-latin-ext-600-normal.woff2) format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Barlow Condensed"; font-style: normal; font-display: swap; font-weight: 500; src: url(../fonts/barlow-condensed-latin-500-normal.woff2) format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2199, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Barlow Condensed"; font-style: normal; font-display: swap; font-weight: 500; src: url(../fonts/barlow-condensed-latin-ext-500-normal.woff2) format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Barlow Condensed"; font-style: normal; font-display: swap; font-weight: 600; src: url(../fonts/barlow-condensed-latin-600-normal.woff2) format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2199, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Barlow Condensed"; font-style: normal; font-display: swap; font-weight: 600; src: url(../fonts/barlow-condensed-latin-ext-600-normal.woff2) format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Barlow Condensed"; font-style: normal; font-display: swap; font-weight: 700; src: url(../fonts/barlow-condensed-latin-700-normal.woff2) format("woff2"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2199, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Barlow Condensed"; font-style: normal; font-display: swap; font-weight: 700; src: url(../fonts/barlow-condensed-latin-ext-700-normal.woff2) format("woff2"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Archivo"; font-style: normal; font-display: swap; font-weight: 100 900; font-stretch: 62.5% 125%; src: url(../fonts/archivo-latin-wdth-normal.woff2) format("woff2-variations"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2199, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Archivo"; font-style: normal; font-display: swap; font-weight: 100 900; font-stretch: 62.5% 125%; src: url(../fonts/archivo-latin-ext-wdth-normal.woff2) format("woff2-variations"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: "Saira"; font-style: normal; font-display: swap; font-weight: 100 900; font-stretch: 62.5% 125%; src: url(../fonts/saira-latin-wdth-normal.woff2) format("woff2-variations"); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2190-2199, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: "Saira"; font-style: normal; font-display: swap; font-weight: 100 900; font-stretch: 62.5% 125%; src: url(../fonts/saira-latin-ext-wdth-normal.woff2) format("woff2-variations"); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

/* The font alternatives, switched by data-font on <html> (see /options/fonts/). */
:root[data-font="archivo"] { --font: "Archivo", sans-serif; --display: "Archivo", sans-serif; --display-w: 800; --display-stretch: 72%; --mono: "Archivo", sans-serif; --mono-stretch: 80%; }
:root[data-font="saira"] { --font: "Saira", sans-serif; --display: "Saira", sans-serif; --display-w: 700; --display-stretch: 75%; --mono: "Saira", sans-serif; --mono-stretch: 80%; }

/* ---------- tokens: one set for the whole site ----------
   Light first, like a datasheet; the dark theme swaps the colour tokens only. */
:root {
  --bg: #f3f1ea; --bg-2: #e9e6dc; --bg-3: #dcd9ce; --ink: #1b1b17; --ink-2: #5c5d55; --rule: #cfccc0;
  --hot: #c8440c; --hot-ink: #fff; --hot-text: #a63a0c; --link: #9a370b;
  --todo: #f3dd6d; --todo-ink: #3a3000; --cloud-bg: #f3f1ea; --plate: #e9e6dc; --stage: #0f110f;
  --font: "Barlow", "Helvetica Neue", Arial, sans-serif;
  --display: "Barlow Condensed", "Arial Narrow", sans-serif; --display-w: 700; --display-stretch: 100%;
  --mono: "Barlow Condensed", "Arial Narrow", sans-serif; --mono-stretch: 100%;
  /* type scale */
  --t-label: 13px; --t-caption: 14px; --t-small: 16px; --t-body: 18px; --t-lede: 21px; --t-h3: 23px; --t-h2: 34px; --t-h1: 46px; --t-display: clamp(50px, 7.4vw, 110px);
  /* spacing scale */
  --s1: 8px; --s2: 16px; --s3: 24px; --s4: 32px; --s5: 48px; --s6: 64px; --s7: 96px;
  /* grid */
  --max: 1280px; --gutter: 24px; --pad: 32px;
  /* motion */
  --ease: cubic-bezier(.2, .7, .2, 1);
  color-scheme: light;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #141614; --bg-2: #1c1f1c; --bg-3: #262a26; --ink: #e8e6dd; --ink-2: #a3a59b; --rule: #30342f;
    --hot: #ff6a2b; --hot-ink: #160700; --hot-text: #ff8a55; --link: #ff8a55;
    --todo: #574800; --todo-ink: #fff0a8; --cloud-bg: #141614; --plate: #1c1f1c; color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --bg: #141614; --bg-2: #1c1f1c; --bg-3: #262a26; --ink: #e8e6dd; --ink-2: #a3a59b; --rule: #30342f;
  --hot: #ff6a2b; --hot-ink: #160700; --hot-text: #ff8a55; --link: #ff8a55;
  --todo: #574800; --todo-ink: #fff0a8; --cloud-bg: #141614; --plate: #1c1f1c; color-scheme: dark;
}

/* A shot with a dark twin: show the one that matches the theme. */
.img-dark { display: none; }
:root[data-theme="dark"] .img-dark { display: block; }
:root[data-theme="dark"] .img-light { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .img-dark { display: block; }
  :root:not([data-theme="light"]) .img-light { display: none; }
}

/* ---------- base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body { margin: 0; background: var(--bg); color: var(--ink); font: 400 var(--t-body)/1.55 var(--font); -webkit-font-smoothing: antialiased; transition: background-color .3s, color .3s; }
img, svg, canvas, video { display: block; max-width: 100%; }
img, video { height: auto; }
h1, h2, h3, h4, p, dl, dd, dt, ul, ol, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: inherit; text-decoration-color: var(--hot); text-decoration-thickness: 1px; text-underline-offset: .18em; transition: color .15s; }
a:hover { color: var(--link); }
:focus-visible { outline: 2px solid var(--hot); outline-offset: 3px; }
::selection { background: var(--hot); color: var(--hot-ink); }
button, input, select, textarea { font: inherit; }
mark.todo { background: var(--todo); color: var(--todo-ink); padding: 0 .25em; }
.skip { position: absolute; left: 8px; top: -60px; z-index: 20; padding: 8px 12px; background: var(--hot); color: var(--hot-ink); }
.skip:focus { top: 8px; }

/* ---------- primitives ---------- */
.wrap { max-width: var(--max); margin: 0 auto; padding-left: var(--pad); padding-right: var(--pad); }
.grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gutter); }
.col-3 { grid-column: span 3; } .col-7 { grid-column: span 7; } .col-9 { grid-column: span 9; } .col-12 { grid-column: 1 / -1; }
.label, .kicker, .crumbs, .tags, .see, .spec dt, .pager span, .step-count, .pod-lbl, .rp-h, .sn-auto, .pc-legend, .pc-controls, .pc-readout, .tw-row, .fit-table, .vs-time, .vs-osd {
  font-family: var(--mono); font-stretch: var(--mono-stretch); font-size: var(--t-label); font-weight: 600; line-height: 1.4; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.label a, .see a { text-decoration-color: var(--rule); }
/* Inline links in small text keep a 24 px tap target; block padding on an inline does not move the lines. */
.label a, .caption a, .crumbs a, .see a, .egg { padding-block: 5px; }
.num { color: var(--hot-text); }
.caption, figcaption, .credit, .hero-caption, .avail, .glance, .demo-noscript { font-family: var(--mono); font-stretch: var(--mono-stretch); font-size: var(--t-caption); font-weight: 500; line-height: 1.45; letter-spacing: .02em; color: var(--ink-2); }
.fig { color: var(--hot-text); font-weight: 700; margin-right: .4em; }
.arr { font-family: var(--mono); display: inline-block; transition: transform .2s var(--ease); }
h2 { font: 600 var(--t-h2)/1.1 var(--font); letter-spacing: -.01em; text-wrap: balance; }
h3, .h3 { font: 600 var(--t-h3)/1.25 var(--font); letter-spacing: -.01em; text-wrap: balance; }
h3 a { text-decoration: none; }
h3 a:hover { color: var(--link); }
p { text-wrap: pretty; }
.sum { font-size: var(--t-small); line-height: 1.5; color: var(--ink-2); }
.sum a, .intro a, .lede a, .prose a { text-decoration-line: underline; }
.lede { font-size: var(--t-small); color: var(--ink-2); margin-top: var(--s2); max-width: 36ch; }
.tags { margin-top: var(--s1); }
.plate { background: var(--plate); border: 1px solid var(--rule); transition: border-color .2s; }
.btn { display: inline-flex; align-items: center; min-height: 40px; padding: 8px 16px; border: 1px solid var(--rule); background: var(--bg); color: var(--ink); text-decoration: none; font-weight: 600; font-size: var(--t-small); line-height: 1.2; cursor: pointer; transition: border-color .15s, color .15s, background-color .15s; }
.btn:hover { border-color: var(--hot); color: var(--hot-text); }
.btn-hot, .btn--hot { background: var(--hot); border-color: var(--hot); color: var(--hot-ink); }
.btn-hot:hover, .btn--hot:hover { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.btn--todo { border-style: dashed; }
.actions { display: flex; flex-wrap: wrap; gap: var(--s1); margin-top: var(--s3); }
.more { display: inline-flex; align-items: center; gap: .35em; min-height: 24px; margin-top: var(--s1); font-size: var(--t-small); font-weight: 600; }
.more:hover .arr { transform: translateX(4px); }
.sum-more { white-space: nowrap; font-weight: 600; text-decoration: none; }
.sum-more:hover .arr { transform: translateX(4px); }
.chip, .step-bar button, .vs-bar button, .vs-clips button, .sn-tool { font-family: var(--mono); font-stretch: var(--mono-stretch); font-size: var(--t-label); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; line-height: 1; min-height: 32px; padding: 6px 10px; border: 1px solid var(--rule); background: var(--bg); color: var(--ink); cursor: pointer; transition: border-color .15s, color .15s; }
.chip:hover, .step-bar button:hover, .vs-bar button:hover, .vs-clips button:hover { border-color: var(--hot); color: var(--hot-text); }
.step-bar button[aria-pressed="true"], .step-bar button.hot { background: var(--hot); color: var(--hot-ink); border-color: var(--hot); }
.field, .step-bar select, .pc-controls select, .rp-field input, .rp-field select, .rp-field textarea { font: var(--t-small) var(--font); color: var(--ink); background: var(--bg); border: 1px solid var(--rule); padding: 6px 9px; }
.rp-field input:focus, .rp-field select:focus, .rp-field textarea:focus, .step-bar select:focus { outline: 2px solid var(--hot); outline-offset: 0; }
input[type="range"], input[type="checkbox"] { accent-color: var(--hot); }

/* ---------- top bar: the same on every page ---------- */
/* Sticky and opaque, so the sections are one click away from anywhere on the page; anchors stop below it. */
.top { position: sticky; top: 0; z-index: 30; background: var(--bg); border-bottom: 1px solid var(--rule); transition: background-color .3s; }
:root { --bar: 64px; scroll-padding-top: var(--bar); }
.top-in { height: var(--bar); display: flex; align-items: center; gap: var(--s3); }
.brand { display: flex; align-items: baseline; gap: 10px; font-size: 20px; font-weight: 600; text-decoration: none; white-space: nowrap; }
.brand-photo { align-self: center; width: 36px; height: 36px; border-radius: 50%; overflow: hidden; background: var(--bg-3); flex: none; }
.brand-photo img { width: 100%; height: 100%; object-fit: cover; }
.brand-role { font-family: var(--mono); font-stretch: var(--mono-stretch); font-size: var(--t-label); font-weight: 600; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-2); }
.top nav { margin-left: auto; display: flex; gap: var(--s2); }
.top nav a { position: relative; font-family: var(--mono); font-stretch: var(--mono-stretch); font-size: 17px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; text-decoration: none; color: var(--hot-text); padding: 10px 6px; }
.top nav a::after { content: ""; position: absolute; left: 6px; right: 6px; bottom: 5px; height: 2px; background: var(--hot); transform: scaleX(0); transform-origin: left; transition: transform .25s var(--ease); }
.top nav a:hover, .top nav a:focus-visible { color: var(--ink); }
.top nav a:hover::after, .top nav a:focus-visible::after { transform: scaleX(1); }
.theme-toggle { font-family: var(--mono); font-stretch: var(--mono-stretch); font-size: 15px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; line-height: 1; color: var(--ink-2); background: none; border: 1px solid var(--rule); padding: 7px 10px; cursor: pointer; transition: border-color .15s, color .15s; }
.theme-toggle:not(.on) { visibility: hidden; }
.cbar .theme-toggle { margin-left: auto; min-height: 34px; }
.theme-toggle:hover { color: var(--hot-text); border-color: var(--hot); }
.t-dark { display: none; }
:root[data-theme="light"] .t-dark { display: inline; }
:root[data-theme="light"] .t-light { display: none; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .t-dark { display: inline; }
  :root:not([data-theme="dark"]) .t-light { display: none; }
}

/* ---------- contact bar: fixed at the bottom of every window, like the top bar ---------- */
:root { --cbar: 52px; }
body { padding-bottom: var(--cbar); }
.cbar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 30; height: var(--cbar); background: var(--bg); border-top: 1px solid var(--rule); transition: background-color .3s; }
.cbar-in { height: 100%; display: flex; align-items: center; gap: var(--s3); }
.cbar-mail { font-size: var(--t-small); }
.cbar-mail a { text-decoration-line: underline; text-decoration-color: var(--rule); }
.cbar .btn { min-height: 34px; padding: 5px 14px; }
@media (max-width: 720px) {
  :root { --cbar: 52px; }
  .cbar-mail { display: none; }
  .cbar .btn { flex: 1; justify-content: center; padding: 6px 4px; }
}

/* ---------- the hero becomes the top bar (home.js adds .morph on the home page) ----------
   On the first screen there is no bar: the hero's name and role are the banner. Once the name has scrolled under
   the bar's place, the bar fades in and its name and role fly in from the hero's (a FLIP in home.js), and back.
   Without scripts the bar is the normal sticky one. A link in the hidden bar shows it when it takes focus. */
.morph .top { position: fixed; left: 0; right: 0; transition: opacity .3s var(--ease), background-color .3s; }
.morph:not(.bar-on) .top:not(:focus-within) { opacity: 0; pointer-events: none; }
/* The contact bar leaves with the top bar: none on the first screen, it slides up when the top bar fades in (owner, 2026-10-21). */
.morph .cbar { transition: opacity .3s var(--ease), transform .3s var(--ease), background-color .3s; }
.morph:not(.bar-on) .cbar:not(:focus-within) { opacity: 0; transform: translateY(100%); pointer-events: none; }
.brand-photo, .brand-name, .brand-role { transform-origin: 0 0; }
@media (max-width: 720px) {
  /* Fixed on phones too, both rows, kept short. */
  .morph { --bar: 92px; }
  .morph .top { top: 0; }
  .morph .top-in { padding-top: 6px; }
  .brand-role { display: none; }
  .brand-photo { width: 30px; height: 30px; }
}

/* ---------- hero: a full-width band; the live point cloud fills it, the text sits on the grid over a gradient ---------- */
.hero { position: relative; overflow: hidden; border-bottom: 1px solid var(--rule); background: var(--cloud-bg); }
.hero-cloud { position: absolute; inset: 0; width: 100%; height: 100%; --cx: .78; --cy: .5; }
/* The cloud behind the whole home page (owner's experiment, 2026-10-29): hero.js adds .cloud-fixed on wide screens with
   motion; the canvas then stays fixed behind every section and fades to a faint backdrop past the hero. */
.hero.cloud-fixed { background: none; }
.hero.cloud-fixed .hero-cloud { position: fixed; inset: 0; height: 100vh; z-index: -1; pointer-events: none; }
.hero::before { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(90deg, var(--bg) 0%, var(--bg) 32%, color-mix(in srgb, var(--bg) 85%, transparent) 50%, color-mix(in srgb, var(--bg) 35%, transparent) 64%, transparent 76%); }
.hero-in { position: relative; z-index: 1; min-height: min(calc(100svh - var(--bar) - 1px), 800px); align-content: center; padding-top: var(--s5); padding-bottom: var(--s4); }
.hero-head .kicker { color: var(--ink-2); }
.hero h1 { font-family: var(--display); font-weight: var(--display-w); font-stretch: var(--display-stretch); font-size: var(--t-display); line-height: .9; letter-spacing: -.01em; text-transform: uppercase; margin-top: var(--s1); margin-left: -.03125em; } /* the E's left side bearing, so the name's stem lines up with the photo and the text */
.hero-lead { display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: var(--s3); align-items: start; margin-top: var(--s3); }
.portrait { width: 96px; height: 96px; background: var(--bg-3); border: 1px solid var(--rule); }
.portrait img { width: 100%; height: 100%; }
.portrait--bare { border-color: transparent; background: none; }
.headline { font-size: var(--t-lede); line-height: 1.35; font-weight: 500; text-wrap: balance; }
.intro { color: var(--ink-2); max-width: 60ch; margin-top: var(--s2); }
.avail { margin-top: var(--s2); max-width: 60ch; }
.glance { list-style: none; padding: 0; margin: var(--s3) 0 0; color: var(--ink); font-size: var(--t-small); } /* a step above the captions (owner, 2026-10-21) */
.glance li { display: grid; grid-template-columns: 8.5em minmax(0, 1fr); gap: var(--s2); }
.glance li span:first-child { color: var(--ink-2); font-variant-numeric: tabular-nums; } /* the years line up: "2020" is as wide as "2017" */
.hero-caption { margin-top: var(--s4); max-width: 90ch; }
/* Wide windows: the text block moves left by half the outer margin (less empty background beside it), and the cloud's
   caption sits in the bottom-right corner, over the cloud it describes (from 1200 px, clear of the text). Narrower windows keep both in the flow. */
@media screen and (min-width: 861px) { .hero-in.wrap { margin-left: max(0px, (100vw - var(--max)) / 4); } }
@media screen and (min-width: 1200px) { /* the caption is placed in .hero-in, whose right edge is 3/4 of the outer margin in from the window's */
  .hero-caption.col-12 { position: absolute; right: calc(var(--pad) - max(0px, 100vw - var(--max)) * 3 / 4); bottom: var(--s3); max-width: 58ch; margin: 0; text-align: right; } /* 58ch: the caption fits in three lines (owner, 2026-10-29) */
}

/* ---------- sections: a rail (number, title, lede) beside nine columns of content ---------- */
.sec { border-top: 1px solid var(--rule); padding: var(--s6) 0; }
.rail { align-self: start; position: sticky; top: calc(var(--bar) + var(--s3)); }
.rail h2 { margin-top: var(--s1); }

/* Cards: work and projects share one card. The media is a 16:10 plate that shows the still uncropped; on hover
   the plate's border turns orange, the still zooms a little, a demo loop plays, and a project's second image pops
   up over its cover (hover devices only; the keyboard gets the same through focus). */
.cards { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s4) var(--gutter); }
.card { display: grid; align-content: start; gap: var(--s1); }
.card .cover { position: relative; display: block; aspect-ratio: 16 / 10; overflow: hidden; }
.card .cover > img, .card .cover > video { width: 100%; height: 100%; object-fit: contain; transition: transform .6s var(--ease); }
.card .peek { position: absolute; inset: 0; opacity: 0; transform: translateY(14%); transition: opacity .3s var(--ease), transform .5s var(--ease); pointer-events: none; background: var(--plate); }
.card .peek img { width: 100%; height: 100%; object-fit: cover; }
/* A project whose page leads with a diagram uses it as the card's cover too, on every screen size. */
.card .cover > .diagram { display: block; width: 100%; height: 100%; padding: var(--s1); }
.cover-text { display: grid; place-items: center; width: 100%; height: 100%; font-family: var(--display); font-weight: var(--display-w); font-stretch: var(--display-stretch); font-size: var(--t-h2); line-height: 1; text-transform: uppercase; color: var(--ink-2); }
.card .label { margin-top: var(--s1); }
.card h3 { font-size: 21px; }
.card .sum { margin-top: 0; }
/* A card says it opens: it lifts a little and an arrow follows its title on hover or keyboard focus. */
.card h3 a::after { content: "\2192" / ""; position: absolute; padding-left: .3em; opacity: 0; transition: opacity .2s; } /* out of the flow: it never makes a title wrap */
.card:focus-within h3 a::after { opacity: 1; }
@media (hover: hover) {
  .card { transition: translate .2s var(--ease); } /* translate, not transform: the scroll-in rise animation owns transform */
  .card:hover, .card:focus-within { translate: 0 -3px; }
  .card:hover h3 a::after { opacity: 1; }
  .card:hover .cover, .card:focus-within .cover { border-color: var(--hot); }
  .card:hover .cover > img, .card:hover .cover > video, .card:focus-within .cover > img, .card:focus-within .cover > video { transform: scale(1.03); }
  .card:hover .peek, .card:focus-within .peek { opacity: 1; transform: none; }
  .card:hover h3 a, .card:focus-within h3 a { color: var(--link); }
  .card:hover .arr { transform: translateX(4px); }
}

/* Skills */
.defs { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 var(--gutter); border-top: 1px solid var(--rule); }
.defs div { padding: var(--s2) 0 var(--s3); border-bottom: 1px solid var(--rule); }
.defs dt { font-weight: 600; }
.defs dd { margin-top: 4px; font-size: var(--t-small); color: var(--ink-2); }
.see { display: block; margin-top: var(--s1); line-height: 2; }
.see a { color: var(--ink); }
/* The Skills showcase links: the arrow in the section numbers' accent, nudged on hover like the Work tiles' (owner, 2026-10-29). */
.see .arr { color: var(--hot-text); }
.see a:hover .arr, .see a:focus-visible .arr { transform: translateX(4px); }
.see a:hover { text-decoration-color: var(--hot-text); } /* optional extra: the underline takes the accent on hover */
.see:empty { display: none; }
/* The accent on screen: each skill numbered like the section headings and a short accent tick where its rule starts.
   On screen each skill hangs from a rule above it, so a row of skills shares one rule (owner, 2026-10-22: no line
   under each one, no accent underline on the links). Nothing here adds height, so the pager page still fits from 780 px. */
@media screen {
  .defs { counter-reset: skill; border-top: 0; }
  .defs > div { counter-increment: skill; border-bottom: 0; border-top: 1px solid var(--rule); background: linear-gradient(var(--hot), var(--hot)) 0 0 / 32px 3px no-repeat; }
  .defs dt::before { content: counter(skill, decimal-leading-zero) / ""; margin-right: .6em; font-family: var(--mono); font-stretch: var(--mono-stretch); font-size: var(--t-label); letter-spacing: .08em; color: var(--hot-text); font-variant-numeric: tabular-nums; }
}

/* CV: the timeline (horizontal on wide screens, vertical on narrow ones) above the list. */
.timeline { margin-bottom: var(--s4); padding: var(--s2) var(--s2) var(--s1); background: var(--bg-2); border: 1px solid var(--rule); }
.timeline svg { width: 100%; height: auto; overflow: visible; }
.timeline--tall { display: none; }
.tl-axis path { stroke: var(--ink-2); stroke-width: 1; }
.tl-axis text { font: 600 14px var(--mono); fill: var(--ink-2); text-anchor: middle; }
.timeline--tall .tl-axis text { text-anchor: end; }
.tl-bar rect { fill: var(--hot); }
.tl-bar text { font: 600 14px var(--font); fill: var(--hot-ink); }
.tl-bar text.out { fill: var(--ink); }
.tl-bar path { fill: none; stroke: var(--ink-2); stroke-width: 1; }
.tl-project rect { fill: none; stroke: var(--hot); stroke-width: 2; stroke-dasharray: 6 4; } /* a personal project, not a job */
.tl-bar.tl-project text { fill: var(--ink); }
.tl-mark circle { fill: var(--bg); stroke: var(--ink); stroke-width: 2; }
.tl-mark text { font: 14px var(--font); fill: var(--ink-2); }
.tl-mark .y { fill: var(--ink-2); font-weight: 400; }
/* An entry and its row light up together (home.js): the others step back. */
.timeline g[data-k], .cvrows li { transition: opacity .2s; }
.timeline:has(.lit) g[data-k]:not(.lit), .cvrows:has(.lit) li:not(.lit) { opacity: .35; }
.cvrows li.lit { box-shadow: inset 0 3px 0 var(--hot); }
.cvrows li[tabindex]:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
.cvrows { border-top: 1px solid var(--rule); }
.cvrows li { display: grid; grid-template-columns: 140px minmax(0, 1fr); gap: var(--gutter); padding: var(--s2) 0; border-bottom: 1px solid var(--rule); }
/* A linked row is one link: title, organisation and text, with the Skills links' arrow and hover. */
.cvrows .rowlink { display: block; color: inherit; text-decoration: none; }
.cvrows .rowlink h3 { text-decoration: underline; text-decoration-color: var(--rule); text-underline-offset: 3px; }
.cvrows .rowlink:hover h3, .cvrows .rowlink:focus-visible h3 { text-decoration-color: var(--hot-text); }
.cvrows .rowlink .arr { color: var(--hot-text); }
.cvrows .rowlink:hover .arr, .cvrows .rowlink:focus-visible .arr { transform: translateX(4px); }
.cv-when { padding-top: 5px; }
.cvrows h3 { font-size: var(--t-body); }
.cv-org { font-size: var(--t-small); color: var(--ink-2); }
.cvrows .sum { margin-top: 4px; max-width: 64ch; }



/* Footer */
.foot { border-top: 1px solid var(--rule); }
.foot .wrap { padding-top: var(--s3); padding-bottom: var(--s6); display: grid; gap: 4px; }
.egg { background: none; border: 0; padding: 0; color: inherit; font: inherit; text-decoration: underline dotted; cursor: pointer; }

/* ---------- inner pages: a document on the same grid ---------- */
.doc { padding-top: var(--s5); padding-bottom: var(--s6); row-gap: var(--s4); }
.crumbs { margin-bottom: var(--s2); }
.crumbs a { text-decoration: none; }
.crumbs a:hover { color: var(--ink); }
.doc-head h1 { font: 600 var(--t-h1)/1.05 var(--font); letter-spacing: -.015em; max-width: 20ch; text-wrap: balance; }
.doc-head .headline { max-width: 60ch; margin-top: var(--s2); }
.spec div { padding: var(--s2) 0; border-top: 1px solid var(--rule); }
.spec div:last-child { border-bottom: 1px solid var(--rule); }
.spec dd { margin-top: 2px; font-size: var(--t-small); line-height: 1.45; }
.note { padding: var(--s2) var(--s3); margin-bottom: var(--s3); background: var(--plate); border: 1px solid var(--rule); font-size: var(--t-small); color: var(--ink-2); }
.note strong { color: var(--hot-text); margin-right: .5em; }
.cover img, .cover svg { width: 100%; }
.cover figcaption, .shot figcaption, .demo figcaption, .model figcaption { padding-top: var(--s1); }
.prose { max-width: 66ch; margin-top: var(--s4); display: grid; gap: var(--s2); }
.prose > p:first-child { font-size: var(--t-lede); line-height: 1.45; }
.prose h2 { font-size: var(--t-h3); margin-top: var(--s2); }
.prose h2:first-child { margin-top: 0; }
.dashes { display: grid; gap: var(--s1); }
.dashes li { position: relative; padding-left: 1.2em; color: var(--ink-2); }
.dashes li::before { content: "-"; position: absolute; left: 0; color: var(--hot-text); }
.gallery { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--s3) var(--gutter); margin-top: var(--s5); }
.shot { display: grid; grid-template-rows: minmax(0, 1fr) auto; }
.shot img, .shot video { width: 100%; align-self: center; border: 1px solid var(--rule); background: var(--plate); }
.span-12 { grid-column: span 12; } .span-6 { grid-column: span 6; } .span-4 { grid-column: span 4; } .span-3 { grid-column: span 3; }
.credit { margin-top: var(--s3); }
.pager { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gutter); padding-top: var(--s3); border-top: 1px solid var(--rule); }
.pager a { display: grid; gap: 4px; text-decoration: none; font-weight: 600; font-size: var(--t-h3); letter-spacing: -.01em; text-wrap: balance; }
.pager a[rel="next"] { text-align: right; }
.pager a:hover { color: var(--link); }

/* ---------- demos and the 3D viewer ---------- */
.model-stage, .demo-stage { position: relative; background: var(--stage); }
.model-stage img, .model-stage canvas, .demo-stage img, .demo-stage > canvas { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; }
.demo-stage canvas, .model-stage canvas { touch-action: none; cursor: grab; }
.model-btn, .demo-btn { position: absolute; left: var(--s2); bottom: var(--s2); min-height: 40px; padding: 8px 16px; font: 600 var(--t-small)/1.2 var(--font); background: var(--hot); color: var(--hot-ink); border: 0; cursor: pointer; }
.model-btn:hover, .demo-btn:hover { background: #fff; color: #000; }
.model-btn[hidden], .demo-btn[hidden], .js-only[hidden] { display: none; }
.demo-noscript { margin-top: var(--s1); }
.demo-reserve { min-height: var(--r1); }
.demo-panel { display: grid; gap: var(--s2); padding: var(--s2); background: var(--bg-2); border: 1px solid var(--rule); border-top: 0; }
.step-bar { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.step-text { max-width: 76ch; font-size: var(--t-small); }
.sn-auto { display: inline-flex; align-items: center; gap: 6px; }
.pc-controls { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; gap: 8px 14px; align-items: center; }
.pc-controls input[type="range"] { width: 100%; }
.pc-readout { text-transform: none; letter-spacing: .02em; line-height: 1.5; }
.pc-profile { width: 100%; height: 240px; border: 1px solid var(--rule); }
.pc-legend { border: 0; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px 16px; }
.pc-legend legend { float: left; margin-right: 12px; color: var(--ink); }
.pc-legend label { display: inline-flex; align-items: center; gap: 6px; cursor: pointer; }
.pc-legend .sw, .fit-table .sw { width: 10px; height: 10px; display: inline-block; }
.tw-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 24px; }
.tw-row { display: grid; grid-template-columns: 11em minmax(0, 1fr) 4.5em; gap: 10px; align-items: center; }
.tw-row input { width: 100%; }
.tw-row output { text-align: right; }
.fit-table { border-collapse: collapse; width: 100%; }
.fit-table th, .fit-table td { text-align: left; padding: 5px 12px 5px 0; border-top: 1px solid var(--rule); }
.pod-lbl { min-width: 64px; }
.pod-log { margin: 0; min-height: 4.6em; font: var(--t-caption)/1.45 var(--mono); color: var(--ink-2); white-space: pre-wrap; }

/* SkyNav re-creation: tools | map | instruments, like the real app (its own colours: it is a picture of the cockpit UI). */
.sn { display: grid; grid-template-columns: 58px minmax(0, 1fr) 176px; background: #0b0f0c; color: #e8e4d8; }
.sn > canvas { width: 100%; aspect-ratio: 4 / 3; display: block; touch-action: none; }
.sn > canvas:focus-visible { outline: 2px solid var(--hot); outline-offset: -2px; }
.sn-tools { display: flex; flex-direction: column; gap: 4px; padding: 6px 4px; background: #151a16; }
.sn-tool { padding: 12px 0; min-height: 0; background: #222a24; color: #c9c5b8; border-color: #333c35; letter-spacing: .04em; }
.sn-tool[aria-pressed="true"] { background: #ff4d3d; color: #120604; border-color: #ff4d3d; }
.sn-tool:hover { border-color: #e8e4d8; color: #e8e4d8; }
.sn-inst { display: grid; grid-auto-rows: 1fr; gap: 3px; padding: 3px; background: #151a16; }
.sn-tile { background: #f1ede3; color: #111; display: grid; align-content: start; }
.sn-k { font: 700 12px var(--mono); background: #d6d1c4; padding: 3px 6px; }
.sn-v { font: 700 clamp(14px, 1.5vw, 22px)/1.15 var(--mono); padding: 4px 6px; overflow-wrap: anywhere; }
.sn-tile[data-state="slow"] .sn-v { color: #1f63d6; }
.sn-tile[data-state="fast"] .sn-v { color: #c8261a; }

/* Camera-model demo: world view beside the camera view. */
.cam-split { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; background: var(--stage); }
.cam-pane { margin: 0; position: relative; }
.cam-pane canvas { width: 100%; aspect-ratio: 4 / 3; display: block; }
.cam-pane figcaption { position: absolute; left: 10px; bottom: 8px; margin: 0; padding: 3px 7px; background: rgb(11 13 11 / .7); color: #e8e4d8; max-width: calc(100% - 20px); }
.cam-photo { position: relative; }
.cam-overlay { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

/* Report-generation demo: the form beside the page it fills; the page is paper, whatever the theme. */
.rp { background: var(--bg-2); padding: var(--s2); }
.rp-pipe { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: var(--s2); }
.rp-pipe li { padding: 10px 12px; border: 1px solid var(--rule); background: var(--bg); font-size: var(--t-small); position: relative; }
.rp-pipe li b { display: inline-grid; place-items: center; width: 22px; height: 22px; margin-right: 8px; background: var(--hot); color: var(--hot-ink); font-family: var(--mono); }
.rp-cols { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 7fr); gap: var(--s2); align-items: start; }
.rp-form { display: grid; gap: 10px; }
.rp-field { display: grid; gap: 4px; font-size: var(--t-small); color: var(--ink-2); }
.rp-toggle { margin-bottom: 8px; }
.rp-page { background: #fbfaf6; color: #1b1c19; padding: 26px 28px; aspect-ratio: 1 / 1.3; border: 1px solid var(--rule); font-family: var(--font); display: flex; flex-direction: column; gap: 12px; }
.rp-ph, .rp-pf { display: flex; justify-content: space-between; font: 600 .75rem var(--mono); color: #5c5c55; border-bottom: 1px solid #ddd8cc; padding-bottom: 6px; }
.rp-pf { border: 0; border-top: 1px solid #ddd8cc; padding-top: 6px; margin-top: auto; }
.rp-page h4, .rp-title { margin: 0; font-size: 1.5rem; font-family: var(--display); font-weight: var(--display-w); line-height: 1.1; }
.rp-dl { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; margin: 0; }
.rp-dl dt { font: 600 .7rem var(--mono); color: #5c5c55; text-transform: uppercase; }
.rp-dl dd { margin: 0; font-size: .95rem; }
.rp-imgs { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.rp-img { width: 100%; height: auto; display: block; }
.rp-ph-img { aspect-ratio: 32 / 22; border: 2px dashed #b9b3a4; display: grid; place-items: center; font-family: var(--mono); color: #8a8678; }
.rp-t { border-collapse: collapse; width: 100%; font-size: .9rem; }
.rp-t th { text-align: left; font: 600 .7rem var(--mono); color: #5c5c55; text-transform: uppercase; border-bottom: 1px solid #ddd8cc; padding: 4px 6px 4px 0; }
.rp-t td { padding: 6px 6px 6px 0; }
.rp-sev { font-weight: 600; }
.rp-sev-A { color: #b4230f; } .rp-sev-B { color: #b86a00; } .rp-sev-C { color: #5d6b12; } .rp-sev-D { color: #4a6a63; }
.rp-note { font-size: .95rem; }
.rp-slot { transition: background .6s; }
.rp-flash { background: #ffd8a8; }
.rp-bar { height: 6px; background: var(--bg-3); } .rp-bar i { display: block; height: 100%; width: 0; background: var(--hot); transition: width .1s; }
.rp-thumbs { display: flex; flex-wrap: wrap; gap: 5px; }
.rp-thumb { width: 26px; height: 34px; background: #fbfaf6; display: grid; gap: 3px; padding: 4px; border-top: 3px solid currentColor; }
.rp-thumb i { display: block; height: 3px; background: #cfcabd; }

/* Flight-video demo. */
.vs { display: grid; gap: 2px; background: var(--stage); }
.vs-vwrap { position: relative; }
.vs-video { display: block; width: 100%; aspect-ratio: 2.2 / 1; }
.vs-osd { position: absolute; left: 12px; top: 10px; color: #f2efe6; text-shadow: 0 1px 2px #000; white-space: pre; pointer-events: none; text-transform: none; letter-spacing: .04em; }
.vs-map { display: block; width: 100%; aspect-ratio: 600 / 160; cursor: pointer; }
.vs-bar { display: flex; gap: 10px; align-items: center; }
.vs-bar input { flex: 1; }
.vs-bar button { min-width: 64px; }
.vs-time { min-width: 104px; text-align: right; }
.vs-clips { display: flex; flex-wrap: wrap; gap: 6px; }
.vs-clips button { background: none; color: var(--hot-text); border-color: var(--hot); }

/* Detection demo: six photos of one spot beside the 3D proposals and the votes. */
.dt { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 2px; background: var(--stage); aspect-ratio: 16 / 10; overflow: hidden; }
.dt-photos { position: relative; display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: repeat(3, minmax(0, 1fr)); gap: 2px; min-height: 0; }
.dt-crop { margin: 0; position: relative; min-height: 0; overflow: hidden; }
.demo-stage .dt-crop[hidden], .demo-stage .dt-full[hidden] { display: none; }
.demo-stage .dt-crop canvas, .demo-stage .dt-full { width: 100%; height: 100%; object-fit: cover; display: block; cursor: default; touch-action: auto; }
.demo-stage .dt-full { position: absolute; inset: 0; object-fit: contain; }
.dt-crop figcaption, .dt-view figcaption { position: absolute; left: 6px; top: 6px; margin: 0; padding: 2px 6px; background: rgb(11 13 11 / .72); color: #e8e4d8; pointer-events: none; }
.dt-side { display: grid; grid-template-rows: minmax(0, 1fr) auto; min-height: 0; }
.dt-view { margin: 0; position: relative; min-height: 0; }
.dt-3d { width: 100%; height: 100%; display: block; }
.dt-votes { padding: 10px 14px 12px; color: #e8e4d8; background: #181b18; font-size: var(--t-small); }
.dt-votes p { margin: 0 0 6px; }
.dt-votes .label { color: #a3a59b; }
.dt-tally { display: flex; gap: 6px; margin: 6px 0 8px; }
.dt-tally span { flex: 1; text-align: center; padding: 5px 0 3px; border: 1px solid #30342f; font: var(--display-w) 22px/1 var(--display); color: #a3a59b; }
.dt-tally .on { border-color: var(--hot); color: #ff8a55; }
.dt-toggle { display: inline-flex; gap: 6px; align-items: center; }
.dt-toggle input { accent-color: var(--hot); margin: 0; }

/* Geotagger demo: two linked photo windows beside a QGIS-style map. The map is paper, whatever the theme. */
.gt { position: relative; display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 2px; background: var(--stage); aspect-ratio: 16 / 10; overflow: hidden; }
.gt-wins { display: grid; grid-template-rows: minmax(0, 1fr) minmax(0, 1fr); gap: 2px; min-height: 0; }
.gt-win { margin: 0; display: grid; grid-template-rows: auto minmax(0, 1fr); min-height: 0; background: #1c1f1c; }
.demo-stage .gt canvas { width: 100%; height: 100%; display: block; min-height: 0; touch-action: manipulation; }
.demo-stage .gt-win canvas { cursor: crosshair; }
.demo-stage .gt-map { cursor: pointer; }
.gt-title { margin: 0; padding: 4px 10px; background: #262a26; color: #e8e4d8; font-family: var(--mono); font-stretch: var(--mono-stretch); font-size: var(--t-label); font-weight: 600; letter-spacing: .06em; text-transform: uppercase; line-height: 1.5; }
.gt-qgis { display: grid; grid-template-rows: auto minmax(0, 1fr) auto; min-height: 0; background: #1c1f1c; }
.gt-body { display: grid; grid-template-columns: 9.5em minmax(0, 1fr); min-height: 0; }
.gt-side { padding: 8px 10px; color: #e8e4d8; border-right: 1px solid #30342f; }
.gt-side .label { color: #a3a59b; margin: 0; }
.gt-layers { list-style: none; margin: 6px 0 0; padding: 0; font-size: var(--t-caption); }
.gt-layers label { display: flex; gap: 6px; align-items: center; padding: 3px 0; cursor: pointer; }
.gt-layers input { accent-color: var(--hot); margin: 0; }
.gt-layers i { width: 10px; height: 10px; flex: none; }
.gt-status { margin: 0; padding: 4px 10px; background: #262a26; color: #a3a59b; font-family: var(--mono); font-stretch: var(--mono-stretch); font-size: var(--t-caption); font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gt-cursor { position: absolute; left: 0; top: 0; width: 24px; height: 24px; margin: -2px 0 0 -3px; pointer-events: none; transition: transform .8s var(--ease); background: no-repeat center / contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M3 2l15 9.5-6.6 1.2 3.8 7.4-2.8 1.4-3.8-7.4L3 18.5z' fill='%23fff' stroke='%23111' stroke-width='1.4' stroke-linejoin='round'/%3E%3C/svg%3E"); }
.gt-cursor[hidden] { display: none; }

/* Bundle-adjustment demo: the photos and keypoint rays in 3D beside the photo being corrected, the error curve and the numbers. */
.prose + .demo { margin-top: var(--s3); }
.ba { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: 2px; background: var(--stage); aspect-ratio: 16 / 10; overflow: hidden; }
.ba figure { margin: 0; position: relative; min-height: 0; }
.demo-stage .ba canvas { width: 100%; height: 100%; display: block; }
.demo-stage .ba-photo, .demo-stage .ba-chart { cursor: default; touch-action: auto; }
.ba figcaption { position: absolute; left: 6px; top: 6px; margin: 0; padding: 2px 6px; background: rgb(11 13 11 / .72); color: #e8e4d8; pointer-events: none; }
.ba-side { display: grid; grid-template-rows: minmax(0, 5fr) minmax(0, 3fr) auto; gap: 2px; min-height: 0; }
.ba-shots { list-style: none; margin: 0; padding: 6px 8px; display: grid; grid-template-columns: 1fr 1fr; gap: 2px 10px; background: #181b18; color: #c9c7bd; font: 500 var(--t-label)/1.3 var(--mono); }
.ba-shots li { display: flex; gap: 6px; align-items: baseline; min-width: 0; }
.ba-shots span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ba-shots li { justify-content: space-between; }
.ba-shots .ba-k { color: #a3a59b; }
.ba-shots .ba-held span:last-child { color: #e0523a; }

/* The home-server diagram: wide on wide screens, stacked on narrow ones. */
.diagram { padding: var(--s3); background: var(--bg-2); }
.diagram--tall { display: none; }
.diagram .box { fill: var(--bg); stroke: var(--ink-2); stroke-width: 1.2; }
.diagram .hot { stroke: var(--hot); stroke-width: 2; }
.diagram .wire { fill: none; stroke: var(--ink-2); stroke-width: 1.2; }
.diagram text { text-anchor: middle; fill: var(--ink); font-family: var(--font); }
.diagram .t { font-size: 22px; font-weight: 600; }
.diagram .s { font: 600 15px var(--mono); fill: var(--ink-2); }
.diagram--tall .t { font-size: 17px; }
.md-k { font: 700 14px var(--mono); letter-spacing: .12em; fill: var(--hot-text) !important; text-anchor: start !important; }
/* A day on the home server: the map lights the paths of the event at the clock's time. */
.dy-fw { fill: none; stroke: var(--hot); stroke-width: 2.5; stroke-dasharray: 10 6; }
.dy .dy-fwt { font-size: 11px; }
.dy-zone { fill: none; stroke: var(--hot); stroke-width: 1.5; stroke-dasharray: 4 5; opacity: .7; }
.dy .t { font-size: 19px; } .dy .s { font-size: 13px; }
.dy.diagram--tall .t { font-size: 15px; } .dy.diagram--tall .s { font-size: 11px; }
.dy-band { opacity: .35; }
.dy-zone + .md-k { opacity: 1; }
.dy-e { transition: stroke .3s, opacity .3s; }
.day.js .dy-e { opacity: .35; }
.day .dy-e.on { stroke: var(--hot); stroke-width: 3; opacity: 1; stroke-dasharray: 8 6; animation: dy-flow .6s linear infinite; }
@keyframes dy-flow { to { stroke-dashoffset: -14; } }
.day .dy-n.on .box { stroke: var(--hot); stroke-width: 2.5; fill: var(--bg); }
.day-ui { display: grid; gap: var(--s1); padding: 0 var(--s3) var(--s2); background: var(--bg-2); }
.day-ui[hidden] { display: none; }
.day-clock { display: flex; align-items: center; gap: var(--s2); }
.day-time { font: var(--display-w) 40px/1 var(--display); color: var(--hot-text); font-variant-numeric: tabular-nums; }
.day-play { font: 600 var(--t-label)/1 var(--mono); letter-spacing: .08em; text-transform: uppercase; min-height: 32px; padding: 6px 10px; border: 1px solid var(--rule); background: var(--bg); color: var(--ink); cursor: pointer; }
.day-track { position: relative; }
.day-track input { width: 100%; accent-color: var(--hot); }
.day-track i { position: absolute; top: -4px; width: 2px; height: 8px; background: var(--hot); pointer-events: none; }
.day-say { margin: 0; min-height: 3em; font-size: var(--t-small); max-width: 70ch; }
.day-list { margin: 0; padding: var(--s2) var(--s3); list-style: none; font-size: var(--t-small); background: var(--bg-2); }
.day-list[hidden] { display: none; }
.diagram--tall .s { font-size: 12px; }

/* The agent setup: three worktree lanes, each living through idea → agent → review → tests (fix until clean) → merge →
   cleanup in 18 s, a third of a cycle apart. The card, reduced motion and the still use the .lp-on frame. */
.ag .t { font-size: 18px; } .ag .s { font-size: 13px; }
.ag.diagram--tall .t { font-size: 14px; } .ag.diagram--tall .s { font-size: 11px; }
.ag-lane { fill: none; stroke: var(--rule); stroke-width: 1; stroke-dasharray: 4 5; }
.ag-k { font-size: 11px; }
.ag-tk { font-size: 11px; }
.ag-me .box, .ag-sup .box { stroke: var(--hot); stroke-width: 2; }
.ag-up { stroke: var(--hot); stroke-dasharray: 6 5; }
.ag-retry { stroke: var(--hot); stroke-dasharray: 5 4; opacity: .55; }
.ag-watch { stroke: var(--hot); stroke-width: 1.2; stroke-dasharray: 2 6; opacity: .8; }
.ag .ag-rk { font-size: 10px; }
.lp-on .box { stroke: var(--hot); stroke-width: 3; }
.lp-st { font-size: 11px; opacity: 0; } .lp-st.lp-on { opacity: 1; }
.ag.diagram--tall .lp-st { font-size: 9px; }
.lp-tok { fill: var(--hot); opacity: 0; }
@media (prefers-reduced-motion: no-preference) {
  .ag-fig .lp-L1 { --d: -6s; } .ag-fig .lp-L2 { --d: -12s; }
  .ag-fig .ag-f, .ag-fig .ag-down, .ag-fig .ag-up { stroke-dasharray: 6 5; animation: dy-flow .8s linear infinite; }
  .ag-fig .ag-up { animation-direction: reverse; }
  .ag-fig .ag-watch { animation: dy-flow 1.6s linear infinite; }
  .ag-fig .lp-lane, .ag-fig .lp-lane .box, .ag-fig .lp-st, .ag-fig .lp-retry, .ag-fig .lp-tok { animation: 18s linear infinite; animation-delay: var(--d, 0s); }
  .ag-fig .lp-lane { animation-name: lp-lane; }
  .ag-fig .lp-s0 .box { animation-name: lp-s0; } .ag-fig .lp-s1 .box { animation-name: lp-s1; }
  .ag-fig .lp-s2 .box { animation-name: lp-s2; } .ag-fig .lp-s3 .box { animation-name: lp-s3; }
  .ag-fig .lp-retry { animation-name: lp-retry; }
  .ag-fig .lp-st-new { animation-name: lp-st-new; } .ag-fig .lp-st-fix { animation-name: lp-st-fix; }
  .ag-fig .lp-st-merge { animation-name: lp-st-merge; } .ag-fig .lp-st-done { animation-name: lp-st-done; }
  .ag-fig .lp-tok { animation-name: lp-tok; } .ag-fig .lp-tok-v { animation-name: lp-tok-v; }
}
/* The lifecycle, in % of 18 s: 0–5 the lane appears, 6–22 agent, 22–34 review, 34–44 tests fail, 44–50 the fix goes
   back, 50–58 agent, 58–64 review, 64–72 tests pass, 72–84 merge, 84–92 merged, 92–98 the worktree is removed. */
@keyframes lp-lane { 0% { opacity: 0; } 5%, 91% { opacity: 1; } 98%, 100% { opacity: 0; } }
@keyframes lp-s0 { 0%, 5.9%, 22%, 49.9%, 58%, 100% { stroke: var(--ink-2); stroke-width: 1.2; } 6%, 21.9%, 50%, 57.9% { stroke: var(--hot); stroke-width: 3; } }
@keyframes lp-s1 { 0%, 21.9%, 34%, 57.9%, 64%, 100% { stroke: var(--ink-2); stroke-width: 1.2; } 22%, 33.9%, 58%, 63.9% { stroke: var(--hot); stroke-width: 3; } }
@keyframes lp-s2 { 0%, 33.9%, 44%, 63.9%, 72%, 100% { stroke: var(--ink-2); stroke-width: 1.2; } 34%, 43.9%, 64%, 71.9% { stroke: var(--hot); stroke-width: 3; } }
@keyframes lp-s3 { 0%, 71.9%, 92%, 100% { stroke: var(--ink-2); stroke-width: 1.2; } 72%, 91.9% { stroke: var(--hot); stroke-width: 3; } }
@keyframes lp-retry { 0%, 43.9%, 50%, 100% { opacity: .25; stroke-width: 1.2; } 44%, 49.9% { opacity: 1; stroke-width: 3; } }
@keyframes lp-st-new { 0%, 10% { opacity: 1; } 11%, 100% { opacity: 0; } }
@keyframes lp-st-fix { 0%, 43.9%, 58%, 100% { opacity: 0; } 44%, 57.9% { opacity: 1; } }
@keyframes lp-st-merge { 0%, 71.9%, 84%, 100% { opacity: 0; } 72%, 83.9% { opacity: 1; } }
@keyframes lp-st-done { 0%, 83.9% { opacity: 0; } 84%, 96% { opacity: 1; } 98%, 100% { opacity: 0; } }
@keyframes lp-tok { 0% { opacity: 1; transform: translateX(0); } 5% { opacity: 1; transform: translateX(100px); } 5.1%, 100% { opacity: 0; transform: translateX(100px); } }
@keyframes lp-tok-v { 0% { opacity: 1; transform: translateY(0); } 5% { opacity: 1; transform: translateY(24px); } 5.1%, 100% { opacity: 0; transform: translateY(24px); } }
@media print { .ag-fig { display: none; } }

/* ---------- /options/ pages (owner only) ---------- */
.fonts, .po-list { display: grid; gap: var(--s3); }
.fo, .po { display: grid; gap: var(--s2); padding: var(--s3); border: 1px solid var(--rule); background: var(--bg-2); }
.fo-display { font-family: var(--display); font-weight: var(--display-w); font-stretch: var(--display-stretch); font-size: var(--t-display); line-height: .9; text-transform: uppercase; }
.fo-text { font-size: var(--t-lede); max-width: 52ch; }
.fo-note { color: var(--ink-2); max-width: 70ch; font-size: var(--t-small); }
.fo .btn { justify-self: start; }
.po-pair { display: flex; flex-wrap: wrap; gap: var(--s2); }
.po-panel { display: grid; justify-items: start; gap: var(--s1); padding: var(--s3); }
.po-panel .portrait { width: 200px; height: 200px; margin: 0; }
.po-light { --bg-3: #dcd9ce; --rule: #cfccc0; background: #f3f1ea; color: #5c5d55; }
.po-dark { --bg-3: #262a26; --rule: #30342f; background: #141614; color: #a3a59b; }

/* The agents easter egg (press `): a terminal, so it keeps its own colours. */
.agents { position: fixed; right: 16px; bottom: calc(var(--cbar) + 12px); z-index: 50; width: min(560px, calc(100vw - 32px)); height: min(420px, 70vh); display: none; flex-direction: column; background: #0d100e; color: #d8e0d6; border: 1px solid #2b332d; box-shadow: 0 30px 80px -20px rgb(0 0 0 / .7); font: 14px/1.5 ui-monospace, Menlo, Consolas, monospace; }
.agents.on { display: flex; }
@media (max-width: 600px) { .agents { height: 36vh; font-size: 13px; } } /* the page above stays in view, where the agents work */
.ag-head { display: flex; justify-content: space-between; align-items: center; padding: 6px 10px; background: #18201b; color: #9fb19f; font-size: 12px; }
.ag-x { background: none; border: 0; color: inherit; font-size: 18px; cursor: pointer; }
.ag-out { flex: 1; overflow: auto; padding: 10px 12px; }
.ag-out p { margin: 0 0 2px; white-space: pre-wrap; }
.ag-you { color: #fff; } .ag-lead { color: #f2b56b; } .ag-b { color: #8fc7ff; } .ag-r { color: #c9a7ff; } .ag-ok { color: #7fe08a; } .ag-no { color: #ff7a6b; } .ag-dim { color: #7f8c80; }
.ag-cmds { display: flex; flex-wrap: wrap; gap: 6px; padding: 6px 12px 0; }
.ag-cmds button { background: none; border: 1px solid #2b332d; color: #9fb19f; font: inherit; font-size: 12px; padding: 2px 10px; cursor: pointer; }
.ag-cmds button:hover, .ag-cmds button:focus-visible { color: #fff; border-color: #7fe08a; }
.ag-form { display: flex; gap: 8px; padding: 8px 12px; border-top: 1px solid #2b332d; color: #7fe08a; }
.ag-form input { flex: 1; background: transparent; border: 0; color: #fff; font: inherit; outline: none; }
.agents-calm *, .agents-calm *::before, .agents-calm *::after { animation: none !important; transition: none !important; }
.ag-cur { position: fixed; left: 0; top: 0; z-index: 51; pointer-events: none; }
.ag-cur[hidden] { display: none; }
.ag-cur::before { content: ""; position: absolute; left: -3px; top: -3px; width: 18px; height: 22px; background: var(--c); clip-path: polygon(0 0, 100% 62%, 52% 68%, 30% 100%); }
.ag-cur span { position: absolute; left: 14px; top: 16px; padding: 1px 6px; background: var(--c); color: #0d100e; font: 600 12px/1.4 ui-monospace, Menlo, Consolas, monospace; white-space: nowrap; }
.ag-mark { position: fixed; z-index: 49; pointer-events: none; border: 2px dashed var(--c); animation: ag-in .3s ease-out; }
.ag-stamp { position: fixed; z-index: 51; pointer-events: none; padding: 4px 10px; background: #0d100e; color: #7fe08a; border: 2px solid #7fe08a; font: 600 12px/1.4 ui-monospace, Menlo, Consolas, monospace; transform: rotate(-2deg); animation: ag-in .25s ease-out; max-width: 300px; }
.ag-stamp.no { color: #ff7a6b; border-color: #ff7a6b; }
@keyframes ag-in { from { opacity: 0; transform: scale(1.08); } }

/* ---------- motion: a short rise as cards and rows enter the screen (scroll-driven, so it costs nothing) ---------- */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .card, .defs > div, .cvrows li, .shot { animation: rise linear both; animation-timeline: view(); animation-range: entry 0% entry 30%; }
    @keyframes rise { from { opacity: .85; transform: translateY(14px); } }
  }
}

/* ---------- breakpoints ---------- */
@media (max-width: 1199px) {
  .defs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 1023px) {
  .col-3, .col-9 { grid-column: 1 / -1; }
  .hero-text.col-7 { grid-column: span 8; }
  .rail { position: static; margin-bottom: var(--s3); }
  .rail .lede { max-width: 60ch; }
  .doc .rail { order: 1; } .doc .col-9 { order: 2; } .doc .pager { order: 3; }
  .spec { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0 var(--gutter); }
  .spec div:last-child { border-bottom: 0; }
  .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .demo-reserve { min-height: var(--r2); }
}
@media (max-width: 860px) {
  .hero-text.col-7 { grid-column: 1 / -1; }
  .timeline { display: none; }
  .timeline--tall { display: block; }
  .rp-cols { grid-template-columns: 1fr; } .rp-pipe { grid-template-columns: 1fr 1fr; } .rp-dl { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 760px) {
  .sn { grid-template-columns: 1fr; }
  .sn-tools { flex-direction: row; flex-wrap: wrap; } .sn-tool { flex: 1; padding: 8px 0; }
  .sn-inst { grid-template-columns: repeat(2, 1fr); grid-auto-rows: auto; }
  .sn > canvas { aspect-ratio: 4 / 5; }
  .cam-split { grid-template-columns: 1fr; }
  .dt, .gt, .ba { grid-template-columns: 1fr; aspect-ratio: auto; }
  .ba-view { aspect-ratio: 4 / 3; } .ba-inset { aspect-ratio: 3 / 2; } .ba-plot { aspect-ratio: 2 / 1; }
  .dt-photos { aspect-ratio: 1; }
  .dt-view { aspect-ratio: 4 / 3; }
  .gt-win canvas { aspect-ratio: 3 / 2; }
  .gt-body { grid-template-columns: 1fr; }
  .gt-side { border-right: 0; border-bottom: 1px solid #30342f; }
  .gt-layers { display: flex; flex-wrap: wrap; gap: 0 14px; }
  .demo-stage .gt-map { aspect-ratio: 4 / 3; height: auto; }
  .tw-grid { grid-template-columns: 1fr; } .tw-row { grid-template-columns: 9em minmax(0, 1fr) 4em; }
  .fit-table th:nth-child(4), .fit-table td:nth-child(4) { display: none; }
}
@media (max-width: 720px) {
  :root { --pad: 16px; --t-body: 17px; --t-h1: 34px; --t-h2: 28px; --t-h3: 21px; --t-lede: 19px; --s6: 48px; }
  /* Two rows: the name scrolls away, the section links stay (a negative sticky top, no script). */
  :root { --bar: 48px; }
  .top { top: -50px; }
  .top-in { height: auto; flex-wrap: wrap; padding-top: 10px; padding-bottom: 4px; row-gap: 2px; }
  .top nav { order: 3; width: 100%; margin: 0 -6px; gap: 2px; overflow-x: auto; }
  .top nav a { font-size: 16px; padding: 12px 6px; }
  /* The cloud takes the top of the band (4:3), drawn high so the kicker and the name below it sit on clear ground, the text follows on plain ground. */
  .hero-cloud { height: 75vw; bottom: auto; --cx: .5; --cy: .34; }
  .hero::before { background: linear-gradient(180deg, transparent 0, transparent 42vw, var(--bg) 75vw); }
  .hero-in { min-height: 0; padding-top: 0; padding-bottom: var(--s4); }
  .hero-head { min-height: calc(75vw - var(--s4)); display: grid; align-content: end; }
  .hero-head .kicker, .hero h1 { text-shadow: 0 0 12px var(--bg), 0 0 3px var(--bg); }
  .hero-lead { grid-template-columns: 72px minmax(0, 1fr); gap: var(--s2); }
  .portrait { width: 72px; height: 72px; }
  .cards { grid-template-columns: 1fr; }
  .defs { grid-template-columns: 1fr; }
  .cvrows li { grid-template-columns: 1fr; gap: var(--s1); }
  .spec { grid-template-columns: 1fr; }
  .spec div { display: grid; grid-template-columns: 7em minmax(0, 1fr); gap: var(--s2); padding: var(--s1) 0; }
  .spec dd { margin-top: 0; }
  .span-6 { grid-column: span 12; } .span-4 { grid-column: span 6; } .span-3 { grid-column: span 6; }
  .pager { grid-template-columns: 1fr; }
  .pager a[rel="next"] { text-align: left; }
  .diagram { display: none; padding: var(--s2); }
  .diagram--tall { display: block; }
  .demo-reserve { min-height: var(--r3); }
  .demo[data-demo="pod"] .demo-stage > canvas { aspect-ratio: 4 / 5; }
  .pc-controls { grid-template-columns: 1fr; } .pc-profile { height: 180px; }
  .fo, .po { padding: var(--s2); } .po-panel { padding: var(--s2); } .po-panel .portrait { width: 132px; height: 132px; }
}
/* ---------- compact home: each section is one screen at 1440 x 900 ----------
   The heading sits above the content, which takes the full width; Work shows two featured demos large (still, label, title, first sentence) and the rest as smaller text tiles,
   Projects keep their first sentence, Skills run in five columns. Every item keeps its own page for the detail. */
@media screen {
  .home .sec { padding: var(--s3) 0; }
  .home .sec > .grid > .rail { grid-column: 1 / -1; position: static; display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px var(--s3); margin-bottom: var(--s2); }
  .home .sec > .grid > .rail h2 { margin: 0; }
  .home .sec > .grid > .rail .lede { flex: 1 1 40ch; margin: 0; max-width: 100ch; }
  .home .sec > .grid > .col-9 { grid-column: 1 / -1; }
  .home .defs { grid-template-columns: repeat(5, minmax(0, 1fr)); } /* real rows, read left to right like the Work tiles */
  .home .defs dd { line-height: 1.45; }
  .home :is(#work, #projects) .feat { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s2) var(--gutter); }
  .home :is(#work, #projects) .mini { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s1) var(--gutter); margin-top: var(--s2); }
  .home :is(#work, #projects) .card { gap: 2px; }
  .home :is(#work, #projects) .card .cover { aspect-ratio: 16 / 7; }
  .home :is(#work, #projects) .card .cover > img, .home :is(#work, #projects) .card .cover > video { object-fit: cover; }
  .home :is(#work, #projects) .card .label { margin-top: 6px; }
  .home :is(#work, #projects) .card h3 { font-size: 19px; }
  .home :is(#work, #projects) .card .sum, .home :is(#work, #projects) .card .tags, .home :is(#work, #projects) .card .more { display: none; }
  .home :is(#work, #projects) .feat .sum { display: block; max-width: 70ch; }
  .home :is(#work, #projects) .feat .card h3 a::after { content: none; } /* the large cards end in "More →" instead */
  .home :is(#work, #projects) .mini .card { grid-template-columns: 96px minmax(0, 1fr); column-gap: 12px; align-items: start; align-content: start; border-top: 1px solid var(--rule); padding-top: 8px; } /* the smaller tiles: a rule, a thumbnail beside the label and the title */
  .home :is(#work, #projects) .mini .thumb { grid-row: 1 / span 3; aspect-ratio: 16 / 10; }
  .home :is(#work, #projects) .mini .thumb > img { object-fit: cover; }
  .home :is(#work, #projects) .card h3 a::after { position: static; opacity: 1; } /* Work tiles show their arrow at rest, in the flow */
  .home :is(#work, #projects) .mini .label { margin-top: 0; }
  .home :is(#work, #projects) .mini h3 { font-size: 17px; }
  .home #projects .mini { grid-template-columns: repeat(3, minmax(0, 1fr)); } /* three project tiles fill one row */
  .home #projects .mini { gap: var(--s2) var(--gutter); } /* and are medium cards: the image on top, a larger title (owner, 2026-10-29) */
  .home #projects .mini .card { grid-template-columns: 1fr; gap: 2px; padding-top: 12px; }
  .home #projects .mini .thumb { grid-row: auto; aspect-ratio: 16 / 8; }
  .home #projects .mini .label { margin-top: 6px; }
  .home #projects .mini h3 { font-size: 22px; }
  .home .timeline { margin-bottom: var(--s3); padding: var(--s1) var(--s2) 0; }
  .home .cvrows { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); column-gap: var(--gutter); }
  .home .cvrows li { grid-template-columns: 1fr; gap: 2px; padding: 12px 0; align-content: start; }
  .home .cv-when { padding-top: 0; }
  .home .cvrows .sum { font-size: 15px; }
}
@media screen and (max-width: 1199px) { .home :is(#work, #projects) .mini { grid-template-columns: repeat(3, minmax(0, 1fr)); } .home .defs { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media screen and (max-width: 1023px) { .home .cvrows { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media screen and (max-width: 860px) { .home .cvrows { grid-template-columns: 1fr; } }
@media screen and (max-width: 720px) {
  .home .defs { grid-template-columns: 1fr; }
  .home :is(#work, #projects) .feat { grid-template-columns: 1fr; }
  .home :is(#work, #projects) .mini { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s1) 12px; }
  .home #projects .mini { grid-template-columns: 1fr; gap: var(--s2); }
  .home :is(#work, #projects) .mini .card { grid-template-columns: 1fr; }
  .home :is(#work, #projects) .mini .thumb { grid-row: auto; aspect-ratio: 16 / 7; }
  .home :is(#work, #projects) .card h3, .home #projects .mini h3 { font-size: 19px; }
  .home :is(#work, #projects) .card .label { font-size: 12px; }
}
/* The pager's cue: a pill at the bottom edge (next page) or under the top bar (previous page) that fills as the
   wheel turns, then moves on; it is only a hint, so screen readers skip it. */
.pager-cue { position: fixed; left: 50%; z-index: 40; display: flex; align-items: center; gap: var(--s1); padding: 6px 14px 8px; background: var(--bg); border: 1px solid var(--rule); box-shadow: 0 6px 24px -10px rgb(0 0 0 / .35); color: var(--ink); font: 600 var(--t-label)/1.2 var(--mono); font-stretch: var(--mono-stretch); letter-spacing: .06em; text-transform: uppercase; transform: translate(-50%, 0); opacity: 0; pointer-events: none; transition: opacity .2s; }
.pager-cue.down { bottom: var(--s2); }
.pager-cue.up { top: calc(var(--bar) + var(--s2)); }
.pager-cue.on { opacity: 1; }
.pager-cue::after { content: ""; position: absolute; left: -1px; bottom: -1px; height: 3px; width: calc((100% + 2px) * var(--p, 0)); background: var(--hot); transition: width .12s linear; }
.pager-cue.drain::after { transition-duration: .3s; }
@media print { .pager-cue { display: none; } }
/* The section in view, marked in the top bar; on phones, the rest of a long list behind "Show N more" (home.js).
   The fold is for the screen only, so a print made on a narrow window still has every item. */
.top nav a[aria-current] { color: var(--ink); }
.top nav a[aria-current]::after { transform: scaleX(1); }
@media screen { .folded { display: none !important; } }
.fold-btn { margin-top: var(--s2); width: 100%; justify-content: center; }
@media print { .fold-btn { display: none; } }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } *, *::before, *::after { animation: none !important; transition: none !important; } }
@media print { .top nav, .theme-toggle, .pager, .model-btn, .demo-btn, .hero-cloud, .skip, .cbar .btn, .brand-role, .brand-photo { display: none; } .cbar { position: static; height: auto; border: 0; } body { padding-bottom: 0; } body { background: #fff; color: #000; } .rail, .top { position: static; } .hero::before { display: none; } }
/* ---------- the home page in screen-sized pages ----------
   On a desktop window from 1300 x 780 (with a mouse, no reduced motion) each part of the home page is one window
   tall: the hero, CV, Work, Projects, then Skills and the footer together. Each page keeps its content clear of
   the contact bar at the bottom, which holds the contact details. The pages tighten on shorter windows (covers, the chart, type and gaps
   follow the window height), so every page fits from 780 px tall; the width leaves room for a 15 px scroll bar. pager.js turns the wheel and the keys into one page at a time,
   with the .pager-cue showing how far the wheel has got. Phones, smaller windows, zoomed text and reduced motion
   keep the normal scroll of the same sections. Keep this query the same as GATE in pager.js. */
@media screen and (prefers-reduced-motion: no-preference) and (hover: hover) and (pointer: fine) and (min-width: 1300px) and (min-height: 780px) {
  .home .hero, .home .sec { min-height: calc(100svh - var(--bar)); display: grid; }
  .home .hero { min-height: calc(100svh - var(--bar) - 1px); }
  .morph .home .hero { min-height: 100svh; } /* no bars on the first page */
  .morph .home .hero-in { padding-bottom: var(--s3); }
  .home .hero-in { min-height: 0; padding-top: var(--s3); padding-bottom: calc(var(--s3) + var(--cbar)); }
  .home .hero-caption.col-12 { bottom: calc(var(--s3) + var(--cbar)); } /* clear of the contact bar, which shows on the hero without scripts */
  .morph .home .hero-caption.col-12 { bottom: var(--s3); }
  .home .sec { padding: var(--s2) 0 calc(var(--s2) + var(--cbar)); }
  .home .sec > .wrap { width: 100%; align-content: center; } /* a grid item with auto margins would shrink to its content once --max is lifted (the egg's "wide") */
  .home .hero h1 { font-size: min(var(--t-display), 10svh); }
  .home .hero-lead { grid-template-columns: min(96px, 11svh) minmax(0, 1fr); }
  .home .hero .portrait { width: min(96px, 11svh); height: min(96px, 11svh); }
  .home .hero-lead, .home .intro, .home .glance, .home .hero-links, .home .avail, .home .hero-caption { margin-top: 12px; }
  .home .sec > .grid > .rail { margin-bottom: 8px; }
  .home .sec > .grid > .rail .lede { max-width: none; }
  .home .card .cover { width: 100%; } /* so a lower max-height crops the still instead of narrowing it */
  .home #work .feat .cover { max-height: calc(100svh - var(--bar) - var(--cbar) - 490px); }
  .home #projects .feat .cover { max-height: calc(100svh - var(--bar) - var(--cbar) - var(--foot, 80px) - 640px); } /* Projects shares its page with the footer */
  .home .timeline { margin-bottom: 8px; }
  .home .timeline svg { display: block; max-height: max(150px, calc(100svh - var(--bar) - var(--cbar) - 540px)); margin: 0 auto; } /* 150: labels stay 10 px */
  .home .cvrows li { padding: 4px 0; }
  .home .defs { column-gap: 20px; }
  .home .defs > div { padding: 4px 0 7px; }
  .home .defs dt { line-height: 1.3; }
  .home .defs dd { margin-top: 2px; font-size: 15px; line-height: 1.34; }
  .home .defs .see { line-height: 1.5; margin-top: 4px; } /* a mouse needs less room between the links than a finger */
  .home .cvrows .sum { line-height: 1.36; }
  /* The last page: Projects and the footer, which sits just above the contact bar (home.js measures the footer). */
  .home main > .sec:last-child { min-height: calc(100svh - var(--bar) - var(--cbar) - var(--foot, 80px)); padding-bottom: var(--s2); }
  .home .foot .wrap { padding-top: var(--s2); padding-bottom: var(--s2); }
}
