/* =========================================================================
   PORTFOLIO — editorial
   A document, not an interface. White page, near-black text, one small mark
   of colour. Hierarchy comes from type and whitespace, not from cards,
   borders, gradients or buttons.
   ========================================================================= */

/* ---------- tokens ---------- */
:root {
  --font-sans: "Satoshi", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono: "IBM Plex Mono", "SF Mono", ui-monospace, monospace;
  --font-hand: "Caveat", "Bradley Hand", cursive;

  /* One size does most of the work. Big type is reserved for the two places
     that genuinely are a headline. */
  /* the dot grid behind the page is drawn on this pitch; see GRID in site.js */
  --grid-pitch: 26px;
  --t-base: 1rem;
  --t-lg: clamp(1.35rem, 2.4vw, 1.9rem);
  --t-xl: clamp(1.9rem, 3.6vw, 2.9rem);
  --t-label: 0.76rem;

  /* 1180 left ~190px of dead margin either side of a 1440 screen while the
     reading column sat at 586. Wider container, same reading measure. */
  --wrap: 1320px;
  --wrap-narrow: 720px;
  --gutter: clamp(1.25rem, 5vw, 4rem);
  --block: clamp(4rem, 9vw, 8rem);

  --r-sm: 3px;
  --r-md: 4px;
  --r-lg: 6px;
  --r-pill: 999px;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  --bg: #ffffff;
  --bg-elev: #ffffff;
  --surface: #fafafa;
  --surface-2: #f4f4f2;
  --text: #0a0d10;
  --text-muted: #52585d;
  --text-faint: #767676;
  --line: rgba(10, 13, 16, 0.11);
  --line-strong: rgba(10, 13, 16, 0.26);
  --shadow: none;
  --glow: none;

  /* Key lime, in two strengths, split by AREA not by importance.
     Neon lime is 1.17:1 on white — as text or a hairline it disappears, but as
     a fill with dark text on top it is 16.6:1 and it sings. So: anything with
     area gets the neon, anything thin or small gets the ink. */
  --accent: #ccff33;        /* neon — fills, bars, pills, highlights, pen marks */
  --accent-ink: #4a6f00;    /* 5.89:1 — lime as text or a hairline on white */
  --accent-mark: #ccff33;   /* marker strokes have area, so they take the neon */
  --accent-2: #ccff33;
  --accent-grad: var(--accent);
  --on-accent: #0a0d10;

  /* doodle ink is just the text colour now — no tinted panel */
  --doodle-bg: transparent;
  --doodle-ink: #0a0d10;

  /* the pixel grid behind the page, and the halftone name in the footer */
  --grid-dot: #d1d0ca;
  --grid-ink: #0a0d10;

  /* The page's one vertical seam: the hero's "who" column and the work
     index's company column sit on the same line all the way down. */
  --col-a: minmax(0, 0.85fr);
  --col-b: minmax(0, 2.15fr);
  --col-gap: clamp(2rem, 5vw, 4.5rem);

  --nav-h: 76px;

  color-scheme: light;
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + 24px);
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--t-base);
  font-weight: 500;
  line-height: 1.65;
  overflow-x: hidden;
  transition: background-color 0.4s var(--ease), color 0.4s var(--ease);
}

body.is-locked { overflow: hidden; }

img, svg, video { display: block; max-width: 100%; }

/* =========================================================================
   THE PIXEL GRID
   A fixed canvas behind everything. It scrolls by redrawing rather than by
   moving, so a 13,000px case study costs the same as a short one.
   ========================================================================= */
.dot-grid {
  position: fixed; inset: 0;
  z-index: 0;
  pointer-events: none;
}
/* everything real sits above the grid */
.site-header, .nav-drawer, main, .site-footer, .toast { position: relative; z-index: 1; }

/* the name, screened into dots, closing the page out */
.name-band { padding-top: clamp(2rem, 5vw, 3.5rem); padding-bottom: clamp(0.5rem, 2vw, 1.25rem); }
@media (max-width: 560px) { .name-band { display: none; } }
.name-halftone { width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; padding: 0; }
:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 3px; border-radius: 4px; }
::selection { background: var(--accent); color: var(--on-accent); }

/* ---------- layout helpers ---------- */
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }
.wrap-narrow { max-width: var(--wrap-narrow); margin-inline: auto; }
.block { padding-block: var(--block); }
/* Work runs straight into who I am — one thought, not two chapters. At the
   full block rhythm there were 298px between the last case study and the
   next heading, which just reads as the page having ended. */
#work { padding-bottom: clamp(2rem, 3.6vw, 3rem); }
#offclock { padding-top: clamp(2.25rem, 4vw, 3.25rem); padding-bottom: clamp(1.25rem, 2.5vw, 2rem); }
.rule { height: 1px; background: var(--line); border: 0; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- typography ---------- */
h1, h2, h3, h4 { font-weight: 700; line-height: 1.24; letter-spacing: -0.01em; }
.display { font-size: var(--t-xl); line-height: 1.16; letter-spacing: -0.022em; }
.h1 { font-size: var(--t-lg); line-height: 1.22; letter-spacing: -0.018em; }
.h2 { font-size: var(--t-lg); line-height: 1.25; letter-spacing: -0.015em; }
.h3 { font-size: var(--t-base); font-weight: 700; letter-spacing: 0; line-height: 1.4; }
.lead { font-size: var(--t-base); color: var(--text-muted); line-height: 1.6; }
.muted { color: var(--text-muted); }
.serif { font-weight: 400; letter-spacing: -0.02em; }

.label {
  font-family: var(--font-mono); font-weight: 500;
  font-size: var(--t-label);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint);
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
}
/* the one label a first-time visitor has to notice — it is the handover from
   the hero into the actual work, so it gets the ink and a lime tick */
#work > .wrap > .label {
  color: var(--text);
  font-weight: 700;
  font-size: 0.82rem;
  letter-spacing: 0.12em;
  margin-bottom: clamp(2rem, 4vw, 3.25rem);
}
#work > .wrap > .label::after {
  content: "";
  width: 26px; height: 6px;
  border-radius: 3px;
  background: var(--accent);
}
/* section labels are just small mono text — no rules, no dashes */
.label::before { display: none; }
.label.is-bare::before { display: none; }

.grad-text {
  background: var(--accent-grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ---------- section head ---------- */
.section-head { display: grid; gap: 0.9rem; margin-bottom: clamp(2rem, 4vw, 3.5rem); max-width: 62ch; }
.section-head .h2 { margin-top: 0.2rem; }

/* =========================================================================
   REVEAL — driven by IntersectionObserver in site.js
   ========================================================================= */
[data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity 0.8s var(--ease) calc(var(--i, 0) * 70ms),
    transform 0.8s var(--ease) calc(var(--i, 0) * 70ms);
  will-change: opacity, transform;
}
[data-reveal].is-in { opacity: 1; transform: none; }

[data-reveal="fade"] { transform: none; }
[data-reveal="left"] { transform: translateX(-24px); }
[data-reveal="scale"] { transform: scale(0.96); }

/* "draw" doesn't fade or move anything itself — it exists purely so the
   IntersectionObserver has something to flag, and the line art inside can
   stroke itself in. --len is measured per shape by initDraw() in site.js. */
[data-reveal="draw"] { opacity: 1; transform: none; transition: none; }
[data-reveal="draw"] svg > *:not([stroke-dasharray]) {
  stroke-dasharray: var(--len, 300);
  stroke-dashoffset: var(--len, 300);
}
[data-reveal="draw"].is-in svg > *:not([stroke-dasharray]) {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset 1s var(--ease) calc(var(--d, 0) * 95ms);
}
/* a shape with its own dash pattern can't be stroke-drawn without losing it,
   so those fade in on the tail of their tile instead */
[data-reveal="draw"] svg > *[stroke-dasharray] { opacity: 0; }
[data-reveal="draw"].is-in svg > *[stroke-dasharray] {
  opacity: 1;
  transition: opacity 0.5s var(--ease) calc(var(--d, 0) * 95ms + 0.55s);
}

/* hero headline: word-by-word */
.hero-line { display: block; }
.hero-word {
  display: inline-block;
  transform: translateY(0.42em);
  opacity: 0;
  transition: transform 1s var(--ease), opacity 1s var(--ease);
  transition-delay: calc(var(--w, 0) * 45ms + 120ms);
}
.is-ready .hero-word { transform: none; opacity: 1; }

/* =========================================================================
   HEADER / NAV
   ========================================================================= */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 90;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  transition: background-color 0.4s var(--ease), border-color 0.4s var(--ease), height 0.4s var(--ease);
  border-bottom: 1px solid transparent;
}
.site-header.is-stuck {
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom-color: var(--line);
}
/* brand left, then the whole nav as one block on the right. Contact used to
   sit in its own group with a gap before it, which read as two navigations. */
.nav-inner { display: flex; align-items: center; gap: 1.5rem; width: 100%; }
.nav-inner .nav-links { margin-left: auto; }

.brand {
  font-weight: 600;
  letter-spacing: -0.02em;
  font-size: 0.95rem;
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  white-space: nowrap;
}
/* the one mark of colour, and it is 6px wide */
/* the wordmark is drawn as dots on a canvas over the text; the text stays in
   the flow (invisible) so the header keeps its exact height and the link its
   accessible name */
.brand { position: relative; }
.brand-px { position: absolute; left: 0; top: 50%; transform: translateY(-50%); display: block; pointer-events: none; }
.brand-word.is-px { visibility: hidden; }
.brand-light { color: var(--text-faint); font-weight: 500; }
/* lowercase wordmark: the name set the way it is written, with the lime full
   stop doing the separating instead of a weight change alone */
.brand-word { text-transform: none; letter-spacing: -0.02em; font-size: 1.28rem; }
.brand-word strong { font-weight: 700; }
.brand-dot { color: var(--accent-ink); font-weight: 700; }

.nav-right { display: flex; align-items: center; gap: clamp(1rem, 2vw, 1.75rem); }
.nav-resume { white-space: nowrap; }
@media (max-width: 980px) { .nav-resume { display: none; } }

.nav-links { display: flex; align-items: center; gap: clamp(1rem, 2vw, 2rem); }
/* Off-site links sit behind a hairline, so the nav still reads as four places
   on this site plus somewhere else — six equal links would have flattened the
   difference between "Case studies" and "Substack". */
.nav-social {
  display: flex; align-items: center;
  gap: clamp(0.7rem, 1.4vw, 1.15rem);
  padding-left: clamp(0.9rem, 1.8vw, 1.5rem);
  border-left: 1px solid var(--line);
}
.nav-link.is-social { font-size: 0.82rem; color: var(--text-faint); }
.nav-link.is-social:hover { color: var(--text); }
.nav-link.is-call { display: inline-flex; align-items: center; }
.nav-link.is-call svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linejoin: round; stroke-linecap: round; }
.nav-link.is-call:hover { color: var(--accent-ink); }
/* the drawer already lists these at the bottom, so hide the header copy
   before the nav gets tight rather than letting it wrap under the brand */
@media (max-width: 1080px) { .nav-social { display: none; } }
.nav-link {
  font-size: 1.05rem;
  color: var(--text-muted);
  position: relative;
  padding-block: 4px;
  transition: color 0.3s var(--ease);
}
.nav-link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.45s var(--ease);
}
/* The house hover, everywhere something is a link: a neon marker sweeps in
   behind the words and the ink stays ink. Lime as text is too pale to read;
   lime behind text is the loudest thing on a white page. */
.mk, .nav-link, .prev-item .ttl, .footer-links a, .back-link, .link-arrow, .intro-link, .next-cs h2 {
  background-image: linear-gradient(var(--accent), var(--accent));
  background-repeat: no-repeat; background-size: 0% 100%; background-position: 0 0;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
  transition: background-size 0.3s var(--ease), color 0.3s var(--ease);
}
.mk, .prev-item .ttl, .next-cs h2 { padding: 0.04em 0.22em; margin-inline: -0.22em; border-radius: 4px; }
.nav-link { padding-inline: 0.35em; margin-inline: -0.35em; border-radius: 4px; }
.nav-link:hover, .prev-item:hover .ttl, .feat-card:hover .mk, .work-card:hover .mk,
.footer-links a:hover, .back-link:hover, .link-arrow:hover, .intro-link:hover, .next-cs:hover h2 {
  background-size: 100% 100%; color: var(--text);
}
.nav-link.is-active { color: var(--text); }
.nav-link.is-active { color: var(--text); }
.nav-link.is-active::after { transform: scaleX(1); }

.nav-divider { display: none; }

.nav-actions { display: flex; align-items: center; gap: 0.75rem; }

.icon-btn {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border: 0; color: var(--text-muted);
  transition: color 0.3s var(--ease);
}
.icon-btn:hover { background: var(--accent); }
.icon-btn svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }


/* flex-column, not grid: grid rows stretch to the button height and push the
   two bars too far apart for the X transform to close */
.nav-burger {
  display: none;
  width: 40px; height: 40px;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid var(--line);
}
.nav-burger span {
  display: block; width: 16px; height: 1.5px; background: currentColor; border-radius: 2px;
  transition: transform 0.4s var(--ease), opacity 0.3s var(--ease);
}
.nav-burger span + span { margin-top: 4px; }
body.menu-open .nav-burger span:first-child { transform: translateY(2.75px) rotate(45deg); }
body.menu-open .nav-burger span:last-child { transform: translateY(-2.75px) rotate(-45deg); }

/* mobile drawer */
.nav-drawer {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: var(--bg);
  padding: calc(var(--nav-h) + 2rem) var(--gutter) 2rem;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px);
  transition: opacity 0.45s var(--ease), transform 0.45s var(--ease), visibility 0.45s;
}
body.menu-open .nav-drawer { opacity: 1; visibility: visible; transform: none; }
.nav-drawer-links { display: grid; gap: 0.35rem; }
.nav-drawer-links a {
  font-size: clamp(1.9rem, 9vw, 2.8rem);
  letter-spacing: -0.03em;
  padding-block: 0.35rem;
  border-bottom: 1px solid var(--line);
  display: flex; align-items: baseline; justify-content: space-between;
  opacity: 0; transform: translateY(18px);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
  transition-delay: calc(var(--i) * 60ms);
}
/* only the trailing index gets the mono treatment — not the label */
.nav-drawer-links a .idx { font-family: var(--font-mono); font-weight: 500; font-size: 0.74rem; color: var(--text-faint); }
body.menu-open .nav-drawer-links a { opacity: 1; transform: none; }
.nav-drawer-foot { display: flex; flex-wrap: wrap; gap: 1rem 1.5rem; font-size: 0.85rem; color: var(--text-muted); }

/* =========================================================================
   LINKS — there are no buttons on this site any more
   ========================================================================= */
.btn, .btn-primary {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-size: var(--t-base);
  color: var(--text);
  border: 0; background: none; padding: 0;
  border-bottom: 1px solid var(--line-strong);
  padding-bottom: 2px;
  border-radius: 0;
  transition: color 0.3s var(--ease), border-color 0.3s var(--ease);
}
.btn::before { display: none; }
.btn:hover, .btn-primary:hover { color: var(--accent-ink); border-color: var(--accent-ink); }
.btn svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.btn .arrow, .btn svg { transition: transform 0.35s var(--ease); }
.btn:hover svg { transform: translate(2px, -2px); }
.btn-sm { font-size: var(--t-label); }

/* the one place a lime fill earns its keep: the primary call to action */
.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
  border: 0;
  border-radius: var(--r-pill);
  padding: 0.55rem 1.1rem;
  font-weight: 700;
}
/* Quiet until you touch it, then it goes lime. Two lime buttons never show
   at once — the header one is above the fold, this one is at the bottom. */
.btn-outline {
  border: 1.5px solid var(--text);
  border-radius: var(--r-pill);
  padding: 0.55rem 1.15rem;
  font-weight: 700;
  color: var(--text);
}
.btn-outline:hover {
  color: var(--on-accent);
  background: var(--accent);
  border-color: var(--accent);
}

/* The primary of the pair. Two identical outlines side by side gave the eye
   nowhere to land; the filled one says which is the actual job of the page.
   Both still go lime on hover, so they stay a set. */
.btn-solid {
  border: 1.5px solid var(--text);
  border-radius: var(--r-pill);
  padding: 0.55rem 1.15rem;
  font-weight: 700;
  background: var(--text);
  color: var(--bg);
}
.btn-solid:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}
.btn-solid:hover svg { transform: translateY(2px); }
.btn-outline:hover svg { transform: translateY(2px); }
.btn-primary:hover { color: var(--on-accent); background: #d7ff5c; }
.btn-primary:hover svg { transform: translateY(2px); }

.hero-actions {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0.75rem 1.75rem;
  margin-top: clamp(1.75rem, 4vw, 2.5rem);
}

.link-arrow {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-size: var(--t-base); position: relative;
  transition: color 0.3s var(--ease);
}
.link-arrow::after {
  content: ""; position: absolute; left: 0; bottom: -2px; height: 1px; width: 100%;
  background: currentColor; transform: scaleX(0); transform-origin: right;
  transition: transform 0.4s var(--ease);
}

.link-arrow svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; transition: transform 0.4s var(--ease); }
.link-arrow:hover svg { transform: translateX(3px); }

/* =========================================================================
   HERO — a statement, not a stage
   ========================================================================= */
/* The hero owns the screen between the nav and the work label, and its
   content sits in the middle of it rather than pinned to the top. It was
   top-aligned with all the slack dumped underneath, which read as the block
   being stuck to the header. */
.hero {
  padding-top: var(--nav-h);
  padding-bottom: 0;
  /* leaves ~120px at the bottom of the viewport for the work label to sit in,
     so the fold shows the heading and nothing beneath it */
  min-height: calc(100svh - 120px);
  display: flex;
  align-items: center;
}
.hero > .wrap { width: 100%; }
/* The hero's min-height does the work of placing this; the label lands just
   above the fold and the first case study just below it. */
#work { padding-top: clamp(2rem, 4vw, 3.25rem); }

.hero-statement {
  /* Measured against the column it actually sits in (745px at 1280). Every
     line holds three rows up to 76px and line two breaks to four at 78, so
     the cap sits at 73.6 with headroom for a font swap moving the metrics. */
  /* Set wide now that nothing sits beside it: about three quarters of the
     page at 1440, three rows, and the type up a step to fill the measure. */
  font-size: clamp(2.1rem, 5.6vw, 4.7rem);
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: -0.034em;
  max-width: min(78%, 19ch);
  margin: 0;
  text-wrap: balance;
}
.hero-statement em { font-style: normal; font-weight: 700; position: relative; }

/* --- two-column hero: the statement on the left, the drawing on the right,
   and the line about PDFs written under the drawing in the site's own
   handwriting rather than set as a subtitle. -------------------------- */
.hero-cols {
  display: grid;
  /* The note is a short handwritten remark, not a column of copy — cap it at
     the width it actually needs and give everything else to the statement.
     At a 35% share it was taking 350px and forcing the type down to 64px to
     keep three rows, which defeated the point of making it bigger. */
  grid-template-columns: minmax(0, 1fr) clamp(220px, 21vw, 285px);
  gap: clamp(1.25rem, 3vw, 2.5rem);
  align-items: start;
}
.hero-cols.is-solo { grid-template-columns: 1fr; }
/* statement, then the line, then the buttons. The old gap was one value for
   all three, which put as much air between the line and the button as between
   the headline and the line. */
.hero-say { display: grid; align-content: center; gap: 0; }
.hero-say .hero-sub { margin: clamp(1.4rem, 2.6vw, 2rem) 0 0; }
.hero-say .hero-actions { margin: clamp(1.6rem, 3vw, 2.4rem) 0 0; }
/* Under the statement, one row across the same measure: the line on the
   left, the buttons on the right. Reads as one composition rather than a
   stack of things hugging the left edge. */
.hero-foot {
  display: grid; gap: clamp(1.5rem, 2.8vw, 2.25rem); justify-items: start;
  max-width: 78%;
  margin-top: clamp(1.75rem, 3.5vw, 2.75rem);
}
.hero-foot .hero-sub { margin: 0; max-width: 100%; font-size: clamp(0.98rem, 1.2vw, 1.1rem); }
.hero-foot .hero-actions { margin: 0; }
@media (max-width: 760px) {
  .hero-statement { max-width: 100%; }
  .hero-foot { max-width: 100%; }
}

/* Employer logos, one per group in the work index. Small and flattened to
   ink: three brand palettes side by side would read as a sponsor board, and
   the page already has exactly one colour. */
.org-logo { display: block; margin-bottom: 0.6rem; }
/* Full colour and big enough to read the name. An earlier pass flattened these
   to solid black, which turned a white-on-green mark into a black rectangle
   and a multicolour one into a blob. Brand colour it is.
   The cap on width matters as much as the height: these marks range from 2.7:1
   to 3.9:1, so height alone would make the widest one twice the size of the
   narrowest. Both bounds, and object-fit keeps the whole name in frame. */
.org-logo img {
  height: clamp(26px, 3.4vw, 34px);
  width: auto;
  max-width: 132px;
  object-fit: contain;
  object-position: left center;
  display: block;
  border-radius: 3px;
  opacity: 0.92;
  transition: opacity 0.35s var(--ease);
}
/* A square icon mark cannot be sized on height alone — at the wordmarks'
   height it would render a quarter of their width and look like a mistake.
   Given both axes and a real corner radius, it reads as an app icon instead. */
.org-logo img.is-icon {
  height: clamp(38px, 4.6vw, 46px);
  width: clamp(38px, 4.6vw, 46px);
  max-width: none;
  border-radius: 9px;
}
.work-group:hover .org-logo img { opacity: 1; }
/* the placeholder until a file exists */
.logo-ph {
  font-family: var(--font-mono); font-weight: 500;
  font-size: 0.66rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--text-faint);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-sm);
  padding: 0.24rem 0.5rem;
  display: inline-block;
}


