/* ==========================================================================
   Samuel Bates — portfolio, v5.3 "Sedona"
   The Sonoran desert, day and dusk. By day: Sedona-dust paper, dusk ink, and
   red rock as the one signal colour, juniper for support, prickly-pear
   magenta kept for rare pops, and headline words that catch the sunset.
   After dark: an Arizona sunset gone to violet, the rock lit orange by the
   last light, words lit amber into pink. Archivo Expanded for display,
   Archivo for reading, Martian Mono for data and labels. What's drawn is
   real: the hero's contours and the footer skyline are Camelback Mountain
   from USGS elevation data (scripts/build_terrain.py); the cacti and the
   spring wildflowers come from scripts/draw_desert.py, the animals from
   scripts/draw_fauna.py. See DEV-NOTES.md for the colour roles and the
   guardrails that keep the red from reading as anyone else's brand.

   How this file is organised (top to bottom = general to specific):
     1. Tokens        — every colour, font, and size decision lives here
     2. Base          — element defaults, focus, selection
     3. Primitives    — wrap, buttons, eyebrows, tags, links
     4. Chrome        — nav, footer, toast, skip link
     5. Sections      — hero, migration, work, case studies, how I build,
                        lab, about, toolkit, contact (in page order)
     6. Motion        — reveal-on-scroll, reduced-motion
   Theme switching works by swapping tokens under [data-theme="dark"]; no
   component below should ever need its own dark-mode rule.
   ========================================================================== */

/* ---------- 0. Fonts ----------
   Self-hosted (assets/fonts, SIL OFL 1.1; see its README): Google's Latin and
   Latin Extended subsets with Google's unicode ranges, so a page only fetches
   the files its text needs. Every page preloads archivo-latin.woff2 at low
   priority: it starts early but lets the stylesheet win on a slow phone (two
   high-priority preloads cost ~230 ms of first paint on emulated slow 4G). */
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url("../assets/fonts/archivo-latin.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+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url("../assets/fonts/archivo-latin-ext.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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Archivo";
  font-style: italic;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url("../assets/fonts/archivo-italic-latin.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+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Archivo";
  font-style: italic;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url("../assets/fonts/archivo-italic-latin-ext.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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Martian Mono";
  font-style: normal;
  font-weight: 100 800;
  font-stretch: 75% 112.5%;
  font-display: swap;
  src: url("../assets/fonts/martian-mono-latin.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+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Martian Mono";
  font-style: normal;
  font-weight: 100 800;
  font-stretch: 75% 112.5%;
  font-display: swap;
  src: url("../assets/fonts/martian-mono-latin-ext.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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- 1. Tokens ---------- */
:root {
  color-scheme: light;

  --bg: #f3ebe6;              /* Sedona dust: the pale rose sand of the red-rock trails */
  --bg-tint: #ebe0d9;
  --surface: #fbf7f4;
  --ink: #1c1624;             /* dusk ink: a saguaro's purple-black against the sunset */
  --ink-2: #463d52;
  --ink-3: #625a6c;
  --line: rgba(28, 22, 36, 0.13);
  --line-2: rgba(28, 22, 36, 0.06);
  --line-strong: rgba(28, 22, 36, 0.25);
  --accent: #a8401d;          /* Sedona red rock: deep iron oxide, never clay (5.2:1 on dust) */
  --accent-ink: #923616;      /* small accent text: AA on every surface */
  --accent-soft: rgba(168, 64, 29, 0.1);
  --on-accent: #ffffff;       /* text and ticks drawn on an --accent fill */
  --accent-hover: #8c3316;    /* a pressed-in red rock, for hovering the solid buttons */
  --select: #efd0c3;          /* text selection: a wash of red rock */
  /* emphasised words in headlines catch the sunset: red rock into prickly-pear
     berry by day (both past 4.5:1 on dust). The first 40% of the gradient is
     the word at rest; the ink after it is where the light sweeps in from. */
  --em-sunset: linear-gradient(90deg, #a8401d 0%, #b23346 20%, #c42c6c 40%, var(--ink) 55%, var(--ink) 100%);
  --support: #4f7a2a;         /* juniper and palo verde: the desert's greens */
  --support-ink: #3f6420;
  --bloom: #b8246a;           /* prickly pear fruit: rare pops only */
  --ok: #2f8a4e;
  --neg: #a3122b;             /* losses in charts: crimson, kept apart from the rock red */

  /* schematic fills (work-card SVGs) */
  --g-soft: rgba(28, 22, 36, 0.1);
  --g-soft2: rgba(28, 22, 36, 0.24);

  /* read by js/topo.js — hex only. Low ground to summit: juniper flats,
     red-rock slopes, a gold summit. */
  --topo-low: #4f7a2a;
  --topo-mid: #a8401d;
  --topo-high: #c98f12;
  --topo-alpha: 0.14;

  /* an Arizona sunset, horizon up: the Lab's sky and the dusk afterglows */
  --sun-1: #ffc75a;           /* gold on the horizon */
  --sun-2: #ff8a3d;
  --sun-3: #e8466f;           /* hot pink */
  --sun-4: #8a3a8f;
  --sun-5: #2b1e5c;           /* indigo */
  --sun-6: #120c20;           /* the first stars */

  /* behind the footer skyline: a little warmth by day, the afterglow at dusk */
  --afterglow: linear-gradient(to top, rgba(232, 150, 110, 0.14), transparent clamp(120px, 14vw, 220px));

  /* the desert drawings (assets/desert.svg) */
  --illo-line: rgba(28, 22, 36, 0.26);
  --illo-fruit: var(--bloom);
  --illo-flower: #e9b21a;       /* palo verde, brittlebush, saguaro blossom */
  --illo-poppy: #ee9a14;        /* Mexican gold poppy */
  --illo-lupine: #6a4fc4;
  --illo-mallow: #e5703a;       /* globemallow */
  --illo-pink: #c42c6c;         /* penstemon, hedgehog cactus */
  --illo-ember: #d4452a;        /* ocotillo */
  --illo-blue: #3553c9;         /* desert bluebells */
  --illo-violet: #9a3db3;       /* sand verbena, three-awn */
  --illo-cream: #fff8e8;        /* datura, yucca bells */
  /* the animals (assets/fauna.svg): a firmer line than the plants, so a
     50 px bird still has a face */
  --fauna-line: rgba(28, 22, 36, 0.58);
  --fauna-paper: #ecdccf;       /* roadrunner buff */
  --fauna-hawk: #c9ae99;        /* a red-tail's brown back, lightened to the map */
  --hawk-shade: #1c1624;
  --hawk-shade-a: 0.1;
  --fauna-javelina: #cbbfb4;    /* grizzled grey */
  --fauna-snake: #e5d3b3;       /* diamondback tan */
  --fauna-scorpion: #ecdcab;    /* desert hairy scorpion straw */
  --fauna-toad: #cfcca0;        /* Sonoran Desert toad olive */

  --shadow: 0 1px 2px rgba(28, 22, 36, 0.05), 0 10px 30px -14px rgba(28, 22, 36, 0.22);
  --shadow-lg: 0 2px 6px rgba(28, 22, 36, 0.06), 0 30px 60px -24px rgba(28, 22, 36, 0.34);

  /* the Lab is always the sunset room, whatever the theme */
  --lab-bg: #150f24;
  --lab-surface: #211836;
  --lab-ink: #f5eef2;
  --lab-ink-2: #cdc1d3;
  --lab-ink-3: #a093ab;
  --lab-line: rgba(245, 238, 242, 0.12);
  --lab-line-strong: rgba(245, 238, 242, 0.24);
  --lab-accent: #ff7a45;

  --display: "Archivo", ui-sans-serif, "Helvetica Neue", Arial, sans-serif;
  --sans: "Archivo", ui-sans-serif, -apple-system, "Segoe UI", system-ui, sans-serif;
  --mono: "Martian Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --serif: var(--display);    /* v5.0 name, kept so older pages and digests still resolve */

  --wrap: 1200px;
  --pad: clamp(20px, 4.5vw, 56px);
  --nav-h: 68px;
  --radius: 12px;
  --radius-sm: 8px;
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #150f24;              /* Sonoran dusk: the violet after the sun goes down */
  --bg-tint: #1b1430;
  --surface: #231a3a;
  --ink: #f5eef2;
  --ink-2: #cdc1d3;
  --ink-3: #a093ab;
  --line: rgba(245, 238, 242, 0.12);
  --line-2: rgba(245, 238, 242, 0.06);
  --line-strong: rgba(245, 238, 242, 0.24);
  --accent: #ff7a45;          /* red rock in the last light */
  --accent-ink: #ff9464;
  --accent-soft: rgba(255, 122, 69, 0.1);
  --on-accent: #150f24;
  --accent-hover: #ff9464;
  --select: rgba(255, 122, 69, 0.32);
  /* at dusk the words are the sky itself: amber, orange, pink */
  --em-sunset: linear-gradient(90deg, #ffb547 0%, #ff7a45 20%, #ff5c93 40%, var(--ink) 55%, var(--ink) 100%);
  --support: #a9c46c;
  --support-ink: #b5cf7a;
  --bloom: #ff5c93;
  --ok: #4fbf75;
  --neg: #ff7b72;

  --g-soft: rgba(245, 238, 242, 0.1);
  --g-soft2: rgba(245, 238, 242, 0.26);

  /* alpenglow: violet flats, sunlit slopes, gold summits (peaks hold the light longest) */
  --topo-low: #b69ae6;
  --topo-mid: #ff7a45;
  --topo-high: #ffc94d;
  --topo-alpha: 0.12;

  --afterglow: linear-gradient(to top, rgba(255, 138, 61, 0.3), rgba(232, 70, 111, 0.14) clamp(50px, 6vw, 90px), rgba(138, 58, 143, 0.06) clamp(110px, 12vw, 180px), transparent clamp(170px, 19vw, 280px));

  --illo-line: rgba(245, 238, 242, 0.2);
  --illo-flower: #ffc94d;
  --illo-poppy: #ffb547;
  --illo-lupine: #b09aff;
  --illo-mallow: #ff9a62;
  --illo-pink: #ff6fa3;
  --illo-ember: #ff7a45;
  --illo-blue: #8ea4ff;
  --illo-violet: #d79cff;
  --illo-cream: #efe3cc;
  --fauna-line: rgba(245, 238, 242, 0.55);
  --fauna-paper: #2b2036;
  --fauna-hawk: #4b3747;
  --hawk-shade: #000;
  --hawk-shade-a: 0.45;
  --fauna-javelina: #3b3040;
  --fauna-snake: #3e3341;
  --fauna-scorpion: rgba(80, 255, 220, 0.14);
  --fauna-toad: #34382b;

  --shadow: 0 1px 2px rgba(0, 0, 0, 0.35), 0 12px 32px -16px rgba(0, 0, 0, 0.65);
  --shadow-lg: 0 2px 6px rgba(0, 0, 0, 0.35), 0 30px 60px -24px rgba(0, 0, 0, 0.8);

  --lab-bg: #120c20;
  --lab-surface: #1d1532;
}

/* ---------- 2. Base ---------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scrollbar-gutter: stable;
  scroll-padding-top: calc(var(--nav-h) + 12px);
  background: var(--bg);
}
/* Keyboard focus scrolls clear of the ask bar instead of landing under it. */
html.has-dock { scroll-padding-bottom: 104px; }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 400 1.0625rem/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
}

img, svg, video, canvas, iframe { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; }
p { margin: 0; }
h1, h2, h3, h4 { margin: 0; font-weight: 400; }
ul, ol { margin: 0; padding: 0; }
dl, dd { margin: 0; }
em, i { font-style: italic; }
b, strong { font-weight: 600; }

kbd {
  font: 500 semi-condensed 0.72em var(--mono);
  padding: 0.18em 0.45em;
  border: 1px solid var(--line-strong);
  border-bottom-width: 2px;
  border-radius: 4px;
  color: var(--ink-2);
  background: var(--surface);
}

::selection { background: var(--select); color: var(--ink); }

:focus { outline: none; }
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 6px;
}

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- 3. Primitives ---------- */
.wrap {
  width: 100%;
  max-width: var(--wrap);
  margin-inline: auto;
  padding-inline: var(--pad);
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font: 500 semi-condensed 0.75rem/1.2 var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.eyebrow-num { color: var(--accent-ink); }
.eyebrow-num::after {
  content: "";
  display: inline-block;
  width: 28px;
  height: 1px;
  margin-left: 10px;
  vertical-align: middle;
  background: currentColor;
  opacity: 0.6;
}

.btn {
  --h: 46px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: var(--h);
  padding: 0 20px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  font: 600 0.9375rem/1 var(--sans);
  letter-spacing: -0.005em;
  white-space: nowrap;
  cursor: pointer;
  background: none;
  transition: background-color 0.2s, color 0.2s, border-color 0.2s, transform 0.2s var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn-solid { background: var(--accent); color: var(--on-accent); }
.btn-solid:hover { background: var(--accent-hover); color: var(--on-accent); }
.btn-ghost { border-color: var(--line-strong); color: var(--ink); background: color-mix(in srgb, var(--surface) 55%, transparent); }
.btn-ghost:hover { border-color: var(--ink); background: var(--surface); }
.btn-text { padding: 0 10px; color: var(--ink-2); }
.btn-text:hover { color: var(--ink); }
.btn-sm { --h: 38px; padding: 0 15px; font-size: 0.875rem; }
.btn-lg { --h: 54px; padding: 0 26px; font-size: 1rem; }
.btn-meta { font: 500 semi-condensed 0.6875rem var(--mono); letter-spacing: 0.08em; color: var(--ink-3); }
.btn-solid .btn-meta { color: inherit; opacity: 0.7; }
.btn-arrow { display: inline-block; transition: transform 0.25s var(--ease); }
.btn:hover .btn-arrow { transform: translate(2px, 1px); }
.btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.6; }

.link-arrow {
  display: inline-flex;
  gap: 6px;
  font-weight: 500;
  font-size: 0.9375rem;
  color: var(--accent-ink);
}
.link-arrow span { transition: transform 0.25s var(--ease); }
.link-arrow:hover span { transform: translateX(3px); }

.tags { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; }
.tags li {
  font: 500 semi-condensed 0.75rem/1 var(--mono);
  letter-spacing: 0.02em;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 4px;
  color: var(--ink-2);
}

/* ---------- 4. Chrome ---------- */
.skip {
  position: fixed;
  left: 16px; top: -60px;
  z-index: 200;
  padding: 10px 16px;
  border-radius: var(--radius-sm);
  background: var(--ink);
  color: var(--bg);
  font-weight: 500;
  transition: top 0.2s;
}
.skip:focus-visible { top: 12px; }

.nav {
  position: fixed;
  inset: 0 0 auto;
  z-index: 60;
  height: var(--nav-h);
  transition: background-color 0.3s, border-color 0.3s, backdrop-filter 0.3s;
  border-bottom: 1px solid transparent;
}
/* frosted once you scroll (js/chrome.js), or always when JS is off */
.nav.is-scrolled, html:not(.js) .nav {
  background: color-mix(in srgb, var(--bg) 84%, transparent);
  -webkit-backdrop-filter: saturate(1.4) blur(14px);
  backdrop-filter: saturate(1.4) blur(14px);
  border-bottom-color: var(--line);
}
.nav-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 24px;
  height: 100%;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--pad);
}
/* When the header runs short of room the name gives way (ellipsis), never the mark. */
.brand { display: inline-flex; align-items: center; gap: 10px; justify-self: start; min-width: 0; }
.brand-mark { flex-shrink: 0; width: 26px; height: 26px; color: var(--ink); transition: transform 0.6s var(--ease); }
.brand-dot { fill: var(--accent); }
.brand:hover .brand-mark { transform: rotate(-24deg); }
.brand-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; font: 750 semi-expanded 1.0625rem/1 var(--display); letter-spacing: -0.025em; white-space: nowrap; }

.nav-links { display: flex; gap: 4px; }
.nav-links a {
  position: relative;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  font-size: 0.9375rem;
  color: var(--ink-2);
  transition: color 0.2s, background-color 0.2s;
}
.nav-links a:hover { color: var(--ink); background: var(--line-2); }
.nav-links a[aria-current="true"] { color: var(--ink); }
.nav-links a[aria-current="true"]::after {
  content: "";
  position: absolute;
  left: 50%; bottom: 2px;
  width: 4px; height: 4px;
  margin-left: -2px;
  border-radius: 50%;
  background: var(--accent);
}

.nav-actions { display: flex; align-items: center; gap: 10px; justify-self: end; }
.theme-toggle {
  display: grid;
  place-items: center;
  width: 38px; height: 38px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink-2);
  cursor: pointer;
  transition: color 0.2s, border-color 0.2s, transform 0.5s var(--ease);
}
.theme-toggle:hover { color: var(--ink); border-color: var(--line-strong); transform: rotate(-20deg); }
.theme-toggle svg { grid-area: 1 / 1; width: 19px; height: 19px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; transition: opacity 0.3s, transform 0.5s var(--ease); }
.icon-moon { opacity: 0; transform: rotate(-60deg) scale(0.6); }
[data-theme="dark"] .icon-sun { opacity: 0; transform: rotate(60deg) scale(0.6); }
[data-theme="dark"] .icon-moon { opacity: 1; transform: none; }

.nav-progress {
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 2px;
  background: var(--accent);
  transform-origin: 0 50%;
  transform: scaleX(var(--progress, 0));
  opacity: 0;
  transition: opacity 0.3s;
}
.nav.is-scrolled .nav-progress { opacity: 1; }

/* The phone section menu (js/chrome.js): it only exists under 900px, where .nav-links fold away. */
.nav-menu-toggle {
  display: none;
  place-items: center;
  width: 38px; height: 38px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--ink-2);
  cursor: pointer;
  transition: color 0.2s, border-color 0.2s;
}
.nav-menu-toggle:hover, .nav-menu-toggle[aria-expanded="true"] { color: var(--ink); border-color: var(--line-strong); }
.nav-menu-toggle svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; }
.menu-bar { transform-origin: 12px 12px; transition: transform 0.3s var(--ease), opacity 0.2s; }
.nav-menu-toggle[aria-expanded="true"] .menu-bar-1 { transform: translateY(4.5px) rotate(45deg); }
.nav-menu-toggle[aria-expanded="true"] .menu-bar-2 { opacity: 0; }
.nav-menu-toggle[aria-expanded="true"] .menu-bar-3 { transform: translateY(-4.5px) rotate(-45deg); }

