/* Wilby Labs
   One stylesheet. Tokens first, then components in page order.
   Neutrals carry the page; teal is the one interactive color.
   Pastel aqua, sky, pink and amber appear only in imagery and data.
   Two static tints (azure at the top, peach at the close) are the only washes. */

/* ---------- Fonts ---------- */
@font-face {
  font-family: "Inter";
  src: url("/fonts/inter-latin-400-600.a8404768.woff2") format("woff2-variations"),
       url("/fonts/inter-latin-400-600.a8404768.woff2") format("woff2");
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
  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+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Size-matched fallback so the swap to Inter barely moves text. */
@font-face {
  font-family: "Inter Fallback";
  src: local("Arial"), local("Helvetica Neue"), local("Helvetica");
  size-adjust: 107.12%;
  ascent-override: 90.44%;
  descent-override: 22.52%;
  line-gap-override: 0%;
}

/* ---------- Tokens ---------- */
:root {
  --bg: #F7F7F5;
  --band: #EEF3F4;
  --surface: #FFFFFF;
  --ink: #16191B;
  --ink-2: #42515A;
  --ink-3: #5E6D75;
  --line: #DDE3E5;
  --line-strong: #C4CED3;
  --control: #7E898F;
  --accent: #0B7A73;
  --accent-tint: #E2F3F0;
  --focus: #1F77AE;
  --btn-bg: #16191B;
  --btn-fg: #FFFFFF;
  --btn-hover: #30373B;
  --btn-press: #000000;
  --nav-bg: rgba(247, 247, 245, 0.8);
  --nav-solid: #F7F7F5;
  --chip: rgba(22, 25, 27, 0.06);
  --seg-bg: rgba(22, 25, 27, 0.07);
  --tint-azure: #E5F2F9;
  --tint-peach: #FAF1E6;
  --data-teal: #0B756C;
  --data-sky: #2F8FC4;
  --data-pink: #D0679A;
  /* Amber is used only by the 3D viewer's legend (viewer/viewer.css). */
  --data-amber: #B07516;
  --scaf: #9AA7AD;

  --font: "Inter", "Inter Fallback", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

  --wide: 1200px;
  /* viewport-fit=cover lets the full-bleed chapters reach the screen edge; content keeps out of the safe-area insets. */
  --gutter: max(clamp(20px, 5.2vw, 48px), env(safe-area-inset-left, 0px), env(safe-area-inset-right, 0px));
  --nav-h: 52px;

  --fs-display: 80px;
  --fs-chapter: 56px;
  --fs-section: 44px;
  --fs-tile: 28px;
  --fs-intro: 32px;
  --fs-lede: 21px;
  --fs-body: 17px;

  --pad-chapter: 144px;
  --pad-section: 112px;
  /* From a chapter's lede to the first block under it: the same in every chapter. */
  --gap-block: 64px;
  --card-pad: 48px;

  --r-media: 28px;
  --r-ui: 12px;
  --ease: cubic-bezier(.25, .1, .25, 1);
  --ease-out: cubic-bezier(.2, 0, 0, 1);

  color-scheme: light;
}

/* Dark chapters: a local token swap, so components inside adapt on their own. */
.theme-night {
  --bg: #0E1113;
  --band: #121619;
  --surface: #171C1F;
  --ink: #EDF1F2;
  --ink-2: #AAB7BD;
  --ink-3: #8C9AA1;
  --line: #283034;
  --line-strong: #3A454B;
  --control: #66737A;
  --accent: #5CCABF;
  --accent-tint: #13302D;
  --focus: #5BAFE0;
  --btn-bg: #EDF1F2;
  --btn-fg: #0E1113;
  --btn-hover: #FFFFFF;
  --btn-press: #D5DCDF;
  --chip: rgba(237, 241, 242, 0.08);
  --seg-bg: rgba(237, 241, 242, 0.1);
  --data-teal: #23A89B;
  --data-sky: #7CC3F0;
  --data-pink: #F4A6CC;
  --data-amber: #E0A954;
  --scaf: #6B7980;
  --nav-bg: rgba(14, 17, 19, 0.76);
  --nav-solid: #0E1113;
  color-scheme: dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0E1113;
    --band: #14191C;
    --surface: #1A2024;
    --ink: #EDF1F2;
    --ink-2: #AAB7BD;
    --ink-3: #8C9AA1;
    --line: #262D31;
    --line-strong: #374147;
    --control: #66737A;
    --accent: #5CCABF;
    --accent-tint: #13302D;
    --focus: #5BAFE0;
    --btn-bg: #EDF1F2;
    --btn-fg: #0E1113;
    --btn-hover: #FFFFFF;
    --btn-press: #D5DCDF;
    --nav-bg: rgba(14, 17, 19, 0.76);
    --nav-solid: #0E1113;
    --chip: rgba(237, 241, 242, 0.08);
    --seg-bg: rgba(237, 241, 242, 0.1);
    --tint-azure: #10222C;
    --tint-peach: #15130F;
    --data-teal: #23A89B;
    --data-sky: #7CC3F0;
    --data-pink: #F4A6CC;
    --data-amber: #E0A954;
    --scaf: #6B7980;
    color-scheme: dark;
  }
  .theme-night {
    --bg: #060809;
    --band: #0B0E10;
    --surface: #13181B;
    --line: #22292D;
    --nav-bg: rgba(6, 8, 9, 0.76);
    --nav-solid: #060809;
  }
}

@media (max-width: 1068px) {
  :root {
    --fs-display: 64px;
    --fs-chapter: 46px;
    --fs-section: 38px;
    --fs-tile: 26px;
    --fs-intro: 26px;
    --pad-chapter: 112px;
    --pad-section: 88px;
    --card-pad: 40px;
  }
}
@media (max-width: 734px) {
  :root {
    --fs-display: clamp(40px, 12vw, 52px);
    --fs-chapter: clamp(30px, 8.6vw, 36px);
    --fs-section: clamp(28px, 8vw, 32px);
    --fs-tile: 24px;
    --fs-intro: 22px;
    --fs-lede: 19px;
    --nav-h: 48px;
    --pad-chapter: 88px;
    --pad-section: 72px;
    --gap-block: 40px;
    --r-media: 22px;
  }
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
/* Smooth in-page jumps, but only once the page has loaded, so a link to /#contact
   opens at the contact section instead of scrolling the whole page. Tabbing scrolls
   instantly (app.js sets .kb-nav), so the focused element is in view at once. */
@media (prefers-reduced-motion: no-preference) {
  html.is-ready:not(.kb-nav):not(.jump) { scroll-behavior: smooth; }
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: var(--fs-body);
  line-height: 1.47;
  letter-spacing: -0.011em;
  font-optical-sizing: auto;
  font-feature-settings: "kern", "calt";
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}
/* Anchored targets clear the sticky bar. On the targets only, so focusing a
   link inside the bar never scrolls the page. */
main[id], main [id] { scroll-margin-top: calc(var(--nav-h) + 20px); }
/* Full-bleed chapters land flush with the top: their own padding clears the bar. */
main > section[id] { scroll-margin-top: 0; }

img, svg { display: block; max-width: 100%; }
img { height: auto; }
h1, h2, h3, p, ul, ol, dl, dd, figure, fieldset { margin: 0; }
ul, ol { padding: 0; }
button { font: inherit; color: inherit; }
p, li, dd, td, figcaption { text-wrap: pretty; }
h1, h2, h3, th { text-wrap: balance; }
strong { font-weight: 600; color: var(--ink); }
sup { font-size: max(11px, 0.68em); line-height: 0; }
code { font-family: var(--mono); letter-spacing: 0; }

a { color: var(--accent); text-decoration: none; text-underline-offset: 0.18em; text-decoration-thickness: 1px; -webkit-tap-highlight-color: transparent; }
@media (hover: hover) and (pointer: fine) {
  a:hover { text-decoration: underline; }
}
/* Links inside running text carry an underline, so they never depend on color alone. */
sup a, .specs dd a, .menu-mail a, .notfound .lede a {
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, currentColor 45%, transparent);
}
@media (hover: hover) and (pointer: fine) {
  sup a:hover, .specs dd a:hover, .menu-mail a:hover, .notfound .lede a:hover { text-decoration-color: currentColor; }
}
/* A quiet press state for every text link; buttons and pills have their own. */
a:where(:not(.btn, .nav-cta, .skip)) { transition: opacity .1s var(--ease-out); }
a:where(:not(.btn, .nav-cta, .skip)):active { opacity: .6; }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 6px;
}
main:focus { outline: none; }
/* A chapter that receives focus after a jump from the menu sheet: the heading shows where you are, not a ring. */
main > section[tabindex="-1"]:focus { outline: none; }

