@import url("tokens.css");
* {
  box-sizing: border-box;
}
html {
  overflow-x: clip;
  scroll-behavior: smooth;
}
body {
  min-width: 320px;
  margin: 0;
  overflow-x: clip;
  color: var(--ink);
  background: var(--paper);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
}
body::before {
  position: fixed;
  z-index: 20;
  inset: 0;
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 180 180' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  content: "";
}
a {
  color: inherit;
  text-decoration: none;
}
a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 3px;
}
.work .case-link:focus-visible,
.closing .email:focus-visible,
.closing-bottom a:focus-visible {
  outline-color: var(--paper);
}
h1,
h2,
h3,
p {
  margin-top: 0;
}
.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  /* viewport-fit=cover hands us the whole screen, including the corners the
     browser used to keep clear — see the .header note. In landscape that puts
     the notch inside the page, so the gutter has to be at least as wide as the
     inset. Both insets are 0 everywhere else, so this is the plain gutter on a
     desktop. */
  padding-right: max(var(--gutter), env(safe-area-inset-right));
  padding-left: max(var(--gutter), env(safe-area-inset-left));
}
.mono {
  font: var(--text-label) / 1.4 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
}
/* Archivo Black only ships at 400. Anything that lands on a bold element —
   h1, strong — asks for 700, which Chromium ignores but WebKit answers by
   synthesising the bold, setting the type about 5% wider and slightly
   smeared. Naming the weight is what keeps Safari matching everything else. */
.display {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: var(--tracking-display);
}

/* The bar owns the status-bar strip. Safari 26 lays the page out edge to edge
   and paints scrolling content behind the clock, but a page left on the
   default viewport-fit insets its own sticky and fixed elements to the safe
   area — so the mobile bar parked itself below the strip and the page ran
   visibly through the gap above it. Taking viewport-fit=cover (see the meta
   tag on every page) puts the bar back at the true top of the screen, and this
   padding is what keeps the name and the contact link out from under the
   clock. box-sizing is border-box everywhere here, so the inset has to be
   added to min-height too or the padding would eat the bar instead of
   growing it. Every inset is 0 on a desktop, which leaves that composition
   exactly where it was. */
.header {
  position: relative;
  z-index: 1;
  min-height: calc(73px + env(safe-area-inset-top));
  padding-top: env(safe-area-inset-top);
  align-items: center;
  border-bottom: 1px solid var(--line);
}
.brand {
  grid-column: span 3;
  font:
    500 18px "Libre Baskerville",
    Georgia,
    serif;
  letter-spacing: -0.055em;
}
.brand span {
  color: var(--red);
}
.header nav {
  grid-column: 5 / span 4;
  display: flex;
  justify-content: space-between;
}
.header nav a,
.header .linkedin,
.header .contact {
  font: var(--text-label) / 1.2 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  text-transform: uppercase;
}
.header nav a:hover,
.header .linkedin:hover,
.header .contact:hover {
  color: var(--olive);
}
.header .linkedin {
  grid-column: 9 / span 2;
  justify-self: end;
}
.header .contact {
  grid-column: 11 / span 2;
  justify-self: end;
  /* Keep the ↗ on the same line as the label; below ~360px it otherwise
     wraps alone onto a second line and pushes the header out of alignment. */
  white-space: nowrap;
}

.hero {
  position: relative;
  /* One screen minus the bar. Under viewport-fit=cover the small viewport
     includes the strips the system UI sits on, so they come off the top of
     the hero the same way the header does. */
  min-height: calc(
    100svh - 73px - env(safe-area-inset-top) - env(safe-area-inset-bottom)
  );
  padding-top: clamp(32px, 5vw, 76px);
  overflow: hidden;
}
.hero-stamp {
  grid-column: span 4;
  align-self: start;
  color: var(--olive);
}
.hero h1 {
  grid-column: 2 / span 10;
  z-index: 1;
  margin: clamp(32px, 7vw, 103px) 0 0;
  font-size: clamp(76px, 12.3vw, 200px);
  line-height: 0.72;
}
.hero h1 span {
  display: block;
}
.hero h1 .red {
  color: var(--red);
  font-family: var(--font-serif);
  font-size: 0.78em;
  font-style: italic;
  letter-spacing: var(--tracking-accent);
}
.hero h1 .offset {
  padding-left: 12%;
}
.hero-side {
  grid-column: 2 / span 4;
  z-index: 1;
  align-self: end;
  max-width: 410px;
  margin: 0 0 clamp(42px, 5vw, 84px);
  font:
    italic 22px/1.08 "Libre Baskerville",
    Georgia,
    serif;
}
.hero-side::before {
  display: block;
  width: 42px;
  height: 2px;
  margin-bottom: 14px;
  background: var(--red);
  content: "";
}
.hero-block {
  position: absolute;
  z-index: 0;
  right: 0;
  bottom: 0;
  width: 44%;
  height: 72%;
  background: var(--olive);
}
.hero-block::before {
  position: absolute;
  top: 10%;
  right: 10%;
  width: 48%;
  height: 58%;
  border: 1px solid var(--paper);
  content: "";
  transform: rotate(7deg);
}
.hero-block::after {
  position: absolute;
  right: 0;
  bottom: 11%;
  width: 79%;
  height: 13%;
  background: var(--red);
  content: "";
}
/* The print is tilted off the page plane, the same way the case-study
   artifacts are staged — near edge on the right, far edge receding toward
   the headline. The z-rotation stays at the 7deg of .hero-block::before so
   the photo reads as laid down in line with the outlined square behind it
   rather than dropped on top at its own angle. perspective() rides on the
   element's own transform rather than on .hero, so the other absolutely
   positioned children keep their flat coordinate space.

   --tilt is how far off the plane it still is: 1 at the top of the page,
   0 once it has lain flat. Scroll position drives it (see index.html), so
   the settle tracks the wheel instead of playing itself. Every angle and
   the whole shadow scale off that one number, which is why the shadow
   disappears exactly when the card is flat. Below 720px the photo joins the
   flow and the rule further down overrides both properties outright. */