/* The cycling headline swaps inside this, so the span fades rather than the
   h1 — the h1 has to keep its reserved height or the page jumps every swap.

   Bottom-aligned on purpose. The reserved box is as tall as the longest line,
   so a two-line headline leaves ~130px spare; anchored to the bottom that gap
   opens *above* the words, where the hero already has whitespace, instead of
   between the headline and the sentence it belongs to. */
/* The margin note, in the right-hand column, with a small arrow pointing back
   across at the statement. Black, not lime — the pen underline in the headline
   already carries the colour, and two greens in one block turn a wisecrack
   into decoration. */
.hero-aside {
  display: grid;
  grid-template-columns: 28px minmax(0, 1fr);
  align-items: start;
  gap: 0.55rem;
  margin: 0;
  padding-top: clamp(0.5rem, 2vw, 1.6rem);
  max-width: 20ch;
  font-family: var(--font-hand);
  font-size: clamp(1.1rem, 1.7vw, 1.5rem);
  line-height: 1.2;
  color: var(--text);
  transform: rotate(-1.4deg);
  transform-origin: left top;
  opacity: 0;
  translate: 0 6px;
  transition: opacity 0.5s var(--ease), translate 0.5s var(--ease);
}
.hero-aside.is-on { opacity: 1; translate: 0 0; }
.hero-aside-arrow {
  width: 28px; height: 19px;
  margin-top: 0.26rem;
  color: var(--text);
  /* the glyph ships pointing left, which is exactly where the statement is */
  rotate: -6deg;
}
.hero-aside-arrow .pen { width: 100%; height: 100%; clip-path: inset(0 100% 0 0); }
@media (prefers-reduced-motion: reduce) {
  .hero-aside { transition: none; opacity: 1; translate: 0 0; }
  .hero-aside-arrow .pen { clip-path: none; }
}

@media (max-width: 860px) {
  /* under the statement on a phone, arrow turned up at it */
  .hero-aside { padding-top: 0; max-width: 30ch; }
  .hero-aside-arrow { rotate: 128deg; }
}

/* Not a flex container. It was one so the reserved box could bottom-align a
   short line, but every line is three rows now so there is nothing to align —
   and as a flex parent it was shrinking its own child, which wrapped the type
   at roughly half the width it reported. */
/* The statement moves as one block, so it needs no clipping and no rows —
   just something that can be transformed. */
.hero-line-in { display: block; will-change: transform, opacity; }

@media (prefers-reduced-motion: reduce) {
  .hero-line-in { transition: none !important; transform: none !important; opacity: 1 !important; }
}

/* the resume button and the note that appears beside it on hover */
.hero-resume { position: relative; display: inline-flex; }
.hero-resume-note {
  position: absolute; left: calc(100% + 0.85rem); top: 50%;
  transform: translateY(-50%) rotate(-4deg) translateX(-6px);
  font-family: var(--font-hand);
  font-size: clamp(1rem, 1.5vw, 1.3rem);
  line-height: 1.1;
  color: var(--text);
  white-space: nowrap;
  opacity: 0; pointer-events: none;
  transition: opacity 0.3s var(--ease), transform 0.4s var(--ease);
}
.hero-resume:hover .hero-resume-note,
.hero-resume:focus-within .hero-resume-note {
  opacity: 1;
  transform: translateY(-50%) rotate(-4deg) translateX(0);
}
/* no room for it beside the button on a phone, and no hover to trigger it */
@media (max-width: 760px) { .hero-resume-note { display: none; } }

.hero-face { margin: 0; display: grid; justify-items: center; gap: 0.25rem; }
.hero-face img {
  width: 100%;
  max-width: 340px;
  height: auto;
  display: block;
  /* the drawing is black line art on white; multiply drops its paper so it
     sits on the dot grid instead of punching a white hole in it */
  mix-blend-mode: multiply;
}
/* the PDF line, handwritten, tucked under the drawing */
.hero-scribble {
  font-family: var(--font-hand);
  font-size: clamp(1.05rem, 1.6vw, 1.4rem);
  line-height: 1.25;
  color: var(--accent-ink);
  text-align: center;
  text-wrap: balance;
  max-width: 26ch;
  transform: rotate(-2deg);
  margin-top: -0.35rem;
}

@media (max-width: 860px) {
  /* drawing first: on a phone the statement plus a button fills the screen
     and the face never gets seen at all if it stays in source order */
  .hero-cols { grid-template-columns: 1fr; gap: clamp(1.25rem, 4vw, 2rem); }
  .hero-face { order: -1; justify-items: start; }
  .hero-face img { max-width: 190px; }
  .hero-scribble { text-align: left; max-width: 34ch; }
}

.hero-sub {
  margin-top: clamp(1.75rem, 3.5vw, 2.75rem);
  max-width: 52ch;
  font-size: clamp(1rem, 1.3vw, 1.1rem);
  line-height: 1.6;
  color: var(--text-muted);
}



.hero-scroll {
  margin-top: clamp(2.5rem, 6vw, 4.5rem);
  font-size: var(--t-base);
  color: var(--text);
  display: inline-flex; align-items: center; gap: 0.5rem;
}
.hero-scroll svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; transition: transform 0.4s var(--ease); }
.hero-scroll:hover svg { transform: translateY(3px); }

/* say-my-name — a speaker glyph and an IPA, sitting quietly next to the name */
.say { display: inline-flex; align-items: center; gap: 0.4rem; margin-left: 0.6rem; vertical-align: baseline; }
.say-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.5em; height: 1.5em; padding: 0;
  background: none; border: 0; border-radius: 50%;
  color: var(--text-faint); cursor: pointer;
  transition: color 0.3s var(--ease), background-color 0.3s var(--ease);
}
.say-btn svg {
  width: 0.85em; height: 0.85em;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.say-btn:hover, .say-btn:focus-visible { color: var(--accent-ink); background: color-mix(in srgb, var(--accent) 9%, transparent); }
.say-btn.is-playing svg { animation: say-pulse 0.6s var(--ease) infinite alternate; }
@keyframes say-pulse { to { opacity: 0.4; } }
.say-ipa { font-family: var(--font-mono); font-weight: 500; font-size: 0.62em; letter-spacing: 0.02em; color: var(--text-faint); }

/* =========================================================================
   DECK CHARTS — HMW, 2x2, tension curve
   Rebuilt from the Figma deck's own visual language, in the site's palette.
   ========================================================================= */
.hmw-intent { color: var(--text-muted); max-width: 62ch; }
.hmw-criteria {
  list-style: none; margin: 0.75rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.35rem 1.25rem;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.74rem;
  letter-spacing: 0.04em; color: var(--text-faint);
}
.hmw-criteria li::before { content: "· "; }

.hmw {
  font-size: clamp(1.5rem, 3.2vw, 2.6rem);
  font-weight: 700; line-height: 1.35; letter-spacing: -0.018em;
  max-width: none;
}
.hmw mark {
  background: color-mix(in srgb, var(--accent) 55%, var(--bg)); color: var(--on-accent);
  padding: 0.02em 0.18em; border-radius: 3px;
  transition: background 0.25s var(--ease);
}
.hmw mark.has-tip { cursor: help; outline: none; }
.hmw mark.has-tip:hover, .hmw mark.has-tip:focus-visible { background: var(--accent); filter: brightness(1.06); }

/* The notes, one panel under the statement. On a pointer device only the
   lit one shows, at reading size; on touch all three stack so nothing is
   hidden behind a hover. */
.hmw-notes {
  display: grid; gap: clamp(1rem, 2.5vw, 2rem);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  margin-top: clamp(1.5rem, 3vw, 2.5rem);
}
.hmw-note { padding-top: 0.75rem; }
.hmw-note .k {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--text);
  background: var(--accent); padding: 0.15em 0.45em; border-radius: 3px;
}
.hmw-hint { margin-top: 0.9rem; font-family: var(--font-mono); font-size: 0.74rem; letter-spacing: 0.04em; color: var(--text-faint); }
.hmw-note p { color: var(--text-muted); font-size: 0.92rem; margin-top: 0.35rem; }
@media (hover: hover) and (min-width: 861px) {
  .hmw-notes { grid-template-columns: 1fr; gap: 0; position: relative; min-height: 7.5rem; }
  .hmw-note { position: absolute; inset: 0 auto auto 0; width: min(100%, 62ch); opacity: 0; transform: translateY(6px); transition: opacity 0.3s var(--ease), transform 0.3s var(--ease); }
  .hmw-note.is-on { opacity: 1; transform: none; }
  .hmw-note .k { font-size: 0.78rem; }
  .hmw-note p { font-size: clamp(1.05rem, 1.4vw, 1.25rem); line-height: 1.55; color: var(--text); }
}
}

/* A sitemap or an audit board is unreadable in a 594px reading column. `wide`
   pulls the figure back out over the sticky TOC and across the full wrap, which
   is the only way these diagrams are legible without a lightbox. */
/* `wide` no longer means "break out of the column" — it used to pull the figure
   left over the sticky section nav, which buried the navigation. It now means
   "span both tracks of the section and offer a zoom", so the figure starts
   exactly where the body text starts and never exceeds it. */
.media.is-wide {
  grid-column: 1 / -1;
  width: 100%;
  margin-left: 0;
  max-width: none;
}
.media.is-wide .media-slot { background: var(--surface); }
.media.is-wide img { object-fit: contain; }

/* Any slot that takes a real image: fill it, and never stretch it. */
.media-slot img, .media-slot video,
.ph-media img, .scrap-slot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.phone-screen img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* diagrams and flow boards are the wrong shape for a crop — letterbox them */
/* a recording is never cropped: whatever its shape, the whole frame shows */
.media-slot video { object-fit: contain; background: #0a0d10; }
/* a bare picture: no box, no stroke, just the image on a soft shadow */
.media-slot.is-bare { border: 0; background: transparent; border-radius: 16px; box-shadow: 0 1px 2px rgba(10, 13, 16, 0.06), 0 16px 40px -16px rgba(10, 13, 16, 0.22); }
.media-slot.is-bare img { object-fit: contain; object-position: top; border-radius: 16px; }
/* two bare pictures of very different shapes share a baseline, not a height */
.block-figs:has(.media-slot.is-bare) { align-items: start; }
/* a picture that opens a prototype: the whole slot is the link, and a
   small pill in the corner says so on hover */
.media-href { position: absolute; inset: 0; display: block; cursor: pointer; }
.media-href img { width: 100%; height: 100%; object-fit: cover; object-position: top; transition: transform 0.6s var(--ease); }
.media-href:hover img { transform: scale(1.02); }
.media-open {
  position: absolute; right: 12px; bottom: 12px;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.68rem; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 0.4rem 0.7rem; border-radius: 999px; background: var(--accent); color: var(--text);
  display: inline-flex; gap: 0.35em; align-items: center;
  opacity: 0; transform: translateY(4px); transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}
.media-href:hover .media-open, .media-href:focus-visible .media-open { opacity: 1; transform: none; }
/* a long page capture shows its first screen, not its middle */
.media-slot img[data-full] { object-position: top; }
.media-slot img[src*="diagram"], .media-slot img[src*="flow"],
.media-slot img[src*="map"], .media-slot img[src*="ia-"] { object-fit: contain; background: var(--bg); }
.ph-media:has(img), .scrap-slot:has(img), .media-slot:has(img) { padding: 0; color: transparent; }

/* The grey card is scaffolding for an empty slot. Once a real picture lands it
   is just a box drawn around someone else's artwork, and on a screenshot that
   already has its own rounded frame it reads as a second, wonkier frame. So a
   filled slot drops the border and the fill and shows only the image. */
.media-slot:has(> img), .media-slot:has(> video),
.ph-media:has(> img), .scrap-slot:has(> img),
.media.is-wide .media-slot:has(> img), .media.is-wide .media-slot:has(> video) {
  border-color: transparent;
  background: none;
}
/* the slider is two filled panes, so its outline is the same redundant box */
.ba.is-media:has(img) { border-color: transparent; }

/* Figures attached to a text block. One sits full width; two or more share
   the row, because a pair of screens compared side by side is worth more than
   the same two stacked. */
.block-figs { display: grid; gap: clamp(0.75rem, 1.8vw, 1.25rem); margin-top: clamp(1.25rem, 2.5vw, 2rem); }
.block-figs[data-n="2"], .block-figs[data-n="4"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.block-figs[data-n="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.block-figs .media { margin: 0; }
/* a pair or a trio sits inside the block, so they must not break out of it */
.block-figs .media.is-wide { grid-column: auto; }
/* empty slots read as deliberate space rather than a missing asset */
.block-figs .media-slot:not(:has(img)):not(:has(video)) {
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  place-items: center;
}
.block-figs .media-slot:not(:has(img)) .media-tag { position: static; text-align: center; }
@media (max-width: 720px) {
  .block-figs[data-n="2"], .block-figs[data-n="3"], .block-figs[data-n="4"] { grid-template-columns: 1fr; }
}

/* ---- gallery: diagrams side by side ------------------------------------- */
/* Two per row, not three. At column width a third-width diagram is unreadable
   even before you click it. */
.gallery {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(0.75rem, 1.8vw, 1.25rem);
}
.gallery[data-n="1"] { grid-template-columns: 1fr; }
.gal { margin: 0; display: grid; gap: 0.4rem; align-content: start; }
.gal-slot {
  position: relative;
  aspect-ratio: var(--ratio, 4/3);
  border: 1px solid var(--line);
  border-radius: 6px;
  overflow: hidden;
  background: var(--surface);
  display: grid; place-items: center;
  padding: 0.75rem; text-align: center;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.66rem;
  letter-spacing: 0.06em; color: var(--text-faint);
}
.gal-slot img { width: 100%; height: 100%; object-fit: contain; cursor: zoom-in; }
.gal .figcap { font-size: 0.7rem; }
@media (max-width: 760px) {
  .gallery { grid-template-columns: 1fr; }
}

/* ---- enlarge on click --------------------------------------------------- */
.media-slot img, .scrap-slot img, .ph-media img, .gal-slot img { cursor: zoom-in; }
/* a quiet affordance, so it is discoverable without a label shouting about it */
.media-slot:has(img)::after, .scrap-slot:has(img)::after, .gal-slot:has(img)::after {
  content: "\21F2";
  position: absolute; right: 10px; bottom: 8px;
  width: 24px; height: 24px; display: grid; place-items: center;
  border-radius: 4px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  color: var(--text-muted); font-size: 0.85rem;
  opacity: 0; transition: opacity 0.25s var(--ease);
  pointer-events: none;
}
.media-slot:has(img):hover::after, .scrap-slot:has(img):hover::after, .gal-slot:has(img):hover::after { opacity: 1; }

.lightbox {
  position: fixed; inset: 0; z-index: 300;
  display: grid; place-items: center; gap: 1rem;
  /* minmax(0, 1fr), not 1fr: an auto minimum lets the track grow to the
     media's natural size, so a tall portrait capture ran off the screen
     instead of being capped by its own max-height. */
  grid-template-rows: minmax(0, 1fr) auto;
  padding: clamp(1rem, 4vw, 3rem);
  background: color-mix(in srgb, var(--text) 92%, transparent);
  cursor: zoom-out;
}
.lightbox[hidden] { display: none; }
.lightbox img, .lightbox video {
  max-width: 100%; max-height: 100%;
  object-fit: contain;
  background: var(--bg);
  border-radius: 6px;
  cursor: default;
}
.lightbox video { background: #000; }
/* a long capture: the box becomes a scroller and the image sits at width */
.lightbox.is-scroll {
  display: block; overflow-y: auto; overscroll-behavior: contain;
  padding: clamp(3rem, 6vw, 4.5rem) clamp(1rem, 4vw, 3rem) clamp(2rem, 4vw, 3rem);
}
.lightbox.is-scroll img {
  display: block; width: min(100%, 1100px); max-height: none; height: auto;
  margin: 0 auto;
}
.lightbox.is-scroll .lightbox-cap { margin: 1rem auto 0; }
.lightbox.is-scroll .lightbox-close { position: fixed; }
/* a wide board: the image takes the viewport height and scrolls sideways */
.lightbox.is-scroll-x {
  display: block; overflow-x: auto; overflow-y: hidden; overscroll-behavior: contain;
  padding: clamp(3rem, 6vw, 4.5rem) clamp(1rem, 4vw, 3rem) clamp(2rem, 4vw, 3rem);
}
.lightbox.is-scroll-x img {
  display: block; height: calc(100vh - clamp(3rem, 6vw, 4.5rem) - clamp(2rem, 4vw, 3rem) - 2.5rem);
  width: auto; max-width: none; max-height: none;
}
.lightbox.is-scroll-x .lightbox-cap { position: fixed; left: 0; right: 0; bottom: 0.75rem; margin: 0 auto; }
.lightbox.is-scroll-x .lightbox-close { position: fixed; }
.lightbox img[hidden], .lightbox video[hidden] { display: none; }

/* Clicking a video plays it, so enlarging needs its own control. */
.media-zoom {
  position: absolute; top: 10px; right: 10px; z-index: 3;
  width: 34px; height: 34px;
  border: 0; border-radius: 9px;
  background: rgba(0, 0, 0, 0.55);
  color: #fff; cursor: zoom-in;
  display: grid; place-items: center;
  opacity: 0;
  transition: opacity 0.25s var(--ease), background 0.25s var(--ease);
}
.media-zoom svg {
  width: 17px; height: 17px;
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.media-slot:hover > .media-zoom,
.media-zoom:focus-visible { opacity: 1; }
.media-zoom:hover { background: rgba(0, 0, 0, 0.78); }
/* nothing hovers on a touch screen, so it just stays visible there */
@media (hover: none) { .media-zoom { opacity: 0.85; } }
.lightbox-cap {
  color: rgba(255, 255, 255, 0.75);
  font-family: var(--font-mono); font-weight: 500; font-size: 0.74rem;
  letter-spacing: 0.04em; text-align: center; max-width: 70ch;
}
.lightbox-close {
  position: absolute; top: 1rem; right: 1.25rem;
  width: 40px; height: 40px;
  background: none; border: 0; border-radius: 50%;
  color: #fff; font-size: 1.6rem; line-height: 1; cursor: pointer;
  transition: background-color 0.25s var(--ease);
}
.lightbox-close:hover, .lightbox-close:focus-visible { background: rgba(255,255,255,0.14); }

/* A research verbatim, set to be read from across the room. */
.say-quote { margin: 0; }
.say-quote blockquote {
  margin: 0;
  font-size: clamp(1.3rem, 2.6vw, 2rem);
  font-style: italic;
  font-weight: 500;
  line-height: 1.32;
  letter-spacing: -0.018em;
  max-width: 26ch;
  border-left: 2px solid var(--accent);
  padding-left: clamp(1rem, 2.5vw, 1.75rem);
}
.say-quote blockquote::before { content: "\201C"; }
.say-quote blockquote::after { content: "\201D"; }
.say-quote figcaption {
  margin-top: 0.9rem;
  padding-left: clamp(1rem, 2.5vw, 1.75rem);
  font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint);
}

/* ---- pillars: the deck's three-column slides ---------------------------- */
.pillars {
  display: grid;
  grid-template-columns: repeat(var(--n, 3), minmax(0, 1fr));
  gap: clamp(1.75rem, 4vw, 3.5rem);
}
.pillars[data-n="2"] { --n: 2; }
.pillars[data-n="4"] { --n: 4; }
/* five and six wrap to three a row; a 6-up strip is unreadable */
.pillars[data-n="5"], .pillars[data-n="6"] { --n: 3; row-gap: clamp(1.5rem, 3vw, 2.5rem); }
/* a montage with its own shadows: no box around it */
.media.is-bare .media-slot { border: 0; background: transparent; border-radius: 0; overflow: visible; }
.media.is-bare .media-slot img { object-fit: contain; }
.pillar { display: grid; gap: 0.6rem; align-content: start; }
/* A row of cards was landing 23px under its heading, close enough to read as
   part of the sentence above it rather than as a new thing. */
.cs-section > .pillars { margin-top: clamp(0.75rem, 2vw, 1.9rem); }
/* A neon-lime stroke is 1.17:1 on white — as a hairline it disappears. So the
   key lime becomes the disc and the icon is knocked out of it: same colour,
   actually legible, and it matches how lime is used everywhere else (fills,
   pills, highlights) rather than as a line. */
.pillar-ico {
  display: grid; place-items: center;
  width: 68px; height: 68px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--on-accent);
  margin-bottom: 1.15rem;
}
.pillar-ico svg {
  width: 34px; height: 34px;
  fill: none; stroke: currentColor; stroke-width: 1.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.pillar h3 {
  font-size: clamp(1.05rem, 1.7vw, 1.3rem);
  font-weight: 700; line-height: 1.2; letter-spacing: -0.015em;
}
.pillar p { color: var(--text-muted); font-size: 0.94rem; line-height: 1.55; }

/* the number, sized to be read from across a room */
/* figure cards sit tighter than text cards, and the number is the thing
   that lights up on hover */
.pillar:has(.pillar-fig) { gap: 0.3rem; }
.pillar:has(.pillar-fig) h3 { margin-top: 0.15rem; }
.pillar-fig { transition: color 0.3s var(--ease); }
.pillar:hover .pillar-fig { color: var(--text); }
.pillars:has(.pillar-fig) { gap: clamp(1.25rem, 3vw, 2.25rem); }
.cs-section > .pillars:has(.pillar-fig) { margin-top: clamp(0.5rem, 1.5vw, 1.25rem); }
.pillar-fig {
  /* Third pass on this: a row of six numbers does not need any of them to be
     a billboard. The label under it has to stay readable next to it. */
  font-size: clamp(1.45rem, 2.4vw, 1.95rem);
  font-weight: 700; line-height: 1; letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;          /* "28 min" must not break, or the row misaligns */
  margin-bottom: 0.15rem;
}
/* the unit rides smaller so the numeral is what carries, and every figure in
   the row keeps the same cap height and the same baseline */
.pillar-fig i {
  font-style: normal;
  font-size: 0.46em;
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-left: 0.12em;
}

/* one item promoted out of the row — the thing to read first */
/* context and ask as full-width lines rather than two narrow columns, so the
   text stops wrapping every four words */
/* Cards that introduce the slider below them. Without this they sit almost on
   top of it and read as one crowded block. */
.pillars.ba-lead { margin-bottom: clamp(2.25rem, 4.5vw, 3.5rem); }
.pillars.is-stacked { grid-template-columns: 1fr; gap: clamp(1.1rem, 2.2vw, 1.6rem); }
.pillars.is-stacked .pillar { grid-template-columns: minmax(120px, 0.5fr) minmax(0, 3fr); display: grid; gap: 0.35rem 2rem; align-items: baseline; }
.pillars.is-stacked .pillar h3 { font-size: var(--t-base); }
.pillars.is-stacked .pillar p { max-width: 74ch; }
.pillars.is-stacked .pillar.is-lead { display: grid; grid-template-columns: 1fr; }
/* the stacked-row rule above outranks .pillar.is-lead h3 on specificity, so the
   lead has to restate its own size here or it silently drops to body text */
.pillars.is-stacked .pillar.is-lead h3 {
  font-size: clamp(1.2rem, 2.9vw, 2.35rem);
  line-height: 1.06; letter-spacing: -0.035em;
  max-width: 22ch; text-wrap: balance;
}
.pillars.is-stacked .pillar.is-lead p { font-size: clamp(1rem, 1.5vw, 1.15rem); }

.pillar.is-lead {
  grid-column: 1 / -1;
  gap: 0.6rem;
  padding-bottom: clamp(1rem, 2vw, 1.5rem);
  border-bottom: 1px solid var(--line);
}
.pillar.is-lead h3 {
  font-size: clamp(1.2rem, 2.9vw, 2.35rem);
  line-height: 1.06; letter-spacing: -0.035em;
  max-width: 22ch;
  text-wrap: balance;
}
.pillar.is-lead p {
  font-size: clamp(1rem, 1.5vw, 1.15rem);
  line-height: 1.55; color: var(--text-muted); max-width: 62ch;
}

@media (max-width: 820px) {
  .pillars { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .pillars { grid-template-columns: 1fr; gap: 1.75rem; }
}

.pillars-media { margin-top: 0.5rem; }
.pillars-media .media-slot img { width: 100%; height: 100%; object-fit: contain; background: var(--bg); }

/* ---- cohort comparison -------------------------------------------------- */
.cohorts {
  display: grid;
  border-top: 1px solid var(--line-strong);
}
.co-head, .co-row {
  display: grid;
  grid-template-columns: minmax(105px, 0.8fr) repeat(var(--n, 3), minmax(0, 1fr));
  gap: clamp(0.75rem, 2vw, 1.75rem);
  padding-block: 0.85rem;
  border-bottom: 1px solid var(--line);
}
.cohorts[data-n="2"] { --n: 2; }
.cohorts[data-n="4"] { --n: 4; }
.co-head { border-bottom-color: var(--line-strong); }
.co-name {
  font-size: var(--t-base); font-weight: 700; letter-spacing: -0.01em;
}
.co-key, .co-val {
  font-size: 0.88rem; line-height: 1.45;
}
.co-key {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.7rem;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint);
  align-self: start; padding-top: 0.15rem;
}
.co-val { color: var(--text-muted); }
/* the row worth reading across — the number that shows the gap */
.co-row.is-lead .co-val {
  font-size: clamp(1.25rem, 2.2vw, 1.7rem);
  font-weight: 700; line-height: 1.1; letter-spacing: -0.025em;
  color: var(--text); font-variant-numeric: tabular-nums;
}
@media (max-width: 720px) {
  .co-head { display: none; }
  .co-row { grid-template-columns: 1fr; gap: 0.25rem; padding-block: 1rem; }
  .co-val::before {
    content: attr(data-co) " ";
    font-family: var(--font-mono); font-size: 0.68rem;
    letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint);
  }
}

/* ---- 2x2 --------------------------------------------------------------- */
.matrix {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-areas: "tl tr" "bl br";
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
}
.mq { background: var(--bg); padding: clamp(1rem, 2.5vw, 1.75rem); min-height: 150px; }
.mq-tl { grid-area: tl; } .mq-tr { grid-area: tr; }
.mq-bl { grid-area: bl; } .mq-br { grid-area: br; }
.mq-name {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.7rem;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint);
}
.mq ul { list-style: none; margin: 0.6rem 0 0; padding: 0; display: grid; gap: 0.3rem; }
.mq li { font-weight: 500; }
.mq-tl li::before, .mq-tr li::before { content: "● "; color: var(--accent-ink); font-size: 0.7em; }
.mq-bl li::before, .mq-br li::before { content: "○ "; color: var(--text-faint); font-size: 0.7em; }

.matrix .ax {
  position: absolute;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.68rem;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint);
  background: var(--bg); padding: 0 0.5rem; white-space: nowrap;
}
.ax-y  { top: -0.6em; left: 50%; transform: translateX(-50%); }
.ax-y2 { bottom: -0.6em; left: 50%; transform: translateX(-50%); }
.ax-x  { left: -0.5rem; top: 50%; transform: translate(-100%, -50%); }
.ax-x2 { right: -0.5rem; top: 50%; transform: translate(100%, -50%); }
@media (max-width: 700px) {
  .ax-x, .ax-x2 { position: static; transform: none; display: none; }
}

/* ---- tension curve ----------------------------------------------------- */
.tension {
  display: grid;
  grid-template-columns: repeat(var(--n), minmax(0, 1fr));
  align-items: end;
  gap: 2px;
  height: clamp(140px, 20vw, 200px);
  border-bottom: 1px solid var(--line-strong);
}
.tstep { display: grid; align-content: end; justify-items: center; height: 100%; gap: 0; }
.tbar {
  width: 100%;
  height: var(--h);
  background: var(--line);
  border-radius: 2px 2px 0 0;
  transition: background-color 0.3s var(--ease);
}
.tstep.is-focus .tbar { background: var(--accent); }
.tlabel {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.58rem;
  letter-spacing: 0.02em; color: var(--text-faint);
  writing-mode: vertical-rl; text-orientation: mixed;
  margin-top: 0.5rem; max-height: 8.5em; overflow: hidden;
}
.tstep.is-focus .tlabel { color: var(--text); }
.tension-key {
  display: flex; gap: 1.25rem; margin-top: 4rem;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.7rem;
  letter-spacing: 0.06em; color: var(--text-faint);
}
.tension-key span { display: inline-flex; align-items: center; gap: 0.4rem; }
.tension-key i { width: 12px; height: 8px; border-radius: 2px; display: inline-block; }
.k-bar { background: var(--line); }
.k-focus { background: var(--accent); }

/* =========================================================================
   BACK LINK — on every page but home
   ========================================================================= */
.back-link {
  display: inline-flex; align-items: center; gap: 0.3rem;
  margin-top: calc(var(--nav-h) + clamp(1rem, 3vw, 1.75rem));
  font-family: var(--font-mono); font-weight: 500;
  font-size: var(--t-label); letter-spacing: 0.06em;
  color: var(--text-faint);
  transition: color 0.3s var(--ease), gap 0.3s var(--ease);
}
.back-link svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* the page head already clears the fixed nav; the back link is doing it now */
.back-link + * .page-head, .wrap:has(> .back-link) + .page-head { padding-top: clamp(1rem, 3vw, 2rem); }

/* =========================================================================
   ABOUT — portrait, and the journey as a horizontal track
   ========================================================================= */
.page-head:has(.about-head) { padding-bottom: clamp(1.1rem, 2.2vw, 1.6rem); }
.about-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
  gap: clamp(1.5rem, 5vw, 4.5rem);
  align-items: center;
}
/* Sized off the viewport, not the content: tall enough to carry the page and
   short enough that the next section shows below the fold. */