.nav-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: var(--pad);
  width: min(300px, calc(100vw - 2 * var(--pad)));
  padding: 8px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
}
.nav-menu[hidden] { display: none; }
.nav-menu-list { margin: 0; padding: 0; list-style: none; }
.nav-menu-list a {
  display: grid;
  grid-template-columns: 2.6em 1fr;
  align-items: baseline;
  padding: 11px 12px;
  border-radius: var(--radius-sm);
  font: 600 1rem/1.2 var(--display);
  color: var(--ink);
  transition: background-color 0.2s;
}
.nav-menu-list a:hover { background: var(--line-2); }
.nav-menu-list a[aria-current="true"] { background: var(--accent-soft); }
.nav-menu-num { font: 500 semi-condensed 0.72rem/1 var(--mono); letter-spacing: 0.06em; color: var(--accent-ink); }
.nav-menu-cv { display: flex; justify-content: center; margin: 6px 4px 4px; }
@media (prefers-reduced-motion: no-preference) {
  .nav-menu:not([hidden]) { animation: nav-menu-in 0.22s var(--ease-out); }
}
@keyframes nav-menu-in { from { opacity: 0; transform: translateY(-6px); } }
@media (min-width: 901px) { .nav-menu { display: none; } }

@media (max-width: 900px) {
  .nav-links { display: none; }
  .nav-inner { grid-template-columns: 1fr auto; }
  .nav-menu-toggle { display: grid; }
}
@media (max-width: 389px) {
  /* With the section menu, the mark, theme, Get in touch and the menu need the whole row; the name
     leads the hero anyway. Only the homepage has the menu. */
  .nav:has(.nav-menu-toggle) .brand-name { display: none; }
}
@media (max-width: 520px) {
  :root { --nav-h: 60px; }
  .nav-cv { display: none; }
  .brand-name { font-size: 0.9375rem; }
  .nav:has(.nav-menu-toggle) .nav-inner { gap: 10px; }
  .nav:has(.nav-menu-toggle) .nav-actions { gap: 6px; }
  .nav:has(.nav-menu-toggle) .nav-actions .btn-sm { padding: 0 12px; }
}

/* The footer is ground level: the real skyline (assets/skyline.svg, drawn by
   scripts/build_terrain.py) rises out of it on every page, looking north
   across the city at the Phoenix Mountains and Camelback. */
.footer { position: relative; padding: 28px 0 40px; background: var(--bg-tint); }
.footer::before {
  content: "";
  position: absolute;
  inset: auto 0 100%;
  height: clamp(40px, 6vw, 86px);
  background: var(--bg-tint);
  /* never narrower than 900px, so phones see Camelback, not a squashed range */
  -webkit-mask: url("../assets/skyline.svg") 85% 100% / max(100%, 900px) 100% no-repeat;
  mask: url("../assets/skyline.svg") 85% 100% / max(100%, 900px) 100% no-repeat;
  pointer-events: none;
}
.footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 14px 32px;
  font-size: 0.8125rem;
  color: var(--ink-3);
}
.side-quests { display: flex; flex-wrap: wrap; gap: 6px 16px; }
.side-quests a { color: var(--ink-2); text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; transition: color 0.2s, text-decoration-color 0.2s; }
.side-quests a:hover { color: var(--accent-ink); text-decoration-color: currentColor; }
.footer-copy { max-width: 46ch; }
.footer-note { flex-basis: 100%; max-width: 78ch; }
.footer-hint { flex-basis: 100%; color: var(--ink-3); }
.footer-hint kbd { font-size: 0.75rem; }
@media (hover: none) { .footer-hint { display: none; } }

.toast {
  position: fixed;
  left: 50%; bottom: max(24px, env(safe-area-inset-bottom));
  z-index: 300;
  padding: 11px 18px;
  border-radius: var(--radius-sm);
  background: var(--ink);
  color: var(--bg);
  font-size: 0.875rem;
  font-weight: 500;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translate(-50%, 12px);
  pointer-events: none;
  transition: opacity 0.25s, transform 0.35s var(--ease-out);
}
.toast.is-shown { opacity: 1; transform: translate(-50%, 0); }

/* ---------- 5a. Hero ---------- */
.hero {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: center;
  min-height: max(640px, min(100svh, 1000px));
  padding: calc(var(--nav-h) + clamp(40px, 7vh, 88px)) 0 clamp(56px, 8vh, 96px);
  overflow: hidden;
}
.topo {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  /* keep the contours out from under the words: strong on the right, faint behind the text */
  -webkit-mask-image: linear-gradient(100deg, rgba(0, 0, 0, 0.32) 0%, rgba(0, 0, 0, 0.5) 35%, #000 70%);
  mask-image: linear-gradient(100deg, rgba(0, 0, 0, 0.32) 0%, rgba(0, 0, 0, 0.5) 35%, #000 70%);
  opacity: 0;
  transition: opacity 1.4s var(--ease);
}
.topo.is-ready { opacity: 1; }
.hero-fade {
  position: absolute;
  inset: auto 0 0;
  z-index: -1;
  height: 28%;
  background: linear-gradient(to bottom, transparent, var(--bg));
  pointer-events: none;
}
.hero-inner { position: relative; }

.status {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 7px 14px 7px 12px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  font-size: 0.8125rem;
  color: var(--ink-2);
}
.status-dot {
  position: relative;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--ok);
}
.status-dot::after {
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 1px solid var(--ok);
  opacity: 0;
  animation: ping 2.8s var(--ease-out) infinite;
}
@keyframes ping {
  0% { transform: scale(0.5); opacity: 0.8; }
  70%, 100% { transform: scale(1.6); opacity: 0; }
}

.hero-title { margin: clamp(22px, 3.2vh, 34px) 0 0; }
.hero-id {
  display: flex;
  align-items: center;
  gap: 12px;
  font: 500 1rem/1.3 var(--sans);
  letter-spacing: -0.005em;
}
.avatar {
  width: 44px; height: 44px;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 3px var(--line-strong);
}
.hero-role { color: var(--ink-3); font-weight: 400; }
.hero-sep { white-space: pre; }
.hero-statement {
  display: block;
  max-width: 13ch;
  margin-top: clamp(16px, 2.4vh, 26px);
  font: 800 semi-expanded clamp(2.5rem, 5.05vw, 5.15rem)/0.96 var(--display);
  letter-spacing: -0.045em;
  text-wrap: balance;
}
/* Emphasis: the word catches the sunset. Red rock into prickly-pear berry by
   day, amber into orange into pink at dusk (--em-sunset). As the heading
   arrives the light sweeps across it from the ink; where background-clip:
   text isn't supported the word is simply red rock. This is the only
   emphasis rule. */
.hero-statement em, .section-title em, .contact-title em {
  font-style: normal;
  color: var(--accent);
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero-statement em, .section-title em, .contact-title em {
    padding: 0 0.04em;
    background: var(--em-sunset) 0 0 / 250% 100% no-repeat;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
    -webkit-box-decoration-break: clone;
    box-decoration-break: clone;
  }
  /* the light crosses the word in reading order, slowly, like a sunrise */
  .js .reveal .section-title em, .js .contact-title.reveal em { background-position: 100% 0; transition: background-position 2.2s cubic-bezier(0.5, 0, 0.2, 1) 0.5s; }
  .js .reveal.in .section-title em, .js .contact-title.reveal.in em { background-position: 0 0; }
  .js .hero-statement em { animation: sunlit 2.4s cubic-bezier(0.5, 0, 0.2, 1) 0.9s both; }
}
@keyframes sunlit { from { background-position: 100% 0; } }
@media (prefers-reduced-motion: reduce) {
  .js .reveal .section-title em, .js .contact-title.reveal em { transition: none; }
  .js .hero-statement em { animation: none; }
}

.hero-lede {
  max-width: 58ch;
  margin-top: clamp(22px, 3vh, 32px);
  font-size: clamp(1.0625rem, 1.35vw, 1.25rem);
  line-height: 1.55;
  color: var(--ink-2);
  text-wrap: pretty;
}
.hero-cta { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-top: clamp(24px, 3.4vh, 36px); }
/* Under the calls to action: the note from Anthropic's Claude Code team,
   pointing down to How I build. It lives in this column, not in the field
   notes card: a taller card would rise into the hawk's thermal. */
.hero-note { margin-top: clamp(20px, 2.8vh, 30px); }
/* The four numbers the field-notes card used to hold, in one line under the calls to action. */
.hero-stats { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 16px; list-style: none; font-size: 0.875rem; line-height: 1.4; color: var(--ink-2); }
.hero-stats b { font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; }
.hero-note a { display: inline-flex; flex-direction: column; gap: 5px; padding-top: 14px; border-top: 1px solid var(--line); }
.hero-note-title { font: 800 semi-expanded clamp(1.02rem, 1.25vw, 1.12rem)/1.2 var(--display); letter-spacing: -0.025em; transition: color 0.25s; }
.hero-note-text { font-size: 0.9375rem; line-height: 1.45; color: var(--ink-2); text-wrap: pretty; }
.hero-note-arrow { display: inline-block; color: var(--accent-ink); transition: transform 0.25s var(--ease); }
.hero-note a:hover .hero-note-title { color: var(--accent); }
.hero-note a:hover .hero-note-arrow { transform: translateY(2px); }
.copy-email .icon-copy { width: 16px; height: 16px; opacity: 0.7; }
.copy-email.is-copied .icon-copy { opacity: 1; stroke: var(--ok); }

/* the "Try it" card: a map legend holding three questions for the ask bar (js/ask.js asks
   them: [data-ask]) and the way into the starship */
.hero-inner {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 356px);
  gap: clamp(40px, 5vw, 88px);
  align-items: end;
}
.legend {
  padding: 16px 20px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--surface) 74%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  backdrop-filter: blur(14px) saturate(1.2);
  box-shadow: var(--shadow);
}
.legend-head, .legend-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  font: 500 semi-condensed 0.6875rem/1 var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.legend-head { padding-bottom: 13px; border-bottom: 1px solid var(--line); }
.legend-title { color: var(--ink); }
.legend-coords { display: flex; gap: 10px; }
.legend-foot { flex-wrap: wrap; justify-content: flex-start; gap: 6px 8px; padding-top: 12px; border-top: 1px solid var(--line); }
.legend-place { margin-left: auto; color: var(--accent-ink); white-space: nowrap; }
.legend-elev { margin-left: 4px; color: var(--ink-2); }
/* a true scale bar: js/topo.js sets --scale-w from the map's zoom */
.scale { display: inline-flex; width: var(--scale-w, 61px); }
.scale i { flex: 1 1 0; height: 5px; border: 1px solid var(--ink-3); }
.scale i + i { border-left: 0; }
.scale i:nth-child(odd) { background: var(--ink-3); }

.try-lede { margin-top: 13px; font-size: 0.875rem; line-height: 1.5; color: var(--ink-2); text-wrap: pretty; }
.try-asks { display: grid; gap: 6px; margin-top: 12px; list-style: none; }
.try-ask {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--surface) 55%, transparent);
  font: 500 0.875rem/1.35 var(--sans);
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.2s, background-color 0.2s, color 0.2s;
}
.try-ask-go { flex: none; color: var(--accent-ink); transition: transform 0.25s var(--ease); }
.try-ask:hover, .try-ask:focus-visible { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-ink); }
.try-ask:hover .try-ask-go { transform: translateY(2px); }
.try-more { display: flex; flex-wrap: wrap; gap: 6px 18px; margin: 13px 0 14px; }
.try-more .link-arrow { font-size: 0.875rem; }
.try-meta { align-self: center; font: 500 semi-condensed 0.625rem/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }

