/* ═══════════════════════════════════════════════════════════════
   EDITORIAL PORTFOLIO — Design System
   Newsreader (serif) · DM Mono (mono) · Figtree (sans)
   Three themes: Editorial Paper / Blueprint / Graphite + Acid
   ═══════════════════════════════════════════════════════════════ */

/* ── Tokens ─────────────────────────────────────────────────── */
:root {
  --paper:   #F1ECE1;
  --paper-2: #E8E2D4;
  --ink:     #14120F;
  --ink-soft:#2A2622;
  --ink-dim: #6B6359;
  --rule:    #14120F;
  --accent:  oklch(0.58 0.19 28);
  --accent-2: oklch(0.42 0.10 240);  /* Deep editorial blue. Used only in jobs-lab for robotics axis. */
  --mark-bg: color-mix(in oklab, var(--accent) 35%, transparent);
  /* Chart-series tokens — used by escape-velocity-lab and atlas
     destinations. Defined per theme so charts read on light or dark. */
  --chart-1: #264F73;  /* deep blue */
  --chart-2: #7A6C8A;  /* dusty purple */
  --chart-3: #B85C2E;  /* burnt orange */
  --chart-4: #8B7032;  /* deep gold */
  --chart-5: #8E3A3A;  /* deep red */
  --grain:   0.035;
}
[data-theme="blueprint"] {
  --paper:   #E8E9E4;
  --paper-2: #DCDED8;
  --ink:     #0E1418;
  --ink-soft:#1E2A30;
  --ink-dim: #5B6670;
  --accent:  oklch(0.48 0.12 230);
  --accent-2: oklch(0.55 0.14 25);
  --mark-bg: color-mix(in oklab, var(--accent-2) 38%, transparent);
  --chart-1: #264F73;
  --chart-2: #7A6C8A;
  --chart-3: #B85C2E;
  --chart-4: #8B7032;
  --chart-5: #8E3A3A;
}
[data-theme="graphite"] {
  --paper:   #141311;
  --paper-2: #1C1A17;
  --ink:     #EEE8D8;
  --ink-soft:#D6CFBE;
  /* Bumped from #8B8374 — was 4.4:1 against --paper at small sizes,
     just under WCAG AA. New value clears 5.5:1. */
  --ink-dim: #A09885;
  --rule:    #EEE8D8;
  --accent:  oklch(0.88 0.18 100);
  --accent-2: oklch(0.72 0.15 220);
  /* Deep red-brown mark in dark mode — readable cream text on top,
     distinguishable from the bright yellow accent used elsewhere. */
  --mark-bg: oklch(0.42 0.16 25 / 0.88);
  /* Chart series re-mapped for dark — the lighter palette I was using
     hardcoded across the JS now lives here. */
  --chart-1: #5B9BD5;  /* sky blue */
  --chart-2: #A89BB8;  /* lavender */
  --chart-3: #FF6B3D;  /* bright orange */
  --chart-4: #D4B970;  /* warm gold */
  --chart-5: #C66E6E;  /* terra rose */
}

/* Midnight tokens are defined in the 1-bit dither override block
   below. See the AESTHETIC EXPERIMENT section near the bottom of
   this file. Both graphite and midnight share the dither aesthetic;
   only the brightness polarity differs. */

/* ── Reset & Base ───────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: var(--paper); color: var(--ink); }
body {
  font-family: 'Figtree', system-ui, sans-serif;
  font-size: 15px; line-height: 1.55; font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  transition: background 400ms ease, color 400ms ease;
  overflow-x: hidden;
}

/* ── Paper Grain Overlay ────────────────────────────────────── */
body::before {
  content: '';
  position: fixed; inset: 0;
  pointer-events: none; z-index: 100;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.5 0'/></filter><rect width='100%' height='100%' filter='url(%23n)' opacity='1'/></svg>");
  opacity: var(--grain);
  mix-blend-mode: multiply;
}
[data-theme="graphite"] body::before { mix-blend-mode: screen; }

/* ── Typography Classes ─────────────────────────────────────── */
.mono {
  font-family: 'DM Mono', ui-monospace, monospace;
  font-weight: 400; letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
}
.serif {
  font-family: 'Newsreader', 'Times New Roman', serif;
  font-weight: 300;
}
.serif-italic {
  font-family: 'Newsreader', serif;
  font-style: italic; font-weight: 300;
}

/* ── Selection ──────────────────────────────────────────────── */
::selection { background: var(--ink); color: var(--paper); }

/* ── Links ──────────────────────────────────────────────────── */
a { color: inherit; text-decoration: none; }
main { position: relative; }
/* Note: main is intentionally NOT a stacking context (no z-index)
   so fixed-position dialogs inside it (like .af-side-panel) can
   render above the masthead at z-index 50. */

/* ── Scroll Progress ────────────────────────────────────────── */
.progress {
  position: fixed; top: 0; left: 0;
  height: 2px; background: var(--ink);
  width: 0%; z-index: 200;
  transition: width 80ms linear;
}

/* ── Utility Rules ──────────────────────────────────────────── */
.rule { border: 0; border-top: 1px solid var(--rule); opacity: 0.4; }
.hair { border: 0; border-top: 1px solid var(--rule); opacity: 0.15; }

/* ── Custom Cursor ──────────────────────────────────────────── */
.cursor-dot {
  position: fixed; left: 0; top: 0;
  pointer-events: none; z-index: 500;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--accent);
  mix-blend-mode: multiply;
  transition: width 180ms, height 180ms;
  transform: translate(-5px, -5px);
}
.cursor-dot.hover {
  width: 36px; height: 36px;
  transform: translate(-18px, -18px);
}

/* ── Masthead ───────────────────────────────────────────────── */
/* 3-column grid so the name stays exactly center regardless of
   whether the dateline is hidden by media queries. The previous
   flex layout put the name at "center of remaining space," which
   slid left as soon as the dateline hid. Grid pins it to the
   middle column. */
.masthead {
  position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  padding: 14px 28px;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  column-gap: 24px;
  background: color-mix(in oklab, var(--paper) 82%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid color-mix(in oklab, var(--ink) 18%, transparent);
  transition: padding 220ms ease, background 220ms ease;
}
/* Condensed state — toggled by main.js once scrollY > 80px. */
.masthead.scrolled {
  padding: 8px 28px;
  background: color-mix(in oklab, var(--paper) 92%, transparent);
}
.masthead.scrolled .masthead-name { font-size: 18px; }
.masthead-dateline {
  font-size: 11px; letter-spacing: 0.2em; text-transform: uppercase;
  justify-self: start;
  white-space: nowrap;
}
.masthead-name {
  text-align: center;
  font-size: 22px; letter-spacing: 0.02em;
  transition: font-size 220ms ease;
  justify-self: center;
  white-space: nowrap;
}
.masthead-nav {
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  display: flex; gap: 18px; align-items: center;
  justify-self: end;
}
.masthead-nav a { transition: opacity 200ms; }
.masthead-nav a:hover { opacity: 0.7; }
.masthead-nav .btn-pill {
  padding: 7px 14px;
  border: 1px solid var(--ink);
  border-radius: 999px;
  color: var(--ink);
  transition: background 200ms, color 200ms;
}
.masthead-nav .btn-pill:hover {
  background: var(--ink); color: var(--paper);
}

/* ── Nav dropdown (Model Examples) ────────────────────────────
   Editorial masthead vibe: flat DM Mono uppercase, hairline card,
   no pill / no blur / no native button chrome. Every value is
   explicit rather than inherited, because Safari leaks user-agent
   button styles through `inherit` and produces a pill-looking box. */
.nav-dropdown { position: relative; display: inline-block; }

.nav-dropdown-toggle {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  background: transparent;
  border: 0;
  margin: 0;
  padding: 0;
  /* match adjacent <a> nav links EXACTLY — do not rely on inherit */
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: inherit;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  line-height: inherit;
  color: var(--ink);
  cursor: pointer;
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  white-space: nowrap;
  transition: opacity 200ms, color 200ms;
}
.nav-dropdown-toggle:hover { opacity: 0.7; }
.nav-dropdown-toggle:focus { outline: none; }
.nav-dropdown-toggle:focus-visible {
  outline: 1px dashed var(--accent);
  outline-offset: 4px;
}
.nav-dropdown-toggle.has-active { color: var(--accent); }

.nav-caret {
  font-size: 8px;
  display: inline-block;
  transform: translateY(-1px);
  transition: transform 200ms;
}
.nav-dropdown:hover .nav-caret,
.nav-dropdown:focus-within .nav-caret {
  transform: translateY(-1px) rotate(180deg);
}

.nav-dropdown-menu {
  position: absolute;
  top: 100%; right: 0;
  margin: 6px 0 0 0;
  padding: 0;
  min-width: 240px;
  list-style: none;
  /* Card style applied directly to the menu so every item — including
     scrolled-past-the-fold items — lives inside one consistent
     background. (Previously the card was an absolutely-positioned
     ::before that didn't scroll with the items, so items past the
     fold rendered "outside" the card frame.) */
  background: var(--paper);
  border: 1px solid var(--ink);
  opacity: 0;
  pointer-events: none;
  transform: translateY(-4px);
  transition: opacity 180ms ease, transform 180ms ease;
  z-index: 60;
  /* Cap height so a long list (15+ labs) stays reachable on short
     viewports — items past max-height become scrollable rather than
     bleeding out below the card. */
  max-height: calc(100vh - 96px);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--ink-dim) transparent;
}
.nav-dropdown-menu::before { display: none; }
.nav-dropdown-menu::-webkit-scrollbar { width: 6px; }
.nav-dropdown-menu::-webkit-scrollbar-thumb { background: var(--ink-dim); border-radius: 3px; }
.nav-dropdown-menu::-webkit-scrollbar-track { background: transparent; }
/* Re-create the hover bridge: a small invisible buffer above the card
   so the cursor can travel from button → menu without losing hover. */