/* Square, because the drawing is square. It used to be a tall 63vh box with
   object-fit:cover, which was right for a photograph and wrong for line art \u2014
   it cropped the top of the hair and the shoulders straight off. */
.portrait {
  margin: 0;
  aspect-ratio: 1;
  height: auto;
  max-height: 540px;
  display: grid;
  place-items: center;
}
.portrait img {
  width: 100%; height: 100%;
  object-fit: contain;
  /* black line art on a white ground: multiply drops the paper so the drawing
     sits on the dot grid instead of punching a white hole through it */
  mix-blend-mode: multiply;
}
/* the dashed slot keeps its own box when there is no file yet */
.portrait:has(.portrait-ph) { aspect-ratio: 4 / 5; }
.portrait-ph {
  display: grid; place-items: center; width: 100%; height: 100%;
  border: 1px solid var(--line); border-radius: 10px;
  padding: 1rem; text-align: center; text-wrap: balance;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.7rem;
  letter-spacing: 0.06em; color: var(--text-faint);
}
.portrait-ph em { font-style: normal; color: var(--text-muted); }

/* How I got here — a vertical rail. As a grid of six cards the dates had
   nowhere to live and the order stopped being obvious; read down a rail, the
   route is the shape. Images came out as six empty boxes, so they are gone. */
.jrail {
  --col: clamp(58px, 8vw, 92px);   /* the date gutter */
  --gut: clamp(1.25rem, 3vw, 2.25rem);
  list-style: none; margin: 0; padding: 0;
}
.jstop {
  position: relative;
  display: grid;
  grid-template-columns: var(--col) minmax(0, 1fr);
  column-gap: var(--gut);
  padding-bottom: clamp(1.6rem, 3.2vw, 2.6rem);
}
/* drawn per stop so the line stops at the last dot instead of running on */
.jstop::before {
  content: ""; position: absolute;
  top: 0.75rem; bottom: 0;
  left: calc(var(--col) + var(--gut) / 2);
  width: 1px; background: var(--line);
}
.jstop:last-child { padding-bottom: 0; }
.jstop:last-child::before { display: none; }
.jdot {
  position: absolute; top: 0.42rem;
  left: calc(var(--col) + var(--gut) / 2 - 4.5px);
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px var(--bg);
  transition: transform 0.4s var(--ease);
}
.jstop:hover .jdot { transform: scale(1.35); }
.jwhen {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem;
  letter-spacing: 0.06em; color: var(--text-faint);
  padding-top: 0.2rem; text-align: right;
}
.jbody { display: grid; gap: 0.3rem; }
.jbody h3 { font-size: var(--t-base); font-weight: 700; letter-spacing: -0.01em; }
.jbody p { color: var(--text-muted); font-size: 0.95rem; line-height: 1.6; max-width: 56ch; text-wrap: pretty; }

/* =========================================================================
   WHAT SETS ME APART — the line is the content
   As a four-up grid of numbered cells the titles were the same size as the
   body and read as a list of features. Set large, down the page, they are
   the thing you actually take away.
   ========================================================================= */
.apart { list-style: none; margin: 0; padding: 0; display: grid; gap: clamp(1.1rem, 2.2vw, 1.7rem); }
.apart-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(0.4rem, 3vw, 3rem);
  align-items: start;
  /* A rule per row. On the facets these read as an unfinished table, but here
     the rows are long and unequal and the line is what separates one claim
     from the next. */
  border-top: 1px solid var(--line);
  padding-top: clamp(0.9rem, 1.9vw, 1.35rem);
}
/* 24px against the section heading's 30px and the body's 16px. At 32px these
   were larger than the h2 above them and the section read as four headings
   with no owner. */
.apart-line {
  font-size: clamp(1.15rem, 1.95vw, 1.5rem);
  font-weight: 700; line-height: 1.2; letter-spacing: -0.02em;
  text-wrap: balance;
}
.apart-row p { color: var(--text-muted); font-size: 1rem; line-height: 1.65; text-wrap: pretty; padding-top: 0.15rem; }
@media (max-width: 720px) {
  .apart-row { grid-template-columns: 1fr; gap: 0.5rem; }
  .apart-row p { padding-top: 0; }
}
@media (max-width: 520px) {
  .jrail { --col: 0px; --gut: 1.4rem; }
  .jstop { grid-template-columns: 1fr; padding-left: 1.4rem; }
  .jstop::before { left: 3.5px; }
  .jdot { left: -1px; }
  .jwhen { text-align: left; padding-top: 0; margin-bottom: 0.2rem; }
}

@media (max-width: 860px) {
  .about-head { grid-template-columns: 1fr; }
  /* full-width on mobile — the 190px cap was for the old left-hand column */
  .portrait { height: auto; aspect-ratio: 1; max-height: none; max-width: none; }
  .portrait:has(.portrait-ph) { aspect-ratio: 4 / 5; }
}
@media (max-width: 520px) {
}

/* =========================================================================
   ABOUT STATEMENT + PHOTO RAIL
   Same two-tone trick as the hero: a black sentence and a grey one. Then the
   rail, which is the only thing on the site that moves on its own.
   ========================================================================= */
.about-statement {
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
  font-size: clamp(1.25rem, 2.1vw, 1.7rem);
  font-weight: 700;
  line-height: 1.55;
  letter-spacing: -0.012em;
  max-width: 46ch;
}
.about-statement .outside { color: var(--text-faint); }

/* The two grey lines under the statement. They were sitting right on top of it
   — this is the gap that makes the block read as statement-then-footnote
   rather than one run-on paragraph. */
.about-past {
  margin-top: clamp(2.25rem, 5vw, 3.5rem);
  display: grid;
  gap: 0.9rem;
  max-width: 60ch;
}
.about-past p {
  font-size: 1rem;
  line-height: 1.65;
  color: var(--text-muted);
}

/* the company, set into the sentence */
.chip {
  display: inline-flex; align-items: center; gap: 0.35em;
  padding: 0.12em 0.55em;
  margin-inline: 0.05em;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--on-accent);
  white-space: nowrap;
}
.chip img { height: 0.9em; width: auto; border-radius: 2px; }

/* ---- the rail ---------------------------------------------------------- */
.rail {
  /* Well clear of the paragraph above. The tilt and the drop lift the tallest
     tiles ~14px past the top of the track, so the gap has to cover that plus
     ordinary section spacing before it stops crowding the copy. */
  /* The tilt and the drop push tiles past the track's box, so it is padded to
     stop them being sheared off by the overflow clip. That padding is then
     pulled back out of the margins so the section rhythm is unchanged.

     Both values go in ONE property. Written as `margin-top` plus a later
     `margin-block`, the shorthand silently overwrote the margin-top and the
     rail stayed jammed against the paragraph no matter what it was set to. */
  padding-block: 26px;
  margin-top: calc(clamp(5rem, 10vw, 8rem) - 26px);
  margin-bottom: calc(clamp(2rem, 4vw, 3rem) - 26px);
  overflow: hidden;
  /* full-bleed: the rail should run off both edges, not sit inside the wrap */
  width: 100vw;
  margin-inline: calc(50% - 50vw);
}
.rail-track {
  align-items: center;
  --rail-gap: clamp(0.6rem, 1.2vw, 1rem);
  display: flex;
  gap: var(--rail-gap);
  width: max-content;
  animation: rail-run 70s linear infinite;
}
.rail-copy { display: contents; }
.rail:hover .rail-track,
.rail:focus-within .rail-track { animation-play-state: paused; }

/* half the track, plus half a gap — otherwise the seam drifts by a gap each loop */
@keyframes rail-run {
  to { transform: translateX(calc(-50% - var(--rail-gap) / 2)); }
}

.rail-item {
  position: relative;
  flex: 0 0 auto;
  height: clamp(190px, 22vw, 290px);
  aspect-ratio: var(--ratio);
  margin: 0;
  border-radius: 10px;
  overflow: hidden;
  background: var(--surface-2);
  transform: translateY(var(--drop, 0)) rotate(var(--tilt, 0));
  transition: transform 0.5s var(--ease), box-shadow 0.5s var(--ease);
}
/* Touch the rail and the whole thing tidies itself: every tile straightens
   and lines up, and the marquee stops so you can actually look. Take the
   cursor away and it goes back to being a pile of photographs. */
.rail:hover .rail-item,
.rail:focus-within .rail-item {
  transform: translateY(0) rotate(0deg);
}
/* The one under the cursor rises by exactly one square of the dot grid —
   28px, the same pitch the background is drawn on — so the movement lands on
   the page's own rhythm instead of being an arbitrary nudge. */
.rail-item:hover {
  transform: translateY(calc(var(--grid-pitch) * -1)) rotate(0deg) !important;
  box-shadow: 0 16px 34px rgb(0 0 0 / 0.14);
  z-index: 2;
}

/* what the photograph is, on hover */
.rail-cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 1.6rem 0.85rem 0.7rem;
  font-family: var(--font-mono); font-weight: 500;
  font-size: 0.68rem; letter-spacing: 0.05em;
  line-height: 1.35; color: #fff;
  text-wrap: pretty;
  background: linear-gradient(transparent, rgb(0 0 0 / 0.72));
  opacity: 0; translate: 0 6px;
  transition: opacity 0.35s var(--ease), translate 0.35s var(--ease);
  pointer-events: none;
}
.rail-item:hover .rail-cap { opacity: 1; translate: 0 0; }
.rail-item img { width: 100%; height: 100%; object-fit: cover; }

/* until there are photographs, say what belongs in the gap */
.rail-ph {
  display: grid; place-items: center;
  width: 100%; height: 100%;
  padding: 1rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  font-family: var(--font-mono); font-weight: 500;
  font-size: 0.7rem; letter-spacing: 0.06em;
  color: var(--text-faint); text-align: center;
  text-wrap: balance;
}

@media (prefers-reduced-motion: reduce) {
  .rail { overflow-x: auto; }
  .rail-track { animation: none; }
}

/* =========================================================================
   WORK INDEX — grouped by where it happened
   ========================================================================= */
/* Company on the left, what happened there on the right, and the outcome set
   large at the end of each row. Rules sit under the project rows only — a rule
   spanning both columns turns two columns into one table and the company name
   stops reading as a heading. */
/* the career track on the home page */
.career { display: grid; position: relative; }
.career-stop {
  --stop-pad: clamp(1rem, 2vw, 1.5rem);
  display: grid;
  grid-template-columns: var(--col-a) var(--col-b);
  gap: var(--col-gap);
  padding-block: var(--stop-pad);
  position: relative;
}
.career-stop:first-child { padding-top: 0.25rem; }
/* one continuous rule down the left, with a dot per employer: each stop
   draws its own segment from its dot down through the gap to the next dot */
.career-when { position: relative; display: flex; align-items: flex-start; gap: 0.75rem; padding-left: 1.25rem; align-self: stretch; }
.career-when::before {
  content: ""; position: absolute; left: 4px; top: 0.55em; bottom: calc(-1 * var(--stop-pad) * 2 - 0.5em);
  width: 1px; background: var(--line-strong);
}
.career-stop:last-child .career-when::before { display: none; }
.career-dot {
  position: absolute; left: 0; top: 0.42em;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--accent); box-shadow: 0 0 0 3px var(--bg);
}
.career-when .yrs { font-family: var(--font-mono); font-weight: 500; font-size: var(--t-label); letter-spacing: 0.08em; color: var(--text-faint); white-space: nowrap; }
.career-body { display: grid; gap: 0.45rem; min-width: 0; }
.career-head { display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap; }
.career-head .org-logo { margin: 0; }
.career-role { font-weight: 600; font-size: var(--t-base); letter-spacing: -0.005em; }
.career-line { color: var(--text-muted); font-size: 0.95rem; line-height: 1.55; max-width: 62ch; text-wrap: pretty; }
.career-body .work-list { margin-top: 0.35rem; }
.career .work-item { align-items: start; }
.career .work-copy { display: grid; gap: 0.2rem; min-width: 0; }
.career .work-item .blurb { color: var(--text-muted); font-size: 0.9rem; line-height: 1.5; text-wrap: pretty; }
.career .work-item .work-meta { padding-top: 0.3rem; }
/* the spotlight: hover one study and every other row on the track steps
   back, so the one under the cursor is the only thing lit */
.career .work-item { transition: opacity 0.3s var(--ease), border-color 0.35s var(--ease); }
.career .work-item.is-muted:hover { opacity: 1; }
.career-body .work-item:first-child { padding-top: clamp(0.7rem, 1.4vw, 0.95rem); border-top: 1px solid var(--line); }
@media (max-width: 760px) {
  .career-stop { grid-template-columns: 1fr; gap: 0.6rem; }
  .career-when::before { display: none; }
}

/* Glance: the employer in the left column, and its studies stacked on the
   right, one wide row each. No boxes; a hairline between rows, the screen
   on the left of each and the words on the right. */