@media (max-width: 1100px) {
  .hero-inner { grid-template-columns: 1fr; align-items: start; row-gap: 0; }
  /* One column: the Try it card comes after the calls to action and before the Claude Code note
     (under 640px it moves up under the headline: see below). */
  .hero-main { display: contents; }
  .legend { order: 1; max-width: 560px; margin-top: clamp(28px, 4vh, 40px); }
  .hero-note { order: 2; }
}
@media (max-width: 640px) {
  .legend-coords { display: none; }
  /* A phone puts the Try it card straight under the headline, so its first question is on the first
     screen; the lede, the calls to action, the numbers and the note follow it. */
  .legend { order: 1; max-width: none; margin-top: 22px; }
  .hero-lede, .hero-cta, .hero-stats { order: 2; }
  .hero-note { order: 3; }
}
@media (max-width: 520px) {
  .hero { min-height: 0; }
  .hero-statement { font-size: clamp(2.05rem, 10.2vw, 2.7rem); max-width: none; }
  .hero-role { display: block; font-size: 0.875rem; }
  .hero-sep { display: none; }
  .avatar { width: 40px; height: 40px; }
  .hero-cta .btn { flex: 1 1 auto; }
  .hero-cta .copy-email { flex-basis: 100%; }
  .legend { padding: 14px 16px 12px; }
}

/* ---------- 5b. Section scaffolding ---------- */
.section {
  position: relative;
  padding-block: clamp(80px, 10vw, 144px);
}
.section-tint { background: var(--bg-tint); }
.section-head { position: relative; margin-bottom: clamp(44px, 6vw, 80px); }
.section-head > :not(.head-illo) { max-width: 900px; }
.section-title {
  margin-top: 20px;
  font: 800 semi-expanded clamp(1.9rem, 3.75vw, 3.25rem)/1.04 var(--display);
  letter-spacing: -0.04em;
  text-wrap: balance;
}
.section-lede {
  max-width: 64ch;
  margin-top: 22px;
  font-size: clamp(1.0625rem, 1.3vw, 1.1875rem);
  line-height: 1.6;
  color: var(--ink-2);
  text-wrap: pretty;
}

/* ---------- 5c. Migration (featured program) ---------- */
.mig {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(40px, 6vw, 104px);
  align-items: start;
}
.mig-viz {
  position: sticky;
  top: calc(var(--nav-h) + 32px);
  margin: 0;
}
.mig-headline { display: flex; align-items: flex-end; gap: 18px; margin-bottom: 26px; }
.mig-big {
  font: 800 semi-expanded clamp(4rem, 7.6vw, 7rem)/0.86 var(--display);
  letter-spacing: -0.05em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.mig-big-label { max-width: 17ch; padding-bottom: 6px; font-size: 0.9375rem; line-height: 1.4; color: var(--ink-2); }

.units {
  display: grid;
  grid-template-columns: repeat(10, 1fr);
  gap: 5px;
  max-width: 440px;
}
.u {
  aspect-ratio: 1;
  border-radius: 2px;
  background: var(--accent);
  transition: background-color 0.5s var(--ease), transform 0.5s var(--ease);
  transition-delay: calc(var(--i) * 9ms);
}
.u-lost { background: transparent; box-shadow: inset 0 0 0 1.5px var(--line-strong); }
.js .mig-viz:not(.in) .u:not(.u-lost) { background: var(--g-soft); transform: scale(0.82); }

.units-cap {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 10px;
  max-width: 440px;
  margin-top: 16px;
  font-size: 0.8125rem;
  color: var(--ink-3);
}
.key { width: 10px; height: 10px; border-radius: 2px; }
.key-on { background: var(--accent); }
.key-off { box-shadow: inset 0 0 0 1.5px var(--line-strong); margin-left: 8px; }
.units-note { flex-basis: 100%; }

.rate { max-width: 440px; margin-top: 34px; padding-top: 22px; border-top: 1px solid var(--line); }
.rate-title { margin-bottom: 14px; font: 500 semi-condensed 0.75rem var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }
.rate-row {
  display: grid;
  grid-template-columns: 9.5rem 1fr 3rem;
  align-items: center;
  gap: 14px;
  padding: 7px 0;
  font-size: 0.875rem;
  color: var(--ink-2);
}
.rate-track { height: 10px; border-radius: 2px; background: var(--g-soft); overflow: hidden; }
.rate-bar {
  display: block;
  width: var(--w);
  height: 100%;
  border-radius: inherit;
  transform-origin: 0 50%;
  transition: transform 1.2s var(--ease-out) 0.9s;
}
.rate-bar-before { background: var(--ink-3); }
.rate-bar-after { background: var(--accent); }
.rate-v { font: 500 semi-condensed 0.875rem var(--mono); text-align: right; color: var(--ink); }
.js .mig-viz:not(.in) .rate-bar { transform: scaleX(0); }

.steps { list-style: none; counter-reset: step; }
.step {
  display: grid;
  grid-template-columns: 7.5rem 1fr;
  gap: 20px;
  padding: 30px 0;
  border-top: 1px solid var(--line);
}
.step:first-child { border-top-color: var(--line-strong); }
.step-n {
  counter-increment: step;
  padding-top: 4px;
  font: 500 semi-condensed 0.75rem var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent-ink);
}
.step-n::before { content: "0" counter(step) "  "; color: var(--ink-3); white-space: pre; }
.step p { font-size: 1.0625rem; line-height: 1.65; color: var(--ink-2); text-wrap: pretty; }
.mini-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 22px 24px; }
.mini-stats dt { font: 500 semi-condensed 0.6875rem var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }
.mini-stats dd { margin-top: 6px; font: 800 semi-expanded clamp(1.2rem, 1.7vw, 1.45rem)/1.1 var(--display); letter-spacing: -0.03em; }
.mini-stats small { display: block; margin-top: 4px; font: 400 0.875rem/1.35 var(--sans); letter-spacing: 0; color: var(--ink-3); }
.step-more { margin-top: 24px; }
/* "DoorDash's numbers stay internal": says why the results above are words, not figures. */
.step .step-aside { margin-top: 24px; font-size: 0.875rem; line-height: 1.5; color: var(--ink-3); }
.step-aside + .step-more { margin-top: 10px; }

@media (max-width: 900px) {
  .mig { grid-template-columns: 1fr; }
  .mig-viz { position: static; }
}
@media (max-width: 520px) {
  .step { grid-template-columns: 1fr; gap: 10px; padding: 24px 0; }
  .rate-row { grid-template-columns: 1fr 2.5rem; }
  .rate-track { grid-column: 1 / -1; grid-row: 2; }
}

/* ---------- 5d. Work: bento of schematics ---------- */
.bento { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 20px; }
.card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  transition: transform 0.45s var(--ease), box-shadow 0.45s var(--ease), border-color 0.3s;
}
.card-7 { grid-column: span 7; }
.card-6 { grid-column: span 6; }
.card-5 { grid-column: span 5; }
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); border-color: var(--line-strong); }
.card:has(.card-link:focus-visible) { outline: 2px solid var(--accent); outline-offset: 3px; }
.card-link:focus-visible { outline: none; }