.nav-dropdown::after {
  content: '';
  position: absolute;
  top: 100%; right: 0;
  width: 240px;
  height: 10px;
  pointer-events: none;
}
.nav-dropdown:hover::after,
.nav-dropdown:focus-within::after {
  pointer-events: auto;
}
.nav-dropdown-menu::before {
  /* the visible card — starts below the hover-bridge padding */
  content: '';
  position: absolute;
  top: 14px; left: 0; right: 0; bottom: 0;
  background: var(--paper);
  border: 1px solid var(--ink);
  z-index: -1;
}
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
.nav-dropdown-menu a {
  display: block;
  padding: 13px 20px;
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 10.5px;
  font-weight: 400;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
  text-align: left;
  border-top: 1px solid color-mix(in oklab, var(--ink) 12%, transparent);
  transition: background 160ms, color 160ms;
}
.nav-dropdown-menu a:first-of-type { border-top: 0; }
.nav-dropdown-menu a:hover {
  background: color-mix(in oklab, var(--ink) 6%, transparent);
  color: var(--accent);
}
.nav-dropdown-menu a.active,
.nav-dropdown-menu a[aria-current="page"] {
  color: var(--accent);
}
.nav-dropdown-menu a.active::before,
.nav-dropdown-menu a[aria-current="page"]::before {
  content: '▸ ';
  color: var(--accent);
  margin-right: 2px;
}

/* ── 3D Scene Stage ─────────────────────────────────────────── */
.scene-stage {
  position: fixed; top: 50%; right: 24px;
  transform: translateY(-50%);
  height: min(560px, 70vh);
  width: min(460px, 34vw);
  pointer-events: none; z-index: 0;
}
.scene-stage-inner {
  position: relative; width: 100%; height: 100%;
  pointer-events: none;
}
.scene-stage canvas { display: block; }

/* ── Section Label ──────────────────────────────────────────── */
.section-label {
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-dim);
  display: flex; align-items: baseline; gap: 14px;
  /* Reset defaults — class applies to both <div> (hero kickers) and <h2>
     (section headers, post-batch-2 SEO conversion). */
  font-weight: 400;
  margin: 0;
}
.section-label .idx { color: var(--accent); }

/* ── Hero Role Cycle (large, layered over the 3D scene) ─────── */
/* Lives inside the hero section so it scrolls off with the hero   */
/* instead of tracking the fixed 3D scene. The cycling word is     */
/* stacked directly above "Engineer" so the two read as one phrase.*/
.hero-role {
  position: absolute;
  /* Align roughly to the middle of the right-side 3D object.       */
  top: 50%;
  right: clamp(40px, 10vw, 140px);
  transform: translateY(-50%);
  font-weight: 300;
  letter-spacing: -0.025em;
  line-height: 0.95;
  pointer-events: none;
  z-index: 2;
  color: var(--ink);
  font-size: clamp(48px, 6.5vw, 92px);
  /* Flex column so the flipping word and "Engineer" share a common   */
  /* vertical axis and center on each other regardless of glyph       */
  /* widths (ML vs. Analytics vs. Engineer).                          */
  display: flex;
  flex-direction: column;
  align-items: center;
}
.hero-role-words {
  position: relative;
  /* Fixed viewport width keeps "Analytics" fully visible and keeps    */
  /* the cycling word perfectly centered over "Engineer" at all sizes. */
  width: 5.5em;
  /* Tall enough to avoid clipping glyph descenders during the slide.  */
  height: 1.1em;
  overflow: hidden;
  color: var(--accent);
  font-style: italic;
  text-align: center;
}
.hero-role-words > span {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  opacity: 0;
  animation: hero-role-cycle 6s infinite cubic-bezier(.5,.05,.2,1);
  white-space: nowrap;
}
.hero-role-words > span:nth-child(1) { animation-delay: 0s; }
.hero-role-words > span:nth-child(2) { animation-delay: 2s; }
.hero-role-words > span:nth-child(3) { animation-delay: 4s; }
@keyframes hero-role-cycle {
  0%   { opacity: 0; transform: translate(-50%, calc(-50% - 18px)); }
  8%   { opacity: 1; transform: translate(-50%, -50%); }
  28%  { opacity: 1; transform: translate(-50%, -50%); }
  36%  { opacity: 0; transform: translate(-50%, calc(-50% + 18px)); }
  100% { opacity: 0; transform: translate(-50%, calc(-50% + 18px)); }
}
.hero-role-suffix {
  display: block;
  margin-top: -0.05em;
  /* Kerning the leading "E" optically back to center under the cycling word. */
  text-indent: -0.02em;
}
@media (prefers-reduced-motion: reduce) {
  .hero-role-words > span { animation: hero-role-fade 6s infinite steps(1,end); transform: translate(-50%, -50%) !important; }
  @keyframes hero-role-fade {
    0%, 33%  { opacity: 1; }
    34%, 100% { opacity: 0; }
  }
}
@media (max-width: 900px) {
  /* On narrow screens the 3D scene is hidden, so hide the role too.   */
  .hero-role { display: none; }
}

/* ── Big Display Text ───────────────────────────────────────── */
.big-display {
  font-size: clamp(48px, 7.4vw, 96px);
  line-height: 0.95; letter-spacing: -0.02em;
  margin: 18px 0 0; font-weight: 300; text-wrap: balance;
}

/* ── Hero Section ───────────────────────────────────────────── */
.hero {
  min-height: 100vh;
  padding: 140px 48px 60px;
  padding-right: min(520px, 38vw);
  display: flex; align-items: center;
  position: relative;
}
.hero-inner { max-width: 780px; width: 100%; }
.hero h1 {
  font-size: clamp(56px, 7.6vw, 128px);
  line-height: 0.92; letter-spacing: -0.035em;
  font-weight: 300; margin: 28px 0 0;
}
.hero-sub {
  margin-top: 32px; max-width: 560px;
  font-size: 18px; line-height: 1.5;
  color: var(--ink-soft);
}
.hero-ctas {
  margin-top: 44px;
  /* stack vertically so primary stays primary; secondary becomes a
     small mono footnote underneath rather than a sibling button */
  display: flex; flex-direction: column; align-items: flex-start; gap: 14px;
}
.btn-primary {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 14px 22px;
  background: var(--ink); color: var(--paper);
  border-radius: 999px; font-size: 13px; letter-spacing: 0.02em;
  transition: opacity 200ms;
}
.btn-primary:hover { opacity: 0.85; }
.btn-link {
  font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-dim);
  border-bottom: 1px solid color-mix(in oklab, var(--ink) 22%, transparent);
  padding-bottom: 2px;
  transition: color 200ms, border-color 200ms;
}
.btn-link:hover { color: var(--ink); border-color: var(--ink); }
.hero-dateline {
  margin-top: 56px;
  display: flex; gap: 32px;
  font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-dim);
}
.hero-dateline .label { opacity: 0.6; }
.hero-dateline .value { color: var(--ink); margin-top: 4px; }