.feat-stack { display: grid; gap: clamp(2.5rem, 5vw, 4rem); }
.career-feature {
  display: grid; grid-template-columns: var(--col-a) var(--col-b); gap: var(--col-gap);
  align-items: start;
}
.feat-org { display: grid; gap: 0.4rem; justify-items: start; position: sticky; top: 90px; }
.feat-org .org-logo { margin: 0; }
.feat-org .yrs { font-family: var(--font-mono); font-weight: 500; font-size: var(--t-label); letter-spacing: 0.08em; color: var(--text-faint); }
.feat-list { display: grid; }
.feat-card {
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); gap: clamp(1rem, 2.5vw, 2rem);
  align-items: center; padding-block: clamp(1.1rem, 2vw, 1.5rem);
  color: inherit; text-decoration: none;
  transition: opacity 0.3s var(--ease);
}
.feat-card:first-child { padding-top: 0; }
.feat-thumb {
  position: relative; aspect-ratio: 1440 / 836; border-radius: 14px; overflow: hidden;
  background: var(--surface);
  box-shadow: 0 1px 2px rgba(10, 13, 16, 0.05), 0 12px 32px -12px rgba(10, 13, 16, 0.18);
  transition: box-shadow 0.35s var(--ease);
}
.feat-card:hover .feat-thumb { box-shadow: 0 1px 2px rgba(10, 13, 16, 0.06), 0 22px 44px -16px rgba(10, 13, 16, 0.26); }
/* the older studies have no picture, so the row says what it is */
.prev-item .read { font-family: var(--font-mono); font-weight: 500; font-size: 0.68rem; letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-faint); margin-left: 0.5rem; white-space: nowrap; }
.feat-thumb img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  transition: transform 0.6s var(--ease);
}
/* the Healthify export is two phones on a transparent ground, so it sits
   whole in the frame rather than being cropped to it */
.feat-thumb img[src$=".png"] { object-fit: contain; padding: 4%; box-sizing: border-box; }
.feat-card:hover .feat-thumb img { transform: scale(1.03); }
.feat-body { display: grid; gap: 0.5rem; align-content: center; min-width: 0; }
.feat-body h3 { font-size: clamp(1.15rem, 1.6vw, 1.4rem); font-weight: 600; letter-spacing: -0.014em; line-height: 1.25; transition: color 0.3s var(--ease); }
/* the arrow arrives on hover, after the title, and that is the whole cue:
   nothing else on the list changes */
.feat-body h3 .arw {
  display: inline-block; margin-left: 0.35em; color: var(--text);
  opacity: 0; transform: translateX(-6px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}
.feat-card:hover h3 .arw { opacity: 1; transform: translateX(0); }
.feat-body h3 .ttl-tag { vertical-align: 0.2em; }
.feat-body .blurb { color: var(--text-muted); font-size: 0.95rem; line-height: 1.55; text-wrap: pretty; }
.feat-body .chips { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.25rem; }
.feat-body .chip {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.68rem; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 0.3rem 0.65rem; border-radius: 999px; border: 0; background: var(--surface-2); color: var(--text);
  margin: 0; white-space: nowrap;
}

.feat-card:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 4px; border-radius: 6px; }
@media (max-width: 760px) {
  .career-feature { grid-template-columns: 1fr; gap: 1rem; }
  .feat-org { position: static; }
  .feat-card { grid-template-columns: 1fr; gap: 0.8rem; }
}

/* Everyone else: one strip, the mark and years on the left of each stop,
   the studies by name on the right. Deliberately no thumbnails. */
.prev-label { margin-top: clamp(2rem, 4vw, 3rem); }
.prev { display: grid; gap: 0; margin-top: 0.25rem; }
.prev-stop { /* the first rule sits right under the label */
  display: grid; grid-template-columns: var(--col-a) var(--col-b); gap: var(--col-gap);
  align-items: start; padding-block: clamp(0.9rem, 1.6vw, 1.2rem);
}
.prev-org { display: grid; gap: 0.35rem; justify-items: start; }
.prev-org .org-logo { margin: 0; }
.prev-org .yrs { font-family: var(--font-mono); font-weight: 500; font-size: var(--t-label); letter-spacing: 0.08em; color: var(--text-faint); white-space: nowrap; }
.prev-list { list-style: none; margin: 0; padding: 0; display: grid; justify-items: start; }
.prev-item {
  display: inline-flex; align-items: baseline; gap: 0.6rem;
  padding-block: 0.45rem; color: inherit; text-decoration: none;
  transition: opacity 0.3s var(--ease);
}
.prev-item .ttl {
  font-weight: 600; font-size: clamp(1.05rem, 1.4vw, 1.25rem); letter-spacing: -0.012em;
  transition: color 0.3s var(--ease);
}
/* same cue as the Glance rows: the title goes lime and the arrow slides in */
.prev-item .arw {
  color: var(--text); opacity: 0; transform: translateX(-6px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}
.prev-item:hover .arw { opacity: 1; transform: translateX(0); }
.prev-item.is-muted { color: var(--text-muted); }
.prev-item.is-muted .ttl { font-weight: 500; }
.prev-note { font-size: 0.95rem; line-height: 1.55; color: var(--text-muted); max-width: 56ch; text-wrap: pretty; margin: 0; padding-block: 0.4rem; }
@media (max-width: 760px) { .prev-stop { grid-template-columns: 1fr; gap: 0.5rem; } }

.work-index { display: grid; }

.work-group {
  display: grid;
  grid-template-columns: var(--col-a) var(--col-b);
  gap: var(--col-gap);
  /* Groups sat ~128px apart, which read as four separate lists rather than one
     career. Tightened so the run scans as a single column while the org column
     still has room to breathe. */
  padding-block: clamp(1.1rem, 2vw, 1.6rem);
}
.work-group:first-child { padding-top: 0; }

.work-org { display: grid; gap: 0.3rem; align-content: start; }
.work-org h3 { font-size: var(--t-base); font-weight: 700; letter-spacing: 0; }
.work-org .yrs {
  font-family: var(--font-mono); font-weight: 500;
  font-size: var(--t-label); color: var(--text-faint);
}
.work-org .role { font-size: 0.86rem; line-height: 1.5; color: var(--text-faint); margin-top: 0.35rem; }

.work-list { display: grid; align-content: start; }
/* A role with no case study behind it. Same two-column rhythm as the rest of
   the index so it reads as part of the list, not an afterthought pinned on. */
.past-note {
  font-size: 0.95rem; line-height: 1.6; color: var(--text-muted);
  max-width: 56ch; text-wrap: pretty; margin: 0;
  padding-block: clamp(0.6rem, 1.4vw, 1rem);
}

/* The case-studies page: a grid of contained cards rather than rows grouped
   by employer. Three across on a wide screen, two on a laptop, one on a
   phone. Each card is one rounded panel: the screen at the top, then the
   title, what the study is about, and its tags, all inside the same edge.
   The employer is on the study itself; roles with no study are left off. */
.work-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.75rem, 3vw, 2.5rem);
}
.work-card {
  display: grid; grid-template-rows: auto 1fr; align-content: start;
  color: inherit; text-decoration: none;
  background: var(--bg);
  border: 0; border-radius: 18px;
  /* lifted off the page by a shadow rather than drawn on it with a stroke */
  box-shadow: 0 1px 2px rgba(10, 13, 16, 0.05), 0 12px 32px -12px rgba(10, 13, 16, 0.16);
  overflow: hidden;
  transition: border-color 0.35s var(--ease), transform 0.35s var(--ease), box-shadow 0.35s var(--ease);
}
.work-card-thumb {
  position: relative;
  aspect-ratio: 1440 / 836;
  background: var(--surface-2);
  border-bottom: 0;
  display: grid; place-items: center; padding: 0.55rem;
  overflow: hidden;
}
/* Pinned to the box, not flowed in it: a portrait export's intrinsic height
   otherwise beats the aspect ratio and the box grows to fit the picture. */
.work-card-thumb img {
  position: absolute; inset: 0.55rem;
  width: calc(100% - 1.1rem); height: calc(100% - 1.1rem);
  object-fit: contain; border-radius: 10px;
  transition: filter 0.4s var(--ease), transform 0.4s var(--ease);
}
.work-card-thumb .work-thumb-ph { font-size: 0.62rem; }
.work-card-body { display: grid; gap: 0.55rem; align-content: start; padding: 1.15rem 1.4rem 1.35rem; }
.work-card h3 { font-size: clamp(1.1rem, 1.5vw, 1.3rem); font-weight: 600; letter-spacing: -0.014em; line-height: 1.3; transition: color 0.3s var(--ease); }
.work-card h3 .ttl-tag { vertical-align: 0.2em; }
.work-card .work-meta { margin-top: 0.1rem; }
.work-card h3 .arw {
  display: inline-block; margin-left: 0.35em; color: var(--text);
  opacity: 0; transform: translateX(-6px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}
.work-card:hover h3 .arw { opacity: 1; transform: translateX(0); }
.work-card:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 4px; }
/* The parked study looks like every other card; the pill says "not yet".
   A glimpse of the product is worth more than a blur telling you it exists. */
.work-card.is-muted { cursor: default; }
.work-card.is-muted:hover h3 { color: inherit; }
@media (max-width: 640px)  { .work-grid { grid-template-columns: 1fr; } }

.work-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  /* Title, tags, arrow on one baseline. The tags sit right-aligned so they
     line up down the list and the eye can compare what kind of work each
     row is without reading every title. */
  align-items: baseline;
  gap: 0.35rem clamp(1rem, 2vw, 1.75rem);
  padding-block: clamp(0.7rem, 1.4vw, 0.95rem);
  border-bottom: 1px solid var(--line);
  transition: border-color 0.35s var(--ease);
}
/* the tags sit on the right and stay on one line; a status pill joins them
   there rather than hanging off the title, so titles stay clean to scan */
.work-item .work-meta { justify-content: flex-end; text-align: right; align-items: baseline; max-width: 30ch; }
.work-item .work-meta .ttl-tag { margin-left: 0.35rem; white-space: nowrap; }
@media (max-width: 640px) {
  .work-item { grid-template-columns: minmax(0, 1fr) auto; }
  .work-item .work-meta { grid-column: 1; justify-content: flex-start; text-align: left; white-space: normal; }
  .work-item .arw { grid-row: 1; grid-column: 2; }
}
.work-item:first-child { padding-top: 0; }
.work-item:hover { border-color: var(--line-strong); }

/* A parked study. Still a link, still in the tab order, but it declines every
   affordance the other rows have: greyed copy, a washed-out thumbnail, no hover
   colour, no arrow, an arrow cursor. Somebody who tries it gets in; nobody is
   invited to. */
.work-item.is-muted { cursor: default; }
.work-item.is-muted .ttl,
.work-item.is-muted .work-meta { color: var(--text-faint); }
.work-item.is-muted:hover { border-color: var(--line); }
.work-item.is-muted:hover .ttl { color: var(--text-faint); font-weight: 600; }
.work-item.is-muted .ttl-tag,
.work-item.is-muted:hover .ttl-tag { background: var(--surface); color: var(--text-faint); border: 1px solid var(--line); }
.work-item.is-muted .work-thumb { opacity: 0.55; filter: grayscale(1); border-color: var(--line); }
.work-item.is-muted .arw,
.work-item.is-muted:hover .arw { opacity: 0; }
.work-item.is-muted:focus-visible { outline: 2px solid var(--text-faint); outline-offset: 3px; }

/* the thumbnail. Small on purpose: a real screen reads as a preview and an
   empty one reads as a quiet placeholder rather than a hole in the page. */
.work-thumb {
  /* Was 76-104px, which at arm's length read as a swatch rather than a
     picture. Big enough now that the subject is legible without opening the
     study, still short enough that the title stays the loudest thing in the row.
     The ceiling matters: the page stops widening at --wrap (1180px), so a vw
     that kept growing past that took its extra width straight out of the
     title and started wrapping it. */
  width: clamp(132px, 14vw, 176px);
  /* The screens are 1440x836 exports, so the tile is that shape and the
     image is contained in it: a 4:3 tile with cover was cutting the sides
     off every thumbnail. A portrait export sits inside the same tile on the
     surface colour rather than being cropped to fit. */
  aspect-ratio: 1440 / 836;
  border: 1px solid var(--line);
  border-radius: 5px;
  overflow: hidden;
  background: var(--surface);
  display: grid; place-items: center;
  padding: 0.3rem; text-align: center;
}
.work-thumb { position: relative; }
.work-thumb img { position: absolute; inset: 0.3rem; width: calc(100% - 0.6rem); height: calc(100% - 0.6rem); object-fit: contain; }
.work-thumb-ph {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.56rem;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--text-faint);
  line-height: 1.25;
  /* The tile clips, so a long label used to be cut mid-word with no sign it
     had been. Ellipsise instead. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4;
  overflow: hidden;
}

/* The title is what someone is actually scanning for, so it outranks the
   body copy it used to match. */
.work-item .ttl {
  font-size: clamp(1.05rem, 1.35vw, 1.2rem);
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.01em;
  transition: color 0.3s var(--ease);
}
.work-item:hover .ttl { color: var(--accent-ink); }
.ttl-tag {
  display: inline-block;
  margin-left: 0.55rem;
  vertical-align: 0.1em;
  padding: 0.1rem 0.45rem;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-mono); font-weight: 700; font-size: 0.6rem;
  letter-spacing: 0.1em; text-transform: uppercase;
}
.work-item:hover .ttl-tag { color: var(--on-accent); }

.work-meta {
  display: flex; flex-wrap: wrap; gap: 0.25rem 0.7rem;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.66rem;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--text-faint);
}

.work-item .arw {
  color: var(--text-faint);
  opacity: 0; transform: translateX(-4px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease), color 0.3s var(--ease);
}
.work-item:hover .arw { opacity: 1; transform: none; color: var(--accent-ink); }


@media (max-width: 760px) {
  .work-group { grid-template-columns: 1fr; gap: 1.9rem; }
  .work-org .role { display: none; }
  .work-item { column-gap: 1.25rem; }
  .work-item .arw { opacity: 1; transform: none; }
}

/* =========================================================================
   INTRO PANEL — doodle sheet + short copy (home "Who is Anmol?" block)
   ========================================================================= */
.intro {
  padding-top: clamp(3.5rem, 8vw, 7rem);
  max-width: 46ch;
}
.intro-copy { display: grid; gap: 1rem; justify-items: start; }
.intro-copy h2 {
  font-family: var(--font-mono);
  font-size: clamp(1.35rem, 2.4vw, 1.9rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}
.intro-copy p { color: var(--text-muted); max-width: 32ch; }
.intro-links { display: flex; flex-wrap: wrap; gap: 0.5rem 1.75rem; margin-top: 0.35rem; }
.intro-link {
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-weight: 500;
  border-bottom: 1.5px solid currentColor;
  padding-bottom: 3px;
  transition: color 0.3s var(--ease);
}
.intro-link svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; transition: transform 0.4s var(--ease); }
.intro-link:hover svg { transform: translate(3px, -3px); }

/* =========================================================================
   ABOUT PAGE — long-form blocks
   ========================================================================= */
.definition {
  font-family: var(--font-mono); font-weight: 500;
  font-size: 0.85rem;
  color: var(--text-faint);
  line-height: 1.7;
  border-left: 2px solid var(--accent-ink);
  padding-left: 1rem;
  max-width: 46ch;
}
/* The meaning of the name is the most interesting thing in this block and it
   was set in the same weight as the part of speech. Marker, not colour: lime
   text on white is 1.4:1, lime behind near-black text is 16:1. */
.definition b {
  color: var(--text); font-weight: 700;
  background: linear-gradient(transparent 56%, var(--accent) 56%, var(--accent) 95%, transparent 95%);
  padding: 0 0.14em;
}
.hl {
  font-weight: 600; padding: 0 0.14em;
  background: linear-gradient(transparent 58%, var(--accent) 58%, var(--accent) 95%, transparent 95%);
}
.about-badge { margin-top: 0.7rem; }
.about-intro { display: grid; gap: 0.72rem; margin-top: 1.15rem; max-width: 62ch; }
.about-intro p { font-size: clamp(0.97rem, 1.3vw, 1.04rem); line-height: 1.6; color: var(--text-muted); text-wrap: pretty; }
.about-intro p b { color: var(--text); font-weight: 600; }
.about-intro p:first-child { color: var(--text); }
.definition i { font-style: italic; }

/* facet cards — Designer / Runner / Writer / Home brewer */
/* One row of four, not a two-by-two block. Four short things read as a list
   of who somebody is; four paragraphs in a grid read as homework. */
.facets { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); column-gap: clamp(1.25rem, 2.6vw, 2.25rem); row-gap: clamp(1.75rem, 3.5vw, 2.75rem); }
.facets .facet p { font-size: 0.92rem; line-height: 1.55; }
@media (max-width: 900px) { .facets { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 460px) { .facets { grid-template-columns: 1fr; } }
/* No rule above each card. Hairlines over a grid of four read as a table
   someone forgot to finish. */
.facet { display: grid; gap: 0.6rem; align-content: start; }
/* A photograph, not a pictogram. A line drawing of a mountain says the word
   "mountain"; a picture of one says something about the person. */
.facet-shot {
  /* Contained rather than cropped: the whole frame is the point. The box
     matches the images so contain wastes nothing — change both together if
     the source ratio ever changes. */
  aspect-ratio: 1 / 1;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--surface);
  display: grid; place-items: center;
  margin-bottom: 0.4rem;
}
.facet-shot img {
  width: 100%; height: 100%;
  object-fit: contain;
  border-radius: var(--r-lg);
  display: block;
}
.facet-slot {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.66rem;
  letter-spacing: 0.06em; color: var(--text-faint); text-align: center;
  padding: 0.5rem;
  width: 100%; height: 100%;
  display: grid; place-items: center;
  border: 1px dashed var(--line-strong); border-radius: var(--r-sm);
}
.facet h3 { font-size: clamp(1rem, 1.5vw, 1.15rem); }
.facet-head { display: grid; gap: 0.65rem; justify-items: start; }
.facet-mark {
  width: 58px; height: 58px; flex: none;
  color: var(--doodle-ink);
  display: grid; place-items: center;
  padding: 0;
  transition: transform 0.5s var(--ease);
}
.facet:hover .facet-mark { transform: rotate(-6deg) scale(1.06); }
.facet-mark svg { width: 100%; height: 100%; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; overflow: visible; }
.facet-mark img { width: 100%; height: 100%; object-fit: contain; display: block; }
/* the slot that names the file it is waiting for */
.icon-ph {
  width: 100%; height: 100%;
  display: grid; place-items: center;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-sm);
  padding: 0.25rem; text-align: center;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.52rem;
  letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-faint); line-height: 1.2;
  overflow: hidden;
}
.facet p { color: var(--text-muted); }

/* how I work — 8 numbered steps */
.steps { display: grid; grid-template-columns: repeat(4, 1fr); column-gap: clamp(1.25rem, 2.5vw, 2.25rem); row-gap: clamp(1.5rem, 3vw, 2.25rem); }
.step {
  padding-top: 0.8rem;
  display: grid; gap: 0.35rem; align-content: start;
}
.step .n { font-family: var(--font-mono); font-weight: 500; font-size: 0.74rem; color: var(--text-faint); }
.step h3 { font-size: var(--t-base); font-weight: 700; line-height: 1.3; }
.step p { font-size: 0.92rem; color: var(--text-muted); line-height: 1.55; }

/* closing note under the process */
.step-note {
  margin-top: 1.25rem;
  font-family: var(--font-mono); font-weight: 500;
  font-size: 0.8rem;
  color: var(--text-faint);
  display: flex; align-items: center; gap: 0.6rem;
}
.step-note::before { content: "\21BB"; color: var(--accent-ink); font-size: 1rem; }

/* =========================================================================
   ABOUT PREVIEW / QUOTE
   ========================================================================= */
.quote {
  font-size: clamp(1.5rem, 3.4vw, 2.5rem);
  line-height: 1.25;
  letter-spacing: -0.02em;
  padding-left: clamp(1rem, 3vw, 2rem);
  border-left: 2px solid var(--accent-ink);
}

.split { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2rem, 5vw, 5rem); align-items: start; }
.split-narrow { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); }

.prose { display: grid; gap: 1.1rem; max-width: 68ch; }
.prose p { color: var(--text-muted); }
/* <b> as well as <strong>: prose is set in muted grey, so an unstyled <b>
   came out bold-but-grey and read as no emphasis at all. */
.prose strong, .prose b { color: var(--text); font-weight: 700; }

/* portrait / media placeholder */
.ph-media {
  position: relative;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--surface);
  display: grid; place-items: center;
  color: var(--text-faint);
  font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase;
  aspect-ratio: var(--ratio, 4 / 5);
  overflow: hidden;
}

/* =========================================================================
   NUMBERED LISTS (disciplines, decisions, principles)
   ========================================================================= */
.num-grid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  column-gap: clamp(1.5rem, 3vw, 3rem);
  row-gap: clamp(1.75rem, 3.5vw, 2.75rem);
}
/* Six-column base so the count can decide the shape and nothing is orphaned.
   A five-item list should not leave a hole where a sixth would go. */
.num-grid > * { grid-column: span 2; }
.num-grid[data-n="1"] > * { grid-column: span 6; }
.num-grid[data-n="2"] > * { grid-column: span 3; }
.num-grid[data-n="4"] > * { grid-column: span 3; }
.num-grid[data-n="5"] > *:nth-child(n + 4) { grid-column: span 3; }
.num-grid[data-n="7"] > *:last-child { grid-column: span 6; }
.num-grid[data-n="8"] > * { grid-column: span 3; }

/* A screen beside each decision. Phone shots letterbox rather than crop —
   a cropped phone screenshot is worse than a small one. */
.num-fig { margin: 0.9rem 0 0; display: grid; gap: 0.5rem; }
.num-fig .media-slot {
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-sm);
  display: grid; place-items: center;
  overflow: hidden;
}
.num-fig .media-slot img { width: 100%; height: 100%; object-fit: contain; background: var(--bg); }
/* the card version: picture first, then the words, in a soft rounded tile */
.pillars.is-cards .pillar { display: grid; }
.pillars.is-cards .pillar .num-fig { order: -1; margin: 0 0 0.9rem; }
.pillars.is-cards .num-fig .media-slot { border: 0; border-radius: 18px; background: var(--surface-2); }
.pillars.is-cards .num-fig .media-slot img { object-fit: cover; background: none; }
.pillars.is-cards .pillar h3 { font-size: clamp(0.98rem, 1.3vw, 1.1rem); }
.pillars.is-cards .pillar p { font-size: 0.88rem; }
.pillars.is-cards[data-n="6"] { --n: 3; }
.num-fig .media-tag {
  position: static; text-align: center; padding: 0.5rem;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.66rem;
  letter-spacing: 0.07em; text-transform: uppercase; color: var(--text-faint);
}
.num-cell {
  padding-top: 0.85rem;
  display: grid; gap: 0.4rem;
  align-content: start;
}
.num-cell-head { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; }
.num-cell .n { font-family: var(--font-mono); font-weight: 500; font-size: 0.74rem; color: var(--text-faint); }
.num-cell p { color: var(--text-muted); }