.card-art {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  height: clamp(200px, 18.5vw, 256px);
  padding: 18px 22px 8px;
  border-bottom: 1px solid var(--line-2);
  background:
    radial-gradient(120% 90% at 100% 0%, var(--accent-soft), transparent 55%),
    linear-gradient(var(--surface), var(--surface));
}
.card-art .glyph { width: 100%; height: 100%; }
.card-body { display: flex; flex: 1; flex-direction: column; gap: 10px; padding: 22px 28px 26px; }
.card-title { font: 800 semi-expanded clamp(1.3rem, 1.75vw, 1.55rem)/1.1 var(--display); letter-spacing: -0.03em; text-wrap: balance; }
.card-link::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
.card-one { font-size: 1rem; line-height: 1.55; color: var(--ink-2); text-wrap: pretty; }
.card-stats { display: flex; flex-wrap: wrap; gap: 6px 18px; margin-top: 4px; list-style: none; font-size: 0.875rem; color: var(--ink-3); }
.card-stats b { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.card-cta { display: inline-flex; gap: 6px; margin-top: auto; padding-top: 12px; font-size: 0.9375rem; font-weight: 500; color: var(--accent-ink); }
.card-cta-arrow { transition: transform 0.3s var(--ease); }
.card:hover .card-cta-arrow { transform: translateX(4px); }

@media (max-width: 1000px) {
  .card-7, .card-6, .card-5 { grid-column: span 6; }
}
@media (max-width: 700px) {
  .bento { gap: 14px; }
  .card-7, .card-6, .card-5 { grid-column: 1 / -1; }
  .card-body { padding: 20px 22px 22px; }
}

/* schematic vocabulary (shared by cards and case studies) */
.glyph { overflow: visible; }
.g-soft { fill: var(--g-soft); }
.g-soft2 { fill: var(--g-soft2); }
.g-ink { fill: none; stroke: var(--ink-3); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.g-acc { fill: none; stroke: var(--accent); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.g-accf { fill: var(--accent); }
.g-faint { opacity: 0.4; }
.g-faint2 { opacity: 0.65; }
.g-dash { stroke-dasharray: 4 5; }
.g-flow { stroke-dasharray: 6 7; }
.g-txt { font: 500 semi-condensed 13px var(--mono); letter-spacing: 0.04em; fill: var(--ink-3); }
.g-txt-acc { fill: var(--accent-ink); }
.g-num { font: 800 semi-expanded 34px var(--display); fill: var(--ink); letter-spacing: -0.04em; }
.g-node { fill: var(--surface); stroke: var(--ink-3); stroke-width: 1.5; }
.g-node-acc { stroke: var(--accent); stroke-width: 2; }
.g-win { fill: var(--surface); stroke: var(--ink-3); stroke-width: 1.3; }
.g-win-strong { stroke: var(--ink-2); stroke-width: 1.5; }
.g-field { fill: var(--bg); stroke: var(--line-strong); }
.g-tick { fill: none; stroke: var(--on-accent); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.g-chip-t { font: 700 semi-condensed 8.5px var(--mono); fill: var(--on-accent); letter-spacing: 0.04em; }
.g-ring { fill: none; stroke: var(--accent); stroke-width: 1.5; opacity: 0; transform-box: fill-box; transform-origin: center; }
.g-draw { stroke-dasharray: 1; stroke-dashoffset: 0; transition: stroke-dashoffset 1.8s var(--ease) 0.3s; }
.g-arc { stroke-dasharray: 1; stroke-dashoffset: 0; transition: stroke-dashoffset 0.9s var(--ease); transition-delay: calc(0.3s + var(--i) * 0.28s); }
.g-head { transition: opacity 0.3s; transition-delay: calc(0.9s + var(--i) * 0.28s); }
.g-bars rect, .g-tabs > g, .g-sections rect, .g-check { transform-box: fill-box; transition: transform 0.6s var(--ease), opacity 0.4s; }
.g-bars rect { transform-origin: 50% 100%; transition-delay: calc(var(--i) * 8ms); }

.js .card:not(.in) .g-draw { stroke-dashoffset: 1; }
.js .card:not(.in) .g-arc { stroke-dashoffset: 1; }
.js .card:not(.in) .g-head { opacity: 0; }
.js .card:not(.in) .g-bars rect { transform: scaleY(0.2); }

@media (hover: hover) {
  .card:hover .g-flow { animation: flow 1.1s linear infinite; }
  .card:hover .g-bars rect:nth-child(3n) { transform: scaleY(1.14); }
  .card:hover .g-bars rect:nth-child(4n + 1) { transform: scaleY(0.88); }
  .card:hover .g-wall rect { opacity: 0.45; }
  .card:hover .g-sections rect { transform: translateX(4px); }
  .card:hover .g-tabs > g { transform: translate(calc((4 - var(--i)) * 5px), calc((var(--i) - 2) * 2px)); }
  .card:hover .g-check { transform: translateX(3px); }
  .card:hover .g-ring { animation: ring 1.6s var(--ease-out) infinite; }
  .card:hover .g-chip { animation: blink 1.2s steps(2, jump-none) infinite; }
}
@keyframes flow { to { stroke-dashoffset: -26; } }
@keyframes ring { 0% { opacity: 0.9; transform: scale(1); } 100% { opacity: 0; transform: scale(1.9); } }

/* ---------- 5e. Case studies (<dialog>, opened by js/case-studies.js) ---------- */
.cs {
  width: min(900px, calc(100vw - 32px));
  max-width: none;
  max-height: calc(100dvh - 48px);
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--ink);
  overflow: visible;
}
.cs::backdrop { background: rgba(14, 12, 10, 0.5); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
.cs[open] { animation: fade-in 0.3s var(--ease); }
.cs[open]::backdrop { animation: fade-in 0.35s var(--ease); }
.cs[open] .cs-sheet { animation: sheet-in 0.5s var(--ease-out); }
.cs.is-closing, .cs.is-closing::backdrop { animation: fade-out 0.2s var(--ease) forwards; }
.cs.is-closing .cs-sheet { animation: sheet-out 0.22s var(--ease) forwards; }
@keyframes fade-in { from { opacity: 0; } }
@keyframes fade-out { to { opacity: 0; } }
@keyframes sheet-in { from { opacity: 0; transform: translateY(28px) scale(0.985); } }
@keyframes sheet-out { to { opacity: 0; transform: translateY(16px) scale(0.99); } }

.cs-sheet {
  max-height: calc(100dvh - 48px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: clamp(24px, 4.5vw, 52px);
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--bg);
  box-shadow: var(--shadow-lg);
}
.cs-top { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.cs-close {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px 8px 16px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  font-size: 0.875rem;
  font-weight: 500;
  transition: background-color 0.2s, border-color 0.2s;
}
.cs-close:hover { background: var(--surface); border-color: var(--ink); }
@media (hover: none) { .cs-close kbd { display: none; } .cs-close { padding-right: 16px; } }
.cs-title { margin-top: 18px; font: 800 semi-expanded clamp(1.75rem, 3.5vw, 2.6rem)/1.05 var(--display); letter-spacing: -0.04em; text-wrap: balance; }
.cs-one { max-width: 56ch; margin-top: 14px; font: 500 clamp(1.125rem, 1.6vw, 1.3rem)/1.45 var(--sans); color: var(--ink-2); }
.cs-art {
  display: flex;
  align-items: center;
  justify-content: center;
  height: clamp(200px, 30vw, 280px);
  margin: 28px 0;
  padding: 22px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: radial-gradient(120% 100% at 100% 0%, var(--accent-soft), transparent 60%), var(--surface);
}
.cs-art .glyph { width: 100%; height: 100%; }
.cs-stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--line-strong);
  border-bottom: 1px solid var(--line);
}
.cs-stats div { padding: 16px 14px 18px 0; }
.cs-stats div + div { padding-left: 16px; border-left: 1px solid var(--line); }
.cs-stats dt { font: 500 semi-condensed 0.6875rem/1.35 var(--mono); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
.cs-stats dd { margin-top: 8px; font: 800 semi-expanded 1.2rem/1.15 var(--display); letter-spacing: -0.03em; }
.cs-body { margin: 12px 0 28px; }
.cs-body section { display: grid; grid-template-columns: 9.5rem 1fr; gap: 20px; padding: 22px 0; border-bottom: 1px solid var(--line-2); }
.cs-body h4 { padding-top: 5px; font: 500 semi-condensed 0.75rem var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent-ink); }
.cs-body p { font-size: 1.0625rem; line-height: 1.7; color: var(--ink-2); text-wrap: pretty; }
.cs-body .cs-more { margin-top: 14px; }
.cs-nav { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 32px; }
.cs-nav a {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  transition: border-color 0.2s, background-color 0.2s;
}
.cs-nav a:hover { border-color: var(--line-strong); background: var(--surface); }
.cs-next { text-align: right; }
.cs-nav-k { font: 500 semi-condensed 0.6875rem var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }
.cs-nav-t { font: 750 semi-expanded 1rem/1.2 var(--display); letter-spacing: -0.02em; }

/* Without JavaScript a case study still opens: its card links to #cs-id and
   :target shows the dialog inline, in the flow of the page. */
.cs:target:not([open]) { display: block; position: static; margin: 48px auto 0; max-height: none; outline: none; }
.cs:target:not([open]) .cs-sheet { max-height: none; }
.js .cs:target:not([open]) { display: none; }

@media (max-width: 640px) {
  .cs { width: 100vw; max-height: 94dvh; margin: auto 0 0; }
  .cs-sheet { max-height: 94dvh; padding: 22px 20px 28px; border-radius: 16px 16px 0 0; border-bottom: 0; }
  .cs[open] .cs-sheet { animation: sheet-up 0.45s var(--ease-out); }
  .cs.is-closing .cs-sheet { animation: sheet-down 0.22s var(--ease) forwards; }
  .cs-stats { grid-template-columns: 1fr 1fr; }
  .cs-stats div:nth-child(3) { padding-left: 0; border-left: 0; }
  .cs-stats div:nth-child(n + 3) { border-top: 1px solid var(--line); }
  .cs-body section { grid-template-columns: 1fr; gap: 8px; }
  .cs-nav { grid-template-columns: 1fr; }
  .cs-next { text-align: left; }
}
@keyframes sheet-up { from { transform: translateY(100%); } }
@keyframes sheet-down { to { transform: translateY(100%); } }

html.has-modal { overflow: hidden; }

/* ---------- 5n. How I build ---------- */
/* Between Work and the Lab: the card from Anthropic's Claude Code team (a
   print like the portrait in About, landscape: .portrait-wide) and its words,
   set the way the card sets them, beside the practices, which reuse the
   Featured program's .steps. */
.build {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}
.build-side { position: sticky; top: calc(var(--nav-h) + 32px); }
.pull { margin: 34px 0 0; padding-left: 22px; border-left: 2px solid var(--accent); }
.pull blockquote { margin: 0; }
.pull p { font-size: 1rem; line-height: 1.6; color: var(--ink-2); text-wrap: pretty; }
.pull p + p { margin-top: 10px; }
.pull .pull-lead { font: 800 semi-expanded clamp(1.15rem, 1.55vw, 1.35rem)/1.25 var(--display); letter-spacing: -0.03em; color: var(--ink); text-wrap: balance; }
.pull figcaption { margin-top: 14px; font: 500 semi-condensed 0.75rem/1.4 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }
/* links inside the practices: underlined, like the footer's side quests */
.build-main .step a { color: var(--ink); text-decoration: underline; text-decoration-color: var(--line-strong); text-underline-offset: 3px; transition: color 0.2s, text-decoration-color 0.2s; }
.build-main .step a:hover { color: var(--accent-ink); text-decoration-color: currentColor; }
.build-more { display: flex; flex-wrap: wrap; gap: 8px 24px; margin-top: 26px; }

@media (max-width: 900px) {
  .build { grid-template-columns: 1fr; }
  .build-side { position: static; max-width: 620px; }
}

/* ---------- 5f. Lab (always a night room) ---------- */
.lab {
  --em-sunset: linear-gradient(90deg, #ffb547 0%, #ff7a45 20%, #ff5c93 40%, var(--lab-ink) 55%, var(--lab-ink) 100%);
  --on-accent: #150f24;
  --bg: var(--lab-bg);
  --surface: var(--lab-surface);
  --ink: var(--lab-ink);
  --ink-2: var(--lab-ink-2);
  --ink-3: var(--lab-ink-3);
  --line: var(--lab-line);
  --line-strong: var(--lab-line-strong);
  --accent: var(--lab-accent);
  --accent-ink: #ff9464;
  --accent-soft: rgba(255, 122, 69, 0.1);
  --support: #a9c46c;
  --bloom: #ff5c93;
  --bg-tint: #1b1430;
  --line-2: rgba(245, 238, 242, 0.06);
  --g-soft: rgba(245, 238, 242, 0.1);
  --g-soft2: rgba(245, 238, 242, 0.26);
  --illo-line: rgba(245, 238, 242, 0.2);
  color-scheme: dark;
  background: var(--bg);
  color: var(--ink);
}
.lab-feature {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  gap: clamp(28px, 4.5vw, 64px);
  align-items: center;
}
.lab-poster {
  position: relative;
  display: block;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: #0a0a0e;
  box-shadow: 0 40px 80px -40px rgba(0, 0, 0, 0.8);
}
.lab-poster img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; transition: transform 1.4s var(--ease-out), filter 0.4s; }
.lab-poster:hover img { transform: scale(1.04); filter: brightness(1.08); }
.lab-bar {
  position: absolute;
  inset: 0 0 auto;
  z-index: 1;
  display: flex;
  justify-content: space-between;
  padding: 14px 18px 26px;
  background: linear-gradient(rgba(5, 8, 12, 0.78), transparent);
  font: 500 semi-condensed 0.6875rem var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(245, 238, 242, 0.74);
}
.lab-play {
  position: absolute;
  left: 50%; top: 50%;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 22px 14px 18px;
  border: 1px solid rgba(245, 238, 242, 0.28);
  border-radius: var(--radius-sm);
  background: rgba(10, 10, 14, 0.62);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  color: #e8edf1;
  font-weight: 600;
  font-size: 0.9375rem;
  transform: translate(-50%, -50%);
  transition: background-color 0.25s, border-color 0.25s, transform 0.4s var(--ease);
}
.lab-play svg { width: 16px; height: 16px; fill: currentColor; }
.lab-poster:hover .lab-play { background: var(--accent); border-color: var(--accent); color: var(--on-accent); transform: translate(-50%, -50%) scale(1.04); }

.lab-copy { display: flex; flex-direction: column; gap: 14px; }
.lab-title { font: 800 semi-expanded clamp(1.7rem, 2.8vw, 2.4rem)/1.02 var(--display); letter-spacing: -0.04em; }
.lab-copy > p { color: var(--ink-2); line-height: 1.65; }
.lab-links { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-top: 4px; }

.lab-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 20px;
  margin-top: clamp(28px, 4vw, 48px);
}
/* Each card is one big link (the title's link stretches over it); the orb button,
   game chips and the small links below sit above that layer and stay their own. */
.lab-card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  transition: border-color 0.25s, transform 0.35s var(--ease-out), box-shadow 0.35s;
}
.lab-card:hover { border-color: var(--line-strong); transform: translateY(-3px); box-shadow: 0 30px 60px -36px rgba(0, 0, 0, 0.9); }
.lab-card:has(.lab-card-link:focus-visible) { outline: 2px solid var(--accent); outline-offset: 3px; }
.lab-card-link { color: inherit; outline: none; }
.lab-card-link::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.lab-card-go { display: inline-block; margin-left: 8px; color: var(--accent-ink); font-weight: 500; transition: transform 0.25s var(--ease); }
.lab-card:hover .lab-card-title { color: var(--accent-ink); }
.lab-card:hover .lab-card-go { transform: translateX(3px); }
.lab-card .lab-links, .lab-chips { position: relative; z-index: 2; }
.lab-card .orb-wake { z-index: 2; }
.lab-card-body { display: flex; flex: 1; flex-direction: column; gap: 12px; padding: 22px 24px 24px; }
.lab-card-title { font: 800 semi-expanded 1.35rem/1.1 var(--display); letter-spacing: -0.03em; transition: color 0.2s; }
.lab-card-body > p { font-size: 0.9688rem; line-height: 1.6; color: var(--ink-2); }
.lab-card-body > p.lab-how { padding-left: 14px; border-left: 2px solid var(--line-strong); font-size: 0.9063rem; line-height: 1.55; color: var(--ink-3); }
.lab-how-label { display: block; margin-bottom: 4px; font: 500 semi-condensed 0.6875rem/1.3 var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent-ink); }
.lab-card .lab-links { margin-top: auto; padding-top: 6px; }
.lab-try { padding: 0; border: 0; background: none; font-family: inherit; cursor: pointer; }
.lab-try:hover span { transform: translateY(2px); }
/* jump-in chips on the Arcade card: tags you can press */
.lab-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-top: auto; padding-top: 6px; list-style: none; }
.lab-chips a {
  display: inline-block;
  padding: 8px 11px;
  border: 1px solid var(--line-strong);
  border-radius: 4px;
  font: 500 semi-condensed 0.75rem/1 var(--mono);
  letter-spacing: 0.02em;
  color: var(--ink);
  transition: border-color 0.2s, background-color 0.2s, color 0.2s;
}
.lab-chips a:hover, .lab-chips a:focus-visible { border-color: var(--accent); background: var(--accent-soft); color: var(--accent-ink); }

/* stages: the top half of each lab card */
.orb-slot, .arcade-stage, .dispatch-stage, .ask-stage, .guard-stage, .eval-stage {
  position: relative;
  display: block;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-bottom: 1px solid var(--line);
  background: #0d0918;
}
/* stand-in until the real orb loads: gradients only (large box-shadow glows band on some GPUs) */
.orb-poster {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding-bottom: 36px;
  background: radial-gradient(circle at 50% 44%, rgba(255, 150, 70, 0.24), rgba(232, 70, 111, 0.07) 36%, transparent 60%);
}
.orb-core {
  height: 58%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 36% 30%, #fff6dc 0%, #ffd66e 15%, #ff8a3d 42%, #c2364f 72%, #3a0f24 100%);
  animation: breathe 5.5s ease-in-out infinite;
}
@keyframes breathe { 50% { transform: scale(1.05); } }
.orb-slot iframe {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  border: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 1.2s var(--ease);
}
.orb-slot.is-live iframe { opacity: 1; }
.orb-slot.is-live .orb-poster { opacity: 0; transition: opacity 1.2s; }
.orb-wake {
  position: absolute;
  left: 50%; bottom: 16px;
  z-index: 2;
  padding: 9px 16px;
  border: 1px solid rgba(245, 238, 242, 0.25);
  border-radius: var(--radius-sm);
  background: rgba(18, 12, 32, 0.6);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  font-size: 0.8125rem;
  font-weight: 500;
  color: #f5eef2;
  cursor: pointer;
  transform: translateX(-50%);
  transition: background-color 0.2s, border-color 0.2s;
}
.orb-wake:hover { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.orb-slot.is-live .orb-wake, .orb-slot.is-loading .orb-wake { display: none; }
.lab-live {
  position: absolute;
  top: 14px; right: 16px;
  z-index: 2;
  display: none;
  align-items: center;
  gap: 7px;
  font: 500 semi-condensed 0.6875rem var(--mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--support);
}
.lab-live::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; box-shadow: 0 0 8px currentColor; animation: blink 1.8s infinite; }
.orb-slot.is-live .lab-live { display: inline-flex; }
@keyframes blink { 50% { opacity: 0.35; } }