[hidden] { display: none !important; }
.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }
.nw { white-space: nowrap; }
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.skip {
  position: absolute;
  left: max(12px, env(safe-area-inset-left, 0px)); top: -60px;
  z-index: 100;
  padding: 10px 16px;
  border-radius: 999px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: 14px;
  font-weight: 500;
}
.skip:focus { top: 8px; text-decoration: none; }

/* ---------- Layout ---------- */
.wrap-wide { width: min(var(--wide), 100% - 2 * var(--gutter)); margin-inline: auto; }

.chapter { padding-block: var(--pad-chapter); background: var(--bg); color: var(--ink); }
.section { padding-block: var(--pad-section); }
.band { background: var(--band); }

/* ---------- Type ---------- */
.display {
  font-size: var(--fs-display);
  line-height: 1.04;
  font-weight: 600;
  letter-spacing: -0.034em;
}
.h-chapter {
  max-width: 19em;
  font-size: var(--fs-chapter);
  line-height: 1.08;
  font-weight: 500;
  letter-spacing: -0.03em;
}
.h-section {
  max-width: 20em;
  font-size: var(--fs-section);
  line-height: 1.1;
  font-weight: 500;
  letter-spacing: -0.028em;
}
.h-tile {
  font-size: var(--fs-tile);
  line-height: 1.16;
  font-weight: 500;
  letter-spacing: -0.022em;
}
.lede {
  margin-top: 20px;
  max-width: 34em;
  font-size: var(--fs-lede);
  line-height: 1.43;
  letter-spacing: -0.013em;
  color: var(--ink-2);
}
.small { font-size: 14px; line-height: 1.45; letter-spacing: -0.006em; color: var(--ink-3); }

/* ---------- Buttons and links ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 22px;
  border: 1px solid transparent;
  border-radius: 980px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: 17px;
  font-weight: 500;
  letter-spacing: -0.012em;
  line-height: 1;
  cursor: pointer;
  transition: background-color .2s var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) and (pointer: fine) {
  .btn:hover { background: var(--btn-hover); text-decoration: none; }
  .btn-quiet:hover { background: color-mix(in srgb, var(--ink) 6%, transparent); }
}
.btn:active { background: var(--btn-press); }
.btn-quiet {
  background: transparent;
  color: var(--ink);
  border-color: var(--control);
}
.btn-quiet:active { background: color-mix(in srgb, var(--ink) 11%, transparent); }
.btn-sm { font-size: 15px; padding: 0 18px; }

.more {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  min-height: 44px;
  font-size: var(--fs-body);
  font-weight: 500;
  color: var(--accent);
}
.more svg { width: 0.62em; height: 0.62em; margin-left: 3px; transform: translateY(0.02em); transition: transform .2s var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .more:hover svg { transform: translate(2px, 0.02em); }
}
/* A .more on its own line under a lede. */
.lede + .more { display: flex; width: fit-content; margin-top: 12px; }
/* A smaller .more that sits under a line of text. */
.more-sm { display: flex; width: fit-content; min-height: 36px; font-size: 15px; letter-spacing: -0.01em; }

sup a { position: relative; padding: 0 1px; font-weight: 500; color: var(--accent); }
/* A larger hit area than the numeral, without moving the text around it. */
sup a::after { content: ""; position: absolute; inset: -9px -4px -5px; }

/* ---------- Nav ---------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  height: var(--nav-h);
  background: var(--nav-bg);
  -webkit-backdrop-filter: saturate(180%) blur(20px);
  backdrop-filter: saturate(180%) blur(20px);
  border-bottom: 1px solid transparent;
  transition: border-color .2s var(--ease-out), background-color .3s var(--ease-out), color .3s var(--ease-out);
}
/* Crossing into or out of a dark chapter, the bar swaps theme in one frame: text and fill never cross-fade
   past each other. app.js adds .no-theme-anim for that frame only. */
.nav.no-theme-anim, .nav.no-theme-anim * { transition: none !important; }
/* At the very top the bar sits on the hero's tint with no fill of its own. This waits for app.js, which
   tracks the scroll: a page restored partway down keeps the fill until then, so the bar stays legible. */
html.app:not(.menu-open):not(.menu-closing) .nav:not(.is-scrolled):not(.theme-night) { background: transparent; -webkit-backdrop-filter: none; backdrop-filter: none; }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .nav { background: var(--nav-solid); }
}
.nav.is-scrolled, html:not(.js) .nav { border-bottom-color: var(--line); }
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  height: 100%;
}
.brand {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 8px;
  white-space: nowrap;
  min-height: 44px;
  color: var(--ink);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.016em;
}
.brand svg { flex: none; width: 24px; height: auto; color: var(--ink); }
.nav-links {
  display: flex;
  align-items: center;
  gap: 4px;
  list-style: none;
}
.nav-links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 12px;
  color: color-mix(in srgb, var(--ink) 78%, transparent);
  font-size: 14px;
  letter-spacing: -0.006em;
  transition: color .2s var(--ease-out), opacity .1s var(--ease-out);
}
.nav-links a[aria-current] { color: var(--ink); }
@media (hover: hover) and (pointer: fine) {
  .nav-links a:hover { color: var(--ink); text-decoration: none; }
}
.nav-links a[aria-current] { font-weight: 500; }
.nav-actions { display: flex; align-items: center; gap: 4px; }
.nav-cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  padding: 0 14px;
  margin-left: 12px;
  border: 1px solid transparent;
  border-radius: 980px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.006em;
  transition: background-color .2s var(--ease-out), opacity .2s var(--ease-out), visibility 0s;
}
/* 44px hit area around the 32px pill */
.nav-cta::after { content: ""; position: absolute; inset: -6px -4px; }
@media (hover: hover) and (pointer: fine) {
  .nav-cta:hover { background: var(--btn-hover); text-decoration: none; }
}
.nav-cta:active { background: var(--btn-press); }
.nav-toggle { display: none; }
.nav-links .menu-only { display: none; }
@media (forced-colors: active) {
  /* The bar keeps an edge when system colors replace its fill. */
  .nav { border-bottom-color: CanvasText; }
}