/* =========================================================================
   TIMELINE (experience)
   ========================================================================= */
.timeline { display: grid; }
.tl-row {
  display: grid;
  grid-template-columns: minmax(150px, 0.85fr) minmax(0, 2.6fr);
  gap: clamp(1rem, 4vw, 3rem);
  padding-block: clamp(1.5rem, 3vw, 2.25rem);
}
.tl-row:first-child { padding-top: 0; }
/* the rule belongs to the right column, not the row — spanning both turns two
   columns into one table and the company stops reading as a heading */
.tl-right {
  padding-bottom: clamp(1.5rem, 3vw, 2.25rem);
  margin-bottom: calc(clamp(1.5rem, 3vw, 2.25rem) * -1);
  border-bottom: 1px solid var(--line);
  transition: border-color 0.35s var(--ease);
}
.tl-row:hover .tl-right { border-color: var(--line-strong); }
.tl-row:hover .tl-org { background: var(--accent); }
.tl-left { display: grid; gap: 0.25rem; align-content: start; justify-items: start; }
/* dates and place read as metadata under the company, not as pills */
.tl-left .tag {
  font-family: var(--font-mono); font-weight: 500;
  font-size: var(--t-label); letter-spacing: 0.02em;
  text-transform: none; color: var(--text-faint);
  background: none; border: 0; padding: 0;
}
.tl-left .tl-org { font-size: var(--t-base); font-weight: 700; transition: color 0.3s var(--ease); }
.tl-right > * + * { margin-top: 0.5rem; }
.tl-role { font-size: var(--t-base); font-weight: 700; }
.tl-right p { color: var(--text-muted); }

/* stat row */
/* three numbers, set large, with a flag or a logo beside the line */
.bigstats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(1.5rem, 4vw, 3rem); align-items: start; }
/* one number, and the rest of the facts as a sentence beside it */
.bigstats.has-text { grid-template-columns: auto minmax(0, 1fr); align-items: center; }
.bigstats.has-text .bs-text { order: 2; font-size: clamp(1.05rem, 1.5vw, 1.3rem); line-height: 1.55; color: var(--text-muted); max-width: 46ch; text-wrap: pretty; margin: 0; }
.bigstats.has-text .bs-text b { color: var(--text); font-weight: 600; }
.bigstats.has-text .bs { order: 1; padding-right: clamp(1rem, 3vw, 2.5rem); border-right: 1px solid var(--line); }
.bigstats.has-text .bs-fig { font-size: clamp(3rem, 6vw, 5rem); }
@media (max-width: 640px) { .bigstats.has-text { grid-template-columns: 1fr; } .bigstats.has-text .bs { border-right: 0; padding-right: 0; } }
.fig-link { margin-top: 0.5rem; }
.bs { display: grid; gap: 0.5rem; align-content: start; justify-items: start; }
.bs-fig { font-size: clamp(2rem, 3.5vw, 3rem); font-weight: 700; letter-spacing: -0.03em; line-height: 1; transition: color 0.3s var(--ease); }

.bs-label { font-size: clamp(1rem, 1.3vw, 1.15rem); line-height: 1.45; color: var(--text-muted); max-width: 24ch; text-wrap: pretty; }
.bs-art { display: inline-flex; align-items: center; gap: 0.5rem; margin-top: 0.4rem; }
.bs-flags .flag { display: inline-block; width: 36px; height: 24px; border-radius: 3px; overflow: hidden; box-shadow: 0 0 0 1px var(--line); }
.bs-flags .flag svg { display: block; width: 100%; height: 100%; }
.bs-logo img { height: 28px; width: auto; display: block; }
.bs.has-top .bs-art { margin: 0 0 0.35rem; min-height: 28px; }
@media (max-width: 640px) { .bigstats { grid-template-columns: 1fr; } }

/* a section whose heading is led by a single big numeral */
.sec-num { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: clamp(1rem, 3vw, 2.5rem); align-items: center; margin-bottom: clamp(1.5rem, 3vw, 2.5rem); }
.flow-scroll { margin-top: clamp(1.5rem, 3vw, 2.5rem); }
.sec-num-head { min-width: 0; }
.sec-num > b { font-size: clamp(4rem, 10vw, 8.5rem); font-weight: 700; letter-spacing: -0.05em; line-height: 0.85; color: var(--text); }
@media (max-width: 640px) { .sec-num { grid-template-columns: 1fr; } }

/* the ladder: five numbers, one under the other, in journey order. Plain
   rows, nothing to hover: they are not links. */
.ladder { list-style: none; margin: 0; padding: 0; display: grid; }
.rung {
  display: grid; grid-template-columns: 2.5rem minmax(0, 1fr) minmax(0, 1.6fr); gap: 0.35rem 1.5rem;
  align-items: baseline; padding-block: 0.7rem;
}
.rung-n { font-family: var(--font-mono); font-weight: 500; font-size: var(--t-label); letter-spacing: 0.08em; color: var(--text-faint); }
.rung-ttl { font-size: 1rem; font-weight: 600; letter-spacing: -0.01em; line-height: 1.3; }
.rung-body { color: var(--text-muted); font-size: 0.9rem; line-height: 1.5; max-width: 52ch; text-wrap: pretty; }
@media (max-width: 760px) { .rung { grid-template-columns: 2rem minmax(0, 1fr); } .rung-body { grid-column: 2; } }

.stat-row {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: clamp(1.5rem, 3vw, 3rem);
  row-gap: 1.75rem;
  border-top: 1px solid var(--line);
  padding-top: 1.25rem;
}
.stat-row > * { grid-column: span 3; }
.stat-row[data-n="2"] > * { grid-column: span 6; }
.stat-row[data-n="3"] > * { grid-column: span 4; }
.stat-row[data-n="5"] > * { grid-column: span 4; }
.stat-row[data-n="5"] > *:nth-child(n + 4) { grid-column: span 6; }
.stat-row[data-n="6"] > * { grid-column: span 4; }
.stat-cell { display: grid; gap: 0.25rem; align-content: start; }
.stat-cell b { font-size: var(--t-lg); font-weight: 700; letter-spacing: -0.01em; line-height: 1.05; }
.stat-cell span { color: var(--text-muted); }
.stat-cell small { font-size: 0.74rem; color: var(--text-faint); font-family: var(--font-mono); font-weight: 500; letter-spacing: 0.06em; }

/* chips */
.phase-fig { margin: clamp(0.9rem, 2vw, 1.35rem) 0 0; display: grid; gap: 0.6rem; }

.locked-error {
  margin: 0.75rem 0 0; font-size: 0.88rem; color: var(--accent-ink); font-weight: 500;
}
.phase-state {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.66rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text);
  background: var(--accent);
  border-radius: 999px; padding: 0.2rem 0.55rem;
  margin-left: 0.6rem;
}

.chips { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.chips li {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem; letter-spacing: 0.06em;
  padding: 0.35rem 0.7rem; border: 1px solid var(--line); border-radius: var(--r-pill);
  color: var(--text-muted);
  transition: border-color 0.35s var(--ease), color 0.35s var(--ease);
}
.chips li:hover { border-color: var(--accent-ink); color: var(--text); }

/* =========================================================================
   CASE STUDY PAGE
   ========================================================================= */
.progress-bar {
  position: fixed; top: 0; left: 0; z-index: 95;
  height: 2px; width: 100%;
  background: var(--accent-grad);
  transform: scaleX(var(--p, 0));
  transform-origin: left;
}

.cs-hero { padding-top: calc(var(--nav-h) + clamp(3rem, 9vw, 7rem)); padding-bottom: clamp(2rem, 5vw, 4rem); position: relative; }
.cs-hero::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 100%; background: var(--glow); pointer-events: none; }
.cs-hero-inner { position: relative; }
.cs-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem 1.25rem; margin-bottom: 1.5rem; }
/* 18ch wrapped every long title to three lines with a third of the row
   empty beside it; 26ch lets a title use the width it has. */
.cs-hero h1 { max-width: 26ch; margin-bottom: 1.25rem; }
.cs-hero .lead { max-width: 52ch; }

/* The credit line under the hero. It was a bordered 2x2 card, which is the
   only card on the site and read as a table dropped onto the page. Now it is
   a hairline row that follows the count, so three facts do not leave a hole. */
.cs-facts {
  display: grid;
  grid-template-columns: repeat(var(--n, 4), minmax(0, 1fr));
  gap: clamp(1.25rem, 3vw, 3rem);
  margin-top: clamp(2rem, 5vw, 3.5rem);
  padding-top: 1rem;
  border-top: 1px solid var(--line-strong);
}
.cs-facts[data-n="2"] { --n: 2; }
.cs-facts[data-n="3"] { --n: 3; }
.cs-facts[data-n="5"] { --n: 5; }
.cs-fact { display: grid; gap: 0.3rem; align-content: start; }
.cs-fact dt {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.68rem;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--text-faint);
}
.cs-fact dd { font-size: 0.95rem; line-height: 1.4; margin: 0; color: var(--text-muted); }
.cs-fact dd span { display: block; font-size: 0.8rem; color: var(--text-faint); margin-top: 0.15rem; font-weight: 500; }
/* the role is the one a reader is actually here for */
.cs-fact:first-child dd { color: var(--text); font-weight: 700; }

@media (max-width: 700px) {
  .cs-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 1.25rem; }
}

/* sticky section index */
.cs-body { display: grid; grid-template-columns: 190px minmax(0, 1fr); gap: clamp(2rem, 5vw, 4.5rem); align-items: start; }
.cs-toc { position: sticky; top: calc(var(--nav-h) + 24px); display: grid; gap: 0.55rem; }
.cs-toc a {
  font-size: 0.78rem;
  font-family: var(--font-mono); font-weight: 500;
  letter-spacing: 0.06em;
  color: var(--text-faint);
  display: flex; align-items: center; gap: 0.6rem;
  transition: color 0.35s var(--ease);
}
.cs-toc a::before { content: ""; width: 12px; height: 1px; background: currentColor; transition: width 0.4s var(--ease); flex: none; }
.cs-toc a:hover { color: var(--text-muted); }
.cs-toc a.is-active { color: var(--text); }
.cs-toc a.is-active::before { width: 26px; background: var(--accent); }

/* One more dot of the background grid between sections. At 56px they read as
   one continuous column; at 84 they read as separate pieces of an argument. */
.cs-sections { display: grid; gap: clamp(2.6rem, 5.8vw, 5.25rem); min-width: 0; }
/* A numbered sub-principle. It has no label, so it stays out of the section
   index, and a rule down its left ties the three of them to the DESIGN
   PRINCIPLES heading above rather than reading as three more sections. */
/* No rule and no indent: the numeral is enough to say these belong to the
   principles heading, and a bar down the side boxed them in. */
.cs-section.is-part {
  margin-top: calc(clamp(2.6rem, 5.8vw, 5.25rem) * -0.42);
}
.cs-section.is-part > .h2 { font-size: clamp(1.4rem, 2.5vw, 2rem); }
.part-n {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.76rem;
  letter-spacing: 0.18em; color: var(--accent-ink); margin: 0;
}

.cs-section { scroll-margin-top: calc(var(--nav-h) + 32px); display: grid; gap: 1.4rem; }
/* a block that continues the section above it: pulled up under it */
.cs-section.is-tight { margin-top: calc(-1 * clamp(1.6rem, 3.8vw, 3.25rem)); }
/* a numbered subsection inside a section: the number and a smaller heading
   on one line, so the parts read as parts and not as three more chapters */
.cs-section.is-tight.is-part { margin-top: 0; padding-top: clamp(0.5rem, 1.5vw, 1.25rem); }
.cs-section.is-tight.is-part .h2 { font-size: clamp(1.25rem, 1.9vw, 1.6rem); margin-top: 0.25rem; }
.cs-section.is-tight.is-part .lead { font-size: 0.98rem; }
/* a chapter opens with its objective: the label is set as a lime marker so
   the three of them read as the spine of the study */
.cs-section.is-chapter { padding-top: clamp(1.5rem, 4vw, 3rem); }
.cs-section.is-chapter > .label { display: inline-block; background: var(--accent); color: var(--text); padding: 0.3em 0.6em; border-radius: 4px; }
/* No reading measure inside a section. Headings, prose and leads all run the
   full width of the column, matching the grids and figures beside them. This
   is a deliberate call: it puts the line length past the usual 65-75 character
   comfort range in exchange for a page with no half-empty rows in it. */
.cs-section > h2 { max-width: none; }
.cs-section .prose { max-width: none; }
.cs-section > .lead { max-width: none; }
.cs-section .cs-task { max-width: none; }
/* the teaser on the next-study card is 16px body copy in a much wider box */
.next-cs .lead { max-width: 60ch; }

/* -------------------------------------------------------------------------
   INK — handwritten marginalia on an annotated case study.
   Opt in per case study with `ink: true`; each section carries its own note.
   ------------------------------------------------------------------------- */
.ink-note {
  font-family: var(--font-hand);
  font-size: 1.4rem;
  line-height: 1.2;
  color: var(--text-faint);
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  transform: rotate(-2.5deg);
  transform-origin: left top;
}
.ink-note .pen {
  width: 40px; height: 26px; flex: none;
  color: var(--accent-mark);
  margin-top: 0.3rem;
  clip-path: inset(0 100% 0 0);
}
/* arrow and handwriting arrive together, both only once the note scrolls in */
.ink-note.is-in .pen, [data-reveal].is-in .ink-note .pen {
  clip-path: inset(0 -4% 0 0);
  transition: clip-path 0.55s var(--ease) 0.1s;
}

/* below the note gutter breakpoint the note sits inline, under the label */
.cs-section > .ink-note { margin-top: -0.25rem; }

@media (min-width: 1220px) {
  /* The note used to own a 168px column for the whole section, which is what
     kept every block beside it at half width. It is now lifted out of the flow
     entirely and parked on the label row, where nothing else sits — so the
     content below runs edge to edge and the note costs no layout at all.
     It also stops shouting: hidden until you hover or tab into the section. */
  .cs-section { position: relative; }
  .cs-section.has-ink > .ink-note {
    position: absolute;
    top: 0;
    right: 0;
    max-width: 270px;
    margin: 0;
    z-index: 2;
    pointer-events: none;
    opacity: 0;
    transform: rotate(2deg) translateY(-6px);
    transition: opacity 0.3s var(--ease), transform 0.4s var(--ease);
  }
  .cs-section.has-ink:hover > .ink-note,
  .cs-section.has-ink:focus-within > .ink-note {
    opacity: 1;
    transform: rotate(2deg) translateY(0);
  }
  /* the pen draws itself on hover rather than on scroll, so the gesture and
     the handwriting arrive together */
  .cs-section.has-ink > .ink-note .pen { clip-path: inset(0 100% 0 0); }
  .cs-section.has-ink:hover > .ink-note .pen,
  .cs-section.has-ink:focus-within > .ink-note .pen {
    clip-path: inset(0 -4% 0 0);
    transition: clip-path 0.55s var(--ease) 0.08s;
  }
  /* right-aligned so the arrow keeps its right-to-left curve back at the text */
  .ink-note { text-align: right; transform-origin: right top; }
}

@media (prefers-reduced-motion: reduce) {
  .cs-section.has-ink > .ink-note { transition: opacity 0.2s linear; }
}

/* an outbound link hung under a figure — the prototype, a live build */
.cs-link { margin: 0.9rem 0 0; }
.cs-link a {
  display: inline-flex; align-items: baseline; gap: 0.45rem;
  font-size: 0.95rem; font-weight: 500;
  color: var(--text);
  text-decoration: none;
  border-bottom: 1px solid var(--accent);
  padding-bottom: 2px;
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.cs-link a:hover { background: var(--accent); border-color: var(--accent); color: var(--text); }
.cs-link a span { font-size: 0.9em; }

/* -------------------------------------------------------------------------
   MEDIA + SCRAPWORK — the slots a case study grows into
   ------------------------------------------------------------------------- */
.media { display: grid; gap: 0.75rem; }
/* Frames of one screen, stacked in a single slot and stepped through by dots.
   All of them are in the DOM so switching costs nothing, and only the active
   one is painted. */
.media-slot > .fig-frame {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0; pointer-events: none;
  transition: opacity 0.35s var(--ease);
}
.media-slot > .fig-frame.is-on { pointer-events: auto; }
.media-slot > .fig-frame.is-on { opacity: 1; }
/* An empty carousel frame: same box, same fade, but it reads as a slot. */
.media-slot > .fig-ph {
  display: grid;
  place-items: center;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-faint);
  text-align: center;
  padding: 1rem;
}
.fig-dots { display: flex; gap: 0.5rem; justify-content: center; }
.fig-dot {
  appearance: none; border: 0; padding: 0; cursor: pointer;
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--line-strong);
  transition: background 0.25s var(--ease), transform 0.25s var(--ease);
}
.fig-dot:hover { background: var(--text-faint); }
.fig-dot.is-on { background: var(--accent-ink); transform: scale(1.25); }
.fig-dot:focus-visible { outline: 2px solid var(--text); outline-offset: 3px; }
/* A portrait capture in a two-up row is twice the height of the 16:9 beside
   it, so the pair reads as a mistake. Cap it and centre it in its column. */
.media.is-phone .media-slot { max-width: 220px; margin-inline: auto; border-radius: var(--r-lg); }
/* A 4:9 phone capture beside a 16:9 one is twice its height on equal columns,
   so the phone dominates a row where the television is the point. Flex, not
   grid, so the phone takes only the width it needs whichever side it sits on. */
.block-figs[data-n="2"]:has(.media.is-phone) { display: flex; align-items: flex-start; }
.block-figs[data-n="2"]:has(.media.is-phone) > .media { flex: 1 1 0; min-width: 0; }
.block-figs[data-n="2"]:has(.media.is-phone) > .media.is-phone { flex: 0 0 auto; width: 220px; }
@media (max-width: 640px) {
  .block-figs[data-n="2"]:has(.media.is-phone) { flex-direction: column; }
  .block-figs[data-n="2"]:has(.media.is-phone) > .media.is-phone { width: 100%; }
}
.media.is-phone .figcap { text-align: center; }
.media-slot {
  aspect-ratio: var(--ratio, 16 / 9);
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--surface);
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
}
.media-slot > img, .media-slot > video { width: 100%; height: 100%; object-fit: cover; }
/* A slot crops to its declared ratio, and a video element carries that crop
   into the browser's own fullscreen — so expanding a 16:9 capture in a 4:3
   slot showed a cropped frame rather than the real one. Fullscreen always
   shows the whole picture. */
video:fullscreen, video:-webkit-full-screen {
  width: 100%; height: 100%;
  object-fit: contain;
  background: #000;
}
.media-play {
  width: 44px; height: 44px;
  border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--line-strong);
  color: var(--text-muted);
  transition: transform 0.4s var(--ease), color 0.4s var(--ease);
}
.media-slot:hover .media-play { transform: scale(1.08); color: var(--text); }
.media-play svg { width: 18px; height: 18px; fill: currentColor; stroke: none; margin-left: 3px; }
.media-tag {
  position: absolute; left: 14px; bottom: 12px;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem;
  letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--text-faint);
}

/* phone screens — most of the healthcare work lives here, not on a 16:9 */
/* a phone and a browser, side by side */
.devices {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 2.4fr);
  gap: clamp(1.5rem, 3.5vw, 3rem);
  /* frames share a top edge; the captions under them share a baseline row */
  align-items: start;
}
.devices .device { grid-template-rows: auto 1fr; }
.devices .device figcaption { align-self: end; }
.devices .phone-frame, .devices .browser-frame {
  border: 0; padding: 0; overflow: hidden;
  box-shadow: 0 1px 2px rgba(10, 13, 16, 0.06), 0 16px 40px -16px rgba(10, 13, 16, 0.22);
}
.devices .phone-frame { border-radius: 22px; }
.devices .phone-screen { border-radius: 22px; }
.devices .browser-bar { border-bottom: 0; background: var(--surface-2); }
.cs-section > .devices { margin-top: clamp(0.75rem, 2vw, 1.9rem); }
.device { margin: 0; display: grid; gap: 0.75rem; min-width: 0; }
.device.is-phone .phone-frame { max-width: 280px; }
/* the whole capture, top-aligned: a phone export is rarely the frame's exact shape, and a cropped screen is worse than a short one */
.device .phone-screen > img { object-fit: contain; object-position: top center; background: var(--surface); }
.browser-frame {
  border: 1px solid var(--line-strong); border-radius: 12px; overflow: hidden;
  background: var(--surface);
}
.browser-bar {
  display: flex; align-items: center; gap: 6px;
  padding: 9px 12px; border-bottom: 1px solid var(--line);
}
.browser-bar i { width: 9px; height: 9px; border-radius: 50%; background: var(--line-strong); display: block; }
.browser-bar span {
  margin-left: 10px; flex: 1; text-align: center;
  font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.06em; color: var(--text-faint);
  background: var(--bg); border-radius: 6px; padding: 3px 10px;
}
.browser-screen { position: relative; aspect-ratio: var(--ratio, 16/9); background: var(--bg); display: grid; place-items: center; }
.browser-screen > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; object-position: top center; }
@media (max-width: 760px) {
  .devices { grid-template-columns: 1fr; align-items: start; }
  .device.is-phone .phone-frame { max-width: 220px; }
}