.arcade-stage { background: radial-gradient(120% 90% at 50% 120%, var(--accent-soft), transparent 60%), #0d0918; }
.arcade-stage::before, .arcade-stage::after {
  content: "";
  position: absolute;
  left: 8%; right: 8%;
  height: 12px;
  border: 2px solid color-mix(in srgb, var(--accent) 45%, transparent);
  border-radius: 4px;
}
.arcade-stage::before { top: calc(50% - 52px); }
.arcade-stage::after { top: calc(50% + 40px); }
@property --mouth { syntax: "<angle>"; inherits: false; initial-value: 34deg; }
.pac {
  position: absolute;
  left: 20%; top: 50%;
  z-index: 1;
  width: 50px; height: 50px;
  margin: -25px 0 0 -25px;
  border-radius: 50%;
  background: var(--accent);
  -webkit-mask: conic-gradient(from calc(90deg + var(--mouth)), #000 calc(360deg - 2 * var(--mouth)), transparent 0);
  mask: conic-gradient(from calc(90deg + var(--mouth)), #000 calc(360deg - 2 * var(--mouth)), transparent 0);
  animation: chomp 0.36s ease-in-out infinite alternate;
}
@keyframes chomp { to { --mouth: 3deg; } }
.pellets {
  position: absolute;
  left: 20%; right: 8%; top: 50%;
  height: 8px;
  margin-top: -4px;
  background: radial-gradient(circle, var(--ink) 0 3px, transparent 3.5px) 0 0 / 34px 8px repeat-x;
  animation: pellets 0.72s linear infinite;
}
@keyframes pellets { to { background-position: -34px 0; } }
.arcade-coin {
  position: absolute;
  left: 0; right: 0; bottom: 18px;
  text-align: center;
  font: 500 semi-condensed 0.75rem var(--mono);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-2);
  animation: coin 1.1s steps(2, jump-none) infinite;
}
@keyframes coin { 50% { opacity: 0.2; } }

.dispatch-stage { display: flex; flex-direction: column; justify-content: flex-end; padding: 22px; background: radial-gradient(100% 80% at 0% 0%, var(--accent-soft), transparent 60%), #0d0918; }
.ticker {
  position: absolute;
  top: 20px; left: 0; right: 0;
  overflow: hidden;
  border-block: 1px solid var(--line);
  padding: 9px 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.ticker-track { display: flex; width: max-content; animation: marquee 28s linear infinite; }
.ticker-track span { padding: 0 14px; font: 500 semi-condensed 0.6875rem var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); white-space: nowrap; }
.ticker-track span:nth-child(4n + 2) { color: var(--accent-ink); }
@keyframes marquee { to { transform: translateX(-50%); } }
.dispatch-latest { display: flex; flex-direction: column; gap: 8px; }
.dispatch-kicker { font: 500 semi-condensed 0.6875rem var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent-ink); }
.dispatch-title { font: 750 semi-expanded 1.15rem/1.2 var(--display); letter-spacing: -0.02em; color: var(--ink); text-wrap: balance; }
.dispatch-date { font: 500 semi-condensed 0.75rem var(--mono); color: var(--ink-3); }
.lab-card:hover .dispatch-title { color: var(--accent); }

/* the Answer Finder's stage: the bar in miniature, and the four real steps it takes */
.ask-stage {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 18px;
  padding: 0 clamp(18px, 6%, 40px);
  background: radial-gradient(90% 80% at 50% 110%, rgba(255, 92, 147, 0.12), transparent 60%), #0d0918;
}
.ask-mini {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 7px 7px 9px;
  border: 1px solid rgba(245, 238, 242, 0.16);
  border-radius: 999px;
  background: rgba(245, 238, 242, 0.05);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
.ask-mini-orb {
  flex: 0 0 24px;
  height: 24px;
  border-radius: 50%;
  background: radial-gradient(circle at 36% 30%, #fff6dc 0%, #ffd66e 15%, #ff8a3d 42%, #c2364f 72%, #3a0f24 100%);
  animation: breathe 5.5s ease-in-out infinite;
}
.ask-mini-q { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.875rem; color: var(--ink-2); }
.ask-mini-send { flex: 0 0 26px; height: 26px; display: grid; place-items: center; border: 1.6px solid var(--ink-2); border-radius: 50%; }
.ask-mini-send svg { width: 12px; height: 12px; fill: none; stroke: var(--accent-ink); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.ask-steps { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 14px; }
@media (max-width: 480px) { .ask-steps { grid-template-columns: 1fr; gap: 6px; } }
.ask-steps span {
  display: flex;
  align-items: center;
  gap: 8px;
  font: 500 semi-condensed 0.6875rem/1.3 var(--mono);
  letter-spacing: 0.04em;
  color: var(--ink-3);
  animation: ask-step 6s infinite;
}
.ask-steps span::before { content: ""; flex: 0 0 6px; height: 6px; border-radius: 50%; background: var(--accent-ink); }
.ask-steps span:nth-child(2) { animation-delay: 0.6s; }
.ask-steps span:nth-child(3) { animation-delay: 1.2s; }
.ask-steps span:nth-child(4) { animation-delay: 1.8s; }
@keyframes ask-step { 0%, 6% { color: var(--ink-3); } 12%, 70% { color: var(--ink); } 80%, 100% { color: var(--ink-3); } }

/* Training wheels' stage: one refused command, the way the hook answers it */
.guard-stage {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 10px;
  padding: 0 clamp(18px, 6%, 40px);
  background: radial-gradient(90% 80% at 0% 110%, rgba(169, 196, 108, 0.12), transparent 60%), #0d0918;
}
.guard-cmd { display: flex; flex-direction: column; gap: 6px; font: 500 semi-condensed 0.875rem/1.2 var(--mono); color: var(--ink); }
.guard-who { font-size: 0.6875rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-3); }
.guard-stop, .guard-instead { padding-left: 12px; border-left: 2px solid var(--accent-ink); font: 500 semi-condensed 0.75rem/1.45 var(--mono); color: var(--ink-2); }
.guard-instead { border-left-color: var(--support); color: var(--ink); }

/* Field guide evals' stage: the held-out scores, as bars */
.eval-stage {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 14px;
  padding: 0 clamp(18px, 6%, 40px);
  background: radial-gradient(90% 80% at 100% 110%, rgba(255, 181, 71, 0.1), transparent 60%), #0d0918;
}
.eval-head, .eval-foot { font: 500 semi-condensed 0.6875rem/1.3 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }
.eval-row { display: grid; grid-template-columns: 7.5em minmax(0, 1fr) 2em; align-items: center; gap: 12px; font: 500 semi-condensed 0.8125rem/1 var(--mono); color: var(--ink-2); }
.eval-bar { position: relative; height: 10px; overflow: hidden; border-radius: 999px; background: rgba(245, 238, 242, 0.08); }
.eval-bar::before { content: ""; position: absolute; inset: 0 auto 0 0; width: var(--p); border-radius: inherit; background: var(--ink-3); }
.eval-row.is-new { color: var(--ink); }
.eval-row.is-new .eval-bar::before { background: var(--accent-ink); }
.eval-n { text-align: right; color: var(--ink); }

@media (max-width: 1000px) {
  .lab-feature { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
  .lab-grid { grid-template-columns: 1fr; }
  .orb-slot, .arcade-stage, .dispatch-stage, .ask-stage, .guard-stage, .eval-stage { aspect-ratio: 16 / 10; }
}
@media (prefers-reduced-motion: reduce) {
  .lab-card { transition: none; }
  .lab-card:hover { transform: none; }
  .ask-steps span, .ask-mini-orb { animation: none; color: var(--ink-2); }
}

/* ---------- 5g. About ---------- */
.about {
  display: grid;
  grid-template-columns: minmax(0, 340px) minmax(0, 1fr);
  gap: clamp(40px, 6vw, 96px);
  align-items: start;
}
.about-side { position: sticky; top: calc(var(--nav-h) + 32px); }
.portrait {
  margin: 0;
  padding: 12px 12px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  transform: rotate(-1.4deg);
  transition: transform 0.6s var(--ease);
}
.portrait:hover { transform: rotate(0deg) translateY(-2px); }
.portrait img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 6px; }
.portrait figcaption { margin-top: 12px; font: 400 semi-condensed 0.8125rem/1.5 var(--mono); color: var(--ink-3); }
.fig { color: var(--ink); font-weight: 500; margin-right: 4px; }
/* the same print, landscape and tipped the other way: the Claude Code card in How I build */
.portrait-wide { transform: rotate(1.1deg); }
.portrait-wide img { aspect-ratio: 4 / 3; }
.facts { margin-top: 28px; }
.facts div { padding: 13px 0; border-top: 1px solid var(--line); }
.facts dt { font: 500 semi-condensed 0.6875rem var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }
.facts dd { margin-top: 4px; font-size: 0.9375rem; line-height: 1.5; color: var(--ink-2); }

.timeline { position: relative; list-style: none; }
.timeline::before {
  content: "";
  position: absolute;
  left: 5px; top: 34px; bottom: 34px;
  width: 1px;
  background: linear-gradient(var(--ink-3), var(--accent));
  opacity: 0.45;
}
.tl {
  position: relative;
  display: grid;
  grid-template-columns: 4.75rem 1fr;
  gap: 20px;
  padding: 26px 0 26px 30px;
  border-top: 1px solid var(--line);
}
.tl:first-child { border-top-color: var(--line-strong); }
.tl::before {
  content: "";
  position: absolute;
  left: 0; top: 33px;
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--bg);
  box-shadow: inset 0 0 0 2px var(--dot, var(--ink-3));
}
.tl[data-phase="specialist"] { --dot: var(--ink-2); }
.tl[data-phase="builder"] { --dot: var(--accent); }
.tl[data-phase="architect"]::before { background: var(--accent); box-shadow: 0 0 0 4px var(--accent-soft); }
.tl-year { padding-top: 3px; font: 500 semi-condensed 0.9375rem var(--mono); font-variant-numeric: tabular-nums; }
.tl-phase { font: 500 semi-condensed 0.6875rem var(--mono); letter-spacing: 0.14em; text-transform: uppercase; color: var(--dot, var(--ink-3)); }
.tl[data-phase="architect"] .tl-phase { color: var(--accent-ink); }
.tl[data-phase="builder"] .tl-phase { color: var(--accent-ink); }
.tl-role { margin-top: 6px; font: 800 semi-expanded clamp(1.1rem, 1.5vw, 1.3rem)/1.2 var(--display); letter-spacing: -0.03em; }
.tl-org { display: block; margin-top: 4px; font: 400 0.875rem/1.4 var(--sans); color: var(--ink-3); letter-spacing: 0; }
.tl p { margin-top: 10px; max-width: 62ch; font-size: 1rem; line-height: 1.6; color: var(--ink-2); }

.recognition {
  margin-top: 40px;
  padding: 24px 28px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.recognition-title { font: 500 semi-condensed 0.75rem var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-3); }
.recognition ul { list-style: none; margin-top: 8px; }
.recognition li { display: grid; grid-template-columns: 2.5rem 1fr; gap: 12px; padding: 12px 0; font-size: 0.9688rem; line-height: 1.55; color: var(--ink-2); }
.recognition li + li { border-top: 1px solid var(--line-2); }
.recognition b { color: var(--ink); font-weight: 600; }
.award-mark { font: 800 semi-expanded 1.25rem/1.2 var(--display); letter-spacing: -0.03em; color: var(--accent); text-align: center; }

@media (max-width: 900px) {
  .about { grid-template-columns: 1fr; }
  .about-side { position: static; display: grid; grid-template-columns: minmax(0, 240px) 1fr; gap: 28px; align-items: start; }
  .facts { margin-top: 0; }
}
@media (max-width: 560px) {
  .about-side { grid-template-columns: 1fr; }
  .portrait { max-width: 300px; }
  .portrait-wide { max-width: none; }
  .tl { grid-template-columns: 1fr; gap: 4px; }
}

/* ---------- 5h. Toolkit ---------- */
.toolkit {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  border-top: 1px solid var(--line-strong);
}
.tk { padding: 26px 26px 28px 0; border-bottom: 1px solid var(--line); }
.tk:not(:nth-child(3n + 1)) { padding-left: 26px; border-left: 1px solid var(--line); }
.tk h3 { font: 500 semi-condensed 0.75rem var(--mono); letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent-ink); }
.tk ul { list-style: none; margin-top: 14px; }
.tk li { padding: 5px 0; font-size: 1rem; color: var(--ink-2); }
@media (max-width: 800px) {
  .toolkit { grid-template-columns: 1fr 1fr; }
  .tk:not(:nth-child(3n + 1)) { padding-left: 0; border-left: 0; }
  .tk:nth-child(2n) { padding-left: 22px; border-left: 1px solid var(--line); }
}
@media (max-width: 520px) {
  .tk { padding: 22px 14px 22px 0; }
  .tk:nth-child(2n) { padding-left: 16px; }
  .tk li { font-size: 0.9375rem; }
}
@media (max-width: 340px) {
  .toolkit { grid-template-columns: 1fr; }
  .tk:nth-child(2n) { padding-left: 0; border-left: 0; }
}

/* ---------- 5i. Contact ---------- */
.contact {
  position: relative;
  overflow: hidden;
  padding: clamp(104px, 13vw, 190px) 0 clamp(64px, 8vw, 110px);
  background: var(--afterglow), radial-gradient(70% 60% at 85% 100%, var(--accent-soft), transparent 70%);
}
.contact-title {
  max-width: 15ch;
  font: 800 semi-expanded clamp(2.3rem, 5.8vw, 5.4rem)/0.98 var(--display);
  letter-spacing: -0.045em;
  text-wrap: balance;
}
.contact-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 28px 48px;
  align-items: end;
  margin-top: clamp(36px, 5vw, 60px);
}
.contact-lede { font-size: clamp(1.0625rem, 1.4vw, 1.25rem); line-height: 1.55; color: var(--ink-2); }
.contact-lede > :first-child { max-width: 46ch; }
/* local time for whoever is scheduling a call; js/clock.js keeps it current */
.contact-clock { margin-top: 10px; font: 500 semi-condensed 0.8125rem/1.5 var(--mono); letter-spacing: 0.02em; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.contact-actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: flex-end; }
.contact-links {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  list-style: none;
  border-top: 1px solid var(--line-strong);
}
.contact-links li + li { border-left: 1px solid var(--line); }
.contact-links a {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 12px;
  padding: 20px 20px 20px 0;
  transition: color 0.2s;
}
.contact-links li + li a { padding-left: 20px; }
.cl-k { grid-column: 1; font: 500 semi-condensed 0.6875rem var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3); }
.cl-v { grid-column: 1; font: 750 semi-expanded 1.05rem/1.25 var(--display); letter-spacing: -0.02em; overflow-wrap: anywhere; }
.contact-links a > span[aria-hidden] { grid-column: 2; grid-row: 1 / span 2; align-self: center; color: var(--ink-3); transition: transform 0.25s var(--ease), color 0.2s; }
.contact-links a:hover .cl-v { color: var(--accent-ink); }
.contact-links a:hover > span[aria-hidden] { color: var(--accent); transform: translate(2px, -2px); }

@media (max-width: 800px) {
  .contact-grid { grid-template-columns: 1fr; }
  .contact-actions { justify-content: flex-start; }
  .contact-links { grid-template-columns: 1fr; }
  .contact-links li + li { border-left: 0; border-top: 1px solid var(--line); }
  .contact-links li + li a { padding-left: 0; }
}
@media (max-width: 520px) {
  .contact-actions .btn { flex: 1 1 auto; }
}

/* ---------- 5j. Desert drawings ---------- */
/* Line drawings of the Sonoran desert (assets/desert.svg, generated by
   scripts/draw_desert.py) beside the section headings, like margin plates in
   a field guide. The sprite's paths read custom properties, which inherit
   into a <use>: --illo-line and --illo-paper colour them, --illo-w sets the
   stroke in the drawing's own units, --draw (0..1) is how much is drawn. */
@property --draw { syntax: "<number>"; inherits: true; initial-value: 1; }

.head-illo {
  position: absolute;
  /* out past the text column, into the page margin */
  right: calc(-1 * (max(0px, (100vw - var(--wrap)) / 2) + var(--pad) - var(--edge, 28px)));
  bottom: calc(-1 * clamp(18px, 2.4vw, 40px));
  display: flex;
  align-items: flex-end;
  pointer-events: none;
  --illo-w: 1.8;
}
.illo { display: block; width: auto; height: var(--h); overflow: visible; }
.illo-saguaro { --h: clamp(270px, 25vw, 370px); }
.illo-saguaro-young { --h: clamp(150px, 14.5vw, 215px); margin-right: -30px; }
.illo-pear { --h: clamp(170px, 15vw, 230px); }
.illo-palo { --h: clamp(190px, 18vw, 270px); }
.illo-sedona { --h: clamp(130px, 12vw, 172px); }
.head-illo:has(.illo-sedona) { --edge: 76px; }
.illo-ocotillo { --h: clamp(220px, 21vw, 310px); }
.illo-barrel { --h: clamp(80px, 7.5vw, 116px); margin-left: -70px; }
.illo-agave { --h: clamp(190px, 18vw, 262px); }
.contact > .wrap { position: relative; }
/* its box is the padded .wrap, not a heading, so the page padding is already inside it */
.contact-illo { top: clamp(-30px, -2vw, -10px); bottom: auto; right: calc(-1 * (max(0px, (100vw - var(--wrap)) / 2) - var(--edge, 28px))); }