@media (max-width: 734px) {
  .nav-cta { margin-left: 0; }
  .nav-toggle {
    display: inline-grid;
    place-items: center;
    width: 44px;
    height: 44px;
    margin-right: -10px;
    padding: 0;
    border: 0;
    background: none;
    color: var(--ink);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
  }
  /* Until app.js has wired the menu, the button keeps its place but is not shown: never a dead control. */
  html.js:not(.app) .nav-toggle { visibility: hidden; }
  /* Keep the ring inside the bar, so its top edge is never cut off. */
  .nav-toggle:focus-visible { outline-offset: -2px; border-radius: 12px; }
  .nav-toggle span {
    grid-area: 1 / 1;
    display: block;
    width: 18px;
    height: 1.5px;
    border-radius: 1px;
    background: currentColor;
    transition: transform .28s var(--ease-out);
  }
  /* Forced colors repaints fills with the page color, which would erase the bars: paint them as button text. */
  @media (forced-colors: active) {
    .nav-toggle span { forced-color-adjust: none; background: ButtonText; }
  }
  .nav-toggle span:first-child { transform: translateY(-3.5px); }
  .nav-toggle span:last-child { transform: translateY(3.5px); }
  .menu-open .nav-toggle span:first-child { transform: rotate(45deg); }
  .menu-open .nav-toggle span:last-child { transform: rotate(-45deg); }

  /* The sheet fades in and out. Hidden, it leaves the tab order and the accessibility tree. */
  html.js .nav-links {
    position: fixed;
    inset: var(--nav-h) 0 0 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 12px var(--gutter) 40px;
    background: var(--nav-solid);
    overflow-y: auto;
    overscroll-behavior: contain;
    visibility: hidden;
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity .18s var(--ease-out), transform .18s var(--ease-out), visibility 0s linear .18s;
  }
  html.js.menu-open .nav-links {
    visibility: visible;
    opacity: 1;
    transform: none;
    transition: opacity .24s var(--ease-out), transform .24s var(--ease-out), visibility 0s;
  }
  /* The sheet already lists Contact, so the pill steps aside while it is open. */
  html.menu-open .nav-cta { visibility: hidden; opacity: 0; transition: opacity .15s var(--ease-out), visibility 0s linear .15s; }
  html.js .nav-links li { border-bottom: 1px solid var(--line); }
  html.js .nav-links a {
    display: flex;
    min-height: 60px;
    padding: 0;
    opacity: 1;
    font-size: 28px;
    font-weight: 500;
    letter-spacing: -0.022em;
  }
  html.js .nav-links a[aria-current] { font-weight: 600; }
  html.js .nav-links .menu-only { display: block; }
  html.js .nav-links .menu-mail { border-bottom: 0; padding-top: 28px; }
  html.js .nav-links .menu-mail p { font-size: 15px; color: var(--ink-3); }
  html.js .nav-links .menu-mail a {
    display: inline-flex;
    min-height: 44px;
    font-size: 17px;
    font-weight: 500;
    letter-spacing: -0.012em;
    color: var(--accent);
  }
  html.js.menu-open .nav-links li { animation: sheet-in .28s var(--ease-out) both; }
  html.js.menu-open .nav-links li:nth-child(2) { animation-delay: .025s; }
  html.js.menu-open .nav-links li:nth-child(3) { animation-delay: .05s; }
  html.js.menu-open .nav-links li:nth-child(4) { animation-delay: .075s; }
  html.js.menu-open .nav-links li:nth-child(5) { animation-delay: .1s; }
  html.js.menu-open .nav-links li:nth-child(6) { animation-delay: .125s; }
  /* Lock the page on html only: hiding body overflow too would make body the sticky bar's scroller. */
  html.menu-open { overflow: hidden; }
  /* backdrop-filter makes the bar a containing block for the fixed sheet, so drop it while the sheet is open or fading out */
  html.menu-open .nav, html.menu-closing .nav { border-bottom-color: var(--line); background: var(--nav-solid); -webkit-backdrop-filter: none; backdrop-filter: none; }
  /* Without JS there is no sheet: the Contact pill stays, and the page is one scroll. */
  html:not(.js) .nav-links, html:not(.js) .nav-toggle { display: none; }
}
@keyframes sheet-in {
  from { opacity: 0; transform: translateY(-8px); }
  to { opacity: 1; transform: none; }
}

/* ---------- Hero ---------- */
/* One quiet, static azure tint behind the top of the page. It fades out before the statement. */
body {
  background:
    radial-gradient(130% 100% at 78% 0%, var(--tint-azure) 0%, color-mix(in srgb, var(--tint-azure) 45%, transparent) 38%, transparent 72%) 0 0 / 100% min(1320px, 150vh) no-repeat,
    var(--bg);
}
.hero { padding-top: 64px; }
.hero-head {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: 24px 48px;
  align-items: end;
}
.hero .display { max-width: 8.4em; }
.hero-sub .lede { margin-top: 0; max-width: 24em; }
.hero-cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px 28px;
  margin-top: 24px;
}
.hero-media { margin-top: 36px; }
.hero-media img {
  width: 100%;
  height: auto;
  /* The first screen ends on the caption, with the specs strip just below the fold... */
  max-height: clamp(240px, calc(100vh - 440px), 540px);
  max-height: clamp(240px, calc(100svh - 440px), 540px);
  object-fit: contain;
}
/* ...or, on screens tall enough, holds the whole strip. */
@media (min-height: 985px) {
  .hero-media img {
    max-height: clamp(240px, calc(100vh - 590px), 540px);
    max-height: clamp(240px, calc(100svh - 590px), 540px);
  }
}
/* Tablets: the head stacks above the image, so the image starts lower. */
@media (min-width: 735px) and (max-width: 1068px) {
  .hero-media img {
    max-height: clamp(240px, calc(100vh - 530px), 540px);
    max-height: clamp(240px, calc(100svh - 530px), 540px);
  }
}
@media (min-width: 735px) and (max-width: 1068px) and (min-height: 985px) {
  .hero-media img {
    max-height: clamp(240px, calc(100vh - 750px), 540px);
    max-height: clamp(240px, calc(100svh - 750px), 540px);
  }
}
.hero-caption { margin-top: 8px; max-width: 46em; }
.specs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 24px 32px;
  margin-top: 56px;
  padding-top: 20px;
  border-top: 1px solid var(--line-strong);
}
.specs dt { font-size: 14px; color: var(--ink-3); }
.specs dd { margin-top: 4px; font-size: 17px; line-height: 1.35; color: var(--ink); }
/* Short blocks of a few lines: even lines, never a lone last word. */
.specs dd, .layer-model p, .vtable td { text-wrap: balance; }

/* ---------- Statement ---------- */
.statement { padding-top: calc(var(--pad-section) + 8px); }
.statement p {
  max-width: 27em;
  font-size: var(--fs-intro);
  line-height: 1.28;
  font-weight: 500;
  letter-spacing: -0.021em;
  color: var(--ink-3);
}
.statement strong { font-weight: 600; color: var(--ink); }

/* ---------- Yield chapter ---------- */
.report {
  margin-top: var(--gap-block);
  padding: calc(var(--card-pad) - 4px) var(--card-pad) var(--card-pad);
  border-radius: var(--r-media);
  background: var(--surface);
}
.report-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 24px;
}
.report-head .file { font-family: var(--mono); font-size: 14px; color: var(--ink); letter-spacing: 0; }
.report-head .meta { color: var(--ink-3); font-size: 14px; margin-left: 8px; }
.report-head .tag { color: var(--ink-3); font-size: 14px; }