/* ── Hero Logo Carousel ─────────────────────────────────────── */
.hero-logos {
  margin-top: 48px;
  padding-top: 28px;
  border-top: 1px solid color-mix(in oklab, var(--ink) 12%, transparent);
}
.logo-marquee {
  position: relative;
  overflow: hidden;
  /* fade: opaque left → transparent right */
  -webkit-mask-image: linear-gradient(to right, black 0%, black 60%, transparent 100%);
  mask-image: linear-gradient(to right, black 0%, black 60%, transparent 100%);
}
.logo-track {
  display: flex; align-items: center; gap: 48px;
  width: max-content;
  animation: marquee 28s linear infinite;
}
.logo-track img {
  height: 22px; width: auto;
  object-fit: contain;
  opacity: 0.4;
  filter: grayscale(1) brightness(0);
  flex-shrink: 0;
}
/* Dark theme: invert to white */
[data-theme="graphite"] .logo-track img {
  filter: grayscale(1) brightness(0) invert(1);
}
/* Blueprint: still dark */
[data-theme="blueprint"] .logo-track img {
  filter: grayscale(1) brightness(0);
}

@keyframes marquee {
  0%   { transform: translateX(0); }
  100% { transform: translateX(-50%); }
}

/* ── Capabilities Section ───────────────────────────────────── */
.capabilities { padding: 140px 48px 120px; }
.capabilities-intro { max-width: 900px; }
.capabilities-intro p {
  margin-top: 24px; max-width: 560px;
  color: var(--ink-soft); font-size: 17px;
}
.capability-grid { margin-top: 80px; }
.capability-row {
  display: grid;
  grid-template-columns: 80px minmax(0, 1fr) minmax(0, 1.3fr);
  gap: 32px; padding: 28px 0;
  border-bottom: 1px solid color-mix(in oklab, var(--ink) 18%, transparent);
  align-items: baseline;
}
.capability-fig {
  font-size: 11px; letter-spacing: 0.14em; color: var(--ink-dim);
}
.capability-title {
  font-size: 32px; line-height: 1.05; letter-spacing: -0.01em;
}
.capability-desc {
  color: var(--ink-soft); font-size: 16px; line-height: 1.5;
}

/* ── Metrics Row ────────────────────────────────────────────── */
.metrics { margin-top: 96px; }
.metrics-grid {
  margin-top: 28px;
  display: grid; grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 24px; align-items: end;
}
.metric { border-top: 1px solid var(--ink); padding-top: 14px; }
.metric-value {
  font-size: 52px; line-height: 1; letter-spacing: -0.02em;
  color: var(--accent);
}
.metric-label {
  margin-top: 10px; font-size: 10.5px; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-dim);
}

/* ── Work / Experience ──────────────────────────────────────── */
.work-section { padding: 140px 0 60px; }
.work-header { padding: 0 48px; max-width: 900px; }
.work-entries { margin-top: 80px; }
.experience-entry {
  padding: 80px 48px;
  border-top: 1px solid var(--ink);
  display: grid;
  grid-template-columns: 80px minmax(0, 1fr) minmax(0, 1fr);
  gap: 32px; position: relative;
  align-items: baseline;
}
.exp-idx {
  font-size: 12px; color: var(--ink-dim); letter-spacing: 0.14em;
  padding-top: 2px;
}
.exp-meta {
  font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-dim);
}
.exp-company {
  font-size: 52px; line-height: 1; letter-spacing: -0.02em;
  margin: 14px 0 6px; font-weight: 300;
}
.exp-role {
  font-size: 22px; color: var(--accent);
}
.exp-tags {
  margin-top: 28px; display: flex; flex-wrap: wrap; gap: 6px;
}
.exp-tag {
  font-size: 11px; letter-spacing: 0.06em;
  padding: 5px 10px; border-radius: 999px;
  border: 1px solid color-mix(in oklab, var(--ink) 30%, transparent);
  color: var(--ink-soft);
}
.exp-body {
  display: flex; flex-direction: column; gap: 14px;
  font-size: 16px; line-height: 1.55; color: var(--ink-soft);
}
.exp-body p { margin: 0; }
.exp-drop-cap {
  font-size: 26px; float: left; line-height: 0.9;
  padding: 4px 8px 0 0; color: var(--ink);
}
.exp-logo {
  display: block;
  width: 32px; height: 32px; object-fit: contain;
  margin-top: 16px;
  opacity: 0.3;
  filter: grayscale(1);
}
[data-theme="graphite"] .exp-logo,
[data-theme="midnight"] .exp-logo,
[data-theme="midnight"] .exp-logo {
  filter: grayscale(1) invert(1);
}

/* ── Lab-to-lab navigation (Prev / Next at bottom of each lab) ── */
.lab-nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 24px;
  margin: 0 0 40px;
  padding: 18px 0;
  border-top: 1px solid var(--ink-dim);
  border-bottom: 1px solid var(--ink-dim);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.lab-nav a {
  color: var(--ink-soft);
  transition: color 180ms;
}
.lab-nav a:hover { color: var(--ink); }
.lab-nav span { display: inline-block; }

/* ── Labs Section (five model labs as cards) ─────────────────── */
.labs-section {
  padding: 80px 48px 100px;
  border-top: 1px solid var(--ink);
}
.labs-intro { max-width: 900px; }
.labs-intro p {
  margin-top: 24px; max-width: 560px;
  color: var(--ink-soft); font-size: 17px;
}
.labs-grid {
  margin-top: 64px;
  display: grid;
  /* Adaptive: as many columns as fit at 320px min, down to 1 col on narrow */
  /* viewports. No special-cased data-wide cards — every cell is identical. */
  grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr));
  gap: 0;
  /* Top + left borders on the container; cards supply right + bottom. */
  border-top: 1px solid var(--ink);
  border-left: 1px solid var(--ink);
}
.lab-card {
  background: var(--paper);
  padding: 24px 22px 20px;
  display: flex;
  flex-direction: column;
  min-height: 240px;
  text-decoration: none;
  color: inherit;
  border-right: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
  transition: background 220ms ease, color 220ms ease;
}
.lab-card:hover {
  background: var(--ink);
  color: var(--paper);
}
.lab-card:hover .lab-fig,
.lab-card:hover .lab-arrow { color: var(--paper); opacity: 0.8; }
.lab-fig {
  font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--accent);
}
.lab-name {
  margin: 14px 0 10px;
  font-size: 28px; line-height: 1.05; letter-spacing: -0.015em;
  font-weight: 400;
}
.lab-line {
  font-size: 15px; line-height: 1.45;
  color: var(--ink-soft);
  flex: 1;
}
.lab-card:hover .lab-line { color: var(--paper); opacity: 0.85; }
/* Receipts strip on each lab card — small mono row, real numbers only */
.lab-metric {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px dashed var(--ink-dim);
  font-size: 10px;
  letter-spacing: 0.1em;
  color: var(--ink-dim);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}
.lab-card:hover .lab-metric { color: var(--paper-2); opacity: 0.7; border-top-color: var(--paper-2); }

/* Staggered reveal on first paint. Each card rises 12px and fades
   in, offset by 50ms per card. Pure CSS — no IntersectionObserver
   needed since the user's first impression is the above-fold rows.
   Disabled under prefers-reduced-motion. */