/* Drawn as the heading arrives: lines first, then fruit and flowers. Without
   JS, or without @property, they are simply there, fully drawn. */
.js .reveal .head-illo, .js .head-illo.reveal { --draw: 0; transition: --draw 2.8s var(--ease-out) 0.3s; }
.js .reveal.in .head-illo, .js .head-illo.reveal.in { --draw: 1; }
@media (prefers-reduced-motion: reduce) {
  .js .reveal .head-illo, .js .head-illo.reveal { transition: none; }
}

/* Narrower than the margins they live in: they step up to stand on the
   eyebrow line, top right, small. */
@media (max-width: 1279px) {
  .head-illo { right: 0; bottom: calc(100% - 22px); --illo-w: 6; }
  .contact-illo { right: var(--pad); bottom: auto; top: calc(-1 * clamp(78px, 9vw, 100px)); }
  .illo-saguaro { --h: clamp(84px, 11vw, 120px); }
  .illo-saguaro-young { --h: clamp(52px, 6.6vw, 72px); margin-right: -10px; }
  .illo-pear { --h: clamp(56px, 7vw, 76px); }
  .illo-palo { --h: clamp(64px, 8vw, 88px); }
  .illo-sedona { --h: clamp(50px, 6vw, 66px); }
  .illo-ocotillo { --h: clamp(76px, 9vw, 100px); }
  .illo-barrel { --h: clamp(30px, 3.6vw, 40px); margin-left: -22px; }
  .illo-agave { --h: clamp(62px, 7.6vw, 86px); }
}

/* The body of every drawing is filled with the ground it stands on, so a
   pad in front hides the pad behind; where color-mix exists, that fill takes
   a breath of juniper green (red for the rocks), which is most of what makes
   the cacti look alive. */
.head-illo, .bed { --illo-ground: var(--bg); --illo-paper: var(--illo-ground); }
.section-tint .head-illo, .section-tint .bed, .footer .bed { --illo-ground: var(--bg-tint); }
@supports (color: color-mix(in srgb, red 50%, blue)) {
  .head-illo, .bed { --illo-paper: color-mix(in srgb, var(--support) 11%, var(--illo-ground)); }
  .illo-sedona { --illo-paper: color-mix(in srgb, var(--accent) 10%, var(--illo-ground)); }
}

/* ---------- 5l. Wildflowers ---------- */
/* Poppies, lupine, globemallow, brittlebush and penstemon in beds: along the
   hero's floor, in the quiet bottom corners of sections, and in front of the
   footer's skyline. Each plant is its own <svg>, so each can sway on its own
   timing with a compositor-only transform (no repaint); cacti and agaves
   (.plant) stand still, as they do. */
.bed {
  position: absolute;
  display: flex;
  align-items: flex-end;
  gap: clamp(2px, 0.6vw, 10px);
  pointer-events: none;
  --illo-w: 2.1;
  --k: 1;
}
.bed svg { display: block; flex: none; width: auto; height: calc(var(--h) * var(--k)); overflow: visible; }
/* plants grow in clumps, a little overlapped, not in a row */
.clump { display: flex; align-items: flex-end; }
/* a drawing's second appearance on the page is its mirror image (the
   individual scale property, so the sway's transform still applies) */
.bed svg.flip { scale: -1 1; }
.clump > svg + svg { margin-left: -4px; }
.flora { transform-origin: 50% 100%; animation: sway var(--sway-t, 6.2s) ease-in-out var(--sway-d, 0s) infinite alternate; }
.flora:nth-child(3n + 1) { --sway-t: 5.4s; --sway-d: -2.1s; }
.flora:nth-child(3n + 2) { --sway-t: 7.3s; --sway-d: -4.6s; --sway-a: 1.1deg; }
.flora:nth-child(4n) { --sway-t: 6.6s; --sway-d: -1.3s; --sway-a: 2deg; }
@keyframes sway {
  from { transform: rotate(calc(-1 * var(--sway-a, 1.5deg))); }
  to { transform: rotate(var(--sway-a, 1.5deg)); }
}

/* the hero's floor: spread across the page, standing on its bottom edge */
.hero-bed { left: 0; right: 0; bottom: 0; z-index: 0; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--pad); justify-content: space-between; }
/* section corners live in the bottom padding, so they never meet content */
.section > .bed { bottom: 0; }
.bed-left, .footer-bed-l { left: max(var(--pad), calc((100% - var(--wrap)) / 2 + var(--pad))); }
.bed-right, .footer-bed-r { right: max(var(--pad), calc((100% - var(--wrap)) / 2 + var(--pad))); }
/* the footer's superbloom stands on its top edge, in front of the mountains */
.footer-bed { bottom: 100%; z-index: 1; }

/* they draw on like the other drawings: the hero's at load, the rest as
   they scroll in */
@keyframes draw-in { from { --draw: 0; } to { --draw: 1; } }
.js .hero-bed { animation: draw-in 2.6s var(--ease-out) 0.9s both; }
.js .bed.reveal { --draw: 0; transition: --draw 2.4s var(--ease-out) 0.2s, opacity 0.8s var(--ease), transform 0.8s var(--ease); }
.js .bed.reveal.in { --draw: 1; }