.phones { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(1.25rem, 3vw, 2.5rem); }
/* room between the words and the recordings, and between the parts */
.cs-section > .phones { margin-top: clamp(2.25rem, 5vw, 4rem); }
.cs-section:has(> .phones) { gap: 1.9rem; }
.cs-section:has(> .phones) .lead { margin-top: 0.5rem; }
.cs-section.is-chapter > .label { margin-bottom: 0.5rem; }
.cs-section.is-chapter .h2 { margin-bottom: 0.25rem; }
.phones[data-n="1"] { grid-template-columns: minmax(0, 280px); }
.phones[data-n="2"] { grid-template-columns: repeat(2, 1fr); max-width: 620px; }
.phones[data-n="4"] { grid-template-columns: repeat(4, 1fr); }

.phone { display: grid; gap: 0.75rem; }
/* an outline of a phone, not a rendering of one */
.phone-frame {
  aspect-ratio: 9 / 19.5;
  border-radius: 22px;
  padding: 0;
  border: 0;
  background: var(--surface);
  overflow: hidden;
  box-shadow: 0 1px 2px rgba(10, 13, 16, 0.06), 0 16px 40px -16px rgba(10, 13, 16, 0.22);
  position: relative;
}
.phone-screen { border-radius: 22px; }
/* a recording in a phone: a small pill on hover opens the file itself in a
   new tab, at its own size, nothing cropped */
.phone-open {
  position: absolute; right: 10px; top: 10px; z-index: 2;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.64rem; letter-spacing: 0.06em; text-transform: uppercase;
  padding: 0.35rem 0.6rem; border-radius: 999px; background: var(--accent); color: var(--text);
  display: inline-flex; gap: 0.35em; align-items: center;
  opacity: 0; transform: translateY(-4px); transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}
.phone-frame:hover .phone-open, .phone-open:focus-visible { opacity: 1; transform: none; }
.phones[data-n="2"] { grid-template-columns: repeat(2, minmax(0, 260px)); gap: clamp(2rem, 5vw, 4.5rem); max-width: none; }
.phones[data-n="3"] { grid-template-columns: repeat(3, minmax(0, 260px)); gap: clamp(1.5rem, 3.5vw, 3rem); }
.phone-screen > video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; background: #000; }
.phone-screen {
  position: relative;
  height: 100%;
  border-radius: 14px;
  overflow: hidden;
  background: var(--surface);
  display: grid;
  place-items: center;
  padding: 1rem;
  text-align: center;
}
/* the pill, so it reads as a phone at a glance */
.phone-screen::before {
  content: "";
  position: absolute; top: 8px; left: 50%; transform: translateX(-50%);
  width: 32%; height: 5px; border-radius: 3px;
  background: var(--line-strong);
}
.phone-screen > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.phone-screen span {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.74rem;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-faint); line-height: 1.6;
}
.phone figcaption { font-size: 0.82rem; color: var(--text-muted); }

@media (max-width: 860px) { .phones, .phones[data-n="4"] { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .phones, .phones[data-n="4"], .phones[data-n="2"] { grid-template-columns: 1fr; max-width: 260px; } }

/* scraps sit slightly off-axis, like things pinned to a wall */
.scraps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1rem, 2.5vw, 2rem);
  /* These boards are wildly different heights — one is four times the next.
     Stretched to a common row, the free space fell between each image and its
     own caption, leaving a 287px hole under the shortest one. */
  align-items: start;
}
.scrap { display: grid; gap: 0.4rem; align-content: start; transform: rotate(calc(var(--r, 0) * 1.1deg)); transition: transform 0.5s var(--ease); }
.scrap:hover { transform: rotate(0deg) scale(1.03); z-index: 2; }
.scrap-slot {
  position: relative;
  aspect-ratio: var(--ratio, 4 / 3);
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-sm);
  background: none;
  display: grid; place-items: center;
  padding: 0.75rem;
  text-align: center;
  overflow: hidden;
}
.scrap-slot > img { width: 100%; height: 100%; object-fit: cover; }
.scrap-slot span {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-faint); line-height: 1.5;
}
.scrap figcaption { font-size: 0.8rem; color: var(--text-muted); }

@media (max-width: 860px) { .scraps { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .scraps { grid-template-columns: 1fr; } .scrap { transform: none; } }

/* The task line. Every case study states its brief in the same place and the
   same shape, so an interviewer skimming four of them can find it without
   reading. Costs no section — it hangs off the opening prose block. */
.cs-task {
  margin-top: clamp(1.1rem, 2.2vw, 1.6rem);
  padding-left: clamp(0.85rem, 2vw, 1.25rem);
  border-left: 3px solid var(--accent);
  font-size: clamp(1.02rem, 1.5vw, 1.15rem);
  line-height: 1.55;
  color: var(--text);
  text-wrap: pretty;
}
.cs-task > span {
  display: block;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.68rem;
  letter-spacing: 0.11em; text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 0.3rem;
}
.cs-task strong { font-weight: 700; }

/* =========================================================================
   CALLOUT — one sentence lifted out of the prose
   A lime hairline down the left, not a filled box. A box would read as an
   admonition ("warning:"); this reads as something worth stopping on.
   ========================================================================= */
.callout {
  border-left: 3px solid var(--accent);
  padding: 0.15rem 0 0.15rem clamp(1rem, 2.5vw, 1.75rem);
  max-width: 34ch;
}
.callout p {
  font-size: clamp(1.15rem, 2.4vw, 1.75rem);
  line-height: 1.4;
  letter-spacing: -0.015em;
  font-weight: 500;
  text-wrap: pretty;
}
.callout.is-tight p { font-size: clamp(1rem, 1.9vw, 1.3rem); font-weight: 400; color: var(--text-muted); }
.callout p strong { font-weight: 700; color: var(--text); }
.callout p em { font-style: italic; }
.callout-who {
  display: block; margin-top: 0.75rem;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-faint);
}

/* =========================================================================
   QUOTE SET — several short verbatims as cards
   Five quotes run together in a paragraph read as prose and get skimmed.
   Broken into cards they can be read in any order, and stopped at.
   ========================================================================= */
.quote-set {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: clamp(0.75rem, 1.8vw, 1.25rem);
}
.quote-set[data-n="2"], .quote-set[data-n="4"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.qcard {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: clamp(1rem, 2vw, 1.4rem);
  background: var(--surface);
  display: grid; align-content: start; gap: 0.6rem;
  transition: border-color 0.4s var(--ease), transform 0.4s var(--ease);
}
.qcard:hover { border-color: var(--accent-ink); transform: translateY(-2px); }
.qcard blockquote {
  margin: 0;
  font-size: clamp(0.98rem, 1.7vw, 1.1rem);
  line-height: 1.5; text-wrap: pretty;
}
/* the mark is decoration, so it is drawn rather than typed into the content */
.qcard blockquote::before { content: "\201C"; color: var(--accent-ink); font-weight: 700; }
.qcard blockquote::after { content: "\201D"; color: var(--accent-ink); font-weight: 700; }
.qcard figcaption {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.68rem;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-faint);
}
@media (max-width: 560px) {
  .quote-set, .quote-set[data-n="2"], .quote-set[data-n="4"] { grid-template-columns: 1fr; }
}

/* =========================================================================
   ROLE GRID — the same numbered bullets, but across instead of down
   Five stacked rows is a list to get through; a grid is a set to scan.
   ========================================================================= */
.role-grid {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
  gap: clamp(1rem, 2.2vw, 1.75rem);
}
.role-cell {
  display: grid; gap: 0.5rem; align-content: start;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line);
}
.role-cell .tag {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem;
  letter-spacing: 0.08em; color: var(--accent-ink);
}
.role-cell > span:last-child { font-size: 0.95rem; line-height: 1.55; text-wrap: pretty; }
@media (max-width: 560px) { .role-grid { grid-template-columns: 1fr; } }

/* =========================================================================
   BOOK PAGE — one slot, and a form
   The slot card and the form sit side by side; on a narrow screen the card
   goes first because booking is the faster path.
   ========================================================================= */
.book-cols {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
.book-cols .slot-grid { grid-template-columns: 1fr; }

.cform { display: grid; gap: 0; }
.cform .h2 { margin-top: 0.35rem; }
.cf-sub { margin-top: 0.6rem; max-width: 44ch; }
.cf-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(0.85rem, 2vw, 1.35rem);
  margin-top: clamp(1.5rem, 3vw, 2.25rem);
}
.cfield { display: grid; gap: 0.4rem; grid-column: 1 / -1; align-content: start; }
.cfield.is-half { grid-column: span 1; }
.cfield label {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.7rem;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-muted);
  display: flex; justify-content: space-between; gap: 0.5rem;
}
.cf-hint { color: var(--text-faint); text-transform: none; letter-spacing: 0.04em; }
.cfield input, .cfield textarea {
  font: inherit; font-size: 0.98rem; color: var(--text);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  padding: 0.7rem 0.85rem;
  width: 100%;
  transition: border-color 0.3s var(--ease), box-shadow 0.3s var(--ease), background 0.3s var(--ease);
}
.cfield textarea { resize: vertical; min-height: 7.5rem; line-height: 1.55; }
.cfield input::placeholder, .cfield textarea::placeholder { color: var(--text-faint); }
.cfield input:hover, .cfield textarea:hover { border-color: var(--line-strong); }
.cfield input:focus-visible, .cfield textarea:focus-visible {
  outline: none; background: var(--bg);
  border-color: var(--accent-ink);
  /* lime is the focus colour everywhere else, but at 1px on white it is not
     visible enough to be a focus ring, so it gets a halo behind the hairline */
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 55%, transparent);
}
.cfield input.is-bad, .cfield textarea.is-bad { border-color: #b3261e; }
/* error on the left, counter on the right, sharing one row so neither of
   them shifts the field below when it appears */
.cf-foot { display: flex; justify-content: space-between; align-items: baseline; gap: 0.75rem; min-height: 1rem; }
.cf-foot:has(.cf-count) { min-height: 1.1rem; }
.cf-err { font-size: 0.78rem; color: #b3261e; line-height: 1.4; }
.cf-err:empty { display: none; }
.cf-count {
  margin-left: auto; flex: none;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.7rem;
  letter-spacing: 0.04em; color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  transition: color 0.25s var(--ease);
}
.cf-count.is-near { color: var(--accent-ink); }
.cf-count.is-full { color: #b3261e; font-weight: 700; }

/* off-screen rather than display:none — a bot reading the DOM sees a normal
   field, a screen reader skips it via aria-hidden on the wrapper */
.cf-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.cf-actions {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 0.75rem 1.25rem;
  margin-top: clamp(1.25rem, 2.5vw, 1.75rem);
}
.cf-actions .btn[disabled] { opacity: 0.55; pointer-events: none; }
.cf-status { font-size: 0.88rem; line-height: 1.5; margin: 0; }
.cf-status:empty { display: none; }
.cf-status.is-ok { color: var(--accent-ink); font-weight: 600; }
.cf-status.is-bad { color: #b3261e; }

@media (max-width: 880px) {
  .book-cols { grid-template-columns: 1fr; }
}
@media (max-width: 520px) {
  .cf-grid { grid-template-columns: 1fr; }
  .cfield.is-half { grid-column: 1 / -1; }
}

/* =========================================================================
   FLOW — a procedure as a row of nodes
   Eight steps set as prose is prose. As a track, a presenter can point at the
   one that matters. Sideways scroll beats wrapping: a wrapped track loses the
   left-to-right reading that makes it a sequence at all.
   ========================================================================= */
/* min-width:0 or the grid item refuses to shrink below its content and the
   whole page scrolls sideways instead of just this track */
.flow-scroll { overflow-x: auto; overscroll-behavior-x: contain; padding-bottom: 0.75rem; min-width: 0; max-width: 100%; }
.flow {
  list-style: none; margin: 0; padding: 0.35rem 0 0;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(140px, 1fr);
  gap: 0;
  min-width: min-content;
}
.flow-step {
  position: relative;
  display: grid; align-content: start; gap: 0.3rem;
  padding: 1.5rem 1rem 0 0;
}
/* the rail runs behind the dots, drawn per step so the last one stops */
.flow-step::before {
  content: ""; position: absolute; left: 0; right: 0; top: 5px;
  height: 1px; background: var(--line);
}
.flow-step:last-child::before { right: calc(100% - 11px); }
.flow-step::after {
  content: ""; position: absolute; left: 0; top: 0;
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--bg); border: 1.5px solid var(--line-strong);
}
.flow-step.is-focus::after { background: var(--accent); border-color: var(--accent-ink); }
.flow-n {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.68rem;
  letter-spacing: 0.08em; color: var(--text-faint);
}
.flow-step.is-focus .flow-n { color: var(--accent-ink); }
.flow-ttl { font-size: 0.9rem; font-weight: 700; line-height: 1.3; text-wrap: pretty; }
.flow-body { font-size: 0.82rem; color: var(--text-muted); line-height: 1.5; text-wrap: pretty; }
.flow-tag {
  justify-self: start; margin-top: 0.2rem;
  font-family: var(--font-mono); font-weight: 700; font-size: 0.66rem;
  letter-spacing: 0.07em; text-transform: uppercase;
  background: var(--accent); color: var(--on-accent);
  padding: 0.15rem 0.45rem; border-radius: 3px;
}

/* =========================================================================
   SHIFT CHART — before, after, and why
   ========================================================================= */
.shiftchart { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.shiftrow {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: clamp(0.5rem, 3vw, 2.5rem);
  align-items: start;
  padding: clamp(0.9rem, 2vw, 1.3rem) 0;
}
.shift-pair { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 0.6rem; }
.shift-pair b { font-size: clamp(1rem, 1.7vw, 1.3rem); font-weight: 700; letter-spacing: -0.015em; }
.shift-from { color: var(--text-faint); text-decoration: line-through; text-decoration-thickness: 1px; }
.shift-to { color: var(--text); }
.shift-arrow { color: var(--accent-ink); font-style: normal; font-size: 1.1em; }
.shift-why { color: var(--text-muted); font-size: 0.95rem; line-height: 1.6; text-wrap: pretty; margin: 0; }
.shift-why strong { color: var(--text); font-weight: 600; }
@media (max-width: 720px) {
  .shiftrow { grid-template-columns: 1fr; gap: 0.45rem; }
}

/* =========================================================================
   COMPARE — two columns you read across
   ========================================================================= */
/* A comparison most readers will take on trust. Folded away by default so the
   section reads as one line and a picture, open for anyone who wants the
   detail. Inside <details>, so it works with no JS and is findable by search. */
/* A thumbnail and the folded comparison, side by side: you see what it looks
   like now and can open the row-by-row if you want it. */
.fold-row { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); gap: clamp(1.25rem, 3vw, 2.5rem); align-items: start; }
.fold-row > .block-figs { margin-top: 0; }
.fold-row > .cmp-fold { margin-top: 0; }
@media (max-width: 760px) { .fold-row { grid-template-columns: 1fr; } }

/* prose that picks up after a row of cards rather than introducing it */
.prose-after { margin-top: clamp(1.5rem, 3vw, 2.5rem); }

.cmp-fold { margin-top: clamp(1rem, 2vw, 1.5rem); }
.cmp-fold > summary {
  cursor: pointer; list-style: none;
  display: inline-flex; align-items: center; gap: 0.55rem;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.78rem;
  letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--text-faint);
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--line); border-radius: 999px;
  transition: color 0.25s var(--ease), border-color 0.25s var(--ease);
}
.cmp-fold > summary::-webkit-details-marker { display: none; }
.cmp-fold > summary::after { content: "+"; font-size: 1rem; line-height: 1; }
.cmp-fold[open] > summary::after { content: "\2013"; }
.cmp-fold > summary:hover { color: var(--text); border-color: var(--line-strong); }
.cmp-fold > summary:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
.cmp-fold .cmp { margin-top: clamp(0.75rem, 1.5vw, 1.15rem); }

.cmp { display: grid; gap: 0; margin-top: clamp(1rem, 2vw, 1.5rem); }
.cmp-head, .cmp-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(1rem, 3vw, 2.5rem);
}
.cmp-head {
  padding-bottom: 0.6rem;
  font-family: var(--font-mono); font-weight: 700; font-size: 0.7rem;
  letter-spacing: 0.1em; text-transform: uppercase;
}
.cmp-head span:last-child { color: var(--accent-ink); }
.cmp-row { padding: clamp(0.7rem, 1.6vw, 1.1rem) 0; }
.cmp-cell p { margin: 0; font-size: 0.98rem; line-height: 1.6; text-wrap: pretty; }
.cmp-cell.is-before p { color: var(--text-faint); }
.cmp-cell.is-after p { color: var(--text); font-weight: 500; }
.cmp-k {
  display: block; margin-bottom: 0.3rem;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.66rem;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-faint);
}
@media (max-width: 640px) {
  .cmp-head { display: none; }
  .cmp-row { grid-template-columns: 1fr; gap: 0.5rem; }
  /* without the header row the columns need their own labels */
  .cmp-cell.is-before::before, .cmp-cell.is-after::before {
    content: attr(data-l); display: block;
    font-family: var(--font-mono); font-size: 0.62rem; letter-spacing: 0.1em;
    text-transform: uppercase; color: var(--text-faint); margin-bottom: 0.2rem;
  }
  .cmp-cell.is-after { padding-left: 0.85rem; border-left: 3px solid var(--accent); }
}

/* =========================================================================
   NUMBERED, AS ROWS — one decision per row, its screen beside it
   ========================================================================= */
.num-rows { display: grid; gap: 0; }
.num-rows > .num-cell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
  gap: clamp(1rem, 3vw, 2.75rem);
  align-items: start;
  padding: clamp(1.1rem, 2.4vw, 1.75rem) 0;
}
/* Column two exists to hold a figure. A row without one used to reserve it
   anyway, so the copy wrapped at half width with nothing beside it. With no
   figure the second column is free, so the title takes a narrow lane and the
   body sits beside it — which reads faster than a heading stranded above a
   paragraph by a column gap meant for an image. */
.num-rows > .num-cell:not(:has(.num-fig)) {
  grid-template-columns: minmax(0, 0.42fr) minmax(0, 1fr);
  row-gap: 0.4rem;
}
.num-rows > .num-cell:not(:has(.num-fig)) > p { grid-column: 2; grid-row: 1; }
@media (max-width: 760px) {
  .num-rows > .num-cell:not(:has(.num-fig)) { grid-template-columns: minmax(0, 1fr); }
  .num-rows > .num-cell:not(:has(.num-fig)) > p { grid-column: 1; grid-row: auto; }
}
.num-rows .num-cell-head { grid-column: 1; }
.num-rows > .num-cell > p { grid-column: 1; margin: 0; }
.num-rows .num-fig { grid-column: 2; grid-row: 1 / span 3; margin: 0; align-self: start; }
@media (max-width: 760px) {
  .num-rows > .num-cell { grid-template-columns: 1fr; }
  .num-rows .num-fig { grid-column: 1; grid-row: auto; margin-top: 0.9rem; }
}

/* Pen marks — filled outlines, so they swell and taper like a real marker.
   They reveal with a left-to-right wipe, which is what a pen actually does;
   a stroke-draw would be wrong here because there is no stroke to draw. */
.pen { fill: currentColor; stroke: none; overflow: visible; }

.pen-mark { position: relative; display: inline-block; white-space: nowrap; }
.pen-mark .pen {
  position: absolute;
  color: var(--accent-mark);
  pointer-events: none;
  clip-path: inset(0 100% 0 0);
}
[data-reveal].is-in .pen-mark .pen,
.is-ready .pen-mark .pen {
  clip-path: inset(0 -2% 0 0);
  transition: clip-path 0.7s var(--ease) 0.35s;
}

/* underline sits just under the baseline and runs the width of the word */
.pen-underline .pen { left: -1.5%; bottom: -0.3em; width: 103%; height: 0.34em; }
/* at 88px, -0.3em is 26px of drop — the mark lands in the role line below.
   The hero needs it tucked much closer to the baseline. */
.hero-statement .pen-underline .pen { bottom: -0.1em; height: 0.2em; }

/* the circle overflows the word rather than padding it — padding would push
   the following punctuation away from the word it belongs to */
.pen-circle .pen { left: -9%; top: -26%; width: 118%; height: 152%; }

/* the sign-off scrawl that closes an annotated case study */
.ink-signoff {
  font-family: var(--font-hand);
  font-size: clamp(1.6rem, 3.4vw, 2.4rem);
  color: var(--text-faint);
  transform: rotate(-2deg);
  display: inline-block;
  margin-top: 1.5rem;
}

@media (prefers-reduced-motion: reduce) {
  .pen { clip-path: none !important; }
}

.pullquote {
  /* was up to 2rem against an h2 of 2.4 — near enough to read as a second
     heading, so a section with both had two things shouting at once */
  font-size: clamp(1.1rem, 1.8vw, 1.45rem);
  line-height: 1.4;
  letter-spacing: -0.01em;
  padding: clamp(1.25rem, 3vw, 2rem) 0;
  border-block: 1px solid var(--line);
  margin-block: 0.5rem;
}
/* The exception: a short line that is the whole finding rather than a
   sentence lifted out of one. Big enough to stop on, still under the h2. */
.pullquote.is-big {
  font-size: clamp(1.45rem, 2.6vw, 2.1rem);
  line-height: 1.25;
  letter-spacing: -0.02em;
  padding-block: clamp(1.5rem, 3.4vw, 2.4rem);
}
.pullquote strong { font-weight: 700; }