@keyframes lab-card-rise {
  from { opacity: 0; transform: translateY(12px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: no-preference) {
  .labs-grid .lab-card {
    opacity: 0;
    animation: lab-card-rise 600ms cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
  }
  .labs-grid .lab-card:nth-child(1)  { animation-delay:   0ms; }
  .labs-grid .lab-card:nth-child(2)  { animation-delay:  50ms; }
  .labs-grid .lab-card:nth-child(3)  { animation-delay: 100ms; }
  .labs-grid .lab-card:nth-child(4)  { animation-delay: 150ms; }
  .labs-grid .lab-card:nth-child(5)  { animation-delay: 200ms; }
  .labs-grid .lab-card:nth-child(6)  { animation-delay: 250ms; }
  .labs-grid .lab-card:nth-child(7)  { animation-delay: 300ms; }
  .labs-grid .lab-card:nth-child(8)  { animation-delay: 350ms; }
  .labs-grid .lab-card:nth-child(9)  { animation-delay: 400ms; }
  .labs-grid .lab-card:nth-child(10) { animation-delay: 450ms; }
  .labs-grid .lab-card:nth-child(11) { animation-delay: 500ms; }
  .labs-grid .lab-card:nth-child(12) { animation-delay: 550ms; }
  .labs-grid .lab-card:nth-child(13) { animation-delay: 600ms; }
  .labs-grid .lab-card:nth-child(14) { animation-delay: 650ms; }
  .labs-grid .lab-card:nth-child(15) { animation-delay: 700ms; }
  .labs-grid .lab-card:nth-child(16) { animation-delay: 750ms; }
  .labs-grid .lab-card:nth-child(n+17) { animation-delay: 800ms; }
}
.lab-arrow {
  margin-top: 16px;
  font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-soft);
}
/* Receipts row on project cards — mono separator-delimited line */
.project-receipts {
  margin-top: 18px;
  margin-bottom: 8px;
  font-size: 11px;
  letter-spacing: 0.06em;
  color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}
.project-receipts strong {
  color: var(--accent);
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-size: 10px;
}
.project-medium-card .project-receipts { margin-top: 10px; font-size: 10px; }
/* Grid column count is handled by auto-fill — no media-query overrides needed. */

/* ── Projects Section ───────────────────────────────────────── */
.projects-section {
  padding: 56px 48px 80px;
  border-top: 1px solid var(--ink);
}
.projects-intro { max-width: 900px; }
.projects-intro p {
  margin-top: 18px; max-width: 560px;
  color: var(--ink-soft); font-size: 16px;
}

/* Featured project (video) */
.project-featured {
  border-top: 1px solid var(--ink); padding: 40px 0;
  display: grid; gap: 48px; align-items: center;
}
.project-featured.layout-a { grid-template-columns: 1fr 1.3fr; }
.project-featured.layout-b { grid-template-columns: 1.3fr 1fr; }
.project-kicker {
  font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--accent);
}
.project-title {
  font-size: 64px; line-height: 0.95; letter-spacing: -0.02em;
  margin: 16px 0 14px; font-weight: 300;
}
.project-body {
  font-size: 17px; line-height: 1.5; color: var(--ink-soft); max-width: 520px;
}
.project-meta-line {
  margin-top: 24px; font-size: 11px; letter-spacing: 0.1em;
  color: var(--ink-dim); text-transform: uppercase;
}

/* Video frame */
.video-frame {
  position: relative; width: 100%;
  background: var(--paper-2);
  border: 1px solid color-mix(in oklab, var(--ink) 25%, transparent);
  overflow: hidden;
}
.video-frame video {
  display: block; width: 100%; height: 100%; object-fit: cover;
}
.video-frame .frame-label {
  position: absolute; top: 12px; left: 14px;
  font-size: 10px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-dim);
  z-index: 2; pointer-events: none;
}

/* Medium project cards (2-up) */
.projects-medium-grid {
  border-top: 1px solid var(--ink); padding-top: 48px; margin-top: 24px;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px;
}
.project-medium-card video {
  width: 100%; display: block;
  border: 1px solid color-mix(in oklab, var(--ink) 25%, transparent);
  background: var(--paper-2);
}
.project-medium-card .project-kicker { margin-top: 18px; }
.project-medium-title {
  font-size: 36px; letter-spacing: -0.015em;
  margin: 10px 0 8px; font-weight: 300;
}
.project-medium-body {
  font-size: 15px; color: var(--ink-soft); margin: 0;
}
.project-medium-meta {
  margin-top: 14px; font-size: 10.5px; letter-spacing: 0.1em;
  color: var(--ink-dim); text-transform: uppercase;
}

/* iOS Phone Frames */
.ios-section {
  margin-top: 80px; padding-top: 48px;
  border-top: 1px solid var(--ink);
}
.ios-grid {
  margin-top: 36px;
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 32px;
}
.ios-card { text-align: center; }
.phone-frame {
  width: 220px; margin: 0 auto;
  aspect-ratio: 9 / 19;
  border-radius: 28px;
  border: 1.5px solid var(--ink);
  background: var(--paper-2);
  padding: 8px; position: relative;
  overflow: hidden;
}
.phone-frame-inner {
  width: 100%; height: 100%;
  border-radius: 22px;
  border: 1px solid color-mix(in oklab, var(--ink) 25%, transparent);
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.phone-frame-inner img {
  width: 100%; height: 100%; object-fit: cover;
}
.phone-notch {
  position: absolute; top: 14px; left: 50%;
  transform: translateX(-50%);
  width: 48px; height: 6px; border-radius: 3px;
  background: color-mix(in oklab, var(--ink) 30%, transparent);
  z-index: 2;
}
.ios-card .card-title {
  font-size: 28px; margin-top: 24px; font-weight: 300;
}
.ios-card .card-kicker {
  font-size: 10.5px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-dim); margin-top: 4px;
}
.ios-card .card-body {
  font-size: 14px; color: var(--ink-soft);
  margin-top: 12px; max-width: 280px;
  margin-left: auto; margin-right: auto;
}

/* ── Stack Section ──────────────────────────────────────────── */
.stack-section {
  padding: 140px 48px 120px;
  border-top: 1px solid var(--ink);
}
.stack-grid {
  margin-top: 56px;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 32px;
}
.stack-category-header {
  font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--ink-dim);
  padding-bottom: 10px; border-bottom: 1px solid var(--ink);
}
.stack-list {
  list-style: none; padding: 0; margin: 14px 0 0;
}
.stack-list li {
  font-size: 22px; line-height: 1.35; font-weight: 300; color: var(--ink);
}
.stack-list .num {
  color: var(--ink-dim); font-size: 11px; margin-right: 10px;
}

/* ── Education Section ──────────────────────────────────────── */
.education-section {
  padding: 100px 48px 120px;
  border-top: 1px solid var(--ink);
}
.education-grid {
  margin-top: 24px;
  display: grid; grid-template-columns: 1fr 1fr; gap: 48px;
}
.edu-dates {
  font-size: 11px; letter-spacing: 0.14em; color: var(--ink-dim);
}
.edu-school {
  font-size: 44px; font-weight: 300; letter-spacing: -0.02em;
  margin: 12px 0 4px;
}
.edu-degree {
  font-size: 20px; color: var(--accent);
}
.edu-logo {
  width: 36px; height: 36px; object-fit: contain; opacity: 0.4;
  margin-top: 14px;
}
.edu-certs {
  margin-top: 40px; font-size: 12px;
  color: var(--ink-dim); letter-spacing: 0.06em;
}

/* ── Contact Section ────────────────────────────────────────── */
.contact-section {
  padding: 160px 48px 180px;
  border-top: 1px solid var(--ink);
  text-align: center;
}
.contact-heading {
  font-size: clamp(72px, 12vw, 180px);
  line-height: 0.9; letter-spacing: -0.035em;
  font-weight: 300; margin: 32px 0 0;
}
/* ── Lab business kicker (under each lab H1) ─────────────────── */
/* One-line business translation sitting between the H1 and the     */
/* existing methodological kicker. Larger and heavier than the      */
/* kicker so a warm recruiter can read it in one pass.              */
.lab-biz-line {
  margin: 22px 0 0;
  max-width: 640px;
  font-family: "Newsreader", Georgia, serif;
  font-size: clamp(20px, 2.1vw, 26px);
  line-height: 1.35;
  font-weight: 400;
  color: var(--ink);
  font-style: italic;
}

.contact-kicker {
  margin: 36px auto 0;
  max-width: 560px;
  font-size: 17px; line-height: 1.55;
  color: var(--ink-soft);
}
.contact-ctas {
  /* 56px clears the multi-line .contact-kicker on narrow viewports */
  /* without leaving a wasted gap on wide ones. Was lost in the form */
  /* revert; restoring causes the kicker text to no longer overlap   */
  /* the email button.                                                */
  margin-top: 56px;
  display: flex;
  gap: 18px;
  justify-content: center;
  flex-wrap: wrap;
}
.contact-ctas .btn-dark {
  padding: 16px 28px;
  background: var(--ink); color: var(--paper);
  border-radius: 999px; font-size: 14px; letter-spacing: 0.04em;
  transition: opacity 200ms;
}
.contact-ctas .btn-dark:hover { opacity: 0.85; }
.contact-ctas .btn-outline {
  padding: 16px 28px;
  color: var(--ink); border: 1px solid var(--ink);
  border-radius: 999px; font-size: 14px; letter-spacing: 0.04em;
  transition: background 200ms, color 200ms;
}
.contact-ctas .btn-outline:hover {
  background: var(--ink); color: var(--paper);
}
.contact-meta {
  margin-top: 48px; font-size: 12px; letter-spacing: 0.14em;
  color: var(--ink-dim); text-transform: uppercase;
}