@media (max-width: 1100px) { .bed { --k: 0.8; } }
@media (max-width: 640px) {
  .bed { --k: 0.62; --illo-w: 2.6; }
  .hero-bed > :nth-child(3n + 2), .footer-bed > :nth-child(n + 5) { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .flora { animation: none; }
  .js .hero-bed { animation: none; }
  .js .bed.reveal { transition: none; }
}

/* ---------- 5k. The Lab's horizon ---------- */
/* The one room that is always a sunset: sky banded gold to indigo, the sun
   going down behind the real Camelback range (assets/skyline.svg), and the
   desert in silhouette on the ground line. */
.lab { --horizon: clamp(200px, 24vw, 360px); --ground: clamp(22px, 2.6vw, 34px); --sil: #0c0716; overflow: hidden; padding-bottom: calc(var(--horizon) + clamp(24px, 4vw, 56px)); }
.lab > .wrap { position: relative; z-index: 1; }
.lab-horizon {
  position: absolute;
  inset: auto 0 0;
  height: var(--horizon);
  pointer-events: none;
  background: linear-gradient(to top, var(--sun-1) var(--ground), var(--sun-2) calc(var(--ground) + 9%), var(--sun-3) calc(var(--ground) + 25%), var(--sun-4) calc(var(--ground) + 47%), var(--sun-5) calc(var(--ground) + 70%), transparent);
}
.lab-sun {
  position: absolute;
  left: 63%;
  bottom: calc(var(--ground) - clamp(26px, 3vw, 44px));
  width: clamp(90px, 10vw, 150px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, #fff3c4 0%, #ffd66e 42%, rgba(255, 199, 90, 0.5) 62%, rgba(255, 199, 90, 0) 71%);
}
.lab-range {
  position: absolute;
  inset: auto 0 calc(var(--ground) - 1px);
  height: 38%;
  background: #3a1838;
  -webkit-mask: url("../assets/skyline.svg") 70% 100% / max(100%, 900px) 100% no-repeat;
  mask: url("../assets/skyline.svg") 70% 100% / max(100%, 900px) 100% no-repeat;
}
.lab-ground { position: absolute; inset: auto 0 0; height: var(--ground); background: var(--sil); }
.sil {
  position: absolute;
  bottom: calc(var(--ground) - 14px);
  height: var(--h);
  width: auto;
  overflow: visible;
  --illo-line: var(--sil);
  --illo-paper: var(--sil);
  --illo-fruit: var(--sil);
  --illo-flower: var(--sil);
  --illo-ember: var(--sil);
  --illo-poppy: var(--sil);
  --illo-lupine: var(--sil);
  --illo-mallow: var(--sil);
  --illo-pink: var(--sil);
  --illo-blue: var(--sil);
  --illo-violet: var(--sil);
  --illo-cream: var(--sil);
  --illo-w: 3;
}
.sil-pear { left: 3%; --h: 22%; }
.sil-saguaro { left: 11%; --h: 86%; }
.sil-ocotillo { left: 21%; --h: 50%; }
.sil-barrel { left: 30%; --h: 17%; }
.sil-palo { left: 44%; --h: 46%; }
.sil-young { left: 77%; --h: 52%; }
.sil-saguaro2 { left: 88%; --h: 70%; }
.sil-agave { left: 67%; --h: 62%; }
.sil-lupine { left: 26%; --h: 20%; }
.sil-poppies { left: 58%; --h: 12%; }
.sil-grass { left: 36%; --h: 11%; }
@media (max-width: 720px) {
  .sil-palo, .sil-barrel, .sil-young, .sil-poppies, .sil-grass { display: none; }
  .sil-agave { left: 56%; }
  .sil-ocotillo { left: 34%; }
  .sil-saguaro2 { left: 78%; }
}

/* ---------- 5m. Wildlife ---------- */
/* A roadrunner works the hero's flower bed and the Lab's sunset as you
   scroll (js/roadrunner.js), birds cross the sunset, and a red-tailed hawk
   rides a thermal over Camelback. They're drawn in the plants' hand
   (scripts/draw_fauna.py) and move by transform alone. The roadrunner only
   moves when you do; what moves on its own (the flock, the hawk) is slow and
   kept away from the words. With reduced motion they are simply there. */
@property --frame { syntax: "<integer>"; inherits: true; initial-value: 6; }

/* A trail says where its runner goes: --run-from and --run-to are where the
   hip is (fractions of the trail's width) at the start and end of the run,
   and --rest is where it stands without the script. */
.trail { position: absolute; left: 0; right: 0; pointer-events: none; }
.runner {
  position: absolute;
  bottom: 0;
  left: calc(var(--rest, var(--run-from)) * 100%);
  height: 100%;
  width: auto;
  overflow: visible;
  translate: -53.4% 0;  /* the hip on the resting spot (ROADRUNNER.pivot) */
  --illo-line: var(--fauna-line);
  --illo-paper: var(--fauna-paper);
  --illo-eye: var(--ink);
}
/* once the script has it, the transform does the placing */
.trail.is-live .runner { left: 0; translate: none; will-change: transform; }
/* standing about, a roadrunner flicks its tail */
.runner[data-state="idle"] { animation: tail-flick 5.2s linear infinite; }
@keyframes tail-flick {
  0%, 57% { --frame: 6; }
  58%, 63% { --frame: 7; }
  64%, 69% { --frame: 6; }
  70%, 74% { --frame: 7; }
  75%, 100% { --frame: 6; }
}
/* the hero's: as wide as its flower bed and behind it (the bed comes later
   in the page); it waits just left of the first clump */
.hero-trail {
  left: var(--pad);
  right: var(--pad);
  max-width: calc(var(--wrap) - 2 * var(--pad));
  margin-inline: auto;
  bottom: 3px;
  z-index: 0;
  height: 54px;
  --run-from: -0.045;
  --run-to: 1.1;
}
/* the Lab's: a silhouette on the sunset's ground line, like the plants,
   crossing the whole width */
.lab-trail { bottom: calc(var(--ground) - 5px); height: clamp(30px, 3.9vw, 56px); --run-from: -0.08; --run-to: 1.08; --rest: 0.32; }
.lab-trail, .flock {
  --fauna-line: var(--sil);
  --fauna-paper: var(--sil);
  --illo-ember: var(--sil);
  --illo-lupine: var(--sil);
  --illo-far: 1;
  --illo-w: 3;
}
.lab-trail .runner { --illo-eye: var(--sil); }

/* The rest of the neighbourhood (assets/critters.svg), one to a section and
   each on its own trail in the section's bottom padding, behind its flower
   bed: a rattlesnake that slithers, a scorpion that darts, a toad that hops,
   and a javelina that trots into the footer (js/trails.js has their gaits). */
.walker {
  position: absolute;
  bottom: 0;
  left: calc(var(--rest, var(--run-from)) * 100%);
  height: 100%;
  width: auto;
  max-width: none;
  overflow: visible;
  translate: -50% 0;
  --illo-line: var(--fauna-line);
  --illo-eye: var(--ink);
}
.trail.is-live .walker { left: 0; translate: none; will-change: transform; }
.walker[data-animal="javelina"] { --illo-paper: var(--fauna-javelina); }
.walker[data-animal="rattlesnake"] { --illo-paper: var(--fauna-snake); }
.walker[data-animal="scorpion"] { --illo-paper: var(--fauna-scorpion); }
.walker[data-animal="toad"] { --illo-paper: var(--fauna-toad); }
/* at dusk the scorpion glows, the way scorpions do under ultraviolet light */
[data-theme="dark"] .walker[data-animal="scorpion"] {
  --illo-line: #8ffbe6;
  --illo-eye: #8ffbe6;
  --illo-far: 0.6;
  filter: drop-shadow(0 0 3px rgba(80, 255, 220, 0.7));
}
/* these runs start and end off-screen, in sections that don't clip; clip the
   trail sideways only (a toad in mid-hop rises out of its box) */
.trail-snake, .trail-scorpion, .trail-toad, .trail-javelina { overflow-x: clip; }
.trail-snake { bottom: 10px; height: clamp(15px, 1.5vw, 21px); --run-from: 1.1; --run-to: -0.1; --rest: 0.64; }
.trail-scorpion { bottom: 8px; height: clamp(26px, 2.4vw, 34px); --run-from: -0.06; --run-to: 0.74; --rest: 0.4; }
.trail-toad { bottom: 6px; height: clamp(26px, 2.4vw, 34px); --run-from: 0.84; --run-to: 0.58; --rest: 0.66; }
/* the javelina stands on the footer's top edge, among its flowers (which
   come later in the page, so they're in front) */
.trail-javelina { bottom: 100%; z-index: 1; height: clamp(40px, 4.2vw, 60px); --run-from: 1.12; --run-to: 0.56; --rest: 0.56; }

/* what each does while it rests (frames: 6 at rest, then its own) */
.walker[data-state="idle"] { animation: var(--resting) steps(1, end) infinite; }
.walker[data-animal="javelina"] { --resting: rooting 6.4s; }
.walker[data-animal="rattlesnake"] { --resting: rattling 7.2s; }
.walker[data-animal="scorpion"] { --resting: warning 6.8s; }
.walker[data-animal="toad"] { --resting: blinking 5.6s; }
@keyframes rooting {
  0%, 38% { --frame: 6; }
  40%, 58% { --frame: 7; }
  60%, 64% { --frame: 6; }
  66%, 80% { --frame: 7; }
  82%, 100% { --frame: 6; }
}
@keyframes rattling {
  0%, 30% { --frame: 6; }
  31%, 32.5% { --frame: 7; }
  33%, 34.5% { --frame: 6; }
  35%, 36.5% { --frame: 7; }
  37%, 68% { --frame: 6; }
  69% { --frame: 8; } 70% { --frame: 9; } 71% { --frame: 8; } 72% { --frame: 9; }
  73% { --frame: 8; } 74% { --frame: 9; } 75% { --frame: 8; } 76% { --frame: 9; }
  77%, 100% { --frame: 6; }
}
@keyframes warning {
  0%, 58% { --frame: 6; }
  60%, 78% { --frame: 7; }
  80%, 100% { --frame: 6; }
}
@keyframes blinking {
  0%, 22% { --frame: 6; }
  23%, 25% { --frame: 7; }
  26%, 48% { --frame: 6; }
  50%, 53% { --frame: 8; }
  55%, 58% { --frame: 6; }
  60%, 63% { --frame: 8; }
  65%, 100% { --frame: 6; }
}

/* the flock: each bird crosses the whole sky, flapping and gliding; the
   crossing is one transform on a full-width track, the wingbeat is the bird
   scaled vertically through zero */
.flock { position: absolute; inset: 0 0 var(--ground); overflow: hidden; --illo-line: #1d0f24; }
.flier {
  position: absolute;
  left: 0;
  top: var(--y);
  width: 100%;
  transform: translateX(var(--x));
  animation: fly var(--t) linear var(--d) infinite;
}
.flier.west { animation-direction: reverse; }
@keyframes fly {
  from { transform: translateX(-44px); }
  to { transform: translateX(calc(100% + 44px)); }
}
.bird {
  display: block;
  width: var(--w);
  height: auto;
  overflow: visible;
  transform-origin: 50% 60%;
  animation: flap var(--f) ease-in-out var(--fd) infinite;
}
.west .bird { transform: scaleX(-1); }
@keyframes flap {
  0% { scale: 1 1; }
  11% { scale: 1 -0.55; }
  22% { scale: 1 0.95; }
  33% { scale: 1 -0.55; }
  44% { scale: 1 0.9; }
  56%, 100% { scale: 1 0.35; }
}

/* the hawk circles a thermal over the summit (where js/arizona.js viewFor
   puts it on a wide screen), its shadow on the ground below and to the side */
.thermal { position: absolute; z-index: -1; left: 72%; top: min(36%, 330px); pointer-events: none; --r: clamp(64px, 6.4vw, 104px); }
.soar { position: absolute; left: 0; top: 0; animation: soar 36s linear infinite; }
.soar-shadow { left: 30px; top: 38px; }
@keyframes soar { to { transform: rotate(360deg); } }
.hawk {
  position: absolute;
  left: var(--r);
  top: 0;
  width: clamp(56px, 4.6vw, 72px);
  max-width: none;  /* its box is a zero-size pivot; the global svg reset would crush it */
  height: auto;
  overflow: visible;
  translate: -50% -50%;
  rotate: 180deg;  /* drawn heading up the page; circling clockwise, it heads down at 3 o'clock */
  --illo-line: var(--fauna-line);
  --illo-paper: var(--fauna-hawk);
  --illo-fruit: color-mix(in srgb, var(--accent) 70%, var(--fauna-hawk));
  --illo-w: 1.9;
  animation: wing-flex 9s ease-in-out infinite;
}
@keyframes wing-flex {
  0%, 70%, 100% { scale: 1 1; }
  80% { scale: 0.9 1; }
  90% { scale: 1.02 1; }
}
.soar-shadow .hawk {
  --illo-line: var(--hawk-shade);
  --illo-paper: var(--hawk-shade);
  --illo-fruit: var(--hawk-shade);
  opacity: var(--hawk-shade-a);
  filter: blur(2px);
}
@media (max-width: 1179px) { .thermal { display: none; } }
@media (max-width: 1100px) { .hero-trail { height: 46px; } }
@media (max-width: 640px) { .hero-trail { height: 34px; --run-from: 0.1; } }
@media (prefers-reduced-motion: reduce) {
  .flier, .bird, .soar, .hawk { animation: none; }
}

/* ---------- 6. Motion ---------- */
/* The first screen animates in with CSS alone, so it never waits on JS. */
.rise { animation: rise 1s var(--ease-out) both; animation-delay: var(--delay, 0s); }
@keyframes rise { from { opacity: 0; transform: translateY(18px); } }
/* A section out of view pauses its looping animations (js/quiet.js). */
.is-offscreen *, .is-offscreen *::before, .is-offscreen *::after { animation-play-state: paused !important; }

/* Hidden only when JS is running (html.js, set in <head>) so the page still
   reads top to bottom with scripts off. js/motion.js adds .in on scroll. */
.js .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.9s var(--ease), transform 0.9s var(--ease);
  transition-delay: var(--delay, 0s);
}
.js .reveal.in { opacity: 1; transform: none; }

/* toggled by js/theme.js for one crossfade, then removed */
html.theme-fade, html.theme-fade *, html.theme-fade *::before, html.theme-fade *::after {
  transition: background-color 0.45s ease, color 0.45s ease, border-color 0.45s ease, fill 0.45s ease, stroke 0.45s ease !important;
}

@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
  }
  .card:hover, .portrait:hover { transform: none; }
}

@media print {
  .nav, .topo, .hero-fade, .lab-grid, .dock, .toast, .footer-hint, .orb-slot, .footer::before, .thermal, .trail, .flock { display: none !important; }
  .js .reveal { opacity: 1 !important; transform: none !important; }
  .hero { min-height: 0; padding-top: 24px; }
  .section, .contact { padding-block: 32px; }
  .lab { --bg: #fff; --ink: #000; --ink-2: #222; --ink-3: #444; --surface: #fff; }
  .mig-viz, .about-side, .build-side { position: static; }
}

/* ---------- 7. Ask about my work: the glass bar (js/ask.js) ----------
   Fixed to the bottom of the screen. Liquid glass: a translucent tint over a
   heavy blur and saturation of whatever scrolls behind it, a specular sheen
   across the top, and a rim that catches light. The answers open upward inside
   the same pane. Light glass over the day sections; night glass in dark mode
   and while the Lab (always a night room) is behind it. */
.dock {
  --g-tint-1: rgba(255, 255, 255, 0.62);
  --g-tint-2: rgba(255, 255, 255, 0.30);
  --g-rim: rgba(255, 255, 255, 0.75);
  --g-rim-soft: rgba(255, 255, 255, 0.18);
  --g-ink: var(--ink);
  --g-ink-2: var(--ink-2);
  --g-ink-3: var(--ink-3);
  --g-line: rgba(28, 22, 36, 0.1);
  --g-field: rgba(255, 255, 255, 0.55);
  --g-chip: rgba(255, 255, 255, 0.45);
  --g-accent: var(--accent);
  --g-accent-ink: var(--accent-ink);
  --g-on-accent: #fff;
  --g-shadow: 0 18px 50px -14px rgba(28, 22, 36, 0.42), 0 3px 10px rgba(28, 22, 36, 0.10);
  position: fixed;
  left: 50%;
  bottom: max(16px, env(safe-area-inset-bottom));
  z-index: 250;
  width: min(680px, calc(100vw - 24px));
  border-radius: 26px;
  color: var(--g-ink);
  background: linear-gradient(140deg, var(--g-tint-1), var(--g-tint-2));
  -webkit-backdrop-filter: blur(22px) saturate(1.9) brightness(1.04);
  backdrop-filter: blur(22px) saturate(1.9) brightness(1.04);
  box-shadow:
    inset 0 1px 0 var(--g-rim),
    inset 0 -1px 1px var(--g-rim-soft),
    inset 0 0 0 1px var(--g-rim-soft),
    var(--g-shadow);
  opacity: 0;
  transform: translate(-50%, 18px);
  transition: opacity 0.5s var(--ease-out), transform 0.6s var(--ease-out);
}
.dock.is-in { opacity: 1; transform: translate(-50%, 0); }
/* Until the hero's first screen has scrolled clear of it, the bar waits out of
   sight (js/ask.js): see-through and click-through, still reachable by keyboard. */
.dock:not(.is-in), .dock.is-tucked { pointer-events: none; }
.dock.is-in.is-tucked { opacity: 0; transform: translate(-50%, 18px); transition-duration: 0.3s, 0.35s; }
.dock[hidden] { display: none; }
/* the sheen: light pooling across the top-left of the pane */
.dock::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: radial-gradient(120% 70% at 18% -10%, rgba(255, 255, 255, 0.55), transparent 55%);
  mix-blend-mode: soft-light;
  pointer-events: none;
}
/* the rim: a thin edge, brightest where the light hits */
.dock::after {
  content: "";
  position: absolute;
  inset: 0;
  padding: 1px;
  border-radius: inherit;
  background: linear-gradient(165deg, rgba(255, 255, 255, 0.95), rgba(255, 255, 255, 0.05) 38%, rgba(255, 255, 255, 0.05) 70%, rgba(255, 255, 255, 0.5));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  pointer-events: none;
}
:root[data-theme="dark"] .dock, .dock.on-night {
  --g-tint-1: rgba(48, 36, 82, 0.62);
  --g-tint-2: rgba(21, 15, 36, 0.42);
  --g-rim: rgba(255, 255, 255, 0.22);
  --g-rim-soft: rgba(255, 255, 255, 0.07);
  --g-ink: #f5eef2;
  --g-ink-2: #cdc1d3;
  --g-ink-3: #a093ab;
  --g-line: rgba(245, 238, 242, 0.1);
  --g-field: rgba(255, 255, 255, 0.07);
  --g-chip: rgba(255, 255, 255, 0.06);
  --g-accent: #ff7a45;
  --g-accent-ink: #ff9464;
  --g-on-accent: #150f24;
  --g-shadow: 0 18px 50px -14px rgba(0, 0, 0, 0.75), 0 3px 10px rgba(0, 0, 0, 0.3);
}
:root[data-theme="dark"] .dock::after, .dock.on-night::after {
  background: linear-gradient(165deg, rgba(255, 255, 255, 0.45), rgba(255, 255, 255, 0.03) 38%, rgba(255, 255, 255, 0.03) 70%, rgba(255, 255, 255, 0.2));
}
:root[data-theme="dark"] .dock::before, .dock.on-night::before { opacity: 0.35; }
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .dock { --g-tint-1: rgba(251, 247, 244, 0.97); --g-tint-2: rgba(243, 235, 230, 0.97); }
  :root[data-theme="dark"] .dock, .dock.on-night { --g-tint-1: rgba(35, 26, 58, 0.97); --g-tint-2: rgba(21, 15, 36, 0.97); }
}
.has-modal .dock { visibility: hidden; }
.has-dock .footer { padding-bottom: calc(40px + 92px); }
.has-dock .toast { bottom: calc(max(16px, env(safe-area-inset-bottom)) + 88px); }

/* the bar */
.dock-bar { position: relative; z-index: 1; display: flex; align-items: center; gap: 10px; padding: 8px; }
.dock-orb {
  position: relative;
  flex: none;
  width: 44px;
  height: 44px;
  margin-left: 4px;
}
/* The orb alone, no disc or ring: samantha-ui in transparent mode renders it on a clear canvas,
   so the glass shows through right up to its wobbling edge. Its bloom is off in that mode, so
   the glow is a drop-shadow in the state's colour. The sphere fills about half the frame, so an
   84px frame centred on the 44px slot gives a ~42px orb; it may wobble past the slot, which is
   fine (pointer-events: none). max-width: none undoes the base reset, which caps iframes at 100%.
   color-scheme: normal matches the embedded page; a mismatch makes browsers paint the frame opaque. */
.dock-orb iframe {
  position: absolute;
  left: -20px;
  top: -20px;
  width: 84px;
  height: 84px;
  max-width: none;
  border: 0;
  background: transparent;
  color-scheme: normal;
  pointer-events: none;
  opacity: 0;
  filter: drop-shadow(0 2px 7px rgba(232, 168, 124, 0.6));
  transition: opacity 0.9s var(--ease), filter 0.5s;
}
.dock-orb.is-live iframe { opacity: 1; }
.dock[data-orb="thinking"] .dock-orb iframe { filter: drop-shadow(0 2px 8px rgba(139, 92, 246, 0.7)); }
.dock[data-orb="speaking"] .dock-orb iframe { filter: drop-shadow(0 2px 8px rgba(233, 120, 95, 0.65)); }
/* The drawn orb: the real orb's three moods in CSS. It's the only orb on touch screens and for
   reduced motion (js/ask.js mounts the live one for mouse-and-keyboard screens only), and the
   stand-in on desktop until that one wakes. Everything that moves is a transform or an opacity,
   so it runs on the compositor and never repaints: no filters, no animated border-radius.
   Each mood is its own layer, always turning at its own pace, and a change of mood crossfades the
   layers rather than swapping animations (a new duration mid-turn makes the shape jump). The
   incoming layer fades in at once and the outgoing one waits until it's covered, so the orb never
   thins out in between. A layer's glow is its box-shadow, painted once and turned with it. */