/* before / after slider */
.ba {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  user-select: none;
  touch-action: pan-y;
  cursor: ew-resize;
}
.ba-pane { position: absolute; inset: 0; display: grid; place-items: center; font-family: var(--font-mono); font-weight: 500; font-size: 0.78rem; letter-spacing: 0.2em; text-transform: uppercase; color: rgba(255,255,255,0.85); }
.ba-before { background: linear-gradient(135deg, #232329, #101013); }
.ba-after { background: var(--accent-grad); clip-path: inset(0 0 0 var(--split, 50%)); }
.ba-handle {
  position: absolute; top: 0; bottom: 0; left: var(--split, 50%);
  width: 2px; background: #fff; transform: translateX(-1px);
  pointer-events: none;
}
.ba-handle::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 38px; height: 38px; margin: -19px 0 0 -19px;
  border-radius: 50%; background: #fff;
  box-shadow: 0 4px 18px rgba(0,0,0,0.35);
}
.ba-handle::before {
  content: "‹ ›"; position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -50%); z-index: 2;
  color: #111; font-size: 0.9rem; letter-spacing: 0.05em;
}
.ba-tag { position: absolute; top: 12px; font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem; letter-spacing: 0.18em; color: rgba(255,255,255,0.75); }
.ba-tag.l { left: 14px; }
.ba-tag.r { right: 14px; }

/* Screenshot mode. The abstract version paints its own colour fields; with
   real images the panes have to be neutral, and the white hairline handle
   would vanish on a light screenshot, so it goes dark. */
.ba.is-media { background: var(--surface); }
.ba.is-media .ba-before,
.ba.is-media .ba-after { background: var(--surface); }
.ba.is-media .ba-pane > img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ba.is-media .ba-handle { background: var(--text); }
.ba.is-media .ba-handle::after { background: #fff; box-shadow: 0 2px 10px rgba(0,0,0,0.22); border: 1px solid var(--line); }
/* .media-tag is bottom-left everywhere else on the page, which here puts the
   after pane's label inside the clipped-away half and pushes the before
   pane's off the edge. Centre each label in the half you can actually see. */
.ba.is-media .ba-pane > .media-tag {
  top: 50%; bottom: auto; transform: translate(-50%, -50%);
  max-width: 44%; text-align: center; line-height: 1.4;
}
.ba.is-media .ba-before > .media-tag { left: 25%; }
.ba.is-media .ba-after > .media-tag { left: 75%; }
.ba.is-media .ba-tag {
  color: var(--text-faint);
  background: rgba(255,255,255,0.86);
  padding: 3px 8px; border-radius: 4px;
}
/* On a case study the page ends on the next case study, so the footer is
   reduced to the line of links. The wordmark band and the contact pitch were
   two more full-height things competing with the one link that matters. */
.site-footer.is-slim { padding-top: clamp(1.5rem, 3vw, 2.5rem); }
.site-footer.is-slim .footer-inner { border-top: 1px solid var(--line); padding-top: clamp(1.25rem, 2.5vw, 1.75rem); }

.figcap { font-size: 0.82rem; color: var(--text-faint); font-family: var(--font-mono); font-weight: 500; letter-spacing: 0.04em; }

/* shift pairs */
.shifts { display: flex; flex-wrap: wrap; gap: 0.75rem; }
.shift {
  display: inline-flex; align-items: center; gap: 0.65rem;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  padding: 0.5rem 1rem; font-size: 0.88rem;
  transition: border-color 0.4s var(--ease);
}
.shift:hover { border-color: var(--accent-ink); }
.shift b { font-weight: 700; }
.shift .from { color: var(--text-faint); }
.shift .to { color: var(--text); }
.shift i { color: var(--accent-ink); font-style: normal; }

/* evolution phases (accordion) */
.phases { display: grid; }
.phase { border-top: 1px solid var(--line); }
.phase:last-child { border-bottom: 1px solid var(--line); }
.phase-head {
  width: 100%;
  display: flex; align-items: center; gap: 1rem;
  padding: clamp(1rem, 2.2vw, 1.5rem);
  text-align: left;
  transition: background-color 0.4s var(--ease);
}
.phase-head:hover .phase-name { color: var(--accent-ink); }
.phase-tag {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.74rem; letter-spacing: 0.08em;
  color: var(--text-faint); flex: none;
  transition: color 0.4s var(--ease);
}
.phase.is-open .phase-tag { color: var(--accent-ink); }
.phase-name { font-size: var(--t-base); font-weight: 700; flex: 1; transition: color 0.3s var(--ease); }
.phase-chev { width: 16px; height: 16px; flex: none; transition: transform 0.45s var(--ease); fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; color: var(--text-faint); }
.phase.is-open .phase-chev { transform: rotate(180deg); }
.phase-panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.5s var(--ease); }
.phase.is-open .phase-panel { grid-template-rows: 1fr; }
.phase-panel > div { overflow: hidden; }
.phase-inner { padding: 0 clamp(1rem, 2.2vw, 1.5rem) clamp(1.2rem, 2.2vw, 1.6rem); display: grid; gap: 0.9rem; max-width: 60ch; }
.phase-inner p { color: var(--text-muted); }

/* loop diagram */
.loop { display: grid; grid-template-columns: repeat(6, 1fr); gap: 0.5rem; }
.loop-step {
  border-top: 1px solid var(--line);
  padding: 0.85rem 0 0;
  display: grid; gap: 0.45rem; align-content: start;
  text-align: left;
  position: relative;
  transition: border-color 0.4s var(--ease), background-color 0.4s var(--ease), transform 0.4s var(--ease);
}
.loop-step:hover, .loop-step.is-active { border-top-color: var(--text); }
/* connector between steps */
.loop-step + .loop-step::before { display: none; }
.loop-step .n { font-family: var(--font-mono); font-weight: 500; font-size: 0.74rem; color: var(--text-faint); }
.loop-step.is-active .n { color: var(--accent-ink); }
.loop-step .nm { font-size: var(--t-base); font-weight: 700; }
.loop-step .ds { font-size: 0.8rem; color: var(--text-muted); line-height: 1.45; opacity: 0; max-height: 0; transition: opacity 0.4s var(--ease), max-height 0.4s var(--ease); }
.loop-step:hover .ds, .loop-step.is-active .ds { opacity: 1; max-height: 8rem; }

/* what didn't work */
/* -------------------------------------------------------------------------
   QA + TREE — the spec, laid out the way the spec is laid out
   ------------------------------------------------------------------------- */
.qa { display: grid; gap: clamp(1.4rem, 3vw, 2.25rem); margin-top: clamp(0.5rem, 1.5vw, 1rem); }
.qa-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: 0.6rem clamp(1.5rem, 4vw, 3.5rem);
  padding-top: clamp(0.9rem, 2vw, 1.25rem);
  border-top: 1px solid var(--line);
}
/* The question is the heading for its row, not a label above it. */
.qa-q {
  grid-column: 1 / -1; margin: 0 0 0.5rem;
  font-size: clamp(1.05rem, 1.6vw, 1.3rem);
  font-weight: 600; letter-spacing: -0.01em; line-height: 1.3;
  color: var(--text);
}
.qa-lede { margin: 0; color: var(--text-muted); font-size: 0.98rem; line-height: 1.6; text-wrap: pretty; }
.qa-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; align-content: start; }
.qa-list li {
  position: relative; padding-left: 1.15rem;
  font-size: 0.98rem; line-height: 1.5;
}
.qa-list li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent);
}
@media (max-width: 700px) { .qa-row { grid-template-columns: 1fr; } }

/* the taxonomy, as a taxonomy */
.tree-scroll { overflow-x: auto; margin-top: clamp(0.5rem, 1.5vw, 1rem); padding-bottom: 0.5rem; }
.tree {
  display: grid;
  grid-template-columns: repeat(var(--n, 6), minmax(132px, 1fr));
  gap: clamp(0.85rem, 1.8vw, 1.4rem);
  min-width: min-content;
}
.tree-col {
  display: grid; gap: 0.5rem; align-content: start;
  padding-top: 0.7rem;
  border-top: 2px solid var(--accent);
}
.tree-head { font-size: 0.92rem; font-weight: 600; line-height: 1.3; letter-spacing: -0.01em; }
.tree-pat {
  font-family: var(--font-mono); font-size: 0.72rem; font-weight: 500;
  color: var(--accent-ink); line-height: 1.4;
  display: block;
}
.tree-vals { list-style: none; margin: 0.2rem 0 0; padding: 0; display: grid; gap: 0.28rem; }
.tree-vals li {
  font-family: var(--font-mono); font-size: 0.72rem; line-height: 1.35;
  color: var(--text-faint);
}
.tree-note { margin: 0.2rem 0 0; font-size: 0.78rem; line-height: 1.45; color: var(--text-muted); }
.tree-egs {
  margin-top: clamp(1.1rem, 2.4vw, 1.75rem);
  padding-top: clamp(0.9rem, 2vw, 1.25rem);
  border-top: 1px solid var(--line);
  display: grid; gap: 0.6rem;
}
.tree-egs-lbl {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-faint);
}
.tree-egs ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.45rem; }
.tree-egs li {
  font-family: var(--font-mono); font-size: 0.8rem;
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 20%, transparent);
  border-radius: 6px; padding: 0.3rem 0.65rem;
}

/* -------------------------------------------------------------------------
   SPEC + FORMULA — a rule set drawn rather than described
   ------------------------------------------------------------------------- */
.spec { list-style: none; margin: clamp(0.5rem, 1.5vw, 1rem) 0 0; padding: 0; display: grid; }
.spec-item {
  display: grid; gap: 0.6rem;
  padding-block: clamp(0.95rem, 2vw, 1.35rem);
  border-top: 1px solid var(--line);
}
.spec-item:last-child { border-bottom: 1px solid var(--line); }
.spec-top { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 1rem; }
.spec-ttl { font-size: clamp(1rem, 1.5vw, 1.15rem); font-weight: 600; letter-spacing: -0.01em; }
.spec-pat {
  font-family: var(--font-mono); font-size: 0.82rem; font-weight: 500;
  color: var(--accent-ink);
  background: color-mix(in srgb, var(--accent) 22%, transparent);
  padding: 0.2rem 0.55rem; border-radius: 5px;
  white-space: nowrap;
}
.spec-body { margin: 0; color: var(--text-muted); font-size: 0.95rem; line-height: 1.55; }
.spec-chips { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 0.35rem; }
.spec-chips li {
  font-family: var(--font-mono); font-size: 0.72rem; font-weight: 500;
  color: var(--text-faint);
  border: 1px solid var(--line); border-radius: 999px;
  padding: 0.22rem 0.6rem;
}

/* the equation, set as one */
.fx-wrap {
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--surface);
  padding: clamp(1.25rem, 3vw, 2.25rem);
  display: grid; gap: clamp(1.1rem, 2.4vw, 1.75rem);
  margin-top: clamp(0.5rem, 1.5vw, 1rem);
}
.fx-eq {
  margin: 0;
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.4rem 0.7rem;
  font-size: clamp(1.15rem, 2.2vw, 1.75rem);
  font-weight: 700; letter-spacing: -0.02em;
}
.fx-op { color: var(--text-faint); font-weight: 400; }
.fx-1 { color: var(--text); }
.fx-2 { color: var(--accent-ink); }
.fx-3 { color: var(--text-faint); font-style: italic; font-weight: 600; }
.fx.is-opt { border-bottom: 1px dashed currentColor; }
.fx-out { color: var(--text); border-bottom: 3px solid var(--accent); }
.fx-legend { display: grid; gap: 0.4rem; }
.fx-leg { margin: 0; font-size: 0.9rem; color: var(--text-muted); line-height: 1.5; }
.fx-leg b { font-weight: 700; margin-right: 0.5rem; }
.fx-eg { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.55rem; }
.fx-eg li {
  font-family: var(--font-mono); font-size: 0.88rem;
  padding-top: 0.55rem; border-top: 1px solid var(--line);
}
.fx-eg .fx-1 { font-weight: 500; }
.fx-eg .fx-3 { font-style: italic; }
@media (max-width: 560px) {
  .fx-eq { font-size: 1.05rem; }
  .spec-pat { white-space: normal; }
}

/* shipped versions, folded away */
.vers { display: grid; }
.vers-row { border-top: 1px solid var(--line); }
.vers-row:last-of-type { border-bottom: 1px solid var(--line); }
.vers-row.is-live { border-top: 2px solid var(--accent); }
/* Flex, not grid: a row with a state pill has one more child than a row
   without, so any fixed column count stretched the pill across the gap. */
.vers-sum {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.8rem;
  padding: clamp(0.95rem, 2vw, 1.25rem) 0;
  cursor: pointer;
  list-style: none;
}
.vers-sum::-webkit-details-marker { display: none; }
.vers-sum:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 3px; }
.vers-tag { font-family: var(--font-mono); font-weight: 500; font-size: 0.74rem; letter-spacing: 0.12em; color: var(--text-faint); }
.vers-name { font-size: clamp(1.05rem, 1.6vw, 1.3rem); font-weight: 600; letter-spacing: -0.012em; }
.vers-state {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.6rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--text); background: var(--accent);
  border-radius: 999px; padding: 0.16rem 0.48rem; align-self: center;
  flex: 0 0 auto; white-space: nowrap;
}
.vers-teaser { color: var(--text-muted); font-size: 0.92rem; min-width: 0; flex: 1 1 12rem; }
.vers-chev {
  width: 9px; height: 9px; align-self: center; margin-left: auto; flex: 0 0 auto;
  border-right: 1.5px solid var(--text-faint); border-bottom: 1.5px solid var(--text-faint);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 0.2s ease;
}
.vers-row[open] .vers-chev { transform: rotate(-135deg) translate(-2px, -2px); }
.vers-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr);
  gap: clamp(1.25rem, 3vw, 2.75rem);
  align-items: start;
  padding: 0.35rem 0 clamp(1.5rem, 3vw, 2.25rem);
}
.vers-copy { display: grid; gap: 0.5rem; align-content: start; }
.vers-rows { margin: 0; display: grid; gap: 0.1rem; }
.vers-rows dt {
  font-family: var(--font-mono); font-weight: 500; font-size: 0.66rem;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-ink);
  margin-top: 0.7rem;
}
.vers-rows dt:first-child { margin-top: 0; }
.vers-rows dd { margin: 0; font-size: 0.95rem; line-height: 1.55; color: var(--text-muted); text-wrap: pretty; }
.vers .chips { margin-top: 0.7rem; }
.vers-fig { margin: 0; display: grid; gap: 0.6rem; }
@media (max-width: 760px) { .vers-body { grid-template-columns: 1fr; } }

/* feature cards that share one picture */
.showcase { display: grid; gap: clamp(1.25rem, 2.6vw, 2rem); }
.cs-section > .showcase { margin-top: clamp(0.75rem, 2vw, 1.9rem); }
.show-cards {
  display: grid;
  grid-template-columns: repeat(var(--n, 3), minmax(0, 1fr));
  gap: clamp(1.25rem, 3vw, 2.5rem);
}
.show-cards[data-n="2"] { --n: 2; }
.show-cards[data-n="4"] { --n: 4; }
/* the card is a button, so undo the button */
.show-card {
  all: unset;
  display: grid; gap: 0.6rem; align-content: start;
  text-align: left; cursor: pointer;
  padding-top: 0.85rem; border-top: 2px solid transparent;
  transition: border-color 0.25s var(--ease);
}
.show-card h3 { font-size: clamp(1.05rem, 1.6vw, 1.25rem); font-weight: 600; letter-spacing: -0.012em; }
.show-card p { color: var(--text-muted); font-size: 0.94rem; line-height: 1.55; }
.show-card .pillar-ico { transition: transform 0.25s var(--ease); }
.show-card.is-on { border-top-color: var(--accent); }
.show-card:hover .pillar-ico, .show-card.is-on .pillar-ico { transform: translateY(-2px); }
.show-card:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 4px; border-radius: 4px; }
.show-fig { margin: 0; }
@media (max-width: 760px) {
  .show-cards { grid-template-columns: 1fr; gap: 1.25rem; }
}

.honest { display: grid; gap: clamp(1.5rem, 3vw, 2.25rem); }
/* Three short admissions read better side by side than as a stack: nobody
   scrolls a list of caveats, but they will scan a row of three. */
.honest.is-row { grid-template-columns: repeat(var(--n, 3), minmax(0, 1fr)); gap: clamp(1.25rem, 2.6vw, 2.25rem); }
.honest.is-row[data-n="2"],
.honest.is-row[data-n="4"] { --n: 2; }
.honest.is-row .honest-item p { font-size: 0.92rem; line-height: 1.55; max-width: none; }
.honest.is-row .honest-item h3 { font-size: clamp(1rem, 1.5vw, 1.15rem); }
@media (max-width: 760px) { .honest.is-row { grid-template-columns: 1fr; } }
.honest-item { padding-top: 0.85rem; border-top: 1px solid var(--line); display: grid; gap: 0.35rem; }
.honest-item h3 { display: flex; align-items: center; gap: 0.6rem; }
.honest-item h3::before { display: none; }
.honest-item p { color: var(--text-muted); max-width: 68ch; }

/* locked / confidential */
.locked {
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-lg);
  padding: clamp(1.75rem, 4vw, 3rem);
  display: grid; gap: 1rem; justify-items: center; text-align: center;
  background: var(--surface);
}
.locked svg.lock { width: 26px; height: 26px; fill: none; stroke: var(--text-faint); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.locked form { display: flex; gap: 0.5rem; flex-wrap: wrap; justify-content: center; margin-top: 0.4rem; }
.locked input {
  background: var(--bg); border: 1px solid var(--line-strong); border-radius: var(--r-pill);
  padding: 0.7rem 1.1rem; color: var(--text); font: inherit; font-size: 0.9rem; min-width: 200px;
  transition: border-color 0.3s var(--ease);
}
.locked input:focus { border-color: var(--accent-ink); outline: none; }
.locked.is-wrong { animation: shake 0.45s var(--ease-in-out); }
@keyframes shake {
  10%, 90% { transform: translateX(-2px); }
  20%, 80% { transform: translateX(4px); }
  30%, 50%, 70% { transform: translateX(-7px); }
  40%, 60% { transform: translateX(7px); }
}
.locked-hint { font-size: 0.78rem; color: var(--text-faint); font-family: var(--font-mono); font-weight: 500; }

/* the picture-with-a-lock-on-it variant */
.locked-wrap { position: relative; }
.locked-wrap .block-figs { margin: 0; }
.locked-wrap.is-blurred .stat-row,
.locked-wrap.is-blurred .media-slot > img,
.locked-wrap.is-blurred .media-slot > video {
  filter: blur(22px) saturate(0.85);
  transform: scale(1.08);
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  transition: filter 0.7s var(--ease), transform 0.7s var(--ease);
}
.locked-wrap .stat-row,
.locked-wrap .media-slot > img,
.locked-wrap .media-slot > video { transition: filter 0.7s var(--ease), transform 0.7s var(--ease); }
/* numbers do not need the scale-up that hides a picture's blurred edge, and
   the row needs room for the lock card to sit on */
.locked-wrap.is-blurred .stat-row { transform: none; min-height: 300px; align-content: center; }
.locked-wrap:has(.stat-row) { padding-block: 0.5rem; }
.locked-wrap.is-blurred .media-slot { overflow: hidden; }
.locked-wrap.is-blurred .media-zoom,
.locked-wrap.is-blurred .figcap { visibility: hidden; }
.locked.is-overlay {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(440px, calc(100% - 2rem));
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
  border-style: solid; border-color: var(--line);
  box-shadow: 0 18px 50px -20px rgba(10, 13, 16, 0.35);
  padding: clamp(1.4rem, 3vw, 2.25rem);
}
.locked.is-overlay.is-wrong { animation: shake 0.45s var(--ease-in-out); transform: translate(-50%, -50%); }
@keyframes shakeOverlay {
  10%, 90% { transform: translate(calc(-50% - 2px), -50%); }
  20%, 80% { transform: translate(calc(-50% + 4px), -50%); }
  30%, 50%, 70% { transform: translate(calc(-50% - 6px), -50%); }
  40%, 60% { transform: translate(calc(-50% + 6px), -50%); }
}
.locked.is-overlay.is-wrong { animation-name: shakeOverlay; }
/* the whole-study variant: one screen of blurred study, the card on top */
.page-lock { position: relative; }
.page-lock.is-blurred { max-height: 92vh; overflow: hidden; }
.page-lock.is-blurred .cs-body {
  filter: blur(14px) saturate(0.8);
  pointer-events: none; user-select: none;
  transition: filter 0.9s var(--ease);
}
.page-lock .cs-body { transition: filter 0.9s var(--ease); }
/* fade the clamped study out at the bottom so the cut does not read as a bug */
.page-lock.is-blurred::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 40%;
  background: linear-gradient(to bottom, transparent, var(--bg));
  pointer-events: none;
}
.locked.is-overlay.is-page { top: 42%; z-index: 2; }
.page-lock.is-blurred .cs-toc { visibility: hidden; }

@media (max-width: 600px) {
  .locked.is-overlay { padding: 1.1rem; }
  .locked.is-overlay input { min-width: 0; width: 100%; }
}

/* the NDA gate — a real lock, so it gets a real screen */
.gate {
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-lg);
  padding: clamp(2rem, 5vw, 3.5rem);
  display: grid;
  gap: 1rem;
  justify-items: center;
  text-align: center;
  background: var(--surface);
  max-width: 40rem;
  margin-inline: auto;
}
/* Bigger, and drawn in ink rather than lime. It is the only thing on the page
   before the password, so it carries the whole moment. */