/* ── Breadcrumb nav (visible counterpart to BreadcrumbList JSON-LD) ──
   Sits below the masthead, above the hero. Small mono text, ink-dim,
   mirrors the editorial dateline aesthetic. Both readers and Google
   benefit from a visible hierarchy in addition to the schema. */
.breadcrumb {
  padding: 80px 88px 0;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
/* When a breadcrumb is present, the existing hero padding-top (120px,
   originally meant to clear the fixed masthead) becomes redundant. Pull
   any *-hero section a little closer to the breadcrumb. */
main > .breadcrumb + section[class*="-hero"],
main > .breadcrumb + section.hero,
main > .breadcrumb ~ section[class*="-hero"]:first-of-type {
  padding-top: 32px;
}
.breadcrumb ol {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}
.breadcrumb li { margin: 0; }
.breadcrumb li:not(:last-child)::after {
  content: '/';
  margin-left: 12px;
  color: var(--ink-dim);
  opacity: 0.5;
}
.breadcrumb a {
  color: var(--ink);
  border-bottom: 1px solid transparent;
  transition: border-color 200ms ease, color 200ms ease;
}
.breadcrumb a:hover {
  border-bottom-color: var(--ink);
  color: var(--accent);
}
.breadcrumb [aria-current="page"] { color: var(--accent); }
@media (max-width: 720px) {
  .breadcrumb { padding: 90px 24px 0; }
}

/* ── FAQ section (added on top labs for AI search visibility) ──
   GEO research: pages with FAQ sections get +611% AI Overview lift
   (BrightEdge / OtterlyAI 2025). Format matches how people query
   AI assistants — explicit Q&A pairs that map cleanly to FAQPage
   schema. */
.faq {
  max-width: 880px;
  margin: 60px 88px 60px;
  padding-top: 32px;
  border-top: 1px solid color-mix(in oklab, var(--ink) 22%, transparent);
}
.faq-head {
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 24px;
  font-weight: 400;
}
.faq details {
  border-bottom: 1px solid color-mix(in oklab, var(--ink) 18%, transparent);
  padding: 16px 0;
}
.faq details:last-child { border-bottom: none; }
.faq summary {
  cursor: pointer;
  list-style: none;
  outline: none;
  font-family: 'Newsreader', serif;
  font-weight: 400;
  font-size: 19px;
  line-height: 1.3;
  color: var(--ink);
  position: relative;
  padding-left: 22px;
  letter-spacing: -0.005em;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::before {
  content: '▸';
  position: absolute;
  left: 0;
  color: var(--accent);
  transition: transform 200ms ease;
  display: inline-block;
}
.faq details[open] summary::before {
  transform: rotate(90deg);
}
.faq details[open] summary { color: var(--accent); }
.faq .faq-answer {
  margin-top: 12px;
  padding-left: 22px;
  font-family: 'Newsreader', serif;
  font-weight: 300;
  font-size: 16.5px;
  line-height: 1.6;
  color: var(--ink-soft);
  max-width: 65ch;
}
.faq .faq-answer p { margin: 0; }
.faq .faq-answer code {
  font-family: 'DM Mono', ui-monospace, monospace;
  background: color-mix(in oklab, var(--ink) 8%, transparent);
  padding: 1px 5px;
  font-size: 0.86em;
}
@media (max-width: 900px) {
  .faq { margin: 40px 24px; padding-top: 24px; }
  .faq summary { font-size: 17px; }
}

/* ── Related labs (cross-link block above lab-nav) ──────────── */
/* Inserted programmatically into every main lab. Three thematic
   siblings rendered as a horizontal grid that mirrors the labs-grid
   on the homepage. Builds internal-linking signal for crawlers and
   gives readers a clear "what to read next" path. */
.related-labs {
  margin: 0 88px 60px;
  padding: 36px 0 0;
  border-top: 1px solid color-mix(in oklab, var(--ink) 22%, transparent);
}
.related-labs-head {
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 20px;
}
.related-labs-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0;
  border-top: 1px solid var(--ink);
  border-left: 1px solid var(--ink);
}
.related-labs-list li {
  border-right: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
  margin: 0;
}
.related-labs-list a {
  display: flex;
  flex-direction: column;
  padding: 22px 20px 20px;
  height: 100%;
  text-decoration: none;
  color: inherit;
  background: var(--paper);
  transition: background 220ms ease, color 220ms ease;
}
.related-labs-list a:hover {
  background: var(--ink);
  color: var(--paper);
}
.related-fig {
  font-size: 11px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
}
.related-title {
  font-size: 22px;
  margin-top: 10px;
  line-height: 1.1;
  font-weight: 400;
}
.related-line {
  font-size: 14px;
  line-height: 1.45;
  color: var(--ink-soft);
  margin-top: 10px;
  flex: 1;
}
.related-labs-list a:hover .related-fig,
.related-labs-list a:hover .related-title { color: var(--paper); }
.related-labs-list a:hover .related-line { color: var(--paper-2); opacity: 0.85; }

@media (max-width: 900px) {
  .related-labs { margin: 0 24px 40px; padding-top: 28px; }
  .related-labs-list { grid-template-columns: 1fr; }
}

/* ── Colophon / Footer ──────────────────────────────────────── */
.colophon {
  padding: 40px 48px;
  border-top: 1px solid var(--ink);
  display: flex; justify-content: space-between; align-items: center;
  font-size: 11px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--ink-dim);
}
.colophon a { border-bottom: 1px solid transparent; transition: border-color 200ms; }
.colophon a:hover { border-bottom-color: var(--ink-dim); }