.dock-orb-css {
  position: absolute;
  inset: 2px;
  transition: scale 0.7s var(--ease), opacity 0.9s;
}
.dock-orb.is-live .dock-orb-css { opacity: 0; }
.dock[data-orb="thinking"] .dock-orb-css { scale: 0.9; }
.dock[data-orb="speaking"] .dock-orb-css { scale: 1.05; }
.dock-orb-css > i {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.45s var(--ease) 0.35s;
  animation: dock-orb-turn 16s linear infinite;
}
.dock-orb-css > .dock-orb-listen,
.dock[data-orb="thinking"] .dock-orb-think,
.dock[data-orb="speaking"] .dock-orb-speak { opacity: 1; transition-delay: 0s; }
.dock:is([data-orb="thinking"], [data-orb="speaking"]) .dock-orb-listen { opacity: 0; transition-delay: 0.35s; }
/* a light from the upper left that stays put while the colours turn under it */
.dock-orb-css::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 28%, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0) 34%);
}
.dock-orb-css > .dock-orb-listen {
  border-radius: 46% 54% 52% 48% / 52% 46% 54% 48%;
  background: radial-gradient(circle at 30% 36%, #fde2cc, #e8a87c 50%, #c9805a);
  box-shadow: 0 0 10px rgba(232, 168, 124, 0.55);
  animation: dock-orb-turn 16s linear infinite, dock-orb-breathe 4.5s var(--ease) infinite alternate;
}
.dock-orb-css > .dock-orb-think {
  border-radius: 52% 48% 47% 53% / 45% 55% 45% 55%;
  background:
    radial-gradient(circle at 30% 32%, #d6f6fc, rgba(214, 246, 252, 0) 46%),
    radial-gradient(circle at 72% 66%, #06b6d4, rgba(6, 182, 212, 0) 52%),
    radial-gradient(circle, #a78bfa, #8b5cf6 58%, #6d43e6);
  box-shadow: 0 0 12px rgba(139, 92, 246, 0.6);
  animation-duration: 2.4s;
}
.dock-orb-css > .dock-orb-speak {
  border-radius: 50% 50% 46% 54% / 54% 48% 52% 46%;
  background: radial-gradient(circle at 34% 34%, #ffd9cb, #e9785f 52%, #b9543f);
  box-shadow: 0 0 12px rgba(233, 120, 95, 0.6);
  animation: dock-orb-turn 7s linear infinite, dock-orb-talk 0.8s var(--ease) infinite alternate;
}
/* while it speaks, a ring goes out from it */
.dock-orb-speak::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1.5px solid rgba(233, 120, 95, 0.6);
  border-radius: 50%;
  opacity: 0;
  animation: dock-orb-ripple 1.4s var(--ease-out) infinite;
}
/* out of sight, or handed over to the live orb: stop turning */
.dock:is(:not(.is-in), .is-tucked) .dock-orb-css i,
.dock:is(:not(.is-in), .is-tucked) .dock-orb-css i::before,
.dock-orb.is-live .dock-orb-css i,
.dock-orb.is-live .dock-orb-css i::before { animation-play-state: paused; }
@keyframes dock-orb-turn { to { rotate: 1turn; } }
@keyframes dock-orb-breathe { from { scale: 0.97; } to { scale: 1.02; } }
@keyframes dock-orb-talk { from { scale: 0.96; } to { scale: 1.04; } }
@keyframes dock-orb-ripple { from { opacity: 0.8; scale: 1; } to { opacity: 0; scale: 1.5; } }
.dock-input {
  flex: 1;
  min-width: 0;
  height: 44px;
  padding: 0 16px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: var(--g-field);
  color: var(--g-ink);
  font: inherit;
  font-size: 1rem; /* 16px keeps iOS Safari from zooming in on focus */
  transition: border-color 0.2s, background-color 0.2s, box-shadow 0.2s;
}
.dock-input::placeholder { color: var(--g-ink-3); }
.dock-input:focus { border-color: var(--g-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--g-accent) 18%, transparent); outline: none; }
.dock-kbd {
  position: absolute;
  right: 66px;
  padding: 1px 7px;
  border: 1px solid var(--g-line);
  border-radius: 5px;
  font: 500 0.6875rem/1.5 var(--mono);
  color: var(--g-ink-3);
  pointer-events: none;
}
.dock-input:focus ~ .dock-kbd, .dock-input:not(:placeholder-shown) ~ .dock-kbd { display: none; }
@media (hover: none) { .dock-kbd { display: none; } }
/* The send button, drawn like the page's illustrations: a paper disc with the same 1.6px ink
   line and a red-rock arrow. Hover fills the disc with red rock and turns the arrow cream. When
   the bar arrives the outline draws itself in, then the arrow, the way the desert drawings do
   (pathLength 1 + a dash offset; reduced motion skips it and shows them drawn). */
.dock-send {
  --send-paper: #fbf7f4;
  --send-ink: var(--g-ink);
  --send-arrow: var(--accent);
  display: grid;
  place-items: center;
  flex: none;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  transition: transform 0.2s var(--ease), opacity 0.2s;
}
:root[data-theme="dark"] .dock-send, .dock.on-night .dock-send { --send-paper: #231a3a; --send-arrow: #ff9464; }
.dock-send svg { display: block; width: 44px; height: 44px; overflow: visible; }
.dock-send-disc {
  fill: var(--send-paper);
  stroke: var(--send-ink);
  stroke-width: 1.6;
  transition: fill 0.25s, stroke 0.25s;
}
.dock-send-arrow {
  fill: none;
  stroke: var(--send-arrow);
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: stroke 0.25s;
}
/* The dash pattern exists only while drawing (fill-mode backwards): left on, its seam would show
   as a notch at three o'clock on the finished circle. */
.dock.is-in .dock-send-disc { animation: dock-draw 1.1s var(--ease-out) 0.35s backwards; }
.dock.is-in .dock-send-arrow { animation: dock-draw 0.6s var(--ease-out) 1.2s backwards; }
@keyframes dock-draw {
  from { stroke-dasharray: 1; stroke-dashoffset: 1; }
  to { stroke-dasharray: 1; stroke-dashoffset: 0; }
}
.dock-send:hover .dock-send-disc { fill: #a8401d; stroke: #a8401d; }
.dock-send:hover .dock-send-arrow { stroke: #fff3e6; }
.dock-send:active { transform: scale(0.94); }
.is-busy .dock-send { opacity: 0.55; pointer-events: none; }

/* the answers, opening upward inside the same pane */
.dock-panel { position: relative; z-index: 1; display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.45s var(--ease-out); }
.dock.is-open .dock-panel { grid-template-rows: 1fr; }
.dock-panel-inner { min-height: 0; overflow: hidden; }
.dock-head { display: flex; align-items: center; gap: 10px; padding: 14px 14px 10px 20px; border-bottom: 1px solid var(--g-line); }
.dock-title { font: 800 semi-expanded 0.9375rem/1.2 var(--display); letter-spacing: -0.02em; }
.dock-meta { font: 500 semi-condensed 0.625rem/1 var(--mono); letter-spacing: 0.1em; text-transform: uppercase; color: var(--g-ink-3); }
.dock-collapse {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  margin-left: auto;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--g-ink-2);
  cursor: pointer;
}
.dock-collapse:hover { background: var(--g-chip); color: var(--g-ink); }
.dock-collapse svg { width: 18px; height: 18px; }
.dock-log {
  display: flex;
  flex-direction: column;
  gap: 14px;
  max-height: min(48vh, 440px);
  overflow-y: auto;
  padding: 14px 20px 6px;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--g-line) transparent;
}
.dock-how { padding: 6px 20px 10px; border-bottom: 1px solid var(--g-line); font-size: 0.6875rem; line-height: 1.5; color: var(--g-ink-3); }
.dock-how a { color: var(--g-accent-ink); text-decoration: none; white-space: nowrap; }

.dock-msg { animation: dock-rise 0.35s var(--ease-out); }
.dock-me {
  align-self: flex-end;
  max-width: 85%;
  padding: 8px 13px;
  border-radius: 16px 16px 4px 16px;
  background: var(--g-chip);
  box-shadow: inset 0 0 0 1px var(--g-line);
  font-size: 0.9063rem;
  overflow-wrap: anywhere;
}
.dock-bot { max-width: 100%; }
.dock-answer { font-size: 0.9375rem; line-height: 1.6; text-wrap: pretty; }
.dock-answer + .dock-answer { margin-top: 8px; }
.dock-suggest .dock-answer { color: var(--g-ink-2); }
.dock-aside { margin-bottom: 4px; font-size: 0.8125rem; font-style: italic; color: var(--g-ink-3); }
.dock-answer a { color: var(--g-accent-ink); }
.dock-answer-block .w { animation: dock-word 0.32s var(--ease) both; animation-delay: calc(var(--i) * var(--wms, 16ms)); }
/* an answer's highlights, marked with small red-rock diamonds */
.dock-points { display: flex; flex-direction: column; gap: 6px; margin-top: 9px; list-style: none; }
.dock-points li { position: relative; padding-left: 17px; font-size: 0.875rem; line-height: 1.55; color: var(--g-ink-2); text-wrap: pretty; }
.dock-points li::before { content: ""; position: absolute; left: 3px; top: 0.62em; width: 6px; height: 6px; border-radius: 1.5px; background: linear-gradient(135deg, #e8885a, #a8401d); transform: rotate(45deg); }
.dock-points a { color: var(--g-accent-ink); }
.dock-more { display: inline-flex; gap: 6px; margin-top: 8px; font-size: 0.875rem; font-weight: 500; color: var(--g-accent-ink); text-decoration: none; animation: dock-rise 0.35s var(--ease-out); }
.dock-more span { transition: transform 0.25s var(--ease); }
.dock-more:hover span { transform: translateX(3px); }
.dock-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; animation: dock-rise 0.4s var(--ease-out); }
.dock-chip {
  padding: 6px 11px;
  border: 1px solid var(--g-line);
  border-radius: 999px;
  background: var(--g-chip);
  color: var(--g-ink-2);
  font: 500 0.8125rem/1.25 var(--sans);
  text-align: left;
  cursor: pointer;
  transition: border-color 0.2s, color 0.2s;
}
.dock-chip:hover { border-color: var(--g-accent); color: var(--g-ink); }

/* the trace */
.dock-trace { margin-bottom: 8px; border-radius: 12px; background: var(--g-chip); box-shadow: inset 0 0 0 1px var(--g-line); font-size: 0.8125rem; }
.dock-trace-sum {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 12px;
  list-style: none;
  cursor: pointer;
  color: var(--g-ink-2);
  font: 500 semi-condensed 0.6875rem/1.3 var(--mono);
  white-space: nowrap;
  user-select: none;
}
.dock-trace-sum::-webkit-details-marker { display: none; }
.dock-trace-sum::after { content: "▾"; margin-left: auto; color: var(--g-ink-3); transition: transform 0.2s; }
.dock-trace:not([open]) .dock-trace-sum::after { transform: rotate(-90deg); }
/* Thinking, the way Claude Code shows it: a glyph that blooms and closes (js/ask.js steps it) and a
   verb with light passing over it. The glyph sits in a fixed box, so a wider fallback glyph can't
   nudge the line, and when the answer comes it becomes the receipt's green dot in the same place. */
.dock-trace.is-thinking .dock-trace-sum { cursor: default; }
.dock-trace.is-thinking .dock-trace-sum::after { visibility: hidden; }
.dock-glyph { flex: none; display: grid; place-items: center; width: 14px; height: 16px; margin-left: -1px; font: 600 0.875rem/1 var(--sans); color: var(--g-accent-ink); }
.dock-trace.is-done .dock-glyph::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--support); }
.dock-verb {
  color: var(--g-accent-ink);
  background: linear-gradient(90deg, var(--g-accent-ink) 38%, color-mix(in srgb, var(--g-accent-ink) 30%, #fff) 50%, var(--g-accent-ink) 62%) 0 0 / 250% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: dock-shimmer 1.8s linear infinite;
}
.dock-trace-sum .dock-loading { min-width: 0; overflow: hidden; text-overflow: ellipsis; font: inherit; font-weight: 400; color: var(--g-ink-3); }
.dock-steps { display: flex; flex-direction: column; gap: 9px; padding: 2px 12px 11px; list-style: none; }
.dock-step { display: grid; grid-template-columns: 15px 1fr; column-gap: 8px; row-gap: 5px; align-items: center; animation: dock-rise 0.3s var(--ease-out); }
.dock-step > :nth-child(n + 3) { grid-column: 2; }
.dock-tick { width: 13px; height: 13px; border-radius: 50%; background: var(--support) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 14'%3E%3Cpath d='M3.5 7.2l2.3 2.3 4.7-4.9' fill='none' stroke='%23150f24' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 13px no-repeat; }
.dock-step-title { font-weight: 500; color: var(--g-ink); }
.dock-detail { font: 400 0.6875rem/1.4 var(--mono); color: var(--g-ink-3); }
.dock-pieces { display: flex; flex-wrap: wrap; gap: 4px; }
.dock-pieces code, .dock-more-pieces {
  padding: 1px 6px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--g-accent) 14%, transparent);
  color: var(--g-accent-ink);
  font: 500 0.6875rem/1.5 var(--mono);
  animation: dock-pop 0.25s var(--ease-out) both;
}
.dock-pieces code.unk { background: var(--g-chip); color: var(--g-ink-3); text-decoration: line-through; }
.dock-pieces code.cont { margin-left: -4px; border-left: 1px dashed color-mix(in srgb, var(--g-accent-ink) 50%, transparent); border-radius: 0 4px 4px 0; }
.dock-pieces code:has(+ .cont) { border-radius: 4px 0 0 4px; }
.dock-more-pieces { background: none; color: var(--g-ink-3); }
.dock-vec { display: block; width: 100%; max-width: 380px; height: 26px; }
.dock-vec .pos { fill: var(--g-accent); }
.dock-vec .neg { fill: #ff5c93; opacity: 0.65; }
.dock-vec rect { transform-origin: 50% 50%; transform-box: fill-box; animation: dock-grow 0.4s var(--ease-out) both; }
.dock-matches { display: flex; flex-direction: column; gap: 4px; list-style: none; }
.dock-matches li { display: grid; grid-template-columns: minmax(0, 1fr) 64px 32px; gap: 8px; align-items: center; color: var(--g-ink-3); }
.dock-matches li.is-best { color: var(--g-ink); }
.dock-m-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 0.75rem; }
.dock-bar-fill { position: relative; height: 4px; overflow: hidden; border-radius: 2px; background: var(--g-line); }
.dock-bar-fill::after { content: ""; position: absolute; inset: 0 auto 0 0; width: var(--w); border-radius: 2px; background: var(--g-ink-3); animation: dock-fill 0.5s var(--ease-out) both; }
.is-best .dock-bar-fill::after { background: linear-gradient(90deg, #ffb547, var(--g-accent)); }
.dock-m-score { font: 500 0.6875rem/1 var(--mono); text-align: right; }
.dock-matches .dock-m-note { display: block; margin-top: 3px; font-size: 0.75rem; color: var(--g-ink-2); }

@keyframes dock-rise { from { opacity: 0; transform: translateY(5px); } }
@keyframes dock-word { from { opacity: 0; filter: blur(3px); } }
@keyframes dock-pop { from { opacity: 0; transform: scale(0.85); } }
@keyframes dock-grow { from { transform: scaleY(0); } }
@keyframes dock-fill { from { width: 0; } }
@keyframes dock-shimmer { from { background-position: 100% 0; } }

@media (max-width: 640px) {
  .dock { bottom: max(10px, env(safe-area-inset-bottom)); border-radius: 24px; }
  .dock-bar { gap: 8px; padding: 7px; }
  .dock-head { padding: 12px 10px 8px 16px; }
  .dock-meta { display: none; }
  .dock-log { max-height: min(56svh, 460px); padding: 12px 16px 6px; }
  .dock-how { padding: 6px 16px 10px; }
}
@media (prefers-reduced-motion: reduce) {
  .dock, .dock * { animation: none !important; transition: none !important; }
}

/* ---------- A side-by-side figure in a write-up (work/starship-agent-fleet.html) ----------
   It takes the post's wide lane on a large screen, so each image is about 500px; on a phone the
   pair stacks. ".post-body > .duo" outranks blog.css's ".post-body > *" column rule. */
.post-body > .duo { grid-column: 1 / -1; justify-self: center; width: min(100%, 60rem); margin: 0.4em 0 1.8em; }
.duo-pair { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(10px, 1.6vw, 18px); }
.duo-item img { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-radius: var(--radius-sm); }
.duo-label { margin-top: 8px; font: 500 semi-condensed 0.75rem/1.45 var(--mono); letter-spacing: 0.06em; color: var(--ink-3); }
.duo-label b { font-weight: 600; color: var(--ink); }
.duo figcaption { max-width: 42.5rem; margin: 16px auto 0; font-size: 0.9375rem; line-height: 1.6; color: var(--ink-2); text-wrap: pretty; }
@media (max-width: 640px) { .duo-pair { grid-template-columns: 1fr; } }