.sm-wrap { margin-top: 28px; }
.staplemap { width: 100%; height: auto; overflow: visible; }
.staplemap-port { display: none; }
.sm-scaf { fill: none; stroke: var(--scaf); stroke-width: 1.25px; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.sm-st { fill: none; stroke-width: 3.25px; vector-effect: non-scaling-stroke; stroke-linecap: round; stroke-linejoin: round; }
.sm-strong { stroke: var(--data-teal); }
.sm-mid { stroke: var(--data-sky); }
.sm-weak { stroke: var(--data-pink); stroke-width: 4px; }
.sm-ring { fill: none; stroke: var(--data-pink); stroke-width: 1.5px; vector-effect: non-scaling-stroke; }

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 28px;
  margin-top: 22px;
  list-style: none;
  font-size: 14px;
  color: var(--ink-2);
}
.legend li { display: inline-flex; align-items: center; gap: 10px; }
.legend i { display: inline-block; width: 22px; height: 4px; border-radius: 2px; background: var(--scaf); }
.legend .l-strong { background: var(--data-teal); }
.legend .l-mid { background: var(--data-sky); }
.legend .l-weak { background: var(--data-pink); box-shadow: 0 0 0 3px var(--surface), 0 0 0 4px var(--data-pink); width: 16px; margin-inline: 3px; }
.legend .l-scaf { height: 1.5px; }
@media (forced-colors: active) {
  /* Keep the swatches, so the key still matches the strokes in the map and chart. */
  .legend i, .fc-key i { forced-color-adjust: none; }
}
/* SVG strokes are not forced. A light forced palette turns the dark chapter white, so its figures take
   the colors drawn for a light surface. Dark forced palettes keep the night colors. */
@media (forced-colors: active) and (prefers-color-scheme: light) {
  .theme-night {
    --surface: Canvas;
    --data-teal: #0B756C;
    --data-sky: #2F8FC4;
    --data-pink: #D0679A;
    --scaf: #6B7980;
    --ink-3: #5E6D75;
    --line: #DDE3E5;
    --line-strong: #C4CED3;
  }
}

/* Two-column blocks share one column line across the page: the second column
   starts 7/12 of the way across the content width, with a 48px gutter.
   Inside a card the same line is found by adding the card's padding back. */
.report-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) calc((100% + 2 * var(--card-pad) - 48px) * 5 / 12 - var(--card-pad));
  gap: 48px;
  margin-top: 36px;
  padding-top: 32px;
  border-top: 1px solid var(--line);
}
.report h3 { font-size: 17px; font-weight: 600; letter-spacing: -0.012em; }
.report h3 + p { margin-top: 4px; max-width: 34em; }