.gate svg.lock { width: 46px; height: 46px; fill: none; stroke: var(--text); stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.gate .h3 { font-size: clamp(1.4rem, 2.6vw, 1.9rem); letter-spacing: -0.02em; line-height: 1.2; }
.gate .muted { font-size: clamp(1rem, 1.5vw, 1.08rem); line-height: 1.6; max-width: 44ch; }
.gate form { display: flex; gap: 0.5rem; flex-wrap: wrap; justify-content: center; margin-top: 0.5rem; }
.gate input {
  background: var(--bg);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  padding: 0.75rem 1.15rem;
  color: var(--text);
  font: inherit; font-size: 0.92rem;
  min-width: 230px;
  transition: border-color 0.3s var(--ease);
}
.gate input:focus { border-color: var(--accent-ink); outline: none; }
.gate button[disabled] { opacity: 0.55; pointer-events: none; }
.gate-msg { font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem; letter-spacing: 0.08em; color: var(--text-faint); min-height: 1.2em; }
.gate.is-wrong { animation: shake 0.45s var(--ease-in-out); }
.gate.is-wrong .gate-msg { color: var(--accent-ink); }

/* closing statement */
.cs-closing { display: grid; gap: 0.6rem; padding-block: clamp(3rem, 7vw, 6rem); }
.cs-closing p { font-size: clamp(1.35rem, 3vw, 2.2rem); line-height: 1.25; letter-spacing: -0.028em; }
.cs-closing p.dim { color: var(--text-faint); }

/* next case study */
.next-cs {
  display: block;
  border-top: 1px solid var(--line);
  padding-block: clamp(3rem, 7vw, 5.5rem);
  position: relative;
  overflow: hidden;
}
.next-cs::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: var(--accent-grad); opacity: 0;
  transform: translateY(100%);
  transition: transform 0.7s var(--ease), opacity 0.7s var(--ease);
}
.next-cs:hover::before { display: none; }
.next-cs .wrap { position: relative; z-index: 1; }
.next-cs h2 { transition: color 0.3s var(--ease); margin-block: 0.5rem 0.9rem; }
.next-cs .lead { max-width: 60ch; }

/* =========================================================================
   CONTACT + FOOTER
   ========================================================================= */
/* Top and bottom set separately: the rail above already carries its own
   spacing, and a symmetric 8rem put 282px between the last photograph and
   this line, against 166px everywhere else on the page. */
.contact { border-top: 1px solid var(--line); padding-block: clamp(2rem, 4vw, 3.1rem) clamp(2rem, 4vw, 3.5rem); position: relative; overflow: hidden; }
.contact-inner { display: flex; flex-direction: column; align-items: center; text-align: center; }
.contact-inner .label { letter-spacing: 0.22em; }
.contact-support { max-width: 46ch; color: var(--text-muted); }
.contact-mail {
  display: inline-flex; align-items: center; gap: 0.5rem;
  font-size: clamp(1.75rem, 6.4vw, 4.5rem);
  letter-spacing: -0.04em; font-weight: 500;
  margin-block: clamp(1.25rem, 3vw, 2.25rem) clamp(1rem, 2.5vw, 1.75rem);
  position: relative;
  max-width: 100%;
  word-break: break-word;
}
.contact-mail svg { width: 0.6em; height: 0.6em; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; transition: transform 0.45s var(--ease); }
.contact-mail { transition: color 0.35s var(--ease); }
.contact-mail:hover svg { transform: translate(5px, -5px); }
/* Key lime, but behind the words rather than in them: #ccff33 as 4.5rem text
   on white is 1.4:1 and unreadable. As a swipe under near-black type it is
   the brightest thing on the page and still passes. */
.contact-mail::after {
  content: ""; position: absolute; z-index: -1;
  left: -0.06em; right: -0.06em; bottom: 0.04em; top: 0.16em;
  border-radius: 3px;
  background: var(--accent);
  transform: scaleX(0); transform-origin: right;
  transition: transform 0.55s var(--ease);
}
.contact-mail:hover::after { transform: scaleX(1); transform-origin: left; }

/* isolate so z-index:-1 stays inside the link and not behind the section */
.contact-mail { isolation: isolate; }

.site-footer {
  border-top: 1px solid var(--line); padding-block: 2rem 2.25rem; margin-top: 0;
}
.footer-inner { display: flex; flex-wrap: wrap; gap: 1rem 2rem; justify-content: space-between; align-items: center; font-size: 0.85rem; color: var(--text-muted); }
/* Icons only, black, each in its own square so the hit area is generous.
   The hover wash goes on the whole strip, not the icon: the footer is the
   thing in focus, the icon under the cursor just lifts. */
.footer-links { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.footer-links a {
  display: inline-grid; place-items: center;
  width: 52px; height: 52px; border-radius: 12px;
  color: var(--text);
  transition: color 0.3s var(--ease), background-color 0.3s var(--ease);
}
.footer-links a svg { width: 27px; height: 27px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; transition: transform 0.3s var(--ease); }
.footer-links a:hover svg { transform: translateY(-2px); }
.footer-links a { background-size: 0% 100%; }
.footer-links a:hover { background-size: 100% 100%; }
.footer-links a:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: 2px; }
.footer-time { font-family: var(--font-mono); font-weight: 500; font-size: 0.9rem; color: var(--text-muted); }

/* =========================================================================
   BOOK PAGE
   ========================================================================= */
.slot-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(1rem, 2.5vw, 1.75rem); }
.slot {
  border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: clamp(1.5rem, 3vw, 2.25rem);
  display: grid; gap: 0.75rem; align-content: start;
  position: relative;
  transition: border-color 0.45s var(--ease), transform 0.45s var(--ease);
}
.slot:hover { border-color: var(--line-strong); transform: translateY(-4px); }
.slot .dur { font-family: var(--font-mono); font-weight: 500; font-size: 0.72rem; letter-spacing: 0.14em; color: var(--accent-ink); }
.slot p { color: var(--text-muted); font-size: 0.95rem; }
.slot .btn { justify-self: start; margin-top: 0.5rem; }
.slot-badge {
  position: absolute; top: 1rem; right: 1rem;
  font-family: var(--font-mono); font-weight: 500; font-size: 0.74rem; letter-spacing: 0.14em; text-transform: uppercase;
  background: var(--accent); color: var(--on-accent); border-radius: var(--r-pill); padding: 0.2rem 0.6rem;
}

/* =========================================================================
   PAGE HEAD (inner pages) + transitions
   ========================================================================= */
.page-head { padding-top: calc(var(--nav-h) + clamp(3.5rem, 10vw, 7.5rem)); padding-bottom: clamp(2rem, 5vw, 3.5rem); position: relative; }
.page-head::before { content: ""; position: absolute; inset: 0 0 auto 0; height: 130%; background: var(--glow); pointer-events: none; }
.page-head > .wrap { position: relative; }
.page-head h1 { max-width: 20ch; margin-block: 1rem 1.25rem; }
/* the case-studies page: a short title, less air, so both rows of cards are
   in reach on the first screen */
.page-head:has(.work-h1) { padding-top: calc(var(--nav-h) + clamp(2rem, 5vw, 3.5rem)); padding-bottom: clamp(1.25rem, 2.5vw, 2rem); }
.work-h1 { max-width: 75%; margin-block: 0 0; }

/* ---- the case-studies rail --------------------------------------------- */
.wrail-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 1.5rem; flex-wrap: wrap; }
.wrail-nav { display: flex; align-items: center; gap: 0.5rem; padding-bottom: 0.35rem; }
.wrail-count { font-family: var(--font-mono); font-weight: 500; font-size: var(--t-label); letter-spacing: 0.1em; color: var(--text-faint); margin-right: 0.75rem; display: inline-flex; gap: 0.35em; }
.wrail-count b { color: var(--text); font-weight: 600; }
.wrail-btn {
  width: 44px; height: 44px; border-radius: 50%; border: 1.5px solid var(--text); background: var(--bg); color: var(--text);
  display: grid; place-items: center; cursor: pointer;
  transition: background 0.3s var(--ease), border-color 0.3s var(--ease), opacity 0.3s var(--ease);
}
.wrail-btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.wrail-btn:hover { background: var(--accent); border-color: var(--accent); }
.wrail-btn:disabled { opacity: 0.3; cursor: default; background: var(--bg); border-color: var(--text); }
.wrail {
  overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory;
  scrollbar-width: none; cursor: grab; outline: none;
  /* the track starts at the column edge and the last card can still snap
     to it, so the padding on the right is the leftover of the page */
  padding-inline: calc(max(0px, (100vw - var(--wrap)) / 2) + var(--gutter));
  scroll-padding-inline: calc(max(0px, (100vw - var(--wrap)) / 2) + var(--gutter));
  padding-block: 0.5rem 2.5rem;
}
.wrail::-webkit-scrollbar { display: none; }
.wrail.is-dragging { cursor: grabbing; scroll-snap-type: none; }
.wrail.is-dragging .work-card { pointer-events: none; }
.wrail:focus-visible { outline: 2px solid var(--accent-ink); outline-offset: -2px; }
.wrail-track { display: flex; gap: clamp(1rem, 2vw, 1.75rem); width: max-content; }
.wrail-card {
  /* about three in view: the one in focus at full size, the next two a step
     smaller behind it. No fade; the size difference is the whole cue. */
  flex: 0 0 auto; width: min(560px, 44vw); scroll-snap-align: start;
  transform: scale(0.9); transform-origin: left center;
  transition: transform 0.5s var(--ease), box-shadow 0.35s var(--ease);
  user-select: none; -webkit-user-drag: none;
}
.wrail-card.is-on { transform: none; }
.wrail-card .work-card-body { padding: 1.1rem 1.3rem 1.25rem; }
.wrail-card h3 { font-size: clamp(1.1rem, 1.5vw, 1.3rem); }
@media (max-width: 760px) { .wrail-card { width: 80vw; } }
@media (prefers-reduced-motion: reduce) { .wrail-card { transform: none; } }
.work-card:hover { box-shadow: 0 1px 2px rgba(10, 13, 16, 0.06), 0 22px 44px -16px rgba(10, 13, 16, 0.24); }
.page-head .lead { max-width: 54ch; }

main { transition: opacity 0.32s var(--ease); }
body.is-leaving main { opacity: 0; }

/* =========================================================================
   RESUME — one document, two outputs
   On screen it is the site: black, lime, mono. In print it flips to
   ink-on-white and folds to a single sheet. The print block lives at the very
   bottom of this file so it wins without needing !important everywhere.
   ========================================================================= */
.resume {
  max-width: 60rem;
  margin-inline: auto;
  padding-top: calc(var(--nav-h) + clamp(2.5rem, 6vw, 5rem));
  padding-inline: var(--gutter);
}

.cv-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1.5rem 2rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--line);
}
.cv-name {
  font-size: clamp(2rem, 4vw, 3rem);
  letter-spacing: -0.035em;
  line-height: 1;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
}
.cv-role {
  font-family: var(--font-mono); font-weight: 500;
  font-size: 0.74rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-top: 0.6rem;
}
.cv-contact {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.1rem;
  font-size: 0.86rem;
  color: var(--text-muted);
}
.cv-contact a { border-bottom: 1px solid var(--line-strong); padding-bottom: 1px; transition: color 0.3s var(--ease), border-color 0.3s var(--ease); }
.cv-contact a:hover { color: var(--accent-ink); border-color: var(--accent-ink); }

.cv-summary {
  font-size: clamp(1.05rem, 1.5vw, 1.25rem);
  line-height: 1.5;
  letter-spacing: -0.015em;
  max-width: 62ch;
  margin-top: 1.5rem;
}

.cv-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 2rem;
  margin-top: 1.25rem;
  font-family: var(--font-mono); font-weight: 500;
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.cv-stats b { color: var(--accent-ink); font-size: 0.95rem; letter-spacing: -0.01em; }

.cv-body {
  display: grid;
  grid-template-columns: minmax(0, 2.1fr) minmax(0, 1fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  margin-top: clamp(2rem, 4vw, 3rem);
  padding-bottom: clamp(2rem, 5vw, 4rem);
}

.cv-h {
  font-family: var(--font-mono);
  font-size: 0.64rem;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding-bottom: 0.5rem;
  margin-bottom: 1.1rem;
  border-bottom: 1px solid var(--line);
}

.cv-job { margin-bottom: 1.65rem; break-inside: avoid; }
.cv-job-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0.25rem 1rem; }
.cv-job h3 { font-size: 1.02rem; letter-spacing: -0.005em; font-weight: 700; }
.cv-job-role { color: var(--text-muted); font-weight: 500; }
.cv-period { font-family: var(--font-mono); font-weight: 500; font-size: 0.66rem; letter-spacing: 0.1em; color: var(--text-faint); white-space: nowrap; }

.cv-points { margin-top: 0.5rem; display: grid; gap: 0.3rem; }
.cv-points li {
  position: relative;
  padding-left: 0.95rem;
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--text-muted);
}
.cv-points li::before {
  content: "";
  position: absolute; left: 0; top: 0.62em;
  width: 5px; height: 1px;
  background: var(--accent);
}

.cv-block { margin-bottom: 1.65rem; break-inside: avoid; }
.cv-list { font-size: 0.88rem; line-height: 1.65; color: var(--text-muted); }
.cv-school { font-size: 0.95rem; font-weight: 700; }
.cv-degree { font-size: 0.88rem; color: var(--text-muted); margin-top: 0.15rem; }

.cv-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.65rem;
  max-width: 60rem;
  margin: 0 auto clamp(3rem, 7vw, 6rem);
  padding-inline: var(--gutter);
}

.print-only { display: none; }

@media (max-width: 760px) {
  .cv-body { grid-template-columns: 1fr; }
}

/* toast */
.toast {
  position: fixed; z-index: 200;
  left: 50%; bottom: 28px; transform: translate(-50%, 20px);
  background: var(--text); color: var(--bg);
  padding: 0.6rem 1.1rem; border-radius: var(--r-pill);
  font-size: 0.85rem; font-weight: 500;
  opacity: 0; pointer-events: none;
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
}
.toast.is-on { opacity: 1; transform: translate(-50%, 0); }

/* =========================================================================
   RESPONSIVE
   ========================================================================= */
@media (max-width: 1024px) {
  .num-grid { grid-template-columns: repeat(2, 1fr); }
  .num-grid > *, .num-grid[data-n] > *, .num-grid[data-n] > *:nth-child(n + 4),
  .num-grid[data-n] > *:last-child { grid-column: auto; }
  .steps { grid-template-columns: repeat(2, 1fr); }
  .loop { grid-template-columns: repeat(3, 1fr); }
  .cs-body { grid-template-columns: 1fr; }
  .cs-toc { display: none; }
}

@media (max-width: 860px) {
  .nav-links { display: none; }
  .nav-burger { display: grid; }
  .split, .split-narrow { grid-template-columns: 1fr; }
  .facets { grid-template-columns: 1fr; }
  .case-grid { grid-template-columns: 1fr; }
  .cs-facts { grid-template-columns: repeat(2, 1fr); }
  .stat-row { grid-template-columns: repeat(2, 1fr); }
  .stat-row > *, .stat-row[data-n] > *, .stat-row[data-n] > *:nth-child(n + 4) { grid-column: auto; }
  .slot-grid { grid-template-columns: 1fr; }
  .tl-row { grid-template-columns: 1fr; gap: 0.75rem; }
}

@media (max-width: 620px) {
  .num-grid { grid-template-columns: 1fr; }
  .stat-row, .stat-row[data-n] > * { grid-column: auto; }
  .steps { grid-template-columns: 1fr; }
  .loop { grid-template-columns: 1fr !important; }
  .loop-step .ds { opacity: 1; max-height: none; }
  .loop-step + .loop-step::before { display: none; }
  .cs-facts { grid-template-columns: 1fr; }
}

/* =========================================================================
   REDUCED MOTION
   ========================================================================= */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  [data-reveal], .hero-word { opacity: 1 !important; transform: none !important; }
  [data-reveal="draw"] svg > * { stroke-dashoffset: 0 !important; opacity: 1 !important; }
}


/* =========================================================================
   PRINT — the same document, as ink on paper
   Everything chrome-like goes; the palette inverts; the grid tightens so a
   four-role resume lands on one sheet.
   ========================================================================= */
@media print {
  @page { size: A4; margin: 12mm 12mm 10mm; }

  html, body {
    background: #fff !important;
    color: #111 !important;
    font-size: 10.6pt;
    line-height: 1.45;
  }

  /* site furniture has no business on paper */
  .site-header, .site-footer, .nav-drawer, .toast,
  .cv-actions, .screen-only, .hero, .contact, .progress-bar, .dot-grid, .name-band {
    display: none !important;
  }
  .print-only { display: block !important; }
  li.print-only { display: list-item !important; }

  .resume {
    max-width: none;
    margin: 0;
    padding: 0;
  }

  a { color: #111 !important; text-decoration: none; border: 0 !important; }

  .cv-head { padding-bottom: 9pt; border-bottom: 0.5pt solid #bbb; gap: 7pt 16pt; }
  .cv-name { font-size: 25pt; letter-spacing: -0.022em; }
  /* the pronunciation control is a screen affordance; paper keeps the phonetic */
  .say-btn { display: none !important; }
  .say-ipa { color: #666 !important; font-size: 9pt; margin-left: 6pt; }
  .cv-role { font-size: 8.2pt; color: #555 !important; margin-top: 4pt; letter-spacing: 0.1em; }
  .cv-contact { font-size: 9.2pt; color: #333 !important; gap: 3pt 12pt; }

  .cv-summary { font-size: 11.4pt; margin-top: 11pt; max-width: none; letter-spacing: -0.005em; line-height: 1.4; }

  .cv-stats { margin-top: 9pt; font-size: 8pt; color: #555 !important; gap: 4pt 16pt; }
  .cv-stats b { color: #111 !important; font-size: 9.6pt; }

  .cv-body {
    grid-template-columns: 2.15fr 1fr;
    gap: 18pt;
    margin-top: 15pt;
    padding-bottom: 0;
  }

  .cv-h {
    font-size: 7.8pt;
    color: #666 !important;
    border-bottom: 0.5pt solid #ccc;
    padding-bottom: 4pt;
    margin-bottom: 9pt;
    letter-spacing: 0.16em;
  }

  .cv-job { margin-bottom: 12pt; }
  .cv-job h3 { font-size: 10.8pt; }
  .cv-job-role { color: #444 !important; }
  .cv-period { font-size: 8pt; color: #666 !important; }
  .cv-points { margin-top: 4pt; gap: 2.5pt; }
  .cv-points li { font-size: 9.9pt; line-height: 1.4; color: #222 !important; padding-left: 9pt; }
  .cv-points li::before { background: #111 !important; width: 4pt; top: 0.58em; }

  .cv-block { margin-bottom: 12pt; }
  .cv-list { font-size: 9.4pt; line-height: 1.5; color: #222 !important; }
  .cv-school { font-size: 10.2pt; }
  .cv-degree { font-size: 9.4pt; color: #333 !important; }

  .cv-print-note {
    margin-top: 14pt;
    padding-top: 6pt;
    border-top: 0.5pt solid #ddd;
    font-size: 8pt;
    color: #777 !important;
    letter-spacing: 0.06em;
  }

  /* nothing should orphan across the fold */
  h1, h2, h3 { break-after: avoid; }
}


/* =========================================================================
   MOBILE PASS  —  keep this LAST in the file
   Measured at 390x844. Two classes of problem, both invisible on a desktop:
   links people tap that are 20-38px tall, and editorial type down at 9px that
   works at arm's length on a monitor and not at all in a hand.

   It lives at the end because it is all single-class selectors overriding
   other single-class selectors; sitting mid-file it lost to every later rule.
   `screen and` matters too — the resume prints to a one-page A4 budget and a
   bare max-width query leaks into print.
   ========================================================================= */
@media screen and (max-width: 640px) {
  /* --- tap targets: 44px floor on everything reachable ------------------ */
  .site-header .nav-link,
  .site-header .brand,
  .site-header .btn,
  .nav-drawer-foot a,
  .footer-inner a,
  .footer-links a,
  .cv-contact a,
  .back-link,
  .btn,
  .link-arrow {
    display: inline-flex; align-items: center; min-height: 44px;
  }
  .site-header .btn, .btn { padding-block: 0; }
  /* the drawer links are the primary navigation on a phone, so they get the
     most room of any of these */
  .nav-drawer-foot { gap: 0 1.4rem; }
  .nav-burger { width: 44px; height: 44px; }
  .footer-links { gap: 0 1.4rem; }
  .footer-inner { gap: 0.25rem 2rem; }
  /* the link grew by 24px; pull the block back so the page head does not */
  .back-link { margin-top: -0.6rem; margin-bottom: -0.4rem; }

  /* --- type floor: nothing below ~11.5px ------------------------------- */
  .ttl-tag { font-size: 0.72rem; }
  .work-meta, .work-meta span { font-size: 0.76rem; }
  .work-thumb-ph { font-size: 0.72rem; }
  .rail-ph { font-size: 0.72rem; }
  .flow-n, .flow-tag, .jwhen, .cf-count, .role-cell .tag, .qcard figcaption { font-size: 0.72rem; }
  .dur, .portrait-ph, .cfield label { font-size: 0.72rem; }
  .cv-h, .cv-period, .cv-role { font-size: 0.78rem; }
  .idx, .label, .figcap, .gal .figcap { font-size: 0.75rem; }
  .gal-slot span, .media-tag, .scrap-slot span, .phone-screen span { font-size: 0.72rem; }
  .matrix .ax, .mq-name { font-size: 0.72rem; }
  .cs-facts dt, .cs-fact dt { font-size: 0.72rem; }
  .tension-key, .co-key, .tlabel { font-size: 0.72rem; }
  .callout-who, .cs-fact dd span, .metric sub, .stat sub { font-size: 0.72rem; }

  /* --- the form is the one thing people actually type into -------------- */
  /* 16px or iOS zooms the page on focus and never zooms back out */
  .cfield input, .cfield textarea { font-size: 16px; }
  .cf-actions .btn { width: 100%; justify-content: center; min-height: 48px; }
}