.hero-mark {
  --tilt: 1;
  position: absolute;
  z-index: 1;
  right: 7%;
  bottom: 16%;
  width: clamp(155px, 18vw, 285px);
  margin: 0;
  padding: 12px;
  background: var(--paper);
  transform: perspective(1600px) rotateY(calc(var(--tilt) * -14deg)) rotateX(calc(var(--tilt) * 4deg)) rotate(7deg);
  transform-origin: 70% 50%;
  box-shadow: calc(var(--tilt) * -26px) calc(var(--tilt) * 36px) calc(var(--tilt) * 58px) calc(var(--tilt) * -28px)
    rgba(24, 25, 23, calc(var(--tilt) * 0.6));
}
.hero-mark img {
  display: block;
  width: 100%;
  height: clamp(225px, 30vw, 390px);
  object-fit: cover;
  object-position: 31% center;
  filter: saturate(0.8) contrast(1.08);
}
.hero-mark figcaption {
  padding-top: 8px;
  color: var(--ink);
  font:
    10px/1.35 "DM Mono",
    monospace;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.proof-strip {
  padding-top: 0;
  padding-bottom: 0;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
}
.proof-item {
  grid-column: span 3;
  min-height: 236px;
  padding: 24px 23px 29px;
  border-right: 1px solid var(--ink);
  transition: background 0.2s ease;
}
.proof-item:first-child {
  margin-left: calc(var(--gutter) * -1);
  padding-left: var(--gutter);
}
.proof-item:last-child {
  margin-right: calc(var(--gutter) * -1);
  padding-right: calc(var(--gutter) + 23px);
  border-right: 0;
}
.proof-item .mono {
  display: block;
  margin: 0 0 44px;
  color: var(--olive);
}
.proof-item strong {
  display: block;
  max-width: 14ch;
  font: 400 clamp(21px, 2.15vw, 29px) / 0.98 var(--font-serif);
  letter-spacing: -0.06em;
}
.proof-item > p:last-child {
  max-width: 31ch;
  margin: 13px 0 0;
  font-size: 12px;
  line-height: 1.48;
}
.proof-item:hover {
  background: rgba(78, 91, 79, 0.055);
}
.proof-item:focus-visible {
  outline-offset: -4px;
}
.proof-arrow {
  display: inline-block;
  margin-left: 4px;
  color: var(--red);
  opacity: 0;
  transition:
    opacity 0.2s ease,
    transform 0.2s ease;
}
.proof-item:hover .proof-arrow,
.proof-item:focus-visible .proof-arrow {
  opacity: 1;
  transform: translateX(3px);
}

.thesis {
  position: relative;
  padding-top: clamp(72px, 7vw, 124px);
  padding-bottom: clamp(84px, 8vw, 120px);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.thesis-label {
  grid-column: span 2;
  padding-top: 8px;
  color: var(--olive);
}
.thesis-head {
  grid-column: 3 / span 9;
  margin: 0;
}
.thesis-no-break {
  white-space: nowrap;
}
.thesis h2,
.work-head h2,
.human-copy h2,
.now-copy h2,
.closing h2 {
  font: clamp(47px, 5.75vw, 91px) / 0.88 var(--font-display);
  letter-spacing: var(--tracking-display);
}
.thesis h2 .soft,
.work-head h2 em,
.human-copy h2 em,
.now-copy h2 em,
.closing h2 em {
  color: var(--red);
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: var(--tracking-accent);
}
.thesis-body {
  grid-row: 2;
  grid-column: 3 / span 6;
  margin-top: clamp(46px, 4.5vw, 68px);
  padding: 0 clamp(18px, 2vw, 32px) 0 0;
}
.thesis-body > p {
  max-width: 56ch;
  margin: 0;
  font-size: var(--text-body);
  line-height: var(--leading-body);
}
.thesis-quote {
  grid-row: 2;
  grid-column: 10 / -1;
  align-self: start;
  margin: clamp(58px, 5.2vw, 80px) 0 0;
  padding: 0 0 1px clamp(16px, 1.7vw, 24px);
  border-left: 1px solid var(--ink);
  color: var(--ink-soft);
  font: italic clamp(21px, 1.9vw, 29px) / 1.08 var(--font-serif);
  letter-spacing: -0.045em;
}
.quote-line {
  display: block;
  white-space: normal;
}
.thesis-quote .quote-accent {
  color: inherit;
}

.moves-wrap {
  grid-row: 3;
  grid-column: 1 / -1;
  margin-top: clamp(64px, 6.5vw, 98px);
  border-top: 1px solid var(--ink);
}
.moves {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}
.move {
  position: relative;
  padding: 21px clamp(20px, 2vw, 32px) 24px;
}
.move:first-child {
  padding-left: 0;
}
.move:last-child {
  padding-right: 0;
}
.move + .move {
  border-left: 1px solid var(--line);
}
.move + .move::before {
  position: absolute;
  top: 16px;
  left: 0;
  padding: 5px 0;
  transform: translateX(-50%);
  color: var(--red-deep);
  background: var(--paper);
  font: 12px/1 var(--font-mono);
  content: "→";
}
/* A red rule that runs the ink border above each move while the loop is
   walked. It wipes in from the left and out to the right, so the mark keeps
   travelling forward through 01 → 02 → 03 rather than retracting. */
.move::after {
  position: absolute;
  top: -1px;
  right: 0;
  left: 0;
  height: 1px;
  transform: scaleX(0);
  transform-origin: right center;
  background: var(--red-deep);
  transition: transform 340ms cubic-bezier(0.4, 0, 0.2, 1);
  content: "";
}
.move.is-lit::after {
  transform: scaleX(1);
  transform-origin: left center;
}
.move-num {
  display: block;
  margin-bottom: 26px;
  color: var(--olive);
  font: var(--text-label) / 1.4 var(--font-mono);
  letter-spacing: var(--tracking-mono);
  transition: color 260ms ease;
}
/* The numeral and the heading turn together, so each card reads as one beat
   of the wave rather than two things happening near each other. */
.move.is-lit .move-num,
.move.is-lit h3 {
  color: var(--red-deep);
}
.move h3 {
  max-width: 14ch;
  margin: 0 0 11px;
  font: 400 clamp(22px, 1.9vw, 29px) / 0.98 var(--font-serif);
  letter-spacing: -0.055em;
  transition: color 260ms ease;
}
.move p {
  max-width: 31ch;
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
}
.moves-return {
  position: relative;
  height: 44px;
  margin: 0 16.666%;
  border: 1px solid var(--ink);
  border-top: 0;
  border-radius: 0 0 22px 22px;
}
/* Origin marker where the path leaves "Make it shared" — the same olive
   square that ends the project timeline on the case pages. */
.moves-return::after {
  position: absolute;
  top: -3px;
  right: -4px;
  width: 7px;
  height: 7px;
  background: var(--olive);
  content: "";
}
.moves-return::before {
  position: absolute;
  top: -1px;
  left: -5px;
  border-right: 5px solid transparent;
  border-bottom: 7px solid var(--red-deep);
  border-left: 5px solid transparent;
  content: "";
}
.moves-return-label {
  position: absolute;
  bottom: -0.7em;
  left: 50%;
  padding: 0 13px;
  transform: translateX(-50%);
  color: var(--olive);
  background: var(--paper);
  font: var(--text-caption) / 1.4 var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color 220ms ease;
}
/* No pointer cursor and no button chrome: the line is a caption that happens
   to answer when you rest on it, not a control asking to be clicked. */
.moves-return-label:hover {
  color: var(--red-deep);
}
/* The return path redrawn in red, revealed right to left — the tracer leaves
   "Make it shared" and arrives back at "Find the signal". It is a copy of the
   parent's own border, so the geometry can never drift out of register. */
.return-trace {
  position: absolute;
  inset: 0 -1px -1px;
  border: 1px solid var(--red-deep);
  border-top: 0;
  border-radius: 0 0 22px 22px;
  opacity: 0;
  clip-path: inset(0 0 0 100%);
  pointer-events: none;
}
.is-looping .return-trace {
  opacity: 1;
  clip-path: inset(0 0 0 0);
  transition:
    clip-path 760ms cubic-bezier(0.4, 0, 0.2, 1),
    opacity 120ms ease;
}
/* Fading out holds the drawn clip so the tracer dissolves in place instead
   of rewinding back the way it came. */
.is-looping-out .return-trace {
  opacity: 0;
  clip-path: inset(0 0 0 0);
  transition: opacity 420ms ease;
}

.useful {
  padding-top: 108px;
  padding-bottom: 110px;
  border-bottom: 1px solid var(--line);
}
.useful-label {
  grid-column: span 2;
  padding-top: 8px;
  color: var(--olive);
}
.useful-copy {
  grid-column: 3 / span 7;
}
.useful-copy h2 {
  max-width: 11ch;
  font: clamp(47px, 5.75vw, 91px) / 0.88 var(--font-display);
  letter-spacing: -0.078em;
}
.useful-copy h2 em {
  color: var(--red);
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  letter-spacing: var(--tracking-accent);
}
.useful-copy > p {
  max-width: 635px;
  margin: 30px 0 0;
  font-size: var(--text-body);
  line-height: var(--leading-body);
}
.useful-list {
  grid-column: 3 / span 9;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-top: 62px;
  border-top: 1px solid var(--ink);
  border-left: 1px solid var(--ink);
}
.useful-list article {
  min-height: 222px;
  padding: 20px 24px 24px;
  border-right: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
}
.useful-list .mono {
  display: block;
  margin-bottom: 41px;
  color: var(--olive);
}
.useful-list h3 {
  max-width: 13ch;
  margin-bottom: 14px;
  font:
    400 30px/0.9 "Libre Baskerville",
    Georgia,
    serif;
  letter-spacing: -0.065em;
}
.useful-list p {
  max-width: 310px;
  margin: 0;
  color: rgba(24, 25, 23, 0.86);
  font-size: 14px;
  line-height: 1.5;
}

.work {
  padding-top: 118px;
  padding-bottom: 112px;
  color: var(--paper);
  background: var(--olive);
}
.work-head {
  grid-column: 3 / span 8;
}
.work-head .mono {
  margin-bottom: 25px;
  color: var(--paper);
}
.work-head h2 {
  max-width: 10ch;
}
.work-head h2 em {
  color: var(--paper);
}
.work-head > p {
  max-width: 435px;
  margin: 28px 0 0;
  color: rgba(238, 232, 218, 0.86);
  font-size: 16px;
  line-height: 1.55;
}
.cases {
  grid-column: 1 / -1;
  margin-top: 86px;
}
.case {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  border-top: 1px solid rgba(238, 232, 218, 0.43);
}
.case:last-child {
  border-bottom: 1px solid rgba(238, 232, 218, 0.43);
}
.cases:has(+ .foundations) .case:last-child {
  border-bottom: 0;
}
.case-index {
  grid-column: span 2;
  padding-top: 18px;
  color: var(--paper);
}
.case-copy {
  grid-column: 3 / span 6;
  padding: 45px 34px 44px 0;
}
.case-copy .mono {
  margin-bottom: 16px;
  color: var(--paper);
}
.case-copy h3 {
  max-width: 13ch;
  margin-bottom: 15px;
  font:
    400 clamp(36px, 4.2vw, 62px) / 0.88 "Libre Baskerville",
    Georgia,
    serif;
  letter-spacing: -0.07em;
}
.case-copy p {
  max-width: 510px;
  margin: 0;
  color: rgba(238, 232, 218, 0.86);
  font-size: 14px;
  line-height: 1.55;
}
.case-plate img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.case-plate .plate-caption {
  position: absolute;
  z-index: 2;
  right: 12px;
  bottom: 10px;
  max-width: 145px;
  padding: 5px 6px;
  color: var(--ink);
  background: var(--paper);
  font:
    10px/1.35 "DM Mono",
    monospace;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.notes {
  padding-top: 102px;
  padding-bottom: 105px;
  border-bottom: 1px solid var(--line);
}
.notes-label {
  grid-column: span 2;
  padding-top: 8px;
  color: var(--olive);
}
.notes-copy {
  grid-column: 3 / span 7;
}
.notes-copy h2 {
  max-width: 11ch;
  font: clamp(47px, 5.75vw, 91px) / 0.88 var(--font-display);
  letter-spacing: -0.078em;
}
.notes-copy h2 em {
  color: var(--red);
  font-family: "Libre Baskerville", Georgia, serif;
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.1em;
}
.notes-copy > p {
  max-width: 620px;
  margin: 29px 0 0;
  font-size: var(--text-body);
  line-height: var(--leading-body);
}
.notes-index {
  grid-column: 3 / span 9;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  margin-top: 58px;
  border-top: 1px solid var(--ink);
}
.notes-index article {
  min-height: 217px;
  padding: 19px 19px 22px 0;
  border-right: 1px solid var(--ink);
}
.notes-index article:not(:nth-child(3n + 1)) {
  padding-left: 19px;
}
.notes-index article:nth-child(3n) {
  border-right: 0;
}
.notes-index article:last-child {
  border-right: 0;
}
.notes-index .mono {
  display: block;
  margin-bottom: 37px;
  color: var(--olive);
}
.notes-index h3 {
  max-width: 12ch;
  margin-bottom: 13px;
  font:
    400 26px/0.94 "Libre Baskerville",
    Georgia,
    serif;
  letter-spacing: -0.06em;
}
.notes-index p {
  max-width: 240px;
  margin: 0;
  color: rgba(24, 25, 23, 0.86);
  font-size: 14px;
  line-height: 1.45;
}
.note-link {
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  gap: 10px;
  margin-top: 20px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--ink);
  font: var(--text-label) / 1.3 var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.note-link:hover {
  color: var(--red-deep);
  border-color: var(--red-deep);
}
.notes-all-link {
  grid-column: 3 / span 9;
  display: inline-flex;
  gap: 10px;
  width: fit-content;
  margin-top: 30px;
  padding-bottom: 5px;
  border-bottom: 1px solid var(--ink);
  font:
    11px/1.3 "DM Mono",
    monospace;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.notes-all-link:hover {
  color: var(--red-deep);
  border-color: var(--red-deep);
}

.human {
  border-bottom: 1px solid var(--line);
}
.human-poster {
  grid-column: 1 / span 5;
  position: relative;
  display: flex;
  min-height: 655px;
  justify-content: space-between;
  flex-direction: column;
  margin: 0;
  padding: 27px;
  color: var(--paper);
  background: var(--red-deep);
}
.human-poster .poster-type {
  max-width: 5ch;
  margin: 70px 0 0;
  color: var(--paper);
  font-size: clamp(80px, 13vw, 196px);
  line-height: 0.71;
}
.human-poster .poster-type span {
  color: var(--ink);
}
.human-poster > p:last-child {
  max-width: 180px;
  margin: 0;
  font:
    11px/1.45 "DM Mono",
    monospace;
}
.human-copy {
  grid-column: 6 / span 6;
  display: flex;
  justify-content: center;
  flex-direction: column;
  padding: clamp(55px, 8vw, 120px) 0 clamp(55px, 8vw, 120px)
    clamp(32px, 7vw, 110px);
}
.human-copy .mono {
  margin-bottom: 23px;
  color: var(--olive);
}
.human-copy h2 {
  max-width: 9ch;
}
.human-copy > p {
  max-width: 490px;
  margin: 28px 0 0;
  font-size: var(--text-body);
  line-height: var(--leading-body);
}

.art-studies {
  display: flex;
  align-items: flex-start;
  gap: 18px;
  max-width: 430px;
  margin: 28px 0 0;
}
/* --tilt is the angle each print lies at when it is left alone. Holding it in
   a property rather than in the transform means the lift below can straighten
   the print without knowing which one it is, and reduced motion can put it
   back at exactly its resting angle. */
.art-study {
  --tilt: 0deg;
  position: relative;
  min-width: 0;
  flex: 1;
  margin: 0;
  padding: 6px;
  border: 1px solid rgba(24, 25, 23, 0.16);
  background: var(--paper);
  box-shadow: 4px 4px 0 rgba(24, 25, 23, 0.12);
  transform: rotate(var(--tilt));
  transition:
    transform 300ms cubic-bezier(0.2, 0.7, 0.3, 1),
    box-shadow 300ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.art-study img {
  display: block;
  width: 100%;
  height: auto;
}
/* The image used to zoom inside its frame on hover. That is a screen gesture,
   and it fought the physical staging of these prints — the whole card lifts
   now instead, so nothing needs clipping. */
.art-study-link {
  display: block;
  cursor: zoom-in;
}
.art-study figcaption {
  padding: 6px 1px 1px;
  color: var(--olive);
  font:
    10px/1.35 "DM Mono",
    monospace;
  letter-spacing: 0.035em;
  text-transform: uppercase;
}
.art-study--dogs {
  --tilt: -1.3deg;
  flex: 2;
}
.art-study--giraffe {
  --tilt: 2.2deg;
}
.art-study--portrait {
  --tilt: 0deg;
}

/* Photographs are evidence of a life and a way of seeing, not interchangeable decoration. */
.experiment-copy p + p {
  margin-top: 14px;
}
.case-plate {
  grid-column: 9 / span 4;
  position: relative;
  min-height: 270px;
  overflow: hidden;
  margin: 20px 0;
  border: 7px solid var(--paper);
  background: var(--paper);
  color: var(--ink);
  box-shadow: 5px 5px 0 rgba(24, 25, 23, 0.3);
}
.case-plate::after {
  position: absolute;
  inset: 0;
  background: rgba(207, 73, 60, 0.12);
  content: "";
  mix-blend-mode: multiply;
  pointer-events: none;
}
.plate-one img {
  object-position: 58% 52%;
  filter: saturate(0.74) contrast(1.07);
}
.plate-two img {
  object-position: 47% center;
  filter: grayscale(0.18) saturate(0.7) contrast(1.1);
}
.plate-three img {
  object-position: 67% center;
  filter: grayscale(0.32) contrast(1.23) brightness(0.91);
}
.plate-three::after {
  background: rgba(207, 73, 60, 0.19);
}
.human-photo {
  --tilt: 3.2deg;
  position: absolute;
  right: clamp(18px, 3vw, 34px);
  bottom: 54px;
  width: clamp(100px, 10vw, 148px);
  margin: 0;
  padding: 6px;
  color: var(--ink);
  background: var(--paper);
  box-shadow: 4px 4px 0 var(--ink);
  transform: rotate(var(--tilt));
  transition:
    transform 300ms cubic-bezier(0.2, 0.7, 0.3, 1),
    box-shadow 300ms cubic-bezier(0.2, 0.7, 0.3, 1);
}
.human-photo-link {
  display: block;
  cursor: zoom-in;
}
.human-photo-link:focus-visible {
  outline-color: var(--paper);
}
.human-photo-frame {
  display: block;
  overflow: hidden;
  aspect-ratio: 4 / 3;
}
.human-photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: left center;
  filter: saturate(0.8) contrast(1.06);
  transform: scale(1.1);
  transform-origin: 0 58%;
}
.human-photo figcaption {
  padding: 6px 1px 1px;
  color: var(--olive);
  font:
    10px/1.3 "DM Mono",
    monospace;
  letter-spacing: 0.035em;
  text-transform: uppercase;
}

/* Picking a print up off the desk: it straightens, rises a little toward the
   light, and its shadow lengthens because it is no longer lying flat. Only
   the resting angle and the shadow change, so it reads as the object moving
   rather than the page animating. */
.art-study:has(.art-study-link:focus-visible),
.human-photo:has(.human-photo-link:focus-visible) {
  z-index: 1;
  transform: rotate(0deg) translate(-2px, -4px);
}
.art-study:has(.art-study-link:focus-visible) {
  box-shadow: 7px 10px 0 rgba(24, 25, 23, 0.16);
}
.human-photo:has(.human-photo-link:focus-visible) {
  box-shadow: 7px 10px 0 var(--ink);
}
/* Gated on a real pointer so the lifted state cannot stick after a tap. */
@media (hover: hover) {
  .art-study:hover,
  .human-photo:hover {
    z-index: 1;
    transform: rotate(0deg) translate(-2px, -4px);
  }
  .art-study:hover {
    box-shadow: 7px 10px 0 rgba(24, 25, 23, 0.16);
  }
  .human-photo:hover {
    box-shadow: 7px 10px 0 var(--ink);
  }
}

/* Held up to the light. The print keeps its paper frame and its caption, so
   what arrives is the same object brought closer, not a lightbox. */
.plate-viewer {
  max-width: none;
  max-height: none;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overscroll-behavior: contain;
}
.plate-viewer::backdrop {
  background: rgba(24, 25, 23, 0.82);
}
.plate-viewer-stage {
  display: grid;
  width: 100%;
  height: 100%;
  place-items: center;
  padding: clamp(18px, 4vw, 56px);
  border: 0;
  background: transparent;
  cursor: zoom-out;
}
/* Width is set in JS from the image's own pixels: these are small scans, and
   letting the frame size itself would either strand a 186px sketch in the
   middle of the screen or blow it up past what the file can carry. */
.plate-viewer-frame {
  margin: 0;
  padding: clamp(8px, 1vw, 13px);
  background: var(--paper);
  box-shadow: 10px 13px 0 rgba(24, 25, 23, 0.55);
  cursor: default;
  transform-origin: center center;
}
.plate-viewer-frame img {
  display: block;
  width: 100%;
  height: auto;
}
.plate-viewer-frame figcaption {
  display: flex;
  gap: var(--space-4);
  align-items: baseline;
  justify-content: space-between;
  padding: 10px 2px 1px;
  color: var(--olive);
  font: var(--text-caption) / 1.35 var(--font-mono);
  letter-spacing: 0.035em;
  text-transform: uppercase;
}
.plate-viewer-close {
  position: relative;
  padding: 0;
  border: 0;
  color: rgba(24, 25, 23, 0.5);
  background: transparent;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  white-space: nowrap;
  cursor: pointer;
  transition: color 200ms ease;
}
.plate-viewer-close:hover {
  color: var(--red-deep);
}
/* Same invisible overlay the other tight controls use — the caption line is
   10px mono, so the button is a 14px target without it. */
.plate-viewer-close::after {
  position: absolute;
  inset: 50% 0 auto;
  height: 44px;
  content: "";
  transform: translateY(-50%);
}
.plate-viewer[data-animating] .plate-viewer-frame {
  transition: transform 340ms cubic-bezier(0.2, 0.7, 0.3, 1);
}

.now {
  padding-top: 106px;
  padding-bottom: 110px;
}
.now-label {
  grid-column: span 2;
  padding-top: 8px;
  color: var(--olive);
}
.now-copy {
  grid-column: 3 / span 7;
}
.now-copy h2 {
  max-width: 11ch;
}
.now-copy > p {
  max-width: 650px;
  margin: 29px 0 0;
  font-size: var(--text-body);
  line-height: var(--leading-body);
}
.now-question-link {
  color: var(--red-deep);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}
.now-question-link:hover {
  color: var(--ink);
}
.now-note {
  grid-column: 10 / span 3;
  align-self: end;
  margin: 0;
  color: var(--ink-soft);
  font:
    italic 24px/1.04 "Libre Baskerville",
    Georgia,
    serif;
}
.now-note span {
  color: var(--red);
}

.closing {
  /* Olive rises to its accessible tint so the mono labels clear WCAG AA
     on ink. */
  --olive: var(--olive-light);
  padding-top: 110px;
  /* The last thing on the page, and under viewport-fit=cover it now runs to
     the bottom edge — where iOS floats its toolbar. The inset keeps the credit
     line off it, and keeps the ink field, not paper, behind it. */
  padding-bottom: calc(30px + env(safe-area-inset-bottom));
  color: var(--paper);
  background: var(--ink);
}
.closing h2 {
  grid-column: 3 / span 9;
  max-width: 10ch;
}
.closing h2 em {
  color: var(--red);
}
.closing-copy {
  grid-column: 7 / span 5;
  margin: 34px 0 0;
  color: rgba(238, 232, 218, 0.82);
  font-size: 17px;
  line-height: 1.5;
}
.email {
  grid-column: 3 / span 6;
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  width: fit-content;
  gap: 42px;
  margin-top: 61px;
  padding: 12px 0;
  border-bottom: 1px solid var(--paper);
  font: var(--text-label) / 1.2 var(--font-mono);
  letter-spacing: 0.05em;
}
.email:hover {
  color: var(--paper);
  border-color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 4px;
}
.closing-bottom {
  grid-column: 1 / -1;
  display: flex;
  justify-content: space-between;
  gap: 20px;
  margin-top: 108px;
  padding-top: 16px;
  border-top: 1px solid rgba(238, 232, 218, 0.35);
  color: rgba(238, 232, 218, 0.78);
  font:
    11px/1.4 "DM Mono",
    monospace;
  letter-spacing: 0.03em;
}
.closing-bottom a:hover {
  color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.case-link {
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  gap: 10px;
  margin-top: 22px;
  padding-bottom: 4px;
  border-bottom: 1px solid rgba(238, 232, 218, 0.75);
  color: var(--paper);
  font: var(--text-label) / 1.3 var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.case-link:hover {
  color: var(--paper);
  border-color: var(--paper);
  text-decoration: underline;
  text-underline-offset: 4px;
}
.foundations {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  margin-top: 72px;
  padding-top: 42px;
  border-top: 1px solid rgba(238, 232, 218, 0.43);
}
.foundations-label {
  grid-column: 1 / span 2;
  padding-top: 6px;
  color: var(--paper);
}
.foundations-intro {
  grid-column: 3 / span 8;
  margin-bottom: 34px;
}
.foundations-intro h3 {
  max-width: 30ch;
  margin: 0 0 14px;
  font: 400 clamp(22px, 2.1vw, 29px) / 1.08 var(--font-serif);
  letter-spacing: -0.02em;
  color: var(--paper);
}
.foundations-intro h3 em {
  color: var(--paper);
  font-style: italic;
  font-weight: 400;
}
.foundations-intro p {
  max-width: 520px;
  margin: 0;
  color: rgba(238, 232, 218, 0.82);
  font-size: 15px;
  line-height: 1.55;
}
.foundations-list {
  grid-column: 3 / span 9;
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1px solid rgba(238, 232, 218, 0.43);
}
.foundation {
  padding: 26px 34px 30px 0;
}
.foundation + .foundation {
  padding-right: 0;
  padding-left: 34px;
  border-left: 1px solid rgba(238, 232, 218, 0.43);
}
.foundation .mono {
  display: block;
  margin-bottom: 20px;
  color: rgba(238, 232, 218, 0.85);
}
.foundation h4 {
  max-width: 16ch;
  margin: 0 0 20px;
  font: 400 clamp(22px, 2.1vw, 27px) / 1.05 var(--font-serif);
  letter-spacing: -0.03em;
  color: var(--paper);
}
.foundation .case-link {
  margin-top: 0;
}
.experiment-feature {
  grid-column: 3 / span 9;
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(210px, 0.8fr);
  gap: 31px;
  row-gap: 14px;
  margin-top: 48px;
  padding-top: 0;
  border-top: 0;
}
.experiment-media {
  grid-column: 1;
  grid-row: 1;
  position: relative;
  min-width: 0;
  margin: 0;
  overflow: hidden;
  background: var(--ink);
  aspect-ratio: 16 / 9;
  isolation: isolate;
}
.experiment-media video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  background: var(--ink);
  transition: filter 0.45s ease;
}
.experiment-media:not(.is-playing):not(.is-paused) video {
  filter: grayscale(1) contrast(1.28) brightness(0.74);
}
.video-splash {
  position: absolute;
  z-index: 2;
  inset: 0;
  display: grid;
  grid-template-rows: auto 1fr auto;
  padding: clamp(15px, 2vw, 24px);
  color: var(--paper);
  transition:
    opacity 0.3s ease,
    visibility 0.3s ease;
}
.experiment-media.is-playing .video-splash,
.experiment-media.is-paused .video-splash {
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
}
.video-splash::before {
  position: absolute;
  z-index: -1;
  inset: 0;
  background: linear-gradient(
    125deg,
    rgba(24, 25, 23, 0.76) 0%,
    rgba(169, 54, 44, 0.21) 43%,
    rgba(207, 73, 60, 0.72) 100%
  );
  content: "";
  mix-blend-mode: multiply;
}
.video-splash::after {
  position: absolute;
  z-index: -1;
  inset: 12px;
  border: 1px solid rgba(238, 232, 218, 0.56);
  content: "";
}
.video-splash-meta,
.video-splash-actions {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}
.video-splash-meta {
  color: rgba(238, 232, 218, 0.77);
  font:
    10px/1.3 "DM Mono",
    monospace;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.video-splash-meta span:last-child {
  color: var(--paper);
}
.video-launch {
  position: relative;
  align-self: center;
  justify-self: center;
  display: inline-flex;
  align-items: center;
  gap: 15px;
  margin: 0;
  padding: 7px 12px 7px 7px;
  border: 0;
  color: var(--paper);
  background: rgba(24, 25, 23, 0.25);
  font:
    clamp(25px, 3.2vw, 46px) / 0.85 "Archivo Black",
    Impact,
    sans-serif;
  letter-spacing: -0.075em;
  cursor: pointer;
  transition:
    background 0.2s ease,
    transform 0.2s ease;
}
.video-launch:hover {
  background: rgba(24, 25, 23, 0.55);
  transform: translate(-2px, -2px);
}
.video-launch:focus-visible,
.video-sound-start:focus-visible,
.video-control:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 4px;
}
.video-play-disc {
  position: relative;
  display: grid;
  width: clamp(52px, 6vw, 76px);
  height: clamp(52px, 6vw, 76px);
  place-items: center;
  flex: 0 0 auto;
  border: 1px solid var(--paper);
  border-radius: 50%;
  background: var(--red);
  box-shadow: 4px 4px 0 var(--paper);
}
.video-play-disc::after {
  width: 0;
  height: 0;
  margin-left: 5px;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  border-left: 15px solid var(--paper);
  content: "";
}
.video-launch em {
  color: var(--red);
  font-family: "Libre Baskerville", Georgia, serif;
  font-size: 1.13em;
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.12em;
}
.video-splash-actions {
  align-items: end;
}
.video-quiet-note {
  max-width: 160px;
  margin: 0;
  color: rgba(238, 232, 218, 0.85);
  font:
    italic 14px/1.1 "Libre Baskerville",
    Georgia,
    serif;
}
.video-sound-start {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border: 1px solid var(--paper);
  color: var(--paper);
  background: var(--red);
  box-shadow: 4px 4px 0 rgba(24, 25, 23, 0.75);
  font:
    10px/1.2 "DM Mono",
    monospace;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
  transition:
    background 0.2s ease,
    box-shadow 0.2s ease,
    transform 0.2s ease;
}
.video-sound-start:hover {
  background: var(--red-deep);
  box-shadow: 2px 2px 0 rgba(24, 25, 23, 0.75);
  transform: translate(2px, 2px);
}
.sound-mark {
  display: inline-block;
  width: 12px;
  height: 12px;
  border: 1px solid currentColor;
  border-radius: 50%;
}
.video-controls {
  position: absolute;
  z-index: 3;
  right: 14px;
  bottom: 14px;
  left: 14px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 9px 8px 8px;
  border: 1px solid rgba(238, 232, 218, 0.65);
  color: var(--paper);
  background: rgba(24, 25, 23, 0.78);
  backdrop-filter: blur(8px);
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transform: translateY(12px);
  transition:
    opacity 0.28s ease,
    transform 0.28s ease,
    visibility 0s linear 0.28s;
}
.video-control {
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  gap: 9px;
  padding: 0 8px;
  border: 0;
  color: inherit;
  background: transparent;
  font:
    10px/1.2 "DM Mono",
    monospace;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
}
.video-control:hover {
  color: var(--red);
}
.video-control-play {
  width: 44px;
  justify-content: center;
  padding: 0;
  border-right: 1px solid rgba(238, 232, 218, 0.42);
}
.video-control-symbol {
  position: relative;
  display: block;
  width: 12px;
  height: 14px;
}
.video-control-symbol::before,
.video-control-symbol::after {
  position: absolute;
  top: 1px;
  bottom: 1px;
  width: 4px;
  background: currentColor;
  content: "";
}
.video-control-symbol::before {
  left: 1px;
}
.video-control-symbol::after {
  right: 1px;
}
.experiment-media.is-paused .video-control-symbol::before {
  top: 0;
  bottom: 0;
  left: 2px;
  width: 0;
  height: 0;
  background: transparent;
  border-top: 7px solid transparent;
  border-bottom: 7px solid transparent;
  border-left: 11px solid currentColor;
}
.experiment-media.is-paused .video-control-symbol::after {
  display: none;
}
.video-control-title {
  display: flex;
  min-width: 0;
  flex: 1;
  flex-direction: column;
  gap: 1px;
  padding-left: 2px;
}
.video-control-title strong {
  overflow: hidden;
  font:
    italic 13px/1.05 "Libre Baskerville",
    Georgia,
    serif;
  letter-spacing: -0.04em;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.video-control-title span {
  color: rgba(238, 232, 218, 0.78);
  font:
    10px/1.3 "DM Mono",
    monospace;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.video-control-audio {
  padding-left: 10px;
  border-left: 1px solid rgba(238, 232, 218, 0.42);
}
.video-control-audio .sound-mark {
  width: 10px;
  height: 10px;
}
.experiment-media.has-sound .video-control-audio {
  color: var(--red);
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.experiment-copy {
  display: flex;
  grid-column: 2;
  grid-row: 1 / 3;
  justify-content: center;
  flex-direction: column;
}
.experiment-copy .mono {
  margin-bottom: 16px;
  color: var(--olive);
}
.experiment-copy h3 {
  max-width: 9ch;
  margin-bottom: 14px;
  font:
    400 clamp(29px, 3.5vw, 46px) / 0.88 "Libre Baskerville",
    Georgia,
    serif;
  letter-spacing: -0.07em;
}
.experiment-copy p {
  max-width: 330px;
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
}
/* Set to match .notes-all-link, the other tight mono link on paper. This one
   had drifted to 10px at weight 500 on wider tracking, which read as a
   different kind of link, and it was the only one on paper that highlighted
   olive instead of red-deep. */
.experiment-link {
  display: inline-flex;
  gap: 10px;
  width: max-content;
  margin-top: 22px;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--ink);
  font: var(--text-label) / 1.3 var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.experiment-link:hover {
  color: var(--red-deep);
  border-color: var(--red-deep);
}
.green-wave {
  display: inline-flex;
  gap: 10px;
  margin: 0;
  padding-bottom: 4px;
  border-bottom: 1px solid var(--ink);
  font:
    11px/1.35 "DM Mono",
    monospace;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.green-wave:hover {
  color: var(--red-deep);
  border-color: var(--red-deep);
}
.green-wave-feature {
  width: min(100%, 490px);
  margin-top: 24px;
}
.green-wave-note {
  max-width: 35ch;
  margin: 10px 0 0;
  color: var(--olive);
  font: 10px/1.45 var(--font-mono);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.experiment-media.is-playing:not(.controls-visible) .video-controls {
  visibility: hidden;
  opacity: 0;
  pointer-events: none;
  transform: translateY(12px);
}
.experiment-media.is-playing.controls-visible .video-controls,
.experiment-media.is-playing:has(:focus-visible) .video-controls,
.experiment-media.is-paused .video-controls {
  visibility: visible;
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
  transition-delay: 0s;
}
.video-control-expand {
  width: 36px;
  justify-content: center;
  padding: 0;
  border-left: 1px solid rgba(238, 232, 218, 0.42);
}
.video-expand-mark {
  display: block;
  width: 15px;
  height: 15px;
}
.experiment-media:fullscreen {
  width: 100vw;
  height: 100vh;
  aspect-ratio: auto;
}
.experiment-media:fullscreen::backdrop {
  background: var(--ink);
}

.experiment-detail {
  grid-column: 1;
  grid-row: 2;
  display: grid;
  grid-template-columns: minmax(104px, 0.28fr) minmax(0, 1fr);
  gap: 18px;
  align-self: start;
  padding-top: 12px;
  border-top: 1px solid var(--ink);
}
.experiment-detail .mono {
  margin: 0;
  color: var(--olive);
}
.experiment-detail p:last-child {
  max-width: 500px;
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
}
/* Touch targets. These links are deliberately set tight — the rule sits just
   under the type — so the target is grown with an invisible overlay instead
   of by padding the box out, which would drag the underline away from the
   text and change the composition. 44px is the comfortable minimum.

   Inline links inside sentences (.now-question-link, .context-link) are left
   alone on purpose: the guidance exempts links in running text, and an
   overlay there would sit over the surrounding words and steal their clicks. */
.brand,
.header nav a,
.header .linkedin,
.header .contact,
.notes-all-link,
.experiment-link,
.green-wave,
.closing-bottom a {
  position: relative;
}
.brand::after,
.header nav a::after,
.header .linkedin::after,
.header .contact::after,
.notes-all-link::after,
.experiment-link::after,
.green-wave::after,
.closing-bottom a::after {
  position: absolute;
  inset: 50% 0 auto;
  height: 44px;
  content: "";
  transform: translateY(-50%);
}

@media (max-width: 1100px) {
  /* Keep the compact desktop stamp, then give the four-part kicker room at tablet
     widths. Both spans are sized so the kicker holds two lines: it needs about
     330px, and one column less lands at ~328px right across the common widths. */
  .hero-stamp {
    grid-column: span 6;
  }
}
@media (max-width: 860px) {
  .hero h1 {
    grid-column: 1 / span 10;
  }
  .hero-side {
    grid-column: 2 / span 4;
  }
  .proof-item {
    grid-column: span 6;
    min-height: 238px;
    border-bottom: 1px solid var(--ink);
  }
  .proof-item:nth-child(odd) {
    margin-left: calc(var(--gutter) * -1);
    padding-left: var(--gutter);
  }
  .proof-item:nth-child(even) {
    margin-right: calc(var(--gutter) * -1);
    padding-left: 23px;
    padding-right: calc(var(--gutter) + 23px);
    border-right: 0;
  }
  .proof-item:nth-child(3),
  .proof-item:nth-child(4) {
    border-bottom: 0;
  }
  .thesis-head {
    grid-column: 3 / span 9;
  }
  .thesis-body {
    grid-row: 2;
    grid-column: 3 / span 5;
    padding-right: 0;
  }
  .thesis-body > p {
    max-width: 56ch;
  }
  .moves-wrap {
    grid-row: 3;
    grid-column: 1 / -1;
    margin-top: 70px;
  }
  .thesis-quote {
    grid-row: 2;
    grid-column: 9 / -1;
    align-self: start;
    max-width: none;
    margin-top: clamp(58px, 5.2vw, 80px);
    font-size: clamp(20px, 2.8vw, 24px);
  }
  .quote-line {
    white-space: normal;
  }
  .useful-copy {
    grid-column: 3 / span 8;
  }
  .useful-list {
    grid-column: 3 / span 9;
  }
  .case-copy {
    grid-column: 3 / span 6;
  }
  .notes-copy {
    grid-column: 3 / span 8;
  }
  .notes-index {
    grid-column: 3 / span 9;
  }
  .human-poster {
    grid-column: 1 / span 5;
  }
  .human-copy {
    grid-column: 6 / span 7;
    padding-left: 50px;
  }
  .now-copy {
    grid-column: 3 / span 8;
  }
  .now-note {
    grid-column: 3 / span 8;
    align-self: start;
    max-width: 24ch;
    margin: 30px 0 0;
    padding-left: 16px;
    border-left: 1px solid var(--ink);
  }
}
@media (max-width: 720px) {
  .thesis-body,
  .thesis-quote,
  .moves-wrap {
    grid-row: auto;
  }
  .thesis-body {
    grid-column: 3 / -1;
  }
  .thesis-quote {
    grid-column: 5 / -1;
    margin-top: 38px;
  }
  .moves-wrap {
    grid-column: 1 / -1;
    margin-top: 56px;
  }
  .moves {
    grid-template-columns: 1fr;
  }
  .move {
    min-height: 0;
    padding: 22px 0 24px;
    border-right: 0;
  }
  .move + .move {
    border-top: 1px solid var(--line);
    border-left: 0;
  }
  .move + .move::before {
    top: 0;
    left: 18px;
    padding: 0 5px;
    transform: translateY(-50%);
    content: "↓";
  }
  .moves-return {
    height: auto;
    margin: 0;
    padding: 15px 0 0;
    border: 0;
  }
  /* The U path is gone at this width, so the tracer has nothing to run
     along — the three moves carry the loop on their own. */
  .moves-return::before,
  .moves-return::after,
  .return-trace {
    display: none;
  }
  .moves-return-label {
    position: static;
    padding: 0;
    transform: none;
  }
  .hero-side {
    grid-column: 1 / span 6;
    max-width: 340px;
    font-size: 18px;
  }
  .case-copy {
    grid-column: 3 / span 8;
    padding-bottom: 28px;
  }
  .case-plate {
    grid-column: 3 / span 8;
    min-height: 245px;
    margin: 0 0 28px;
  }
  .human-poster {
    grid-column: 1 / -1;
    min-height: 360px;
  }
  .human-copy {
    grid-column: 1 / -1;
    padding: 72px 0;
  }
  .experiment-feature {
    grid-column: 3 / span 9;
    grid-template-columns: 1fr;
  }
  .experiment-media,
  .experiment-copy,
  .experiment-detail {
    grid-column: auto;
    grid-row: auto;
  }
  .video-launch {
    font-size: clamp(27px, 6vw, 44px);
  }
}
@media (max-width: 600px) {
  .grid {
    padding-right: max(var(--gutter-mobile), env(safe-area-inset-right));
    padding-left: max(var(--gutter-mobile), env(safe-area-inset-left));
  }
  /* Sticky, but only once it has something to come back from — see header.js.
     Paper background is required: the header is transparent by default, and
     without it the copy scrolls visibly through the bar. The bar sticks to the
     true top of the screen and pads itself past the clock, so the paper covers
     the status-bar strip as well — see the base .header rule. */
  .header {
    position: sticky;
    top: 0;
    z-index: 12;
    min-height: calc(65px + env(safe-area-inset-top));
    background: var(--paper);
    /* Only transform is animated. Transitioning min-height animates a layout
       property for 280ms, and Chrome's scroll anchoring compensates for the
       moving content by nudging scrollTop — which reads as an upward scroll and
       re-opens the bar the instant it tries to hide. The height snaps instead. */
    transition: transform 0.28s ease;
  }
  .header.is-condensed {
    min-height: calc(52px + env(safe-area-inset-top));
  }
  /* Condensed keeps the two things a returning reader wants: a way home and a
     way to write. Work / Notes / Now come back at the top of the page. */
  .header.is-condensed nav {
    display: none;
  }
  .header.is-hidden {
    transform: translateY(-100%);
  }
  /* Anchor targets clear the bar. Without this, jumping to #now on a scroll-up
     leaves the section heading under the header. The bar now carries the
     status-bar strip on top of its 52px, so the landing has to clear that too. */
  [id] {
    scroll-margin-top: calc(60px + env(safe-area-inset-top));
  }
  .brand {
    grid-column: span 4;
  }
  .header nav {
    grid-column: 5 / 9;
    display: flex;
    gap: var(--space-2);
    justify-content: flex-end;
  }
  .header nav a {
    display: inline-flex;
    min-height: 44px;
    align-items: center;
    font-size: var(--text-caption);
    letter-spacing: 0.035em;
  }
  /* Keep the primary contact affordance on mobile: the page is ~13,500px
     tall and the only other email link is in the footer. LinkedIn gives up
     its space for it. Now keeps its link — it sits at screen 13 of 16 and
     nothing else on the page points to it, so without the nav item it is
     effectively unreachable on a phone. The human section is reached by
     scrolling through it.
     Nav must stay within columns 5-8: .brand spans 1-4, and any nav start
     before column 5 collides with it and wraps the header onto two rows. */
  .header .linkedin {
    display: none;
  }
  .header .contact {
    grid-column: 10 / -1;
  }
  .hero {
    min-height: 0;
    padding-top: var(--space-4);
    padding-bottom: 10px;
  }
  .hero-stamp {
    grid-column: 1 / -1;
  }
  .hero h1 {
    grid-column: 1 / -1;
    margin-top: 42px;
    font-size: clamp(70px, 18vw, 88px);
    line-height: 0.75;
  }
  .hero h1 .offset {
    padding-left: 3%;
  }
  .hero-side {
    grid-column: 1 / -1;
    max-width: 27ch;
    margin: 48px 0 0;
    font-size: 18px;
  }
  .hero-block {
    width: 57%;
    height: 245px;
  }
  .hero-mark {
    position: relative;
    z-index: 1;
    right: auto;
    bottom: auto;
    grid-column: 7 / -1;
    width: 154px;
    align-self: start;
    justify-self: end;
    margin: 34px 5px 0 0;
    padding: var(--space-1);
    transform: rotate(5deg);
    /* Flat card, so drop the depth shadow that goes with the tilt. */
    box-shadow: none;
  }
  .hero-mark img {
    height: 190px;
  }
  .proof-strip {
    padding-top: 0;
    padding-bottom: 0;
  }
  .proof-item {
    grid-column: 1 / -1;
    min-height: 0;
    padding: 27px 0 30px;
    border-right: 0;
    border-bottom: 1px solid var(--ink);
  }
  .proof-item:nth-child(even) {
    padding-left: 0;
  }
  .proof-strip .proof-item {
    margin-right: calc(var(--gutter-mobile) * -1);
    margin-left: calc(var(--gutter-mobile) * -1);
    padding-right: var(--gutter-mobile);
    padding-left: var(--gutter-mobile);
  }
  .proof-item:nth-child(3) {
    border-bottom: 1px solid var(--ink);
  }
  .proof-item:last-child {
    border-bottom: 0;
  }
  .proof-item .mono {
    margin-bottom: 25px;
  }
  .proof-item strong {
    font-size: 27px;
  }
  .proof-item > p:last-child {
    max-width: 43ch;
    font-size: 13px;
  }
  .thesis {
    padding-top: 64px;
    padding-bottom: 73px;
  }
  .thesis-label {
    grid-column: span 4;
  }
  .thesis-head {
    grid-column: 1 / -1;
    padding-top: 42px;
  }
  .thesis-body,
  .moves-wrap {
    grid-column: 1 / -1;
  }
  .thesis-body {
    margin-top: 40px;
    padding-top: 26px;
  }
  .moves-wrap {
    margin-top: 36px;
  }
  .move {
    grid-template-columns: 40px minmax(0, 1fr);
    padding: 20px 0 22px;
  }
  .move-num {
    font-size: var(--text-label);
  }
  .move h3 {
    font-size: 28px;
  }
  .thesis h2,
  .useful-copy h2,
  .work-head h2,
  .notes-copy h2,
  .human-copy h2,
  .now-copy h2,
  .closing h2 {
    font-size: 49px;
    line-height: 0.9;
  }
  .thesis-body > p {
    font-size: 16px;
  }
  .useful {
    padding-top: 75px;
    padding-bottom: 75px;
  }
  .useful-label {
    grid-column: span 4;
  }
  .useful-copy {
    grid-column: 1 / -1;
    padding-top: 37px;
  }
  .useful-list {
    grid-column: 1 / -1;
    grid-template-columns: 1fr;
    margin-top: 43px;
  }
  .useful-list article {
    min-height: 0;
    padding: 22px;
  }
  .useful-list .mono {
    margin-bottom: 23px;
  }
  .work {
    padding-top: 77px;
    padding-bottom: 74px;
  }
  .work-head {
    grid-column: 1 / -1;
  }
  .cases {
    margin-top: 53px;
  }
  .foundations {
    margin-top: 52px;
    padding-top: 32px;
  }
  .foundations-label,
  .foundations-intro,
  .foundations-list {
    grid-column: 1 / -1;
  }
  .foundations-intro {
    margin-top: 22px;
    margin-bottom: 28px;
  }
  .foundations-list {
    grid-template-columns: 1fr;
  }
  .foundation {
    padding: 22px 0 24px;
    border-bottom: 1px solid rgba(238, 232, 218, 0.43);
  }
  .foundation + .foundation {
    padding-left: 0;
    border-left: 0;
  }
  .foundation:last-child {
    border-bottom: 0;
  }
  .case {
    display: block;
    padding: 18px 0 20px;
  }
  .case-index {
    padding: 0 0 18px;
  }
  .case-copy {
    padding: 0;
  }
  .case-copy h3 {
    font-size: 39px;
  }
  .case-plate {
    min-height: 220px;
    margin: 28px 0 0;
  }
  .notes {
    padding-top: 75px;
    padding-bottom: 75px;
  }
  .notes-label {
    grid-column: span 4;
  }
  .notes-copy {
    grid-column: 1 / -1;
    padding-top: 37px;
  }
  .notes-index {
    grid-column: 1 / -1;
    grid-template-columns: 1fr;
    margin-top: 42px;
  }
  .notes-index article,
  .notes-index article + article {
    min-height: 0;
    padding: 22px 0;
    border-right: 0;
    border-bottom: 1px solid var(--ink);
  }
  .notes-index article:last-child {
    border-bottom: 0;
  }
  .notes-index .mono {
    margin-bottom: 19px;
  }
  .notes-all-link {
    grid-column: 1 / -1;
    margin-top: 27px;
  }
  .human-poster {
    grid-column: 1 / -1;
    min-height: 342px;
  }
  .human-poster .poster-type {
    margin-top: 35px;
    font-size: clamp(88px, 28vw, 122px);
  }
  .human-copy {
    grid-column: 1 / -1;
    padding: 72px 0;
  }
  .now {
    padding-top: 75px;
    padding-bottom: 75px;
  }
  .now-label {
    grid-column: span 4;
  }
  .now-copy {
    grid-column: 1 / -1;
    padding-top: 37px;
  }
  .closing {
    padding-top: 77px;
  }
  .closing h2 {
    grid-column: 1 / -1;
  }
  .closing-copy {
    grid-column: 1 / -1;
  }
  .email {
    grid-column: 1 / -1;
    margin-top: 52px;
  }
  .closing-bottom {
    display: block;
    margin-top: 75px;
  }
  .closing-bottom span {
    display: block;
    margin-top: var(--space-1);
  }
  .experiment-feature {
    grid-column: 1 / -1;
    margin-top: 42px;
  }
  .experiment-detail {
    grid-template-columns: 1fr;
    gap: 7px;
  }
  .video-splash {
    padding: 14px;
  }
  .video-splash::after {
    inset: 9px;
  }
  .video-splash-meta {
    font-size: var(--text-caption);
  }
  .video-launch {
    gap: 10px;
    padding-right: 9px;
    font-size: clamp(25px, 7.1vw, 34px);
  }
  .video-play-disc {
    box-shadow: 3px 3px 0 var(--paper);
  }
  .video-quiet-note {
    max-width: 110px;
    font-size: 12px;
  }
  .video-sound-start {
    gap: 7px;
    padding: 10px;
    font-size: var(--text-caption);
  }
  .video-controls {
    right: 9px;
    bottom: 9px;
    left: 9px;
  }
  .video-control-title strong {
    font-size: 12px;
  }
  .video-control-audio {
    padding-right: 3px;
  }
  .video-control-audio [data-audio-label] {
    display: none;
  }
  .human-photo {
    right: var(--gutter-mobile);
    bottom: 27px;
    width: 90px;
  }
  .human-photo figcaption {
    font-size: var(--text-caption);
  }
  .thesis-quote,
  .now-note {
    grid-column: 1 / -1;
    max-width: 30ch;
  }
  .thesis-quote {
    margin-top: 40px;
    font-size: clamp(20px, 6.3vw, 26px);
  }
  .now-note {
    margin-top: 28px;
  }
}
/* Below ~375px (iPhone SE 1st/2nd gen, small Android) three nav items no
   longer clear the wordmark: at 320px "Work" overlaps "Neil Holt." by 8px.
   Notes is the one to drop — it's linked twice from the body, while Now is
   linked from nowhere else on the page. */
@media (max-width: 374px) {
  .header nav a[href="#notes"] {
    display: none;
  }
  /* Pull the nav in a column so the last item clears "Say hello". Without
     this the gap to the CTA equals the gap between nav items, and
     "NOW SAY HELLO" reads as a single run. */
  .header nav {
    grid-column: 5 / 8;
  }
}
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  /* The mobile header still hides and returns — that is behaviour, not
     decoration, and losing it would put the contact link out of reach again.
     It just arrives instantly instead of sliding. */
  .header,
  .art-study,
  .human-photo,
  .plate-viewer[data-animating] .plate-viewer-frame,
  .proof-arrow,
  .video-launch,
  .video-sound-start,
  .video-controls,
  .move::after,
  .move-num,
  .move h3,
  .moves-return-label,
  .return-trace,
  .is-looping .return-trace,
  .is-looping-out .return-trace {
    transition: none;
  }
  /* The loop still replays, but as a held state: everything arrives at once
     and leaves at once, with nothing travelling across the screen. */
  .move.is-lit::after {
    transform: scaleX(1);
  }
  .proof-item:hover .proof-arrow,
  .video-launch:hover,
  .video-sound-start:hover {
    transform: none;
  }
  /* The print stays exactly where it lies — no straightening, no rise. Only
     the shadow deepens, which is the one part of picking it up that does not
     move anything. --tilt gives each print its own resting angle back. */
  .art-study:hover,
  .human-photo:hover,
  .art-study:has(.art-study-link:focus-visible),
  .human-photo:has(.human-photo-link:focus-visible) {
    transform: rotate(var(--tilt));
  }
}