/* ── Theme Switcher ─────────────────────────────────────────── */
.theme-switcher {
  position: fixed; bottom: 20px; left: 20px; z-index: 300;
  display: flex; gap: 6px;
}
.theme-btn {
  width: 28px; height: 28px; border-radius: 50%;
  border: 1.5px solid var(--ink); cursor: pointer;
  transition: transform 200ms;
  position: relative;
}
.theme-btn:hover { transform: scale(1.15); }
.theme-btn.active::after {
  content: ''; position: absolute; inset: -4px;
  border: 1px solid var(--ink); border-radius: 50%;
}
.theme-btn[data-t="paper"]     { background: #F1ECE1; }
.theme-btn[data-t="blueprint"] { background: #E8E9E4; }
.theme-btn[data-t="graphite"]  { background: #141311; }
.theme-btn[data-t="midnight"]  { background: #07070A; }

/* ── Responsive ─────────────────────────────────────────────── */
@media (max-width: 1100px) {
  .scene-stage { display: none; }
  .hero { padding-right: 48px; }
  .hero-inner { max-width: 100%; }
}
@media (max-width: 900px) {
  .hero h1 { font-size: clamp(40px, 8vw, 72px); }
  /* .big-display now uses a global clamp() — no breakpoint override needed */
  .capability-row { grid-template-columns: 1fr; gap: 8px; }
  .capability-fig { display: none; }
  .metrics-grid { grid-template-columns: repeat(3, 1fr); }
  .experience-entry { grid-template-columns: 1fr; }
  .exp-idx { display: none; }
  .exp-logo { display: none; }
  .project-featured { grid-template-columns: 1fr !important; }
  .project-featured > *:nth-child(2) { order: 0 !important; }
  .projects-medium-grid { grid-template-columns: 1fr; }
  .stack-grid { grid-template-columns: repeat(2, 1fr); }
  .education-grid { grid-template-columns: 1fr; }
  .ios-grid { grid-template-columns: 1fr; }
  .colophon { flex-direction: column; gap: 12px; text-align: center; }
  .masthead { padding: 10px 16px; gap: 12px; }
  .masthead-dateline { display: none; }
  .masthead-nav { gap: 14px; font-size: 10px; }
}
@media (max-width: 600px) {
  .hero { padding: 120px 24px 40px; }
  .hero h1 { font-size: clamp(32px, 9vw, 56px); line-height: 1.02; }
  .capabilities, .projects-section, .stack-section,
  .education-section, .contact-section { padding-left: 24px; padding-right: 24px; }
  .experience-entry { padding: 48px 24px; }
  .work-header { padding: 0 24px; }
  .metrics-grid { grid-template-columns: repeat(2, 1fr); }
  .metric-label { font-size: 9.5px; letter-spacing: 0.06em; }
  .hero-dateline { flex-wrap: wrap; gap: 20px; }
  .logo-track { gap: 32px; }
  .logo-track img { height: 18px; }
  .logo-marquee {
    -webkit-mask-image: linear-gradient(to right, black 0%, black 75%, transparent 100%);
    mask-image: linear-gradient(to right, black 0%, black 75%, transparent 100%);
  }
  .exp-company { font-size: 36px; }
  .project-title { font-size: 42px; }
  .contact-heading { font-size: clamp(48px, 10vw, 120px); }
  .nav-dropdown-menu { min-width: 160px; max-width: calc(100vw - 32px); }
}

/* ═══════════════════════════════════════════════════════════
   MOTION EXTRAS
   Theme cross-fade, marquee pause, rule draw-in, drop caps,
   ink-mark highlight, glossary popover. Each one is small;
   together they make the site feel alive without drifting
   into Webflow-template territory.
   ═══════════════════════════════════════════════════════════ */

/* Theme cross-fade: extend the body transition (already set)
   to the elements most visibly bound to theme tokens, so the
   paper/blueprint/graphite swap fades instead of jumping. */
.lab-card, .masthead, .hero, .scene-stage, .lab-fig,
.btn-primary, .btn-pill, .btn-outline, .btn-dark,
.theme-switcher .theme-btn, .nav-dropdown-menu, .nav-dropdown-toggle,
hr.rule, hr.hair, .section-label .idx, .lab-metric, .project-receipts {
  transition: background-color 280ms ease, color 280ms ease,
              border-color 280ms ease, fill 280ms ease, opacity 280ms ease;
}

/* Logo carousel pauses on hover so a viewer can read individual logos. */
.logo-marquee:hover .logo-track,
.logo-marquee:focus-within .logo-track {
  animation-play-state: paused;
}

/* Section rules animate left-to-right when they enter view. */
hr.rule, hr.hair {
  border: 0;
  height: 1px;
  background-color: currentColor;
  color: var(--ink);
  transform-origin: left center;
  transform: scaleX(0);
  opacity: 0.6;
  transition: transform 700ms cubic-bezier(0.22, 0.61, 0.36, 1) 80ms,
              background-color 280ms ease, color 280ms ease, opacity 280ms ease;
}
hr.rule { color: color-mix(in oklab, var(--ink) 28%, transparent); }
hr.hair { color: color-mix(in oklab, var(--ink) 14%, transparent); }
hr.rule.is-drawn, hr.hair.is-drawn {
  transform: scaleX(1);
}

/* Drop-cap initials on lede paragraphs across the site. The
   selector list covers every per-lab lede class without
   forcing them all to share one class. */
.lab-biz-line::first-letter,
.af-lede::first-letter,
.seg-lede::first-letter,
.lr-lede::first-letter,
.fs-lede::first-letter,
.aw-lede::first-letter,
.tu-lede::first-letter,
.aj-lede::first-letter,
.mp-lede::first-letter,
.churn-lede::first-letter,
.reco-lede::first-letter,
.sk-lede::first-letter,
.ab-lede::first-letter,
.ev-lede::first-letter,
.sc-lede::first-letter,
.pp-lede::first-letter {
  font-family: 'Newsreader', Georgia, serif;
  font-weight: 500;
  font-style: normal;
  float: left;
  font-size: 4em;
  line-height: 0.85;
  padding: 0.05em 0.08em 0 0;
  margin: 0.05em 0.06em 0 0;
  color: var(--ink);
  /* The accent dot of the masthead lives in the typographic
     period; the drop cap echoes that with a subtle shift. */
}

/* Ink-mark: a curated highlight over a key phrase, slides in
   left-to-right on viewport entry. Uses --mark-bg so each theme
   picks a colour that reads cleanly under its body text — light
   yellow on cream paper, light blue on blueprint, deep red-brown
   on graphite (so the cream italic body text reads on top). */
.ink-mark {
  background-image: linear-gradient(to right, var(--mark-bg), var(--mark-bg));
  background-repeat: no-repeat;
  background-size: 0% 100%;
  background-position: 0 0;
  padding: 0.04em 0.14em;
  border-radius: 1px;
  color: inherit;
  transition: background-size 800ms cubic-bezier(0.22, 0.61, 0.36, 1) 60ms;
}
.ink-mark.is-drawn { background-size: 100% 100%; }

/* Glossary footnote-style popover. Triggered by hovering or
   focusing any [data-glossary] element. */
[data-glossary] {
  cursor: help;
  border-bottom: 1px dotted color-mix(in oklab, var(--ink) 50%, transparent);
}
[data-glossary]:hover,
[data-glossary]:focus-visible {
  border-bottom-color: var(--accent);
  outline: none;
}
.glossary-pop {
  position: absolute;
  pointer-events: none;
  z-index: 200;
  max-width: 280px;
  padding: 10px 14px;
  background: var(--paper);
  color: var(--ink);
  border: 1px solid var(--ink);
  box-shadow: 3px 3px 0 color-mix(in oklab, var(--ink) 14%, transparent);
  font-family: 'Figtree', system-ui, sans-serif;
  font-size: 13px;
  line-height: 1.45;
  opacity: 0;
  transform: translateY(2px);
  transition: opacity 140ms ease, transform 140ms ease;
}
.glossary-pop.is-open {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

/* Reduced motion: disable everything decorative. */
@media (prefers-reduced-motion: reduce) {
  hr.rule, hr.hair { transform: scaleX(1) !important; transition: none !important; }
  .ink-mark { background-size: 100% 100% !important; transition: none !important; }
  .glossary-pop { transition: none !important; }
  .logo-track { animation: none !important; }
}

/* ═════════════════════════════════════════════════════════════
   AESTHETIC EXPERIMENT — 1-bit dither (branch: aesthetic/dither-1bit)
   Inspired by isometric-strategy 1-bit aesthetic (Mars After Midnight,
   Songs of Syx, Obra Dinn). To revert: delete this block + bump cache.

   Approach: override the graphite theme tokens (the dark default used
   site-wide) with a pure greyscale palette. Replace the grain overlay
   with a Bayer-ish dither tile. Kill border-radius site-wide. Drop
   color accents — emphasis comes from weight, dither, and 1px frames.
   ═════════════════════════════════════════════════════════════ */

[data-theme="graphite"] {
  /* Light "snowy paper" base — the screenshot's UI panels feel */
  --paper:    #ECE6D8;
  --paper-2:  #DCD5C4;
  --ink:      #0A0907;
  --ink-soft: #1F1C16;
  --ink-dim:  #5D564A;
  --rule:     #0A0907;
  /* Pure B&W — no color accent */
  --accent:   #0A0907;
  --accent-2: #3A352A;
  --mark-bg:  rgba(10, 9, 7, 0.85);
  /* Greyscale chart palette — high contrast for B&W */
  --chart-1: #0A0907;
  --chart-2: #3A352A;
  --chart-3: #6B6359;
  --chart-4: #9A9382;
  --chart-5: #C5BEA9;
}
/* MIDNIGHT — the inverted-polarity twin of the 1-bit graphite theme.
   Same dither aesthetic, every color value flipped across luminance.
   First-paint default for the site (set in the html data-theme attr).
   Contrast against #0A0907 background:
     ink     #ECE6D8 → 17.5:1   (AAA)
     ink-soft#D6CFBE → 14.6:1   (AAA)
     ink-dim #A09885 →  6.8:1   (AA at all sizes)
   Chart palette is the inverse-luminance map of graphite's grayscale
   (#C5BEA9 / #9A9382 / #6B6359 / #3A352A / #ECE6D8 reordered to keep
   the brightest series first, matching the visual weight of graphite). */
[data-theme="midnight"] {
  /* Near-black "ink" base — the OLED inversion of snowy paper */
  --paper:    #0A0907;
  --paper-2:  #15130E;
  --ink:      #ECE6D8;
  --ink-soft: #D6CFBE;
  --ink-dim:  #A09885;
  --rule:     #ECE6D8;
  /* Pure W&B — no color accent (inverted from graphite's pure B&W) */
  --accent:   #ECE6D8;
  --accent-2: #C5BEA9;
  --mark-bg:  rgba(236, 230, 216, 0.88);
  /* Greyscale chart palette — luminance-flipped from graphite */
  --chart-1: #ECE6D8;
  --chart-2: #C5BEA9;
  --chart-3: #9A9382;
  --chart-4: #6B6359;
  --chart-5: #3A352A;
}

/* Replace the soft grain with a Bayer-style dither tile. 4×4 with two
   filled cells = 12.5% coverage; multiply blend over the paper tone
   gives a stippled-print texture. image-rendering: pixelated keeps
   the dots sharp instead of letting the browser smooth them. */
[data-theme="graphite"] body::before {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='4' height='4' shape-rendering='crispEdges'><rect x='0' y='0' width='1' height='1' fill='%230A0907'/><rect x='2' y='2' width='1' height='1' fill='%230A0907'/></svg>");
  background-size: 4px 4px;
  opacity: 0.22;
  mix-blend-mode: multiply;
  image-rendering: pixelated;
}
/* Midnight body::before — same Bayer dither as graphite but with
   the dot color and blend mode flipped. Cream dots on near-black,
   blended via screen so they brighten the paper instead of darken. */
[data-theme="midnight"] body::before {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='4' height='4' shape-rendering='crispEdges'><rect x='0' y='0' width='1' height='1' fill='%23ECE6D8'/><rect x='2' y='2' width='1' height='1' fill='%23ECE6D8'/></svg>");
  background-size: 4px 4px;
  opacity: 0.18;
  mix-blend-mode: screen;
  image-rendering: pixelated;
}


/* Sharp 1-bit framing: kill rounding everywhere. */
[data-theme="graphite"] *,
[data-theme="midnight"] *,
[data-theme="graphite"] *::before,
[data-theme="midnight"] *::before,
[data-theme="graphite"] *::after,
[data-theme="midnight"] *::after,
[data-theme="midnight"] *::after {
  border-radius: 0 !important;
}

/* Make borders feel hand-drawn / 1-bit by hardening their color */
[data-theme="graphite"],
[data-theme="midnight"] {
  --border-1: 1px solid var(--ink);
  --border-thick: 2px solid var(--ink);
}

/* Section labels, datelines, mono chrome get a touch of pixel weight */
[data-theme="graphite"] .mono,
[data-theme="midnight"] .mono,
[data-theme="midnight"] .mono {
  letter-spacing: 0.06em;
  font-feature-settings: "ss01" on;
}

/* Buttons / pills: no fill on default, 1px solid frame, invert on hover.
   Scoped to common button patterns across the labs. */
[data-theme="graphite"] .btn-pill,
[data-theme="midnight"] .btn-pill,
[data-theme="graphite"] .btn-outline,
[data-theme="midnight"] .btn-outline,
[data-theme="graphite"] .btn-primary,
[data-theme="midnight"] .btn-primary,
[data-theme="midnight"] .btn-primary {
  border: 1px solid var(--ink) !important;
  background: transparent !important;
  color: var(--ink) !important;
}
[data-theme="graphite"] .btn-pill:hover,
[data-theme="midnight"] .btn-pill:hover,
[data-theme="graphite"] .btn-outline:hover,
[data-theme="midnight"] .btn-outline:hover,
[data-theme="graphite"] .btn-primary:hover,
[data-theme="midnight"] .btn-primary:hover,
[data-theme="midnight"] .btn-primary:hover {
  background: var(--ink) !important;
  color: var(--paper) !important;
}

/* The .ink-mark highlight (used in homepage hero copy) becomes a
   solid black knockout — text reads as paper inside the mark. */
[data-theme="graphite"] .ink-mark,
[data-theme="midnight"] .ink-mark,
[data-theme="midnight"] .ink-mark {
  background: var(--ink) !important;
  color: var(--paper) !important;
  padding: 0 4px;
}

/* Section labels get a heavier, more "1-bit" feel */
[data-theme="graphite"] .section-label .idx,
[data-theme="midnight"] .section-label .idx,
[data-theme="midnight"] .section-label .idx {
  background: var(--ink);
  color: var(--paper);
  padding: 2px 6px;
}

/* Lab cards, dropdowns, panels — override any soft greys with paper-2
   so the dither shows through cleanly. */
[data-theme="graphite"] .nav-dropdown-menu,
[data-theme="midnight"] .nav-dropdown-menu,
[data-theme="midnight"] .nav-dropdown-menu {
  background: var(--paper) !important;
  border: 1px solid var(--ink) !important;
}
[data-theme="graphite"] .nav-dropdown-menu a,
[data-theme="midnight"] .nav-dropdown-menu a,
[data-theme="midnight"] .nav-dropdown-menu a {
  color: var(--ink) !important;
}
[data-theme="graphite"] .nav-dropdown-menu a:hover,
[data-theme="midnight"] .nav-dropdown-menu a:hover,
[data-theme="graphite"] .nav-dropdown-menu a.active,
[data-theme="midnight"] .nav-dropdown-menu a.active,
[data-theme="midnight"] .nav-dropdown-menu a.active {
  background: var(--ink) !important;
  color: var(--paper) !important;
}

/* The cursor-dot uses --accent — kill the red dot */
[data-theme="graphite"] .cursor-dot,
[data-theme="midnight"] .cursor-dot,
[data-theme="midnight"] .cursor-dot {
  background: var(--ink);
}

/* Logo carousel: the graphite theme had invert(1) to flip dark PNGs to
   white on the old charcoal background. With paper-light graphite, that
   inversion turns the logos white-on-cream and they vanish. Drop the
   invert and bump opacity so they read as solid-ink silhouettes. */
[data-theme="graphite"] .logo-track img,
[data-theme="midnight"] .logo-track img,
[data-theme="midnight"] .logo-track img {
  filter: grayscale(1) brightness(0) !important;
  opacity: 0.55 !important;
}
/* Midnight logo carousel: re-add invert(1) (graphite dropped it
   because its base is light cream; midnight's base is near-black,
   so we need the inversion back to get light silhouettes). */
[data-theme="midnight"] .logo-track img {
  filter: grayscale(1) brightness(0) invert(1) !important;
  opacity: 0.55 !important;
}


/* Selection */
[data-theme="graphite"] ::selection,
[data-theme="midnight"] ::selection,
[data-theme="midnight"] ::selection {
  background: var(--ink);
  color: var(--paper);
}

/* ── CIRIDAE SPARK — single orange accent, used sparingly ───────
   The dither aesthetic deliberately killed color. Borrowing exactly
   one move from Ciridae's style guide: their #CC6437 "subtle orange"
   used as a rare, high-impact accent on otherwise-monochrome pages.
   Curved pill shape contrasts deliberately against the sharp 1-bit
   framing everywhere else. Only marks recently-shipped labs. */
:root {
  --spark: #CC6437;
}
.new-pill {
  display: inline-block;
  background: var(--spark);
  color: #fff;
  font-family: "DM Mono", ui-monospace, monospace;
  font-size: 8.5px;
  letter-spacing: 0.14em;
  font-weight: 500;
  padding: 2px 8px;
  border-radius: 999px !important;  /* override dither's global radius:0 */
  vertical-align: middle;
  margin-left: 6px;
  text-transform: uppercase;
}
.lab-card .new-pill {
  margin-left: 8px;
  font-size: 9px;
}
/* Dropdown items: pill on the right side, slightly smaller */
.nav-dropdown-menu a .new-pill {
  margin-left: 8px;
  font-size: 8px;
  padding: 1px 6px;
}

/* ── CIRIDAE INFLUENCE — three deliberate echoes of the style guide
   borrowed for cohesion without the wholesale conversion. Each one
   picks up a specific motif that survives the cross-aesthetic test:

   1. Ghost-button pill on .btn-pill — the class is literally named
      after the pill shape; the dither override's global radius:0
      flattened it. Restore the radius (1440px-style 999px) for this
      one component. Generous Ciridae-spec padding (10/18). Now the
      "Get in touch ↗" CTA in the masthead reads as a Ciridae ghost
      button: transparent fill, 1px ink border, pill outline.

   2. Tight tracking on .big-display — Ciridae uses -1.24px / -0.02em
      letter-spacing on Pragmatica Cond display sizes for a
      "machined" feel. Apply the same idea to our Newsreader serif
      display headings. Just enough to make the type feel deliberate
      without abandoning the editorial tone.

   3. Orange leader bar on the currently-viewing dropdown item.
      Augments the existing invert-on-active with a 2px #CC6437
      vertical bar. Distinguishes "you are here" from "you are
      hovering" — which used to be ambiguous since both got the
      paper-on-ink invert.
   ─────────────────────────────────────────────────────────── */

[data-theme="graphite"] .btn-pill,
[data-theme="midnight"] .btn-pill,
[data-theme="midnight"] .btn-pill {
  border-radius: 999px !important;
  padding: 10px 18px;
  letter-spacing: 0.04em;
  border: 1px solid var(--ink) !important;
  background: transparent !important;
  color: var(--ink) !important;
}
[data-theme="graphite"] .btn-pill:hover,
[data-theme="midnight"] .btn-pill:hover,
[data-theme="midnight"] .btn-pill:hover {
  background: var(--ink) !important;
  color: var(--paper) !important;
}

[data-theme="graphite"] .big-display,
[data-theme="midnight"] .big-display,
[data-theme="graphite"] .imm-title,
[data-theme="midnight"] .imm-title,
[data-theme="graphite"] .prod-title,
[data-theme="midnight"] .prod-title,
[data-theme="graphite"] .llm-title,
[data-theme="midnight"] .llm-title,
[data-theme="graphite"] .ev-title,
[data-theme="midnight"] .ev-title,
[data-theme="graphite"] .sc-title,
[data-theme="midnight"] .sc-title,
[data-theme="midnight"] .sc-title {
  letter-spacing: -0.012em;
}

[data-theme="graphite"] .nav-dropdown-menu a.active,
[data-theme="midnight"] .nav-dropdown-menu a.active,
[data-theme="graphite"] .nav-dropdown-menu a[aria-current="page"],
[data-theme="midnight"] .nav-dropdown-menu a[aria-current="page"],
[data-theme="midnight"] .nav-dropdown-menu a[aria-current="page"] {
  position: relative;
  padding-left: 28px;
}
[data-theme="graphite"] .nav-dropdown-menu a.active::before,
[data-theme="midnight"] .nav-dropdown-menu a.active::before,
[data-theme="graphite"] .nav-dropdown-menu a[aria-current="page"]::before,
[data-theme="midnight"] .nav-dropdown-menu a[aria-current="page"]::before,
[data-theme="midnight"] .nav-dropdown-menu a[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: 8px; top: 10px; bottom: 10px;
  width: 2px;
  background: var(--spark);
}

/* ── EDITORIAL POSTER ECHOES — borrowed from a Gradient Descent
   editorial illustration. Two moves only:

   1. .lab-rail — fixed-position thin left-edge rail with the lab's
      FIG number, roman-numeral year, and title set in tiny mono
      rotated -90°. Mimics the side-text running up the left margin
      of a printed editorial spread ("GRADIENT DESCENT" up the gutter).
      Zero color; pure typographic chrome.

   2. .spark — single-character/symbol highlight in #CC6437 spark.
      The poster highlights η (learning rate) in yellow-green inside
      its equation; we do the same with the orange spark on the key
      variable per equation. Used inline like:
        <span class="spark">η</span>
   ─────────────────────────────────────────────────────────── */

[data-theme="graphite"] .lab-rail,
[data-theme="midnight"] .lab-rail,
[data-theme="midnight"] .lab-rail {
  position: fixed;
  /* Live in the content band only — clear of the masthead chrome
     (top ~64px) and the theme-switcher (bottom ~80px). */
  top: 80px; bottom: 80px;
  left: 0;
  width: 32px;
  z-index: 5;  /* sits below masthead and theme-switcher */
  pointer-events: none;
  font-family: 'DM Mono', ui-monospace, monospace;
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-soft);
  border-right: 1px solid color-mix(in oklab, var(--ink) 22%, transparent);
  background: var(--paper);
}
/* Push masthead + theme-switcher inward so they clear the 32px rail.
   Done with margin-left rather than padding so the existing rules
   keep working. */
[data-theme="graphite"] .masthead { padding-left: 48px; }
[data-theme="midnight"] .masthead { padding-left: 48px; }
[data-theme="graphite"] .theme-switcher { left: 48px !important; }
[data-theme="midnight"] .theme-switcher { left: 48px !important; }
/* Outer span absolutely-positioned at the centre of the rail and
   rotated around its own centre — avoids the flex-bounding-box trap
   where long horizontal text inside a 32px-wide flex container spills
   off-screen *before* the transform applies. */
[data-theme="graphite"] .lab-rail span,
[data-theme="midnight"] .lab-rail span,
[data-theme="midnight"] .lab-rail span {
  position: absolute;
  top: 50%; left: 50%;
  transform: translate(-50%, -50%) rotate(-90deg);
  transform-origin: center center;
  white-space: nowrap;
  display: inline-block;
}
[data-theme="graphite"] .lab-rail .rail-fig,
[data-theme="midnight"] .lab-rail .rail-fig,
[data-theme="midnight"] .lab-rail .rail-fig {
  color: var(--spark);
  font-weight: 500;
}

/* Spark highlight for one symbol per equation (editorial-poster move) */
[data-theme="graphite"] .spark,
[data-theme="midnight"] .spark,
[data-theme="midnight"] .spark {
  color: var(--spark);
  font-style: italic;
  font-weight: 500;
}

@media (max-width: 720px) {
  [data-theme="graphite"] .lab-rail { display: none; }
  [data-theme="midnight"] .lab-rail { display: none; }
}

/* ── CURSOR GRID — canvas-rendered gravity-grid + chromatic-aberration
   effect on the dither dots near the cursor. The canvas is injected
   by main.js initCursorGrid(); this rule just positions and stacks
   it. Each dither dot within ~200px of the cursor is pulled toward
   the cursor, AND its colour channels separate into peach / coral /
   lavender, like a lens-aberration ripple.

   Sits ABOVE the static SVG dither overlay (z=100) so the canvas's
   colored dots overdraw the local static dots inside the radius.
   Outside the radius the canvas pixels are transparent so the
   static dither shows through unchanged. */
[data-theme="graphite"] .cursor-grid,
[data-theme="midnight"] .cursor-grid,
[data-theme="midnight"] .cursor-grid {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 101;
  /* lighten ensures the colored dots only brighten — they don't
     darken the cream paper between dots even when the canvas pixel
     is partially opaque */
  mix-blend-mode: lighten;
}

/* ── Pixel Icons ───────────────────────────────────────────── */
.pixel-icon {
  display: inline-block;
  width: 12px;
  height: 12px;
  vertical-align: -0.12em;
  fill: currentColor;
  shape-rendering: crispEdges;
  flex-shrink: 0;
}
.pixel-icon-lg {
  width: 16px;
  height: 16px;
  vertical-align: -0.18em;
}

/* Nav links with icons — smaller icon + tighter gap so the full
   nav fits with all five items visible on a 1280-wide viewport */
.masthead-nav { gap: 18px; }
.masthead-nav a,
.masthead-nav .nav-dropdown-toggle {
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.masthead-nav .pixel-icon {
  width: 11px;
  height: 11px;
  opacity: 0.75;
}

/* Section label icons */
.section-label .pixel-icon {
  opacity: 0.6;
}

/* Research chip icons */
.research-chip .pixel-icon {
  opacity: 0.7;
}
.research-chip.is-active .pixel-icon {
  opacity: 1;
}

/* Toolbar — let the search shrink so the readout stays inside the
   viewport edge instead of clipping past it */
.research-toolbar .research-search {
  flex: 1 1 180px;
  min-width: 160px;
}
.research-toolbar .research-readout {
  flex: 0 0 auto;
}

/* Contact CTA icons */
.contact-ctas a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* Hero CTA icons */
.hero-ctas .btn-primary,
.hero-ctas .btn-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* Notes page nav */
.notes-main .section-label .pixel-icon {
  opacity: 0.6;
}

/* Narrow-viewport masthead: drop icons + secondary items so the
   primary nav (Projects · Research · Get in touch) still fits.
   Notes and Education remain reachable through the homepage. */
@media (max-width: 1080px) {
  .masthead-nav .pixel-icon { display: none; }
  .masthead-nav a, .masthead-nav .nav-dropdown-toggle { gap: 0; }
  .masthead-nav { gap: 16px; }
}
@media (max-width: 820px) {
  .masthead-nav a[href="#education"],
  .masthead-nav a[href="/notes/"] { display: none; }
  .masthead { padding: 12px 18px; column-gap: 16px; }
  .masthead-nav { gap: 14px; }
}
@media (max-width: 520px) {
  .masthead-nav a[href="#projects"] { display: none; }
  .masthead { padding: 10px 14px; column-gap: 12px; }
}

@media (hover: none) {
  [data-theme="graphite"] .cursor-grid { display: none; }
  [data-theme="midnight"] .cursor-grid { display: none; }
}
