/* Newsreader (SIL Open Font License), self-hosted: headlines */
@font-face {
  font-family: "Newsreader";
  src: url("fonts/newsreader-latin.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Newsreader";
  src: url("fonts/newsreader-latin-ext.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Newsreader";
  src: url("fonts/newsreader-italic-latin.woff2") format("woff2");
  font-weight: 200 800;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Newsreader";
  src: url("fonts/newsreader-italic-latin-ext.woff2") format("woff2");
  font-weight: 200 800;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Manrope (SIL Open Font License), self-hosted: the wordmark's name */
@font-face {
  font-family: "Manrope";
  src: url("fonts/manrope-400-latin.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Manrope";
  src: url("fonts/manrope-400-latin-ext.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Inter Tight (SIL Open Font License), self-hosted: text and stamps. Cyrillic is for the Ukraine stamp */
@font-face {
  font-family: "Inter Tight";
  src: url("fonts/inter-tight-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter Tight";
  src: url("fonts/inter-tight-latin-ext.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter Tight";
  src: url("fonts/inter-tight-cyrillic.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

:root {
  --bg: oklch(0.979 0.011 89.7);
  --ink: oklch(0.23 0.028 219.7);
  --rule: rgb(0 0 0 / 0.2);
  --tag-bg: oklch(0.882 0.011 89.7 / 0.6);
  --sand: oklch(0.939 0.012 116.8);
  --paper-2: oklch(0.955 0.011 89.7); /* one L step below --bg, same hue */
  --now: oklch(0.5 0.11 155); /* where Anna is now */

  /* emil-surfaces: separation lines go hairline on high-density screens */
  --hairline: 1px;

  --serif: "Newsreader", "Iowan Old Style", Georgia, serif;
  --sans: "Inter Tight", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --ui: "Inter Tight", "Helvetica Neue", Helvetica, Arial, sans-serif;

  /* 1 Figma pixel at the 1512px artboard, clamped so type stays readable */
  --u: clamp(0.4px, calc(100vw / 1512), 1.15px);
  --gutter: clamp(16px, calc(64 * var(--u)), 64px);
  /* Stamps follow whichever is tighter, width or height, so short screens get smaller stamps */
  --u-stamp: min(var(--u), calc(max(100svh, 560px) / 982));

  color-scheme: light;
}

@media (min-resolution: 2dppx) {
  :root { --hairline: 0.5px; }
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-synthesis: none;
}

/* emil-touch-and-accessibility: no double-tap zoom delay on controls */
a, button { touch-action: manipulation; }

img { display: block; max-width: 100%; }
h1, h2, h3, p { margin: 0; }
a { color: inherit; }

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

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

.skip-link {
  position: absolute;
  left: 16px;
  top: -100px;
  padding: 8px 12px;
  background: var(--ink);
  color: var(--bg);
  font: 500 14px/1 var(--ui);
  z-index: 10;
}
.skip-link:focus { top: 16px; }

.container {
  max-width: calc(1384px + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* ---------- Type roles ---------- */

.display {
  font-family: var(--serif);
  font-weight: 440;
  font-size: clamp(32px, calc(48 * var(--u)), 48px);
  line-height: 1.2;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

.eyebrow {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 16px;
  line-height: 1.2;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  opacity: 0.9;
}

.lede {
  font-size: clamp(18px, calc(20 * var(--u)), 20px);
  line-height: 1.3;
  letter-spacing: 0.03em;
  opacity: 0.9;
  text-wrap: pretty;
}
.lede p + p { margin-top: 1lh; }

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  padding: 0;
  margin: 0;
  list-style: none;
}
.tag--caps { text-transform: uppercase; }.tag {
  padding: 6px 8px;
  background: var(--tag-bg);
  font-size: 16px;
  line-height: 1.2;
  letter-spacing: 0.03em;
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  min-height: 100svh;
  min-height: max(100svh, 560px);
  display: grid;
  place-items: center;
  overflow: hidden;
  isolation: isolate;
  /* The paper ends on a ruled line, drawn like the top edge: a major and a minor line together */
  box-shadow: inset 0 -1px 0 var(--grid-line-major), inset 0 -1px 0 var(--grid-line);
}

/* Grid paper: paper grain, a major line every five cells, a minor line every cell.
   The hero sits on it, and so do the animations on case study pages */
.hero, .grid-paper {
  --grid-cell: 24px;
  --grid-line: rgb(127 166 201 / 0.16);
  --grid-line-major: rgb(127 166 201 / 0.22);
  background-color: var(--bg);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' seed='4' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.3 0 0 0 0 0.24 0 0 0 0 0.16 0 0 0 0.4 -0.166'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E"),
    linear-gradient(var(--grid-line-major) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line-major) 1px, transparent 1px),
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size:
    240px 240px,
    calc(var(--grid-cell) * 5) calc(var(--grid-cell) * 5),
    calc(var(--grid-cell) * 5) calc(var(--grid-cell) * 5),
    var(--grid-cell) var(--grid-cell),
    var(--grid-cell) var(--grid-cell);
}
/* Phones round each background layer's tile to device pixels on its own, so a 23.2px cell drifts off
   the 116px major lines and every fifth line shows double. Drawing the minor lines inside the major
   tile gives every layer the same tile, so they round together */
@media (pointer: coarse) {
  .hero, .grid-paper {
    background-image:
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' seed='4' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.3 0 0 0 0 0.24 0 0 0 0 0.16 0 0 0 0.4 -0.166'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E"),
      linear-gradient(var(--grid-line-major) 1px, transparent 1px),
      linear-gradient(90deg, var(--grid-line-major) 1px, transparent 1px),
      repeating-linear-gradient(var(--grid-line) 0 1px, transparent 1px calc(100% / var(--grid-major, 5))),
      repeating-linear-gradient(90deg, var(--grid-line) 0 1px, transparent 1px calc(100% / var(--grid-major, 5)));
    background-size:
      240px 240px,
      calc(var(--grid-cell) * 5) calc(var(--grid-cell) * 5),
      calc(var(--grid-cell) * 5) calc(var(--grid-cell) * 5),
      calc(var(--grid-cell) * 5) calc(var(--grid-cell) * 5),
      calc(var(--grid-cell) * 5) calc(var(--grid-cell) * 5);
  }
}

.hero-name {
  position: absolute;
  top: clamp(20px, calc(44 * var(--u)), 44px);
  left: 50%;
  translate: -50% 0;
  font-size: clamp(18px, calc(24 * var(--u)), 24px);
  line-height: 1.2;
  letter-spacing: 0.02em;
  opacity: 0.9;
  white-space: nowrap;
  z-index: 2;
}

.hero-headline {
  position: relative;
  z-index: 2;
  width: min(calc(1047 * var(--u)), 100% - 2 * var(--gutter));
  font-family: var(--serif);
  font-weight: 360;
  font-size: clamp(34px, calc(88 * var(--u)), 100px);
  line-height: 1.2;
  letter-spacing: -0.011em;
  text-align: center;
  text-wrap: balance;
}
.hero-headline em {
  font-size: 0.98em; /* the slant reads larger at the same size */
}

.hero-nav {
  position: absolute;
  bottom: clamp(16px, calc(29 * var(--u)), 29px);
  left: 50%;
  translate: -50% 0;
  z-index: 2;
}
.hero-nav ul {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--ui);
  font-weight: 500;
  font-size: 16px;
  line-height: 1.2;
  white-space: nowrap;
}
.hero-nav li + li::before {
  content: "•";
  margin-right: 16px;
  font-weight: 200;
  font-size: 12px;
  vertical-align: 0.1em;
}
.hero-nav a {
  display: inline-block;
  padding-block: 10px;
  text-decoration: none;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
@media (hover: hover) and (pointer: fine) {
  .hero-nav a:hover { text-decoration-line: underline; }
}

/* The chapter you just stamped, as a margin note beside its stamp. hero.js picks the side */
.stamp-note {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 2;
  width: max-content;
  max-width: min(230px, 56vw);
  margin: 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(15px, calc(20 * var(--u)), 20px);
  line-height: 1.3;
  text-wrap: balance;
  pointer-events: none;
  opacity: 0;
}
.stamp-note[data-align="end"] { text-align: right; }

/* Passport stamps. Positions and ink opacity are set inline by hero.js */
.stamps { position: absolute; inset: 0; z-index: 1; }
.stamp {
  position: absolute;
  left: var(--x);
  top: var(--y);
  translate: -50% -50%;
  appearance: none;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  user-select: none;
  -webkit-user-select: none;
  mix-blend-mode: multiply;
  transition: opacity 500ms ease-out;
}
.stamp-inner { display: block; transform-origin: 50% 55%; }

/* The dotted route between the stamps (route.js), in their blue ink. A mask reveals it and cuts it
   away under the stamps and the note */
.stamp-route { position: absolute; inset: 0; z-index: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; mix-blend-mode: multiply; }
.stamp-route-dots {
  fill: none;
  stroke: oklch(0.45 0.13 258);
  stroke-width: var(--route-dot);
  stroke-linecap: round;
  stroke-dasharray: 0 var(--route-spacing);
  opacity: var(--route-opacity);
}
.stamp-route-reveal { fill: none; stroke: #fff; stroke-width: 14; stroke-linecap: round; }
.stamp-route mask rect { fill: #000; }
.stamp-route-gap { opacity: 0; transition: opacity 240ms ease-out; }
.stamp-route-gap[data-on] { opacity: 1; transition-duration: 120ms; }
.stamp:focus-visible { outline-offset: 6px; }
/* The chapter being read comes back to full ink */
.stamp:focus-visible { opacity: 0.9 !important; }
.stamp svg { display: block; width: 100%; height: auto; overflow: visible; }
.stamp text { font-family: var(--sans); font-weight: 700; fill: currentColor; }
@media (hover: hover) and (pointer: fine) {
  .stamp { cursor: pointer; }
  .stamp-inner { transition: scale 150ms ease-out; }
  .stamp:hover .stamp-inner { scale: 1.03; }
  .stamp:hover { opacity: 0.9 !important; transition-duration: 150ms; }
}

/* The stamp in hand: a lifted copy of the next chapter's stamp riding the pointer (hero.js) */
.stamp-carry {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 3;
  pointer-events: none;
  opacity: 0;
  mix-blend-mode: multiply;
  will-change: transform;
  transition: opacity 120ms ease-out;
}
.stamp-carry[data-visible] { opacity: 0.5; }
/* Over its own place it settles into position, ready to print */
.stamp-carry[data-snapped] {
  opacity: 0.8;
  transition: opacity 120ms ease-out, transform 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
.stamp-carry-inner {
  display: block;
  translate: -50% -50%;
  scale: 1.06;
  transition: scale 140ms cubic-bezier(0.23, 1, 0.32, 1);
}
.stamp-carry[data-snapped] .stamp-carry-inner { scale: 1; }
.stamp-carry svg { display: block; width: 100%; height: auto; overflow: visible; }
.stamp-carry text { font-family: var(--sans); font-weight: 700; fill: currentColor; }

.hero[data-carry], .hero[data-carry] .stamp { cursor: none; }
.hero[data-carry] a { cursor: pointer; }
.hero[data-carry] .hero-name { cursor: auto; }
/* With a stamp in hand, only its own place responds */
.hero[data-carry] .stamp:not([data-next]):not([data-fresh]):hover { opacity: var(--rest) !important; }
.hero[data-carry] .stamp:hover .stamp-inner { scale: 1; }

/* The stamp just pressed carries the freshest ink */
.stamp[data-fresh] { opacity: 0.9 !important; }
/* Where the stamp in hand belongs */
.stamp[data-next] { animation: stamp-next 1600ms ease-in-out infinite alternate; }
@keyframes stamp-next {
  from { opacity: var(--rest); }
  to { opacity: calc(var(--rest) + 0.28); }
}

/* After the seventh stamp: the way on to the work, under the headline */
.hero-closing {
  position: absolute;
  left: 50%;
  z-index: 2;
  width: min(38ch, 100% - 2 * var(--gutter));
  margin: 0;
  translate: -50% 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(18px, calc(26 * var(--u)), 26px);
  line-height: 1.3;
  text-align: center;
  text-wrap: balance;
}
.hero-closing a { text-decoration-thickness: 1px; text-underline-offset: 3px; }
@media (hover: hover) and (pointer: fine) {
  .hero-closing a { transition: text-decoration-color 150ms ease; }
  .hero-closing a:hover { text-decoration-color: transparent; }
}

/* ---------- Dock: takes over from the hero nav once it scrolls away ---------- */

.dock {
  position: fixed;
  inset: 0 0 auto;
  z-index: 20;
  background: var(--bg);
  border-bottom: var(--hairline) solid var(--rule);
  translate: 0 -100%;
  transition: translate 160ms ease-in;
}
.dock[data-shown] {
  translate: 0 0;
  transition: translate 240ms cubic-bezier(0.23, 1, 0.32, 1);
}
.dock-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  height: 56px;
}
.dock-name {
  font-size: 18px;
  line-height: 1.2;
  letter-spacing: 0.02em;
  text-decoration: none;
}
.dock-nav {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--ui);
  font-weight: 500;
  font-size: 15px;
  line-height: 1.2;
  white-space: nowrap;
}
.dock-nav li + li::before {
  content: "•";
  margin-right: 16px;
  font-weight: 200;
  font-size: 11px;
  vertical-align: 0.1em;
  opacity: 0.45;
}
.dock-nav a {
  display: inline-block;
  padding-block: 18px;
  text-decoration: none;
  opacity: 0.65;
  transition: opacity 150ms ease;
}
.dock-nav a[aria-current] { opacity: 1; }
@media (hover: hover) and (pointer: fine) {
  .dock-nav a:hover { opacity: 1; }
}
.dock-count { font-variant-numeric: tabular-nums; }

#work, #about, #contact { scroll-margin-top: 72px; }

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
@media (prefers-reduced-motion: reduce) {
  .stamp, .stamp-inner, .dock, .dock[data-shown], .dock-nav a { transition: none; }
  .stamp-carry, .stamp-carry[data-snapped], .stamp-carry-inner { transition: none; }
  .stamp[data-next] { animation: none; opacity: calc(var(--rest) + 0.28) !important; }
}
@media (max-width: 640px) {
  /* Stamps hit --u's floor on phones and their lettering goes unreadable, so they're drawn larger */
  :root { --u-stamp: calc(min(var(--u), calc(max(100svh, 560px) / 982)) * 1.3); }
  .stamp { left: var(--x-narrow); top: var(--y-narrow); }
  /* Narrow enough to pass between the stamps on either side of it */
  .hero-closing { width: min(30ch, 54vw); }
  .dock-inner { justify-content: center; }
  .dock-name, .dock-long { display: none; }
  .dock-nav { gap: 10px; font-size: 14px; }
  .dock-nav li + li::before { margin-right: 10px; }
}

/* ---------- Selected work ---------- */

.work {
  padding-block: clamp(48px, calc(96 * var(--u)), 96px) clamp(24px, calc(40 * var(--u)), 40px);
  /* Tonal band: work sits on a deeper sheet of the same paper, full-bleed past the container */
  background: var(--paper-2);
  box-shadow: 0 0 0 100vmax var(--paper-2);
  clip-path: inset(0 -100vmax);
}
/* The band is the section's edge, so the first case needs no rule above it */
.work .case:first-of-type { border-top-color: transparent; }

.case {
  display: grid;
  grid-template-columns: minmax(0, 544fr) minmax(0, 620fr);
  justify-content: space-between;
  column-gap: clamp(32px, calc(204 * var(--u)), 204px);
  row-gap: 32px;
  padding-block: clamp(40px, calc(64 * var(--u)), 64px);
  border-top: var(--hairline) solid var(--rule);
}
.case-meta {
  display: flex;
  flex-direction: column;
  gap: clamp(32px, calc(64 * var(--u)), 64px);
  padding-top: clamp(0px, calc(65 * var(--u)), 65px);
}
.case-body { display: flex; flex-direction: column; gap: 32px; }
/* Title and description read as one group; the tags stay a step apart */
.case .case-body { gap: 16px; }
.case .tags { margin-top: 16px; }
.case-title { font-size: clamp(39px, calc(58 * var(--u)), 58px); }
.case-title a { text-decoration: none; }
a.case-media { display: block; }
/* A case study still to come carries a small rubber stamp instead of a tag: the hero's ink, tilted,
   sized to the tag it replaced */
.soon {
  width: 150px; /* 250 units wide: the lettering stays the size it was at 132px / 220 */
  height: auto;
  margin-block: -6px;
  rotate: -5deg;
  color: oklch(0.45 0.13 258);
  opacity: 0.92;
  overflow: visible;
  font: 700 23px var(--sans);
  letter-spacing: 3px;
}
/* A live case study: the title's link covers the whole row and ends in a drawn hairline arrow, the
   same weight as the hover underline, which is the cue on touch too. Hovering the row underlines the
   title, draws the arrow's line a little longer and lifts the phones a little */
.case:has(.case-title a) { position: relative; }
.case-title a::after { content: ""; position: absolute; inset: 0; }
.case-arrow {
  width: 0.83em;
  height: 0.39em;
  margin-inline-start: 0.3em;
  overflow: visible;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.case-arrow-shaft { transform-box: view-box; transform-origin: 1px 9px; transition: scale 300ms cubic-bezier(0.23, 1, 0.32, 1); }
.case-arrow-head { transition: translate 300ms cubic-bezier(0.23, 1, 0.32, 1); }
.case-media .tile-phones,
.case-media .iris-mark { transition: scale 300ms cubic-bezier(0.23, 1, 0.32, 1); }
@media (hover: hover) {
  .case:has(.case-title a):hover .case-title a { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.12em; }
  .case:has(.case-title a):hover .case-arrow-shaft { scale: 1.2 1; }
  .case:has(.case-title a):hover .case-arrow-head { translate: 7px 0; }
  .case:has(.case-title a):hover .tile-phones { scale: 1.03; }
  .case:has(.case-title a):hover .iris-mark { scale: 1.06; }
}
.case:has(.case-title a:focus-visible) .case-arrow-shaft { scale: 1.2 1; }
.case:has(.case-title a:focus-visible) .case-arrow-head { translate: 7px 0; }
@media (prefers-reduced-motion: reduce) { .case-arrow-shaft, .case-arrow-head, .case-media .tile-phones, .case-media .iris-mark { transition: none; } }
.case-status { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 16px; }

.case-media {
  position: relative;
  aspect-ratio: 620 / 400;
  max-width: 100%;
  align-self: start;
  margin-top: clamp(0px, calc(65 * var(--u)), 65px);
}
.case-media > img { position: absolute; }
.case-media > .tile-photo { inset: 0; width: 100%; height: 100%; object-fit: cover; }
.case-media--iris,
.case-media--fay {
  background: oklch(0.975 0.012 281.1);
  border: 1px solid rgb(209 187 251 / 0.2);
  overflow: hidden;
}
/* An inner line, so a border can't push these tiles' 620×400 grids in */
.case-media--iris,
.case-media--fay { border: 0; box-shadow: inset 0 0 0 1px rgb(209 187 251 / 0.2); }
/* Stand-ins for real photos */
.case-media--fay,
.case-media--grab { container-type: inline-size; overflow: hidden; }
.case-media--fay { background: #3a2e24; }
/* The hero's paper grain over the stand-in */
.case-media--grab {
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' seed='4' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.3 0 0 0 0 0.24 0 0 0 0 0.16 0 0 0 0.4 -0.166'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E") 0 0 / 240px 240px,
    radial-gradient(40% 60% at 15% 25%, #8fc7a0, transparent),
    radial-gradient(45% 70% at 88% 30%, #d9dfa9, transparent),
    radial-gradient(50% 60% at 55% 95%, #5fa987, transparent),
    #c3d8c0;
}

/* One blueprint across the tile, in the 620×400 tile's units: a 20 margin all round and between
   the panels, 12 inside them, taken from the title block in the mark's construction drawing.
   .iris-sheet places that drawing so its 970px frame sits exactly on the grid */
.iris-sheet {
  position: absolute;
  left: 37.842%; top: 3.655%;
  width: 59.860%;
  aspect-ratio: 1;
}
.iris-blueprint {
  position: absolute;
  inset: 0;
  background: #5f48f6;
  opacity: 0.55;
  /* Only the frame, labels and construction lines: the drawn petals are wider than the 3D mark's and
     its aperture is cut through, so the drawn flower would show around and inside it */
  -webkit-mask: url("assets/work/iris-blueprint-frame.webp") center / contain no-repeat;
  mask: url("assets/work/iris-blueprint-frame.webp") center / contain no-repeat;
}
/* Measured so the 3D mark lands on its drawing */
.iris-mark {
  position: absolute;
  left: 0.333%; top: -3.1%;
  width: 99.222%;
  scale: 1.02;
  max-width: none;
  filter: drop-shadow(0 12px 18px rgb(60 40 160 / 0.22));
}
.iris-sheet-left { position: absolute; inset: 0; width: 100%; height: 100%; }
.iris-sheet-left .l { fill: none; stroke: #5f48f6; stroke-width: 0.75; stroke-opacity: 0.55; }
.iris-sheet-left .d { fill: none; stroke: #5f48f6; stroke-width: 0.5; stroke-dasharray: 2 2; stroke-opacity: 0.55; }
.iris-sheet-left .fill { fill: #5f48f6; stroke-opacity: 1; }
.iris-sheet-left .t2 { fill: rgb(95 72 246 / 0.3); }
.iris-sheet-left .t3 { fill: rgb(95 72 246 / 0.12); }
.iris-sheet-left .paper { fill: #fff; }
.iris-sheet-left .aa { font: 400 84px Manrope, sans-serif; fill: none; stroke: #5f48f6; stroke-width: 0.75; }
.iris-sheet-left .n { font: 400 7px ui-monospace, "SF Mono", Menlo, monospace; fill: #5f48f6; fill-opacity: 0.75; }
.iris-sheet-left .cap { text-transform: uppercase; letter-spacing: 0.08em; }
.iris-sheet-left .b { font: 400 13px Manrope, sans-serif; fill: #5f48f6; }
/* Two phones over a photo, turned as one pair and large enough to run off the tile on purpose.
   Fay and Grab lean opposite ways */
.tile-phones {
  position: absolute;
  left: 50%; top: 50%;
  display: flex;
  gap: 3.548cqw;
  width: 60cqw;
  translate: -50% -50%;
  rotate: 11deg;
}
.case-media--grab .tile-phones { rotate: -11deg; }
.tile-phone {
  flex: 1;
  min-width: 0;
  align-self: center;
  border-radius: 8% / 3.7%; /* the screen corners in the Fay photo */
  box-shadow: 0 12px 24px -8px rgb(30 25 60 / 0.35);
}

/* ---------- About ---------- */

.about { margin-top: clamp(64px, calc(85 * var(--u)), 85px); }

.about-intro {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 544px);
  gap: 32px;
  padding-block: clamp(40px, calc(64 * var(--u)), 64px);
  border-top: var(--hairline) solid var(--rule);
}
.about-copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 40px;
  padding-top: clamp(0px, calc(65 * var(--u)), 65px);
}
.about-copy .display { max-width: 840px; }
.about-copy .lede { max-width: 640px; }
.portrait {
  position: relative;
  aspect-ratio: 544 / 670;
  margin-top: clamp(0px, calc(65 * var(--u)), 65px);
  border-radius: clamp(20px, calc(40 * var(--u)), 40px);
  overflow: hidden;
  /* emil-surfaces: images get a 1px inset outline, pure black at 10% */
  outline: 1px solid rgb(0 0 0 / 0.1);
  outline-offset: -1px;
}
.portrait img {
  position: absolute;
  left: -19.58%; top: 0;
  width: 122.84%;
  max-width: none;
}

.away {
  display: grid;
  grid-template-columns: minmax(0, 816px) minmax(0, 442px);
  justify-content: space-between;
  gap: 32px;
  margin-top: clamp(64px, calc(112 * var(--u)), 112px);
  padding: clamp(32px, calc(64 * var(--u)), 64px) clamp(20px, calc(48 * var(--u)), 48px);
  background: var(--sand);
}
.away-copy { display: flex; flex-direction: column; gap: clamp(32px, calc(64 * var(--u)), 64px); }
.eyebrow--status { display: flex; align-items: center; gap: 12px; }
/* Same mark as "now" on the map */
.eyebrow--status::before {
  content: "";
  width: 9px;
  height: 9px;
  margin-inline: 5px 0;
  border-radius: 50%;
  background: var(--now);
  box-shadow: 0 0 0 5px oklch(0.5 0.11 155 / 0.18);
}
/* Stretches to the height of the text beside it; the SVG crops to fill */
.away-map-wrap { position: relative; align-self: stretch; min-height: 470px; outline: 1px solid rgb(0 0 0 / 0.1); outline-offset: -1px; background: oklch(0.925 0.012 116.8); }
.away-map { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.map-land { fill: oklch(0.965 0.008 116.8); stroke: oklch(0.87 0.012 116.8); stroke-width: 0.75; stroke-linejoin: round; }
.map-route { fill: none; stroke: var(--ink); stroke-width: 1.25; stroke-dasharray: 2 4; stroke-linecap: round; stroke-linejoin: round; }
.map-past { fill: var(--bg); stroke: var(--ink); stroke-width: 1.25; }
.map-now { fill: var(--now); }
.map-halo { fill: oklch(0.5 0.11 155 / 0.18); }
.map-stop { font: 400 13px var(--sans); letter-spacing: 0.01em; fill: var(--ink); }
.map-stop--now { font-weight: 700; }
.map-note { font: italic 400 14px var(--serif); fill: var(--ink); opacity: 0.7; }
.map-header { position: absolute; inset: 24px 24px auto; z-index: 1; display: flex; justify-content: space-between; font: 700 11px var(--sans); letter-spacing: 0.12em; text-transform: uppercase; opacity: 0.8; }
.map-ocean { font: italic 400 14px var(--serif); fill: var(--ink); opacity: 0.5; }
.map-locator { fill: oklch(0.965 0.008 116.8); }
.map-frame { fill: none; stroke: var(--now); stroke-width: 1; }

/* ---------- Contact ---------- */

.contact {
  display: flex;
  flex-direction: column;
  gap: clamp(32px, calc(64 * var(--u)), 64px);
  margin-top: clamp(64px, calc(112 * var(--u)), 112px);
  padding-block: clamp(40px, calc(64 * var(--u)), 64px) clamp(64px, calc(128 * var(--u)), 128px);
  border-top: var(--hairline) solid var(--rule);
}
.contact-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 32px;
}
.contact-grid .display { font-weight: 500; }
.contact-side { display: flex; flex-direction: column; gap: 32px; }
.contact-links { display: flex; gap: 32px; }
.contact-links a {
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
@media (hover: hover) and (pointer: fine) {
  .contact-links a { transition: text-decoration-color 150ms ease; }
  .contact-links a:hover { text-decoration-color: transparent; }
}

/* Live: the stamp and its P.S. as one pair under the headline, the links on the right
   (decided 2026-11-02 from lab/signoff.html; see design/decisions/hero.md) */
.contact-head { display: flex; flex-direction: column; gap: 56px; }
.signoff-pair { --size: 210px; --tilt: -6deg; display: flex; flex-wrap: wrap; align-items: center; gap: 28px; }
.signoff-pair .signoff-ps { max-width: 30ch; }
/* On phones the links come first and the stamp signs off below them */
@media (max-width: 860px) {
  .contact-head { display: contents; }
  .signoff-pair { order: 1; margin-top: 24px; }
}

/* The stamp at the end, pressed onto the contact block by signoff.js: placed from
   data/signoff.config.json, its P.S. beside it. The ink multiplies, so type stays legible through it */
.contact { position: relative; }
.signoff { position: absolute; display: flex; align-items: center; gap: var(--gap, 18px); width: max-content; }
.signoff--left { flex-direction: row-reverse; text-align: right; }
.signoff--below { flex-direction: column; text-align: center; }
.signoff--above { flex-direction: column-reverse; text-align: center; }
.signoff-stamp { display: block; flex: none; width: var(--size, 210px); line-height: 0; opacity: var(--ink, 0.86); }
.signoff-stamp svg { display: block; width: 100%; height: auto; rotate: var(--tilt, -6deg); }
.signoff[data-overprint] .signoff-stamp { mix-blend-mode: multiply; }
.signoff-ps { margin: 0; max-width: 30ch; font-size: 15px; line-height: 1.45; opacity: 0.8; }
.signoff-ps a { text-decoration-thickness: 1px; text-underline-offset: 0.2em; }
/* Or a column of its own: headline, then the links, then the stamp with its P.S. */
/* Shared lines: all three columns start together, the links drop to the P.S.'s last line, and the
   stamp and its P.S. share one left edge, flush with the right margin */
.contact-grid--signoff { grid-template-columns: minmax(0, 5fr) minmax(0, 4fr) minmax(0, 3fr); }
.contact-grid--signoff .contact-side { justify-content: space-between; }
.signoff--column { position: static; width: auto; align-self: start; justify-self: stretch; align-items: flex-start; text-align: left; }
.signoff--column .signoff-stamp { width: min(var(--size), 100%); }
.signoff--column .signoff-ps { max-width: none; }
/* Or two: what's next on the left, the stamp and its P.S. on the right half */
.contact-main { display: flex; flex-direction: column; gap: 40px; }
.contact-grid--pair .signoff--column { justify-self: end; width: min(var(--size), 100%); }
.contact-grid--pair .signoff-stamp { width: 100%; }
@media (max-width: 860px) {
  .signoff { position: static; flex-direction: row; flex-wrap: wrap; text-align: left; margin-top: 56px; width: auto; }
}

/* ---------- Case study page ---------- */

.cs-bar { border-bottom: var(--hairline) solid var(--rule); }
.cs-bar-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  height: 56px;
}
.cs-back {
  font-family: var(--ui);
  font-weight: 500;
  font-size: 15px;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* Left rail beside one story column, after claire.io/work/meandu */
.cs-layout {
  display: grid;
  grid-template-columns: minmax(0, 220px) minmax(0, 900px);
  column-gap: clamp(32px, calc(120 * var(--u)), 120px);
  align-items: start;
}
.cs-rail {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 40px;
  height: 100svh;
  padding-block: clamp(48px, calc(112 * var(--u)), 112px) 32px;
  font-family: var(--ui);
  font-size: 14px;
  line-height: 1.45;
}
.cs-rail-product p:not(.cs-rail-name) { opacity: 0.6; }
.cs-rail-name { font-weight: 700; }
.cs-toc { display: flex; flex-direction: column; gap: 6px; margin: 0; padding: 0; list-style: none; }
.cs-toc a { display: block; padding-block: 2px; text-decoration: none; opacity: 0.55; transition: opacity 150ms ease; }
.cs-toc a[aria-current] { opacity: 1; }
.cs-rail-link { opacity: 0.6; text-decoration-thickness: 1px; text-underline-offset: 3px; }
@media (hover: hover) and (pointer: fine) {
  .cs-toc a:hover, .cs-rail-link:hover { opacity: 1; }
}

.cs-head {
  display: flex;
  flex-direction: column;
  gap: 32px;
  padding-block: clamp(48px, calc(112 * var(--u)), 112px) clamp(40px, calc(64 * var(--u)), 64px);
}
.cs-title { max-width: 20ch; font-size: clamp(40px, calc(72 * var(--u)), 72px); line-height: 1.1; }

.cs-cover { width: 100%; margin: 0; }

.cs-section {
  display: flex;
  flex-direction: column;
  gap: clamp(32px, calc(48 * var(--u)), 48px);
  margin-top: clamp(64px, calc(112 * var(--u)), 112px);
  scroll-margin-top: 32px;
}
/* Section titles: the body face in bold, sitting right on top of the story */
.cs-h {
  margin-bottom: -0.6em;
  font-family: var(--sans);
  font-weight: 700;
  font-size: clamp(18px, calc(20 * var(--u)), 20px);
  line-height: 1.4;
  letter-spacing: 0.01em;
}
.cs-prose {
  display: flex;
  flex-direction: column;
  gap: 1.1em;
  max-width: 62ch;
  font-size: clamp(18px, calc(20 * var(--u)), 20px);
  line-height: 1.5;
  letter-spacing: 0.01em;
  text-wrap: pretty;
}
.cs-credits { opacity: 0.75; }

.cs-figure { margin: 0; container-type: inline-size; }
/* The animations are drawn at 1600×1000 and play live over the grid paper (work/iris/*.html).
   They're shown at roughly half size, so the paper's squares shrink with them */
.cs-figure iframe {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  border: 0;
  outline: 1px solid rgb(0 0 0 / 0.06);
  outline-offset: -1px;
  pointer-events: none;
}
/* The paper fits the frame in whole squares instead of a fixed 14px one, which got cut off at the right
   and bottom: 64 × 40 at 16:10 with a major line every four, then a closing line on those two edges.
   Phones get half as many squares so they don't turn to mesh */
.cs-figure iframe.grid-paper {
  --grid-major: 4;
  --cols: 64;
  --rows: 40;
  background-size:
    240px 240px,
    calc(100% * var(--grid-major) / var(--cols)) calc(100% * var(--grid-major) / var(--rows)),
    calc(100% * var(--grid-major) / var(--cols)) calc(100% * var(--grid-major) / var(--rows)),
    calc(100% / var(--cols)) calc(100% / var(--rows)),
    calc(100% / var(--cols)) calc(100% / var(--rows));
  box-shadow: inset -1px -1px 0 var(--grid-line-major);
}
@container (max-width: 560px) {
  .cs-figure iframe.grid-paper { --cols: 32; --rows: 20; }
}
@media (pointer: coarse) {
  .cs-figure iframe.grid-paper {
    background-size:
      240px 240px,
      calc(100% * var(--grid-major) / var(--cols)) calc(100% * var(--grid-major) / var(--rows)),
      calc(100% * var(--grid-major) / var(--cols)) calc(100% * var(--grid-major) / var(--rows)),
      calc(100% * var(--grid-major) / var(--cols)) calc(100% * var(--grid-major) / var(--rows)),
      calc(100% * var(--grid-major) / var(--cols)) calc(100% * var(--grid-major) / var(--rows));
  }
}
/* Screen recordings sit on the case's card background at the animations' 16:10, rounded like the
   card's phones. The Grab recordings are only 372px wide, so they stay small */
.cs-figure:has(> :is(img[src^="grab/"][src$=".gif"], video[src^="grab/"])) {
  display: grid;
  place-items: center;
  /* Without a set width, Safari works the frame's width out from the recording's height and the 16:10
     ratio: about 1000px on a phone, and the whole page zooms out to fit it */
  width: 100%;
  aspect-ratio: 16 / 10;
  padding: 5% 0;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='g' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' seed='4' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.3 0 0 0 0 0.24 0 0 0 0 0.16 0 0 0 0.4 -0.166'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23g)'/%3E%3C/svg%3E") 0 0 / 240px 240px,
    radial-gradient(40% 60% at 15% 25%, #8fc7a0, transparent),
    radial-gradient(45% 70% at 88% 30%, #d9dfa9, transparent),
    radial-gradient(50% 60% at 55% 95%, #5fa987, transparent),
    #c3d8c0;
}
.cs-figure > :is(img[src^="grab/"][src$=".gif"], video[src^="grab/"]) {
  height: 85%; /* about half the recordings' 808px on desktop, so they stay sharp */
  width: auto;
  max-height: 600px;
  aspect-ratio: 371 / 807;
  object-fit: cover;
  border-radius: 12% / 5.5%; /* rounder than the card's, to cut off the recording's black frame */
  box-shadow: 0 12px 24px -8px rgb(30 25 60 / 0.35);
}
/* Media still to be made: holds its space at the animations' 16:10 */
.cs-placeholder {
  display: grid;
  place-items: center;
  aspect-ratio: 16 / 10;
  padding: 24px;
  border: 1px dashed var(--rule);
  font-size: 15px;
  letter-spacing: 0.03em;
  text-align: center;
  opacity: 0.6;
}

.cs-meta {
  display: grid;
  gap: 20px;
  margin: clamp(64px, calc(112 * var(--u)), 112px) 0 0;
  padding-top: clamp(32px, calc(48 * var(--u)), 48px);
  border-top: var(--hairline) solid var(--rule);
}
.cs-meta > div { display: grid; grid-template-columns: minmax(0, 9em) minmax(0, 1fr); gap: 16px; }
.cs-meta dt { font-weight: 700; font-size: 14px; line-height: 1.6; letter-spacing: 0.06em; text-transform: uppercase; opacity: 0.6; }
.cs-meta dd { margin: 0; font-size: clamp(17px, calc(20 * var(--u)), 20px); line-height: 1.4; letter-spacing: 0.01em; }

.cs-next {
  display: flex;
  flex-direction: column;
  gap: 24px;
  margin-top: clamp(64px, calc(112 * var(--u)), 112px);
  padding-block: clamp(40px, calc(64 * var(--u)), 64px) clamp(64px, calc(128 * var(--u)), 128px);
  border-top: var(--hairline) solid var(--rule);
}
.cs-soon { margin-left: 12px; font-family: var(--sans); font-size: 16px; letter-spacing: 0.03em; vertical-align: middle; opacity: 0.6; }

@media (hover: hover) and (pointer: fine) {
  .cs-back { transition: text-decoration-color 150ms ease; }
  .cs-back:hover { text-decoration-color: transparent; }
}

@media (max-width: 860px) {
  /* The rail folds into a header above the story; the page is short enough without a contents list */
  .cs-layout { grid-template-columns: minmax(0, 1fr); }
  .cs-rail { position: static; height: auto; padding-block: 32px 0; }
  .cs-rail nav, .cs-rail-link { display: none; }
  .cs-head { padding-top: 24px; }
}
@media (max-width: 640px) {
  /* The dock hides its name on phones; the case page bar has room for it */
  .cs-bar .dock-name { display: inline; }
}
@media (max-width: 480px) {
  .cs-meta > div { grid-template-columns: minmax(0, 1fr); gap: 4px; }
}

/* ---------- Narrow ---------- */

@media (max-width: 860px) {
  .case, .about-intro, .away, .contact-grid { grid-template-columns: minmax(0, 1fr); }
  .case-meta, .case-media, .about-copy, .portrait { padding-top: 0; margin-top: 0; }
  .portrait { max-width: 480px; }
  /* The map sets its own height from its viewBox; Safari can collapse an aspect-ratio box with only absolute children */
  .away-map-wrap { max-width: 442px; min-height: 0; align-self: start; }
  .away-map { position: relative; height: auto; }
  /* The map scales down on phones; its labels stay readable */
  .map-stop { font-size: 16px; }
  .map-note, .map-ocean { font-size: 17px; }
  .hero-nav ul { gap: 10px; font-size: 14px; }
  .hero-nav li + li::before { margin-right: 10px; }
}