/* Folding chart: the plot is an SVG stretched to its box; every label is HTML set outside it. */
.fc-plot {
  position: relative;
  height: clamp(190px, 20vw, 250px);
  margin: 46px 0 34px 44px;
}
.foldcurve { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.fc-grid { stroke: var(--line); stroke-width: 1px; vector-effect: non-scaling-stroke; }
.fc-base { stroke: var(--line-strong); }
.fc-window { fill: var(--data-teal); opacity: 0.16; }
.fc-edge { stroke: var(--data-teal); stroke-width: 1px; vector-effect: non-scaling-stroke; }
.fc-mid { stroke: var(--ink-3); stroke-width: 1.25px; stroke-dasharray: 3 4; vector-effect: non-scaling-stroke; }
.fc-line { fill: none; stroke: var(--data-teal); stroke-width: 3px; vector-effect: non-scaling-stroke; stroke-linejoin: round; stroke-linecap: round; }
.fc-y, .fc-x {
  position: absolute;
  font-size: 12px;
  line-height: 1;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.fc-y { right: calc(100% + 10px); transform: translateY(-50%); }
.fc-y.y100 { top: 0; }
.fc-y.y50 { top: 50%; }
.fc-y.y0 { top: 100%; }
.fc-x { top: calc(100% + 10px); transform: translateX(-50%); }
.fc-x.x80 { left: 0; transform: none; }
.fc-x.x70 { left: 18.18%; }
.fc-x.x60 { left: 36.36%; }
.fc-x.x50 { left: 54.55%; }
.fc-x.x40 { left: 72.73%; }
.fc-x.x30 { left: 90.91%; }
/* The midpoint label is a flag above the plot: the dashed line runs up into it, and no line crosses its text. */
.fc-mid-label {
  position: absolute;
  left: 19.09%;
  bottom: 100%;
  padding: 0 0 12px 7px;
  border-left: 1.25px dashed var(--ink-3);
  transform: translateX(-0.6px);
  font-size: 12px;
  line-height: 1.3;
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
}
.fc-mid-label span { font-weight: 400; color: var(--ink-3); }
.fc-mid-label i { font-style: normal; }
.fc-key {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  list-style: none;
  font-size: 13px;
  color: var(--ink-3);
}
.fc-key li { display: inline-flex; align-items: center; gap: 8px; }
.fc-key i { display: inline-block; flex: none; }
.fc-key .k-band { width: 14px; height: 14px; border-radius: 3px; background: color-mix(in srgb, var(--data-teal) 24%, var(--surface)); box-shadow: inset 1px 0 var(--data-teal), inset -1px 0 var(--data-teal); }
.fc-key .k-mid { width: 14px; height: 0; border-top: 1.5px dashed var(--ink-3); }

.findings ul { list-style: none; margin-top: 8px; }
.findings li {
  padding: 16px 0;
  border-top: 1px solid var(--line);
  font-size: 15px;
  line-height: 1.47;
  color: var(--ink-2);
}
.findings li:first-child { border-top: 0; padding-top: 8px; }
.findings .more { margin: 4px 0 -8px; }
.findings strong { display: block; margin-bottom: 2px; font-size: 17px; letter-spacing: -0.012em; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.chips code, .checks-list code {
  display: inline-block;
  padding: 3px 8px;
  border-radius: 7px;
  background: var(--chip);
  color: var(--ink);
  font-size: 13px;
  line-height: 1.4;
  white-space: nowrap;
}
.report-cap { margin-top: 32px; max-width: 52em; }
/* A link on its own line under a card. */
.after-card { display: flex; width: fit-content; margin-top: 16px; }

/* ---------- Shape ---------- */
.twist {
  margin-top: var(--gap-block);
  padding: var(--card-pad) var(--card-pad) calc(var(--card-pad) - 4px);
  border-radius: var(--r-media);
  background: var(--surface);
}
.twist-stage {
  position: relative;
  max-width: 720px;
  margin-inline: auto;
  border-radius: var(--r-ui);
  transition: background-color .4s var(--ease), opacity .2s var(--ease);
}
.twist-readout { transition: opacity .2s var(--ease); }
/* Waiting for a still on a slow connection (app.js). */
.twist.is-pending .twist-stage, .twist.is-pending .twist-readout { opacity: .45; }
/* A quiet placeholder until the first still has arrived. */
html.js .twist-stage:not(.has-img) { background: var(--seg-bg); }
.tw { width: 100%; }
.tw + .tw { position: absolute; inset: 0; }
/* The stage keeps the stills' shape by itself, before any of them has loaded. */
@supports (aspect-ratio: 1) {
  .twist-stage { aspect-ratio: 1770 / 1322; }
  .tw { position: absolute; inset: 0; height: 100%; }
}
/* Stills crossfade. Hidden ones leave the accessibility tree once they have faded. */
.tw { opacity: 0; visibility: hidden; transition: opacity .6s var(--ease), visibility 0s linear .6s; }
.twist[data-state="flat"] .tw-flat,
.twist[data-state="pred"] .tw-pred,
.twist[data-state="corr"] .tw-corr { opacity: 1; visibility: visible; transition: opacity .6s var(--ease), visibility 0s; }
/* Without JS the checked radio drives the stills directly. With JS, data-state does, once the still has loaded. */
@supports selector(:has(*)) {
  html:not(.js) .twist:has(#tw-flat:checked) .tw-flat,
  html:not(.js) .twist:has(#tw-pred:checked) .tw-pred,
  html:not(.js) .twist:has(#tw-corr:checked) .tw-corr { opacity: 1; visibility: visible; transition: opacity .6s var(--ease), visibility 0s; }
  html:not(.js) .twist:has(#tw-flat:checked) .tw-pred,
  html:not(.js) .twist:has(#tw-corr:checked) .tw-pred { opacity: 0; visibility: hidden; transition: opacity .6s var(--ease), visibility 0s linear .6s; }
}
.twist-ui {
  display: grid;
  justify-items: center;
  gap: 18px;
  margin-top: 28px;
  text-align: center;
}
.seg {
  position: relative;
  display: inline-grid;
  grid-auto-flow: column;
  grid-auto-columns: 1fr;
  max-width: 100%;
  padding: 3px;
  border: 0;
  border-radius: 980px;
  background: var(--seg-bg);
}
.seg input { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }
.seg label {
  position: relative;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  padding: 0 18px;
  border-radius: 980px;
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink-2);
  text-align: center;
  white-space: nowrap;
  cursor: pointer;
  /* The label color keeps the thumb's timing, so a label turns light as the thumb arrives under it. */
  transition: background-color .34s var(--ease-out), color .34s var(--ease-out), opacity .15s var(--ease-out);
  -webkit-tap-highlight-color: transparent;
}
@media (hover: hover) and (pointer: fine) {
  .seg label:hover { color: var(--ink); }
}
.seg input:not(:checked) + label:active { opacity: .6; }
/* The selected segment is a solid, high-contrast pill, so it reads at a glance in both themes. */
.seg input:checked + label { background: var(--btn-bg); color: var(--btn-fg); }
/* With JS, one thumb slides between segments instead of each label lighting up on its own. */
.seg.has-thumb::before {
  content: "";
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 0;
  width: var(--thumb-w, 0);
  border-radius: 980px;
  background: var(--btn-bg);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14);
  transform: translateX(var(--thumb-x, 0));
}
.seg.has-thumb.is-live::before { transition: transform .34s var(--ease-out), width .34s var(--ease-out); }
.seg.has-thumb input:checked + label { background: transparent; }
.seg input:focus-visible + label { outline: 2px solid var(--focus); outline-offset: 2px; }
@media (forced-colors: active) {
  .seg { outline: 1px solid CanvasText; }
  .seg.has-thumb::before { display: none; }
  .seg input:checked + label, .seg.has-thumb input:checked + label { forced-color-adjust: none; background: Highlight; color: HighlightText; }
}
/* The three readouts share one grid cell, so the block keeps the height of the tallest
   and nothing below it moves. The number crossfades with the render. */
.twist-readout { display: grid; }
.ro {
  grid-area: 1 / 1;
  visibility: hidden;
  opacity: 0;
  transition: opacity .3s var(--ease), visibility 0s linear .3s;
}
.ro b {
  display: block;
  font-size: 28px;
  line-height: 1.15;
  font-weight: 500;
  letter-spacing: -0.025em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.ro span { display: block; margin-top: 4px; font-size: 15px; color: var(--ink-2); text-wrap: balance; }
.twist[data-state="flat"] .ro-flat,
.twist[data-state="pred"] .ro-pred,
.twist[data-state="corr"] .ro-corr { visibility: visible; opacity: 1; transition: opacity .3s var(--ease) .15s, visibility 0s; }
@supports selector(:has(*)) {
  html:not(.js) .twist:has(#tw-flat:checked) .ro-flat,
  html:not(.js) .twist:has(#tw-pred:checked) .ro-pred,
  html:not(.js) .twist:has(#tw-corr:checked) .ro-corr { visibility: visible; opacity: 1; transition: opacity .3s var(--ease) .15s, visibility 0s; }
  html:not(.js) .twist:has(#tw-flat:checked) .ro-pred,
  html:not(.js) .twist:has(#tw-corr:checked) .ro-pred { visibility: hidden; opacity: 0; transition: opacity .3s var(--ease), visibility 0s linear .3s; }
}
.twist-note { margin: 28px auto 0; max-width: 50em; text-align: center; }

/* ---------- Tiles ---------- */
.tiles-section { padding-top: 0; }
.tiles { display: grid; gap: 20px; }
.tile {
  display: grid;
  border-radius: var(--r-media);
  background: var(--surface);
  overflow: hidden;
}
.tile-text p { margin-top: 14px; color: var(--ink-2); max-width: 32em; }
.tile-text p + .more { display: flex; width: fit-content; margin-top: 6px; }
.tile-dyn { grid-template-columns: calc((100% - 48px) * 7 / 12 + 24px) minmax(0, 1fr); align-items: center; }
.tile-dyn .tile-media { align-self: stretch; }
.tile-dyn .tile-media img { width: 100%; height: 100%; object-fit: cover; object-position: 40% 50%; }
.tile-dyn .tile-text { padding: var(--card-pad) var(--card-pad) var(--card-pad) 24px; }
.tile-checks { grid-template-columns: minmax(0, 1fr) calc((100% + 2 * var(--card-pad) - 48px) * 5 / 12 - var(--card-pad)); gap: 48px; padding: var(--card-pad); }
.tile-checks .tile-text { align-self: start; }
.checks-note { margin-top: 20px; }
.checks-list > div { padding: 18px 0; border-top: 1px solid var(--line); }
.checks-list > div:first-child { padding-top: 0; border-top: 0; }
.checks-list dt { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; color: var(--ink); }
.checks-list dd { margin-top: 4px; font-size: 15px; line-height: 1.47; color: var(--ink-2); }
/* Code wraps only between its parts: a structure, or a strand with its run, always stays on one line.
   A part too long for a very narrow column scrolls inside its chip instead of breaking. */
.checks-list code { display: block; width: fit-content; max-width: 100%; margin-top: 10px; white-space: normal; overflow-x: auto; }
.checks-list code .nw { white-space: pre; }

/* ---------- Layers ---------- */
.layers { margin-top: var(--gap-block); }
.layers-row {
  display: grid;
  grid-template-columns: 170px minmax(0, 1fr) calc((100% - 48px) * 5 / 12);
  gap: 32px;
  align-items: center;
  padding: 24px 0;
  border-top: 1px solid var(--line);
}
.layers-row:last-child { border-bottom: 1px solid var(--line); }
.layers-head { padding: 0 0 12px; border-top: 0; align-items: end; }
.layers-head > span { font-size: 12px; line-height: 16px; color: var(--ink-3); }
.layers-row h3 { font-size: 21px; font-weight: 500; letter-spacing: -0.016em; }
.layers-row p { color: var(--ink-2); font-size: 16px; line-height: 1.45; }
.layer-model .more { margin-top: 2px; margin-bottom: -8px; }
.axis {
  position: relative;
  height: 16px;
  font-size: 12px;
  line-height: 16px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.axis span { position: absolute; top: 0; transform: translateX(-50%); white-space: nowrap; }
.axis .a0 { transform: none; }
.axis .a4 { transform: translateX(-100%); }
.track {
  position: relative;
  height: 44px;
  background: linear-gradient(var(--line-strong), var(--line-strong)) 0 14px / 100% 1px no-repeat;
}
.track::before {
  /* tick marks at 1 ms, 1 s, 1 min, 1 h and 1 day on a log scale */
  content: "";
  position: absolute;
  inset: 8px 0 auto;
  height: 13px;
  background:
    linear-gradient(var(--line-strong), var(--line-strong)) 0 0 / 1px 100% no-repeat,
    linear-gradient(var(--line-strong), var(--line-strong)) 37.8% 0 / 1px 100% no-repeat,
    linear-gradient(var(--line-strong), var(--line-strong)) 60.2% 0 / 1px 100% no-repeat,
    linear-gradient(var(--line-strong), var(--line-strong)) 82.6% 0 / 1px 100% no-repeat,
    linear-gradient(var(--line-strong), var(--line-strong)) 100% 0 / 1px 100% no-repeat;
}
/* Each track repeats the scale on phones, where the axis row above the list would be a screen away. */
.track-axis { display: none; }
.mark {
  position: absolute;
  top: 8px;
  height: 12px;
  width: 12px;
  border-radius: 6px;
  background: var(--accent);
  transform: translateX(-6px);
}
/* Every label starts at the left edge of its mark. */
.mark-label {
  position: absolute;
  top: 26px;
  font-size: 13px;
  line-height: 1.2;
  color: var(--ink);
  white-space: nowrap;
  transform: translateX(-6px);
}
.a0 { left: 0; } .a1 { left: 37.8%; } .a2 { left: 60.2%; } .a3 { left: 82.6%; } .a4 { left: 100%; }
/* log10 scale from 1 ms to 1 day: about 5 ms, 1 minute, and 1 to 12 hours */
.m-ms { left: 8.8%; }
.m-min { left: 60.2%; }
.m-hours { left: 82.6%; }
.mark.m-hours { width: 13.6%; }
/* Labels under a single dot are centered on it, so the longer ones stay inside the track. */
.mark-label.m-min { transform: translateX(-50%); }
@media (forced-colors: active) {
  /* Keep the axis, ticks and marks, which are drawn as fills. */
  .track, .track::before, .mark { forced-color-adjust: none; }
  .track { background-image: linear-gradient(CanvasText, CanvasText); }
  .track::before { background-image: linear-gradient(CanvasText, CanvasText), linear-gradient(CanvasText, CanvasText), linear-gradient(CanvasText, CanvasText), linear-gradient(CanvasText, CanvasText), linear-gradient(CanvasText, CanvasText); }
  .mark { background: CanvasText; }
  .mark-label, .track-axis { forced-color-adjust: auto; }
}

/* ---------- Validation table ---------- */
.table-wrap, .landscape { margin-top: var(--gap-block); }
.data { width: 100%; border-collapse: collapse; font-size: 16px; line-height: 1.45; }
.data caption { text-align: left; }
.data thead th {
  padding: 0 24px 12px 0;
  font-size: 13px;
  font-weight: 400;
  text-align: left;
  color: var(--ink-3);
  border-bottom: 1px solid var(--line-strong);
}
.data tbody th, .data td {
  padding: 18px 24px 18px 0;
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--line-strong);
}
.data tbody th { font-weight: 500; color: var(--ink); }
.data td { color: var(--ink-2); }
.data th:last-child, .data td:last-child { padding-right: 0; }
/* Result starts on the shared 7/12 line (60% of the content width). */
.vtable thead th:nth-child(1) { width: 30%; }
.vtable thead th:nth-child(2) { width: 30%; }
.vtable td:last-child { color: var(--ink); }
.vtable tr.open th { font-weight: 400; color: var(--ink-2); }
.vtable tr.open td:last-child { color: var(--ink-3); }
.vtable tr.open td:last-child::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 8px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--ink-3);
  vertical-align: 1px;
}

.status-more {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: 48px;
  margin-top: 64px;
}
.status-more h3 {
  padding-bottom: 12px;
  font-size: 21px;
  font-weight: 500;
  letter-spacing: -0.016em;
  border-bottom: 1px solid var(--ink);
}
.status-more ul { list-style: none; }
.status-more li {
  padding: 13px 0;
  border-bottom: 1px solid var(--line-strong);
  font-size: 16px;
  line-height: 1.45;
  color: var(--ink-2);
}

/* ---------- Research ---------- */
/* Prose pairs (this one and About) split evenly, on the 6/12 line. */
.landscape h3 { font-size: 21px; font-weight: 500; letter-spacing: -0.016em; }
.landscape-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 48px;
  margin-top: 16px;
}
.landscape-body p { max-width: 38em; font-size: var(--fs-body); line-height: 1.53; color: var(--ink-2); }
.gap-statement {
  margin-top: 48px;
  max-width: 30em;
  font-size: var(--fs-lede);
  line-height: 1.43;
  color: var(--ink-2);
}
.gap-statement strong { font-weight: 500; }
.refs { margin-top: 80px; }
.refs h3 { font-size: 21px; font-weight: 500; letter-spacing: -0.016em; }
.ref-list {
  margin-top: 16px;
  list-style: none;
  counter-reset: ref;
  border-top: 1px solid var(--line-strong);
}
.ref-list li {
  counter-increment: ref;
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  column-gap: 8px;
  padding: 14px 0;
  border-bottom: 1px solid var(--line);
  font-size: 16px;
  line-height: 1.4;
}
.ref-list li::before {
  content: counter(ref);
  grid-row: span 2;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.ref-list a { color: var(--ink); font-weight: 500; }
@media (hover: hover) and (pointer: fine) {
  .ref-list a:hover { color: var(--accent); }
}
/* Each title leaves the site for doi.org, and the arrow says so on touch screens too. */
.ref-list .ext { display: inline-block; width: 0.62em; height: 0.62em; margin-left: 0.32em; vertical-align: 0.04em; color: var(--ink-3); transition: color .2s var(--ease-out); }
@media (hover: hover) and (pointer: fine) {
  .ref-list a:hover .ext { color: var(--accent); }
}
.ref-list .ref-meta { margin-top: 2px; font-size: 14px; color: var(--ink-3); }
.ref-list.is-short li:nth-child(n + 9) { display: none; }
/* A citation jump marks the paper it lands on with a brief tint. */
.ref-list li:target { animation: ref-hit 2.4s var(--ease-out); }
@keyframes ref-hit {
  0%, 40% { background: var(--accent-tint); box-shadow: -12px 0 0 var(--accent-tint), 12px 0 0 var(--accent-tint); }
  100% { background: transparent; box-shadow: -12px 0 0 transparent, 12px 0 0 transparent; }
}
@media (prefers-reduced-motion: reduce) {
  .ref-list li:target { animation: none; background: var(--accent-tint); box-shadow: -12px 0 0 var(--accent-tint), 12px 0 0 var(--accent-tint); }
}
.show-all { margin-top: 24px; }

/* ---------- About ---------- */
.macro {
  margin-top: 40px;
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 16%, #000 55%, transparent 98%);
  mask-image: linear-gradient(to bottom, transparent 0, #000 16%, #000 55%, transparent 98%);
}
.macro img { width: 100%; }
.macro + .wrap-wide .about-body { margin-top: -24px; }
.about-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 48px;
  margin-top: 48px;
}
.about-body p { font-size: var(--fs-lede); line-height: 1.45; color: var(--ink-2); }

/* ---------- Contact ---------- */
/* The one warm tint on the page: a flat, still peach for the last chapter. */
.contact { background: var(--tint-peach); }
/* Contact and the footer together are at least one screen tall, so a jump to #contact can always
   bring it flush to the top. app.js measures the footer into --footer-h; the fallback is its desktop height. */
/* The content starts at the chapter's own padding, like every other chapter; any extra height is closing space. */
@media (min-width: 735px) {
  .contact {
    min-height: calc(100vh - var(--footer-h, 297px));
    min-height: calc(100svh - var(--footer-h, 297px));
  }
}
.contact .lede { max-width: 30em; }
.email-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px 24px;
  margin-top: 40px;
}
.email {
  font-size: clamp(24px, 7vw, 44px);
  overflow-wrap: anywhere;
  font-weight: 500;
  letter-spacing: -0.028em;
  color: var(--ink);
  line-height: 1.15;
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-decoration-thickness: 2px;
  text-underline-offset: 0.16em;
  transition: text-decoration-color .2s var(--ease-out), opacity .1s var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .email:hover { text-decoration-color: var(--accent); }
}
.copy-btn svg { width: 16px; height: 16px; flex: none; }
.copy-btn .i-check, .copy-btn.is-copied .i-copy { display: none; }
.copy-btn.is-copied .i-check { display: block; }
.copy-status { margin-top: 12px; }

/* ---------- Footer ---------- */
.footer {
  padding: 40px 0 28px;
  background: var(--band);
  font-size: 12px;
  line-height: 1.33;
  color: var(--ink-3);
  letter-spacing: -0.01em;
}
.footer-cols {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 200px));
  gap: 24px;
  padding-bottom: 28px;
  border-bottom: 1px solid var(--line-strong);
}
.footer h2 { font-size: 12px; font-weight: 600; color: var(--ink); letter-spacing: -0.01em; }
.footer ul { list-style: none; margin-top: 8px; }
.footer li a { display: inline-block; min-height: 24px; padding: 4px 0; color: var(--ink-2); }
.footer a { color: var(--ink-2); }
@media (hover: hover) and (pointer: fine) {
  .footer a:hover { color: var(--ink); }
}
.footer-legal {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 8px 24px;
  padding-top: 16px;
}

/* ---------- 404 ---------- */
.page-404 { display: flex; flex-direction: column; min-height: 100vh; min-height: 100svh; }
.page-404 main { flex: 1 0 auto; display: flex; flex-direction: column; justify-content: center; }
.notfound { display: grid; align-content: center; justify-items: start; padding-block: 96px 120px; }
.notfound .h-chapter { margin-top: 10px; }
.notfound .lede { margin-top: 16px; }
.notfound .btn { margin-top: 32px; }
/* Pages whose footer is the legal row alone (this one and the viewer): even space above and below it. */
.page-404 .footer, .page-viewer .footer { padding-block: 28px; }
.page-404 .footer-legal, .page-viewer .footer-legal { padding-top: 0; }

/* ---------- Motion ---------- */
/* Screen only: printing or saving as PDF always shows every figure in full. */
@media screen and (prefers-reduced-motion: no-preference) {
  html.js .reveal.is-pre { opacity: 0; transform: translateY(24px); }
  html.js .reveal { transition: opacity .7s var(--ease), transform .7s var(--ease); }
  html.js .reveal.is-in { opacity: 1; transform: none; }
  /* A block that holds keyboard focus is never left invisible. */
  html.js .reveal.is-pre:focus-within { opacity: 1; transform: none; transition: none; }

  /* Staples appear in the order they would bind as the anneal cools: strongest domains first. */
  html.js .sm-wrap.is-pre .sm-st, html.js .sm-wrap.is-pre .sm-ring { opacity: 0; }
  html.js .sm-wrap .sm-st, html.js .sm-wrap .sm-ring { transition: opacity .5s var(--ease); }
  html.js .sm-wrap .d1 { transition-delay: .1s; }
  html.js .sm-wrap .d2 { transition-delay: .2s; }
  html.js .sm-wrap .d3 { transition-delay: .3s; }
  html.js .sm-wrap .d4 { transition-delay: .4s; }
  html.js .sm-wrap .d5 { transition-delay: .5s; }
  html.js .sm-wrap .d6 { transition-delay: .6s; }
  html.js .sm-wrap .d7 { transition-delay: .7s; }
  html.js .sm-wrap .d8 { transition-delay: .8s; }
  html.js .sm-wrap .d9 { transition-delay: .9s; }
  html.js .sm-wrap .sm-ring { transition-delay: 1.25s; }

  html.js .fc-plot.is-pre .fc-reveal { transform: scaleX(0); }
  html.js .fc-plot .fc-reveal { transform-box: fill-box; transform-origin: 0 50%; transition: transform 1.6s cubic-bezier(.45, 0, .2, 1) .2s; }
  html.js .fc-plot.is-pre .fc-window, html.js .fc-plot.is-pre .fc-edge, html.js .fc-plot.is-pre .fc-mid, html.js .fc-plot.is-pre .fc-mid-label { opacity: 0; }
  html.js .fc-plot .fc-window, html.js .fc-plot .fc-edge, html.js .fc-plot .fc-mid, html.js .fc-plot .fc-mid-label { transition: opacity .8s var(--ease) 1.2s; }

  /* Shown at once, without a fade: a block someone has jumped or tabbed to. Only the block's own fade
     and the drawing figures stop; controls inside keep their transitions. */
  html.js .no-anim,
  html.js .sm-wrap.no-anim .sm-st, html.js .sm-wrap.no-anim .sm-ring,
  html.js .fc-plot.no-anim .fc-reveal, html.js .fc-plot.no-anim .fc-window, html.js .fc-plot.no-anim .fc-edge,
  html.js .fc-plot.no-anim .fc-mid, html.js .fc-plot.no-anim .fc-mid-label { transition: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; animation-delay: 0s !important; transition-delay: 0s !important; }
}

/* ---------- Responsive ---------- */
@media (max-width: 1068px) {
  .hero-head { grid-template-columns: minmax(0, 1fr); align-items: start; gap: 20px; }
  .hero-sub .lede { max-width: 30em; }
  .specs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .report-body { grid-template-columns: 1fr; gap: 36px; }
  /* The checks card stacks here too: its list column would be too narrow for the code lines. */
  .tile-checks { grid-template-columns: minmax(0, 1fr); gap: 32px; }
  .tile-checks .tile-text p { max-width: 36em; }
  .checks-list { max-width: 36em; }
  /* One column: keep the findings to a readable measure. */
  .findings ul { max-width: 36em; }
  .layers-row { grid-template-columns: 140px minmax(0, 1fr) calc((100% - 48px) * 5 / 12); gap: 24px; }
  /* The staple map gets smaller here, so its rings grow to stay rings. */
  .staplemap-land .sm-ring { r: 9px; }
}

@media (max-width: 900px) {
  /* Tables stack into labeled blocks, like the other two-column blocks. */
  .data thead { display: none; }
  .data, .data tbody, .data tr, .data tbody th, .data td { display: block; width: auto; }
  .data tr { padding: 16px 0; border-bottom: 1px solid var(--line-strong); }
  .data tbody th, .data td { padding: 0; border: 0; }
  .data td { margin-top: 6px; font-size: 15px; }
  .data caption { display: block; }
  .data td[data-label]::before {
    content: attr(data-label) ": ";
    font-size: 15px;
    color: var(--ink-3);
  }
  .data tbody tr:first-child { border-top: 1px solid var(--line-strong); }
  /* An open check shows its real Result cell, set as a small outlined badge. */
  .vtable tr.open td[data-label="Result"] {
    display: inline-block;
    margin-top: 10px;
    padding: 0 8px;
    border: 1px solid var(--line-strong);
    border-radius: 6px;
    font-size: 13px;
    line-height: 1.5;
  }
  .vtable tr.open td[data-label="Result"]::before { display: none; }

  .tile-dyn, .tile-checks { grid-template-columns: minmax(0, 1fr); }
  .tile-dyn .tile-text { order: -1; padding: var(--card-pad) var(--card-pad) 8px; }
  .tile-dyn .tile-media img { height: auto; }
  .status-more { grid-template-columns: 1fr; gap: 40px; }
  .about-body, .landscape-body { grid-template-columns: 1fr; gap: 20px; }
  .axis .a4 { display: none; }
  .staplemap-land .sm-ring { r: 11px; }
}

@media (max-width: 734px) {
  .hero { padding-top: 36px; }
  .hero-cta { margin-top: 20px; gap: 8px 24px; }
  .hero-media { margin-top: 28px; }
  .hero-media img { max-height: none; }
  .specs { margin-top: 36px; gap: 18px 20px; }
  .specs dd { font-size: 16px; }
  .lede { margin-top: 14px; }

  /* Phones: all four simulator cards reach 8 to 12px from the screen edge and share one 20px inset. */
  .report, .twist, .tile { margin-inline: calc(-1 * min(var(--gutter), 12px)); }
  .report { padding: 24px 20px 26px; }
  .report-head .meta { display: block; margin: 2px 0 0; }
  .sm-wrap { margin-top: 18px; }
  .staplemap-land { display: none; }
  .staplemap-port { display: block; width: min(100%, 360px); margin-inline: auto; }
  .sm-st { stroke-width: 2.5px; }
  .sm-weak { stroke-width: 3px; }
  .legend { display: grid; grid-template-columns: 1fr; gap: 10px; }
  .fc-plot { margin-left: 40px; height: 200px; }
  .fc-x { font-size: 11px; }

  .twist { padding: 24px 20px; }
  /* Segments size to their labels here, and a label may wrap rather than push the control past the card. */
  .seg { grid-auto-columns: auto; }
  .seg label { padding: 0 12px; font-size: 14px; line-height: 1.2; min-height: 40px; white-space: normal; }
  .ro b { font-size: 24px; }
  .twist-note { text-align: left; margin-top: 24px; }

  .tile-dyn .tile-text { padding: 28px 20px 4px; }
  .tile-checks { padding: 28px 20px; gap: 28px; }
  .checks-list code { font-size: 12px; }

  .macro img { height: 300px; object-fit: cover; object-position: 0 50%; }

  .layers-head { display: none; }
  .layers-row { grid-template-columns: 1fr; gap: 6px; padding: 22px 0 18px; }
  /* Each track carries its own scale: labels above the line, the mark and its label below. */
  .layers-row .track { margin-top: 12px; height: 58px; background-position: 0 28px; }
  .track::before { top: 22px; }
  .track .mark { top: 22px; }
  .track .mark-label { top: 40px; }
  .track-axis { display: block; position: absolute; inset: 0 0 auto; height: 14px; font-size: 11px; line-height: 14px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
  .track-axis span { position: absolute; top: 0; white-space: nowrap; transform: translateX(-50%); }
  .track-axis .a0 { transform: none; }

  .refs { margin-top: 64px; }
  .ref-list li { grid-template-columns: 30px minmax(0, 1fr); font-size: 15px; }

  .footer-cols { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 28px; }
  .footer li a { padding: 8px 0; font-size: 13px; }
  .footer li + li { margin-top: 0; }
  .footer-legal { flex-direction: column; }

  .notfound { padding-block: 48px 64px; }
}

@media (max-width: 560px) {
  .specs { grid-template-columns: minmax(0, 1fr); gap: 14px; }
}

@media (max-width: 480px) {
  /* Fewer tick labels where they would crowd. */
  .fc-x.x70, .fc-x.x50, .fc-x.x30, .axis .a4 { display: none; }
  /* The midpoint flag takes two lines, so it never runs past the card with larger text spacing. */
  .fc-plot { margin-top: 62px; }
  .fc-mid-label span { display: block; }
  .fc-mid-label i { display: none; }
}

@media (max-width: 374px) {
  .brand span { font-size: 16px; }
  .seg label { padding: 0 9px; font-size: 13px; }
}

/* ---------- Print ---------- */
/* Printing or saving as PDF: every chapter on white with the light tokens, whatever the screen theme,
   the full reference list, and none of the controls that only work on screen. */
@media print {
  :root, .theme-night {
    --bg: #FFFFFF;
    --band: #FFFFFF;
    --surface: #FFFFFF;
    --ink: #16191B;
    --ink-2: #42515A;
    --ink-3: #5E6D75;
    --line: #DDE3E5;
    --line-strong: #C4CED3;
    --control: #7E898F;
    --accent: #0B7A73;
    --accent-tint: #E2F3F0;
    --btn-bg: #16191B;
    --btn-fg: #FFFFFF;
    --chip: rgba(22, 25, 27, 0.06);
    --seg-bg: rgba(22, 25, 27, 0.07);
    --tint-azure: #FFFFFF;
    --tint-peach: #FFFFFF;
    --data-teal: #0B756C;
    --data-sky: #2F8FC4;
    --data-pink: #D0679A;
    --data-amber: #B07516;
    --scaf: #9AA7AD;
    --nav-bg: #FFFFFF;
    --nav-solid: #FFFFFF;
    color-scheme: light;
  }
  body { background: #FFFFFF; }
  .nav { position: static; border-bottom-color: var(--line); -webkit-backdrop-filter: none; backdrop-filter: none; }
  .skip, .nav-actions, .show-all, .copy-btn, .copy-status, .seg, .twist-live { display: none !important; }
  .ref-list.is-short li:nth-child(n + 9) { display: grid !important; }
  /* Swatches, marks and pills are fills: print them even with background graphics off. */
  .legend i, .fc-key i, .track, .track::before, .mark, .chips code, .checks-list code, .btn,
  .vtable tr.open td:last-child::before { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
  .chapter, .section { padding-block: 48px; }
  .contact { min-height: 0 !important; }
  .macro { -webkit-mask-image: none; mask-image: none; }
  .macro + .wrap-wide .about-body { margin-top: 24px; }
  .report, .twist, .tile, .layers-row, .data tr, .ref-list li, figure { break-inside: avoid; }
  h2, h3, .layers-head { break-after: avoid; }
  /* A row's heading sits beside its text, and the rows never split, so neither needs to pull the next one along. */
  .layers-row h3, .layers-head { break-after: auto; }
  .contact .wrap-wide { break-inside: avoid; }
  .hero-cta, .more { display: none !important; }
  .ref-list li:target { animation: none; background: none; box-shadow: none; }
}
