@import url('https://fonts.googleapis.com/css2?family=Geist:wght@400;500;600;700&display=swap');

:root {
  /* primitives */
  --black: 0, 0, 0;
  --white: 255, 255, 255;

  /* semantic — light theme (the only theme this site currently uses).
     Every surface/text/border below flips as a set, so swapping these
     fourteen lines is the whole theme. */
  --surface-primary: rgb(var(--white));
  --surface-secondary: rgba(var(--black), 0.05);
  --surface-tertiary: rgba(var(--black), 0.12);
  --surface-inverse: rgb(var(--black));

  --text-primary: rgb(var(--black));
  --text-secondary: rgba(var(--black), 0.62);
  /* 0.55 is the lightest ink that still clears AA on white at caption sizes */
  --text-tertiary: rgba(var(--black), 0.55);
  --text-inverse: rgb(var(--white));

  --border-primary: rgba(var(--black), 0.10);

  /* ink on white needs a far lighter shadow than white-on-black did */
  --shadow-soft: 0 12px 32px rgba(0, 0, 0, 0.12);

  /* type — desktop scale */
  --fs-display: 64px; --lh-display: 72px; --ls-display: -0.02em;
  --fs-h1: 48px; --lh-h1: 56px; --ls-h1: -0.02em;
  --fs-h2: 32px; --lh-h2: 40px; --ls-h2: -0.01em;
  --fs-h3: 24px; --lh-h3: 32px;
  --fs-body-l: 18px; --lh-body-l: 28px;
  --fs-body: 16px; --lh-body: 24px;
  --fs-body-s: 14px; --lh-body-s: 20px;
  --fs-caption: 12px; --lh-caption: 16px;

  /* spacing — one scale for every gap/padding in the layout
     (decorative/compositional offsets — gallery fan, vinyl reveal — are tuned
     by eye and intentionally excluded from this scale) */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 32px;
  --space-8: 48px;
  --space-9: 64px;
  --space-10: 96px;
  --space-11: 128px;
  --space-12: 256px;

  /* layout stops growing past this, so wide monitors don't stretch the page */
  --max-w: 1800px;
}

* { box-sizing: border-box; }

html, body {
  color-scheme: light;
  margin: 0;
  padding: 0;
  background: var(--surface-primary);
  color: var(--text-primary);
  font-family: 'Geist', -apple-system, BlinkMacSystemFont, sans-serif;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
}

a { color: inherit; text-decoration: none; }

/* every top-level band is capped and centred */
.section,
.ci-section,
.kind-words,
.footer {
  max-width: var(--max-w);
  margin-inline: auto;
}

.text-display { font-size: var(--fs-display); line-height: var(--lh-display); letter-spacing: var(--ls-display); font-weight: 500; margin: 0; }
.text-h1 { font-size: var(--fs-h1); line-height: var(--lh-h1); letter-spacing: var(--ls-h1); font-weight: 500; margin: 0; }
.text-h2 { font-size: var(--fs-h2); line-height: var(--lh-h2); letter-spacing: var(--ls-h2); font-weight: 500; margin: 0; }
.text-h3 { font-size: var(--fs-h3); line-height: var(--lh-h3); font-weight: 500; margin: 0; }
.text-body-l { font-size: var(--fs-body-l); line-height: var(--lh-body-l); font-weight: 400; margin: 0; }
.text-body { font-size: var(--fs-body); line-height: var(--lh-body); font-weight: 400; margin: 0; }
.text-body-s { font-size: var(--fs-body-s); line-height: var(--lh-body-s); font-weight: 400; margin: 0; }
.text-caption { font-size: var(--fs-caption); line-height: var(--lh-caption); font-weight: 400; margin: 0; }

/* ---------- Page head ----------
   No header bar: the wordmark and the CV button simply sit at the top of the
   page, and navigation happens through links inside the text. */
.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  padding-top: var(--space-7);
  padding-bottom: 0;
}
.logo-link { display: inline-block; }
/* mark and role are one block, so the head stays two columns */
.page-mark { display: flex; flex-direction: column; gap: var(--space-1); }
.page-role {
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  color: var(--text-secondary);
}
.page-role-sep { color: var(--text-tertiary); padding: 0 2px; }
.page-actions { display: flex; align-items: center; gap: var(--space-6); }
/* profiles sit beside the CV button, quieter than it; the names are cut to
   initials, so the full name lives in aria-label and in the cursor's chip */
.page-social { display: flex; flex-wrap: wrap; gap: var(--space-4); }
.page-social a {
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  color: var(--text-secondary);
  transition: color 0.15s ease;
}
.page-social a:hover { color: var(--text-primary); }

/* Wordmark: four cuts of the same name running as a 4-frame loop, so the
   letters keep redrawing themselves. Each cut is a mask, so it takes the
   page's ink colour and flips with the theme. */
.logo {
  position: relative;
  display: block;
  margin: 0;
  /* widest of the four cuts, so the row never shifts as they cycle */
  width: 156px;
  height: 26px;
}
.logo-face {
  position: absolute;
  left: 0;
  top: 50%;
  height: 16px;
  margin-top: -8px;
  /* --logo-ink is rolled on hover in script.js; ink colour otherwise */
  background: var(--logo-ink, currentColor);
  -webkit-mask: var(--src) left center / 100% 100% no-repeat;
  mask: var(--src) left center / 100% 100% no-repeat;
  /* 4 frames × 0.12s — each cut holds just long enough to be read */
  animation: logo-cycle 0.48s steps(1, end) infinite;
}
/* each cut keeps its own aspect ratio at 16px tall, and starts one frame
   later than the one before it */
.logo-face--1 { --src: url('assets/logo-wordmark-1.svg'); width: 156px; }
.logo-face--2 { --src: url('assets/logo-wordmark-2.svg'); width: 154px; animation-delay: -0.36s; }
.logo-face--3 { --src: url('assets/logo-wordmark-3.svg'); width: 145px; animation-delay: -0.24s; }
.logo-face--4 { --src: url('assets/logo-wordmark-4.svg'); width: 152px; animation-delay: -0.12s; }

@keyframes logo-cycle {
  0% { opacity: 1; }
  25%, 100% { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .logo-face { animation: none; opacity: 0; }
  .logo-face--1 { opacity: 1; }
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  font-weight: 500;
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  cursor: pointer;
  border: none;
  font-family: inherit;
  transition: opacity 0.15s ease, background-color 0.15s ease;
}
.btn-primary {
  /* --btn-ink is flickered on hover in script.js; ink colour otherwise */
  background: var(--btn-ink, var(--surface-inverse));
  color: var(--text-inverse);
  padding: var(--space-3) var(--space-7);
}

.btn-secondary {
  background: transparent;
  color: var(--text-primary);
  border: 1px solid var(--border-primary);
  padding: var(--space-3) var(--space-7);
}
.btn-secondary:hover { background: var(--surface-secondary); }

/* ---------- Sections ---------- */
.section { padding: var(--space-7) var(--space-12); }

.placeholder-hero {
  min-height: 50vh;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-tertiary);
  border-top: 1px solid var(--border-primary);
}

/* ---------- About: bio ----------
   One column of running text with the photographs set into it: each print sits
   in the line right where the sentence mentions it, and grows when pointed at,
   so the text stays the hero and nothing needs a gallery of its own. */
.about-intro { display: block; }
.bio { display: flex; flex-direction: column; gap: var(--space-5); max-width: 760px; }
.bio-h,
.bio-p,
.signoff div {
  margin: 0;
  font-size: var(--fs-body);
  line-height: 34px;
}
.bio-h { font-weight: 400; letter-spacing: normal; color: var(--text-primary); }
.bio-p { color: var(--text-secondary); }
.bio-p strong { color: var(--text-primary); font-weight: 600; }
.signoff { display: flex; flex-direction: column; margin-top: var(--space-4); }
.signoff .with-love { color: var(--text-tertiary); }
.signoff .signature { font-weight: 600; }

/* the heart stays with the photo it follows, a touch smaller than the text */
.bio-heart { font-size: 0.9em; margin-left: 2px; }

/* a photo never starts a line on its own: it stays with the word it follows */
.bio-keep { white-space: nowrap; }

/* a print dropped into the line of text. Scaled on hover rather than resized,
   so growing one never reflows the paragraph around it. */
.bio-pic {
  display: inline-block;
  vertical-align: middle;
  position: relative;
  width: 40px;
  height: 28px;
  margin: 0 6px;
  border-radius: 7px;
  overflow: hidden;
  background: var(--surface-secondary);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14);
  transition: transform 0.4s cubic-bezier(0.34, 1.3, 0.64, 1),
              box-shadow 0.4s ease, border-radius 0.4s ease, z-index 0s;
  will-change: transform;
}
.bio-pic img,
.bio-pic-box {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* a tall photo cropped to a wide slot loses the faces unless the crop is raised */
.bio-pic--face img { object-position: 50% 36%; }

/* a face sitting off to one side keeps its side of the frame when cropped */
.bio-pic--left img { object-position: 35% 50%; }

/* tilts, so a row of them reads like prints and not like icons */
.bio-pic--a { transform: rotate(-3deg); }
.bio-pic--b { transform: rotate(2.5deg); }
.bio-pic--c { transform: rotate(-1.5deg); }
.bio-pic:hover {
  z-index: 5;
  /* radius and shadow are scaled up with the box, so both shrink to compensate */
  border-radius: 2.5px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.16);
  transform: rotate(0deg) scale(var(--pic-scale, 5.6));
}

/* a narrower window has less room for the grown print than it has text */
@media (max-width: 900px) {
  .bio-pic { --pic-scale: 3.6; }
}
@media (hover: none) {
  /* no hover to grow them with, so they are simply bigger from the start */
  .bio-pic { width: 64px; height: 44px; border-radius: 10px; }
}
@media (prefers-reduced-motion: reduce) {
  .bio-pic { transition: none; }
}

/* ---------- Current Interests (Figma node 61:500) ---------- */
.ci-section {
  display: flex;
  flex-direction: column;
  gap: var(--space-7);
  padding: var(--space-7) var(--space-12);
}

.ci-heading {
  margin: 0;
  font-size: var(--fs-h3);
  line-height: var(--lh-h3);
  font-weight: 500;
  color: var(--text-primary);
}

/* four to a row, no card behind them: with the panels gone the covers carry
   the block on their own and it takes half the height */
.ci-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-6);
}

.ci-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.ci-label {
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  color: var(--text-tertiary);
}

/* cover first, caption under it */
.ci-media {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
}

.ci-cover {
  flex: none;
  width: 92px;
  height: 120px;
  border-radius: 6px;
  background: var(--surface-tertiary);
  overflow: hidden;
}
.ci-cover--square { width: 120px; height: 120px; }
.ci-cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* — Listening: vinyl hidden behind the sleeve, slides out on hover — */
.ci-vinyl {
  position: relative;
  width: 120px;
  height: 120px;
  flex: none;
}
.ci-vinyl .ci-cover { position: relative; z-index: 2; }
.ci-vinyl-disc {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: url('assets/vinyl-disc.png') center / cover;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1;
  transform: translateX(0) rotate(0deg);
  transition: transform 0.55s cubic-bezier(0.34, 1.2, 0.64, 1);
}
.ci-vinyl-label {
  width: 34%;
  height: 34%;
  border-radius: 50%;
  object-fit: cover;
  box-shadow: 0 0 0 2px rgba(var(--white), 0.6);
}
.ci-card:hover .ci-vinyl-disc { transform: translateX(48px) rotate(24deg); }

/* — Watching: a VHS tape slides out of its sleeve, the same gesture as the
   vinyl next door. The cassette is drawn in CSS: no asset for something this
   schematic, and it inherits the theme's colours. */
.ci-vhs {
  position: relative;
  width: 92px;
  height: 120px;
  flex: none;
}
.ci-vhs .ci-cover { position: relative; z-index: 2; }
.ci-tape {
  position: absolute;
  left: 4px;
  top: 10px;
  width: 84px;
  height: 100px;
  z-index: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 10px 8px;
  border-radius: 4px;
  background: linear-gradient(160deg, #2b2b2b, #141414);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14);
  transform: translateX(0) rotate(0deg);
  transition: transform 0.55s cubic-bezier(0.34, 1.2, 0.64, 1);
}
/* the window with two reels — the one detail that makes it read as a tape */
.ci-tape-window {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 30px;
  padding: 0 6px;
  border-radius: 3px;
  background: rgba(255, 255, 255, 0.82);
}
.ci-tape-window span {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: #1d1d1d;
  box-shadow: inset 0 0 0 3px rgba(255, 255, 255, 0.9);
}
.ci-tape-label {
  padding: 3px 4px;
  border-radius: 2px;
  background: #e8e4d8;
  color: #2b2b2b;
  font-size: 7px;
  line-height: 9px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-align: center;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.ci-card:hover .ci-tape { transform: translateX(48px) rotate(3deg); }

/* — Watching: flat poster, lifts on hover — */
.ci-cover--poster {
  transition: transform 0.4s cubic-bezier(0.34, 1.2, 0.64, 1),
              box-shadow 0.4s ease;
}
.ci-card:hover .ci-cover--poster {
  transform: translateY(-8px) scale(1.04);
}

/* — Playing: coins burst out from behind the cover on hover. They start
   hidden behind it, so the poster itself does the hiding — no masks. */
.ci-coins {
  position: relative;
  width: 92px;
  height: 120px;
  flex: none;
}
.ci-coins .ci-cover { position: relative; z-index: 2; }
.ci-coin {
  position: absolute;
  left: 50%;
  top: 55%;
  z-index: 1;
  width: 34px;
  height: 34px;
  margin: -17px 0 0 -17px;
  opacity: 0;
  transform: translate(0, 0) scale(0.6) rotate(0deg);
  transition: opacity 0.25s ease, transform 0.6s cubic-bezier(0.22, 1.2, 0.36, 1);
}
/* three different arcs and sizes, so it reads as a handful, not a row */
.ci-card:hover .ci-coin:nth-child(1) { opacity: 1; transform: translate(54px, -46px) scale(1) rotate(22deg); }
.ci-card:hover .ci-coin:nth-child(2) { opacity: 1; transform: translate(72px, 6px) scale(0.78) rotate(-16deg); transition-delay: 0.07s; }
.ci-card:hover .ci-coin:nth-child(3) { opacity: 1; transform: translate(40px, 44px) scale(0.62) rotate(34deg); transition-delay: 0.14s; }

/* — Tinkering: a terminal instead of a cover. Drawn in CSS for the same
   reason as the VHS tape — it is a diagram, not a photograph — and the caret
   only blinks while the card is hovered, so nothing flickers at rest. */
.ci-term {
  width: 92px;
  height: 120px;
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 8px;
  border-radius: 6px;
  background: linear-gradient(160deg, #222, #0e0e0e);
}
.ci-term-bar { display: flex; gap: 4px; }
.ci-term-bar span {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.25);
}
.ci-term-line {
  display: flex;
  align-items: center;
  gap: 2px;
  color: rgba(255, 255, 255, 0.72);
  font-size: 8px;
  line-height: 11px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}
.ci-term-caret {
  width: 4px;
  height: 9px;
  background: #fff;
}
.ci-card:hover .ci-term-caret { animation: ci-caret 0.9s steps(1, end) infinite; }
@keyframes ci-caret { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .ci-card:hover .ci-term-caret { animation: none; }
}

/* — Reading / Playing: 3D case that opens on hover — */
.ci-book {
  position: relative;
  /* a book's own proportion, so a cover fills the face without the title
     being cropped off the top */
  width: 80px;
  height: 120px;
  flex: none;
  perspective: 1200px;
}
.ci-book-front,
.ci-book-paper,
.ci-book-back {
  position: absolute;
  inset: 0;
  border-radius: 6px;
  transform-style: preserve-3d;
}
.ci-book-front {
  z-index: 3;
  overflow: hidden;
  background: var(--surface-tertiary);
  box-shadow: inset 1.4px 0 3px 0 rgba(255, 255, 255, 0.35),
              inset 2.6px 0 3.6px 0 rgba(0, 0, 0, 0.15);
  transform-origin: left center;
  transform: rotateY(0deg);
  transition: transform 0.55s cubic-bezier(0.34, 1.2, 0.64, 1);
}
.ci-book-front img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.ci-book-paper {
  z-index: 2;
  background: #f0f0f0;
  transform: translateZ(-6px) scaleX(0.97);
  opacity: 0;
  transition: opacity 0.3s ease 0.08s;
}
.ci-book-back {
  z-index: 1;
  background: #cfcfcf;
  transform: translateZ(-12px) scaleX(0.96);
}
.ci-card:hover .ci-book-front { transform: rotateY(-34deg); }
.ci-card:hover .ci-book-paper { opacity: 1; }

.ci-text { display: flex; flex-direction: column; gap: 2px; }
.ci-title { font-size: var(--fs-body); line-height: var(--lh-body); font-weight: 500; color: var(--text-primary); }
.ci-subtitle { font-size: var(--fs-body-s); line-height: var(--lh-body-s); color: var(--text-tertiary); }

.skeleton-loader {
  position: relative;
  background: var(--surface-tertiary);
}
.skeleton-loader::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    100deg,
    transparent 30%,
    rgba(255, 255, 255, 0.85) 50%,
    transparent 70%
  );
  background-size: 200% 100%;
  animation: skeleton-shimmer 1.4s ease-in-out infinite;
}
@keyframes skeleton-shimmer {
  0% { background-position: 150% 0; }
  100% { background-position: -50% 0; }
}

/* ---------- Work: intro ---------- */
/* A plain stack of sentences — the only ornament is the inline company
   chips, so the eye lands on the names. */
.work-intro {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
  padding-bottom: var(--space-6);
}
.wi-text {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
/* a burst of colour that only shows when you point at the photo, rolled
   from the same palette as every other accent */
.wi-photo { position: relative; width: -moz-fit-content; width: fit-content; }
.wi-photo::before {
  content: '';
  position: absolute;
  /* tight around the photo, with just enough spill to reach under the first
     line of text — the glow belongs to the portrait, not to the whole block */
  inset: -12px -30px -26px -12px;
  z-index: 0;
  border-radius: 50%;
  background:
    radial-gradient(56% 64% at 30% 34%, var(--p1) 0%, transparent 72%),
    radial-gradient(54% 62% at 62% 50%, var(--p2) 0%, transparent 74%),
    radial-gradient(58% 66% at 44% 82%, var(--p3) 0%, transparent 74%);
  filter: blur(16px) saturate(1.15);
  opacity: 0;
  transform: scale(0.92);
  transition: opacity 0.35s ease, transform 0.45s cubic-bezier(0.34, 1.3, 0.64, 1);
}
/* the glow passes behind the words, never over them */
.wi-text { position: relative; z-index: 1; }
.wi-photo:hover::before { opacity: 1; transform: scale(1.03); }

/* one tilted card, echoing the fanned photos on About without repeating the
   whole trick; it straightens when you point at it */
.wi-portrait {
  position: relative;
  z-index: 1;
  flex: none;
  width: 140px;
  height: 140px;
  margin: 0;
  border-radius: 20px;
  overflow: hidden;
  transform: rotate(-3deg);
  transition: transform 0.45s cubic-bezier(0.34, 1.3, 0.64, 1);
}
.wi-portrait:hover { transform: rotate(0deg) scale(1.03); }
.wi-portrait img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0%;
  transform: scale(1.45);
  user-select: none;
}

.wi-line {
  margin: 0;
  max-width: 760px;
  font-size: var(--fs-body);
  line-height: 26px;
  color: var(--text-primary);
}
.wi-line--muted { color: var(--text-tertiary); }
.wi-strong { font-weight: 600; }

/* chip + name travel together, so a wrap never leaves a logo stranded.
   Plain inline text — not a flex box — so the name keeps the paragraph's
   own baseline and the chip is the only thing that needs positioning. */
.wi-org { white-space: nowrap; transition: opacity 0.15s ease; }
.wi-org:hover { opacity: 0.6; }
/* this line carries the button, so it gets the full content width and its
   tail never breaks — the pill can't end up stranded on a line of its own */
.wi-tail { white-space: nowrap; }
.wi-cta { white-space: nowrap; font-weight: 500; }
/* the one call to action in the intro: a solid black pill, so it reads as a
   button inside running text rather than one more underlined word */
.wi-cta-box {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  margin-left: var(--space-1);
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--surface-inverse);
  color: var(--text-inverse);
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  font-weight: 500;
  white-space: nowrap;
  vertical-align: middle;
  transition: opacity 0.15s ease, transform 0.2s cubic-bezier(0.34, 1.4, 0.64, 1);
}
.wi-cta-box:hover { opacity: 0.85; transform: translateY(-1px); }
.wi-link {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}
/* `middle` puts the tile's centre on the lowercase middle, which is where
   the eye expects an icon sitting in running text */
.wi-chip {
  display: inline-block;
  width: 20px;
  height: 20px;
  margin-right: 5px;
  vertical-align: middle;
  border-radius: 6px;
  /* a hair of grey: enough to read as a tile under a transparent mark,
     light enough not to sit heavier than the covers beside it */
  background: rgba(var(--black), 0.07);
  overflow: hidden;
}
.wi-chip img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* a mark that ships on a white square: contained with a little air, and
   multiplied so its white ground drops into the tile's grey */
.wi-chip--pad img {
  object-fit: contain;
  padding: 2px;
  mix-blend-mode: multiply;
}
.wi-chip--hidden > span { display: block; width: 100%; height: 100%; }

/* ---------- Work: cases ---------- */
/* the intro owns the first screen; cases start well below it */
.work-cases { padding-top: var(--space-9); }
.wc-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6) var(--space-6);
}
.wc-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
}
.wc-cover {
  width: 100%;
  aspect-ratio: 4 / 3;
  border-radius: 16px;
  overflow: hidden;
  margin-bottom: var(--space-3);
  transition: transform 0.4s cubic-bezier(0.34, 1.2, 0.64, 1);
}
/* the laptop fills this frame edge to edge, so its discs fly out in front of
   the screen instead of behind it the way the phone cards do */
.wc-card[href*="seedja"] .wc-chips { z-index: 2; }
/* the laptop owns the lower two thirds of this frame, so its three discs sit
   in the strip of background above it and never land on the screen */
.wc-card[href*="seedja"] .wc-chip:nth-child(1) { --cx: 14%; --cy: 12%; --dx: 36; --dy: 40; }
.wc-card[href*="seedja"] .wc-chip:nth-child(2) { --cx: 50%; --cy: 7%; --dx: 0; --dy: 48; }
.wc-card[href*="seedja"] .wc-chip:nth-child(3) { --cx: 86%; --cy: 12%; --dx: -36; --dy: 40; }
/* and the two claims move down onto the screen, out of the discs' strip */
.wc-card[href*="seedja"] .wc-badge:nth-child(1) { --bx: 4%; --by: 84%; --dx: 26; --dy: -18; }

/* a laptop instead of a phone: landscape, so it sits low and wide in the
   frame and lifts with everything else when the card is hovered */
.wc-laptop {
  position: absolute;
  left: 50%;
  /* the screen peeks up from the bottom: full width so nothing is cut at the
     sides, low enough that the base runs off the bottom edge */
  top: 28%;
  width: 100%;
  height: auto;
  transform: translateX(-50%);
  filter: drop-shadow(0 18px 36px rgba(0, 0, 0, 0.32));
  transition: transform 0.45s cubic-bezier(0.34, 1.3, 0.64, 1);
}
.wc-card:hover .wc-laptop { transform: translateX(-50%) translateY(-8px); }

/* a research project has no screen to show, so its cover is the finding
   itself, set in type: the entry ritual before and after */
.wc-cover--type {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-6);
  background: var(--surface-inverse);
  color: var(--text-inverse);
  text-align: center;
}
.wc-type-label { font-size: var(--fs-caption); line-height: var(--lh-caption); color: rgba(var(--white), 0.6); }
/* the deadline, stated at the top of the card the way the user states it */
.wc-type-top {
  position: absolute;
  top: var(--space-5);
  left: var(--space-5);
  font-size: var(--fs-body-s);
  line-height: 20px;
  font-weight: 500;
  color: rgba(var(--white), 0.85);
}
/* forty-two ticks along the bottom: one per day of the six weeks left */
.wc-type-ticks {
  position: absolute;
  left: var(--space-5);
  right: var(--space-5);
  bottom: var(--space-5);
  height: 14px;
  background: repeating-linear-gradient(
    90deg,
    rgba(var(--white), 0.42) 0 1px,
    transparent 1px calc(100% / 42)
  );
}
.wc-type-old {
  font-size: clamp(28px, 3vw, 40px);
  line-height: 1.05;
  letter-spacing: -0.03em;
  font-weight: 500;
  color: rgba(var(--white), 0.5);
  text-decoration: line-through;
  text-decoration-thickness: 2px;
}
.wc-type-arrow { font-size: var(--fs-body); line-height: 1; color: rgba(var(--white), 0.45); }
.wc-type-new {
  font-size: clamp(44px, 5vw, 66px);
  line-height: 1.02;
  letter-spacing: -0.04em;
  font-weight: 500;
}

/* a project under NDA: the cover is blurred past recognition and says why,
   so the card still carries the work without showing it */
.wc-card--nda { cursor: default; }
.wc-cover-box { width: 100%; height: 100%; }
.wc-cover--nda > img,
.wc-cover--nda > .wc-cover-box {
  /* scaled up first, or the blur would fray the edges of the frame; the
     radius is heavy enough that a wordmark underneath stays unreadable */
  transform: scale(1.25);
  filter: blur(32px) saturate(0.92);
}
/* a live project with a long summary: it is the last card in the row, so
   letting it run past two lines costs nothing */

/* this card says everything in words, so its summary is never clipped */
.wc-nda {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 8px 14px;
  border-radius: 999px;
  background: rgba(var(--white), 0.78);
  backdrop-filter: blur(8px) saturate(140%);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-primary);
  white-space: nowrap;
}
.wc-nda svg { width: 12px; height: 14px; }

/* a desktop screen instead of a phone: framed like a window, so a flat
   screenshot reads as an app and not as a pasted picture */
.wc-screen {
  position: absolute;
  left: 50%;
  bottom: -14%;
  width: 86%;
  margin: 0;
  overflow: hidden;
  border-radius: 10px;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.1);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.28);
  transform: translateX(-50%);
  transition: transform 0.45s cubic-bezier(0.34, 1.3, 0.64, 1);
}
.wc-card:hover .wc-screen { transform: translateX(-50%) translateY(-8px); }
/* the window bar: three dots are enough to say "this is a screen" */
.wc-screen-bar {
  display: flex;
  align-items: center;
  gap: 5px;
  height: 20px;
  padding: 0 9px;
  background: #f3f3f5;
  border-bottom: 1px solid rgba(0, 0, 0, 0.07);
}
.wc-screen-bar i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.18);
}
.wc-screen img {
  display: block;
  width: 100%;
  height: auto;
}

/* every layer over the cover — the phone's stage, the discs, the badges —
   lifts with it, or whatever stays behind pokes out under the raised frame */
.wc-cover,
.wc-stage,
.wc-chips,
.wc-badges { transition: transform 0.4s cubic-bezier(0.34, 1.2, 0.64, 1); }
.wc-card:hover .wc-cover,
.wc-card:hover .wc-stage,
.wc-card:hover .wc-chips,
.wc-card:hover .wc-badges { transform: translateY(-6px) scale(1.01); }
.wc-cover { position: relative; }
.wc-cover > img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
/* a screen standing on top of the shot: it sits in the middle, overflows the
   bottom edge, and rises a little when the card is hovered */
.wc-mockup {
  position: absolute;
  left: 50%;
  /* cropped well past the bottom edge: the screen is the point, the hardware
     under it is not */
  bottom: -52%;
  width: auto !important;
  height: 136% !important;
  object-fit: contain !important;
  transform: translateX(-50%);
  filter: drop-shadow(0 18px 30px rgba(0, 0, 0, 0.3));
  transition: transform 0.45s cubic-bezier(0.34, 1.3, 0.64, 1);
}
.wc-card:hover .wc-mockup { transform: translateX(-50%) translateY(-8px); }

/* four discs that shoot out from behind the phone on hover and settle at the
   corners of the cover, each hanging over its edge. They live outside
   .wc-cover so they can break its frame; the layer matches the cover's 4:3
   box and is a size container, so both the discs and their flight are
   expressed in units of that box and scale with the card. */
.wc-card { position: relative; }
.wc-chips,
.wc-badges,
.wc-stage {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  aspect-ratio: 4 / 3;
  container-type: size;
  pointer-events: none;
}
/* the phone sits in its own layer above the discs, clipped to the cover's
   box — so a disc can hide behind it instead of landing on top */
.wc-stage { overflow: hidden; border-radius: 16px; }
.wc-chip {
  position: absolute;
  left: var(--cx);
  top: var(--cy);
  display: grid;
  place-items: center;
  width: 21cqw;
  height: 21cqw;
  border-radius: 50%;
  /* frosted glass: the track blurs through each disc, tinted by its own icon,
     with a lit top edge so the circle reads as a physical lens */
  background:
    linear-gradient(160deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.14)),
    var(--tint);
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  backdrop-filter: blur(12px) saturate(1.4);
  box-shadow:
    0 10px 26px rgba(0, 0, 0, 0.2),
    inset 0 0 0 1px rgba(255, 255, 255, 0.5),
    inset 0 2px 1px rgba(255, 255, 255, 0.65);
  opacity: 0;
  /* parked behind the phone in the middle, small */
  transform: translate(-50%, -50%) translate(calc(var(--dx) * 1cqw), calc(var(--dy) * 1cqh)) scale(0.4);
  transition: opacity 0.22s ease, transform 0.55s cubic-bezier(0.22, 1.2, 0.36, 1);
}
/* --cx/--cy are where a disc lands, --dx/--dy point back at the centre it
   starts from; every pair sits on an edge so the frame gets broken */
.wc-chip:nth-child(1) { --cx: 50%; --cy: 78%; --dx: 0; --dy: -28; --tint: rgba(255, 92, 150, 0.22); }
.wc-chip:nth-child(2) { --cx: 83%; --cy: 8%; --dx: -33; --dy: 42; --tint: rgba(124, 92, 255, 0.22); }
.wc-chip:nth-child(3) { --cx: 11%; --cy: 56%; --dx: 39; --dy: -6; --tint: rgba(255, 186, 60, 0.24); }
.wc-chip:nth-child(4) { --cx: 93%; --cy: 71%; --dx: -43; --dy: -21; --tint: rgba(80, 160, 255, 0.22); }
.wc-chip img,
.wc-chip svg { width: 56%; height: 56%; object-fit: contain; }
/* emoji stand in for icons on cases with no icon set of their own */
.wc-chip-emoji { font-size: 38px; line-height: 1; }
.wc-card:hover .wc-chip { opacity: 1; transform: translate(-50%, -50%); }
/* two claims that fly in with the discs — same glass, pill-shaped */
.wc-badge {
  position: absolute;
  left: var(--bx);
  top: var(--by);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px 7px 9px;
  border-radius: 999px;
  /* same glass as the discs, tinted per claim */
  background:
    linear-gradient(160deg, rgba(255, 255, 255, 0.78), rgba(255, 255, 255, 0.46)),
    var(--tint);
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  backdrop-filter: blur(12px) saturate(1.4);
  box-shadow:
    0 10px 26px rgba(0, 0, 0, 0.18),
    inset 0 0 0 1px rgba(255, 255, 255, 0.6);
  color: #171717;
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  font-weight: 600;
  white-space: nowrap;
  opacity: 0;
  transform: translate(calc(var(--dx) * 1cqw), calc(var(--dy) * 1cqh)) scale(0.6);
  transition: opacity 0.22s ease, transform 0.55s cubic-bezier(0.22, 1.2, 0.36, 1);
}
.wc-badge:nth-child(1) { --bx: 4%; --by: 9%; --dx: 28; --dy: 36; --tint: rgba(124, 92, 255, 0.3); }
.wc-badge:nth-child(2) { --bx: 3%; --by: 83%; --dx: 30; --dy: -30; --tint: rgba(80, 160, 255, 0.3); }
.wc-badge-emoji { font-size: 14px; line-height: 1; }
.wc-card:hover .wc-badge { opacity: 1; transform: none; }
.wc-card:hover .wc-badge:nth-child(1) { transition-delay: 0.22s; }
.wc-card:hover .wc-badge:nth-child(2) { transition-delay: 0.28s; }

/* fired one after another, so they read as leaving the phone in turn */
.wc-card:hover .wc-chip:nth-child(2) { transition-delay: 0.06s; }
.wc-card:hover .wc-chip:nth-child(3) { transition-delay: 0.12s; }
.wc-card:hover .wc-chip:nth-child(4) { transition-delay: 0.18s; }
/* title and year share a line: the year is reference, not a heading of its
   own, and the old meta row above the title competed with it */
.wc-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  width: 100%;
}
.wc-title {
  margin: 0;
  font-size: var(--fs-body-l);
  line-height: 26px;
  font-weight: 600;
  color: var(--text-primary);
}
.wc-year {
  flex: none;
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  color: var(--text-tertiary);
  font-variant-numeric: tabular-nums;
}
.wc-desc {
  margin: 0;
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  color: var(--text-secondary);
  /* every card reserves the same three lines, whatever its summary says, so
     the tags below them sit on one baseline across the whole row */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(3 * var(--lh-body-s));
}
/* a card can name more than one craft, so the tags wrap as a row */
.wc-tags { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-1); }
.wc-tag {
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--surface-secondary);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  color: var(--text-secondary);
}

/* ---------- Kind Words ---------- */
.kind-words {
  display: flex;
  flex-direction: column;
  gap: var(--space-7);
  padding: var(--space-7) var(--space-12);
}
.kw-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.kw-subtitle {
  margin: 0;
  font-size: 15px;
  line-height: 22.5px;
  color: var(--text-tertiary);
}

/* sits on the page grid; the outer cards fade at the edges to show
   the row continues past them */
.kw-marquee {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  overscroll-behavior-x: contain;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
}
.kw-marquee::-webkit-scrollbar { display: none; }

/* every card is a third of the visible row, so exactly 3 show at a time
   and the rest are reached by scrolling */
.kw-track {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: calc((100% - 2 * var(--space-6)) / 3);
  gap: var(--space-6);
}

.kw-card {
  min-width: 0;
  min-height: 340px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: var(--space-5);
  padding: 25px;
  border-radius: 20px;
  background: var(--surface-secondary);
}
.kw-quote-mark {
  flex: none;
  width: 44px;
  height: 44px;
  fill: rgba(var(--black), 0.14);
}
.kw-quote {
  margin: 0;
  margin-bottom: auto;
  font-size: 15px;
  line-height: 22.5px;
  color: var(--text-secondary);
}
.kw-divider {
  height: 1px;
  background: var(--border-primary);
}
.kw-author {
  display: flex;
  align-items: center;
  gap: 15px;
}
.kw-avatar {
  flex: none;
  width: 50px;
  height: 50px;
  border-radius: 50%;
  background: var(--surface-tertiary);
}
.kw-author-text { display: flex; flex-direction: column; }
.kw-name { font-size: 15px; line-height: 22.5px; color: var(--text-primary); }
.kw-role { font-size: 12px; line-height: 18px; color: var(--text-tertiary); }

.footer {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-6);
  flex-wrap: wrap;
  padding: var(--space-7) var(--space-12);
  border-top: 1px solid var(--border-primary);
  color: var(--text-tertiary);
  font-size: var(--fs-body-s);
}
/* the safety net: every page is reachable from the bottom of every page */
.footer-nav { display: flex; flex-wrap: wrap; gap: var(--space-6); }
.footer-nav a { color: var(--text-secondary); transition: color 0.15s ease; }
.footer-nav a:hover,
.footer-nav a[aria-current="page"] { color: var(--text-primary); }

/* ---------- Playground ----------
   Lives inside About: side projects say as much about the person as the bio,
   and a page of its own was standing empty. */
.playground { display: flex; flex-direction: column; gap: var(--space-6); }
.pg-head { display: flex; flex-direction: column; gap: var(--space-2); }
.pg-subtitle {
  margin: 0;
  font-size: var(--fs-body-l);
  line-height: 32px;
  color: var(--text-secondary);
}
.pg-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
}
.pg-tile {
  aspect-ratio: 4 / 3;
  border-radius: 16px;
}

/* ---------- Awards & Accolades ---------- */
.awards { position: relative; display: flex; flex-direction: column; gap: var(--space-5); }

.awards-list { display: flex; flex-direction: column; }

.award-row {
  position: relative;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-6);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--border-primary);
  cursor: pointer;
}
/* the hovered row floats above its neighbours so the preview is never clipped */
.award-row:hover { z-index: 5; }

.award-left { display: flex; flex-direction: column; gap: 2px; }

.award-title-row { display: flex; align-items: center; gap: var(--space-2); }
.award-title { font-size: var(--fs-body-l); line-height: 26px; font-weight: 600; color: var(--text-primary); }
.award-arrow {
  font-size: 14px;
  color: var(--text-secondary);
  transition: transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.award-row:hover .award-arrow { transform: translate(3px, -3px); }

.award-subtitle { font-size: var(--fs-body-s); line-height: var(--lh-body-s); }
.award-company { color: var(--text-secondary); }
.award-description { color: var(--text-tertiary); margin-left: var(--space-1); }

.award-years { flex: none; color: var(--text-tertiary); font-size: var(--fs-body-s); line-height: var(--lh-body-s); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Floating hover preview — one per row, overflowing it top and bottom. The
   offsets grew with the rows, so they shrink with them too. */
.award-preview {
  position: absolute;
  top: -44px;
  bottom: -44px;
  right: -36px;
  width: 250px;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  border-radius: 16px;
  overflow: hidden;
  background: var(--surface-secondary);
  border: 1px solid var(--border-primary);
  box-shadow: var(--shadow-soft);
  transform: rotate(7deg) scale(0.94) translateY(12px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease, transform 0.45s cubic-bezier(0.34, 1.3, 0.64, 1);
  z-index: 5;
}
.award-row:hover .award-preview {
  opacity: 1;
  transform: rotate(4deg) scale(1) translateY(0);
}
.award-preview-image {
  flex: 1;
  min-height: 0;
}
.award-preview img {
  flex: 1;
  min-height: 0;
  width: 100%;
  object-fit: cover;
  display: block;
}

/* 256px gutters are right on a wide monitor and absurd on a laptop, where
   they squeezed the About bio to a 45-character measure — step them down */
@media (max-width: 1600px) {
  .section,
  .ci-section,
  .kind-words,
  .footer {
    padding-left: var(--space-10);
    padding-right: var(--space-10);
  }
}
@media (max-width: 1100px) {
  .section,
  .ci-section,
  .kind-words,
  .footer {
    padding-left: var(--space-7);
    padding-right: var(--space-7);
  }

  /* narrower cards need a fourth line to hold the same sentences — still the
     same count on every card, so the tags keep their shared baseline */
  .wc-desc {
    -webkit-line-clamp: 4;
    min-height: calc(4 * var(--lh-body-s));
  }
}

/* ---------- Custom cursor ----------
   An arrow plus a label chip that names what you're over. Only mounted on a
   real pointer (see script.js), and only then is the system cursor hidden. */
.has-cursor,
.has-cursor a,
.has-cursor button { cursor: none; }

.cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9999;
  display: flex;
  align-items: flex-start;
  pointer-events: none;
  user-select: none;
  opacity: 0;
  transition: opacity 0.18s ease;
  will-change: transform;
}
.cursor.is-visible { opacity: 1; }

.cursor-arrow {
  display: block;
  width: 18px;
  height: 18px;
  color: var(--cursor-ink, var(--text-primary));
  /* the system arrow casts one, and without it the tip vanishes on photos */
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.25));
  transition: transform 0.12s ease;
}
.cursor.is-down .cursor-arrow { transform: scale(0.82); }

.cursor-label {
  margin-left: 10px;
  margin-top: 6px;
  padding: 3px 9px;
  border-radius: 999px;
  border-top-left-radius: 3px;
  background: var(--cursor-ink, var(--text-primary));
  color: #fff;
  font-size: 12px;
  line-height: 18px;
  font-weight: 500;
  /* short labels keep to one line on their own; a long one wraps instead of
     running off the side of the screen */
  max-width: 280px;
  white-space: normal;
  text-wrap: pretty;
  opacity: 0;
  transform-origin: top left;
  transition: opacity 0.15s ease;
}
.cursor.is-labelled .cursor-label { opacity: 1; }

/* ---------- Tablet and phone ----------
   The desktop layout leans on wide two-column rows and a 480px photo fan;
   below 900px those are rebuilt rather than merely squeezed. */
@media (max-width: 900px) {
  .page-head {
    flex-wrap: wrap;
    gap: var(--space-4);
    padding-top: var(--space-6);
  }

  .work-cases { padding-top: var(--space-8); }
  .wc-grid { grid-template-columns: repeat(2, 1fr); }
  .pg-grid { grid-template-columns: repeat(2, 1fr); }
  .ci-grid { grid-template-columns: repeat(2, 1fr); }


  /* two cards per screen instead of three */
  .kw-track { grid-auto-columns: calc((100% - var(--space-6)) / 2); }

  .footer { flex-direction: column; align-items: flex-start; gap: var(--space-4); }
}

@media (max-width: 600px) {
  .section,
  .ci-section,
  .kind-words,
  .footer {
    padding-left: var(--space-5);
    padding-right: var(--space-5);
  }

  /* one column everywhere: at this width a second column is unreadable */
  .wc-grid,
  .pg-grid,
  .ci-grid { grid-template-columns: 1fr; }
  /* the cover keeps its 4:3 box here too: the phone, the discs and the badges
     are all laid out against that ratio, and a 3:2 cover let them spill out */

  .kw-track { grid-auto-columns: 86%; }
  .kw-card { min-height: 0; }

  /* the hover preview has nowhere to go on a touch screen, and no hover */
  .award-preview { display: none; }
  .award-row { gap: var(--space-4); }


  .ci-media { gap: var(--space-7); }
  .wi-portrait { width: 112px; height: 112px; }
  .work-cases { padding-top: var(--space-7); }
}


/* ---------- Loader ----------
   Covers the page until it is ready, with the wordmark doing its own flicker
   in the middle. The timing lives in CSS, not JS, so the cover still lifts
   on its own if the script never runs. */
.loader {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* lifted off the optical centre — dead centre reads as low */
  padding-bottom: 14vh;
  background: var(--surface-primary);
  animation: loader-out 0.45s cubic-bezier(0.4, 0, 0.2, 1) 0.75s forwards;
}
.loader-mark {
  /* scaled rather than resized, so the four cuts keep their proportions */
  transform: scale(1.2);
  animation: loader-mark 0.45s cubic-bezier(0.4, 0, 0.2, 1) 0.75s forwards;
}
@keyframes loader-out {
  to { opacity: 0; visibility: hidden; }
}
@keyframes loader-mark {
  to { transform: scale(1.05); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .loader { display: none; }
}

/* ---------- Case study ----------
   A long read with no screenshots: the argument is carried by text, two
   drawn curves and a handful of typographic devices. */
.case-hero { display: flex; flex-direction: column; gap: var(--space-4); }
.case-eyebrow {
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  color: var(--text-tertiary);
}
.case-title {
  margin: 0;
  max-width: 900px;
  font-size: var(--fs-h1);
  line-height: var(--lh-h1);
  letter-spacing: var(--ls-h1);
  font-weight: 600;
}
.case-lead {
  margin: 0;
  max-width: 760px;
  font-size: var(--fs-body-l);
  line-height: 30px;
  color: var(--text-secondary);
}
.case-tags { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.case-tag {
  padding: 5px 12px;
  border-radius: 999px;
  border: 1px solid var(--border-primary);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  color: var(--text-secondary);
}

/* the cover: one photograph at the top, then nothing but argument */
.case-cover { margin: 0 0 var(--space-7); }
.case-cover img {
  display: block;
  width: 100%;
  max-height: 420px;
  object-fit: cover;
  border-radius: 20px;
}

/* the facts row: what a recruiter scans before reading a word */
.case-facts {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-4) var(--space-6);
  margin: var(--space-3) 0 0;
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-primary);
}
.case-facts dt {
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
}
.case-facts dd {
  margin: 2px 0 0;
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  color: var(--text-primary);
}

/* two columns: the section's name parks on the left while its argument
   scrolls past on the right */
.case-block {
  display: grid;
  grid-template-columns: 220px minmax(0, 1fr);
  gap: var(--space-8);
  align-items: start;
}
.case-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  position: sticky;
  top: var(--space-6);
}
.case-body { display: flex; flex-direction: column; gap: var(--space-5); }
.case-step {
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  font-variant-numeric: tabular-nums;
  color: var(--text-tertiary);
}
.case-text,
.case-list,
.case-note {
  margin: 0;
  max-width: 760px;
  font-size: var(--fs-body);
  line-height: 26px;
  color: var(--text-secondary);
}
.case-text strong, .case-list strong { color: var(--text-primary); font-weight: 600; }
.case-list { padding-left: 1.2em; display: flex; flex-direction: column; gap: var(--space-2); }
.case-note {
  padding-left: var(--space-4);
  border-left: 2px solid var(--text-primary);
  color: var(--text-primary);
}

/* the one chart: two curves between the same two points */
.case-chart { margin: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.case-chart svg { width: 100%; max-width: 760px; height: auto; overflow: visible; }
.chart-axis { stroke: var(--border-primary); stroke-width: 1; }
.chart-line { fill: none; stroke-width: 2.5; stroke-linecap: round; }
.chart-line--now { stroke: var(--text-tertiary); }
.chart-line--goal { stroke: var(--text-primary); stroke-dasharray: 5 5; }
.chart-dot--now { fill: var(--text-tertiary); }
.chart-dot--goal { fill: var(--text-primary); }
.chart-label { font-size: 13px; font-weight: 600; fill: var(--text-primary); }
.chart-label--goal { fill: var(--text-primary); }
.chart-label--now { fill: var(--text-tertiary); }
.chart-tick { font-size: 11px; fill: var(--text-tertiary); }
.case-chart figcaption {
  max-width: 760px;
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  color: var(--text-tertiary);
}

/* empty slots waiting for screens: sized by ratio so dropping an image in
   later changes nothing about the layout around them */
.case-slot { margin: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.case-slot--wide { max-width: 1000px; }
.case-slot-box,
.case-slot img {
  width: 100%;
  aspect-ratio: var(--ratio, 16 / 9);
  border-radius: 16px;
  object-fit: cover;
}
.case-slot img { display: block; height: auto; }
.case-slot figcaption {
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  color: var(--text-tertiary);
}

/* the money chain, as pills */
.case-flow { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.case-flow-step {
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--border-primary);
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  font-weight: 500;
}
.case-flow-step.is-focus { background: var(--surface-inverse); border-color: var(--surface-inverse); color: var(--text-inverse); }
.case-flow-arrow { color: var(--text-tertiary); }

.case-quotes { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
.case-quote {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
  border-radius: 16px;
  background: var(--surface-secondary);
}
.case-quote p {
  margin: 0;
  font-size: var(--fs-body-l);
  line-height: 28px;
  font-weight: 500;
  color: var(--text-primary);
}
.case-quote footer { display: flex; flex-direction: column; gap: 2px; }
.case-quote-who { font-size: var(--fs-body-s); line-height: var(--lh-body-s); color: var(--text-secondary); }
.case-quote-tag { font-size: var(--fs-caption); line-height: var(--lh-caption); color: var(--text-tertiary); }

.case-move { display: flex; flex-direction: column; gap: var(--space-4); }
.case-move-title {
  margin: 0;
  font-size: var(--fs-body-l);
  line-height: 26px;
  font-weight: 600;
  color: var(--text-primary);
}
/* barrier on the left, the move against it on the right */
.case-ba { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
.case-ba-col {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-5);
  border-radius: 16px;
  background: var(--surface-secondary);
}
.case-ba-col--after { background: rgba(var(--black), 0.05); }
.case-ba-col p { margin: 0; font-size: var(--fs-body-s); line-height: 22px; color: var(--text-secondary); }
.case-ba-label {
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-tertiary);
}
.case-ba-col--after .case-ba-label { color: var(--text-primary); }

.case-score { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-4); }
.case-score-value { font-size: 44px; line-height: 48px; font-weight: 600; letter-spacing: -0.02em; color: var(--text-primary); }
.case-dots { display: flex; gap: 6px; }
.case-dots i { width: 10px; height: 10px; border-radius: 50%; background: var(--text-primary); }
.case-score-label { font-size: var(--fs-body); line-height: var(--lh-body); color: var(--text-secondary); }

.case-metrics {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3) var(--space-6);
  max-width: 900px;
}
.case-metrics li {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-top: var(--space-3);
  border-top: 1px solid var(--border-primary);
}
.case-metrics strong { font-size: var(--fs-body); line-height: var(--lh-body); font-weight: 600; }
.case-metrics span { font-size: var(--fs-body-s); line-height: var(--lh-body-s); color: var(--text-tertiary); }

@media (max-width: 900px) {
  .case-quotes,
  .case-ba,
  .case-metrics { grid-template-columns: 1fr; }
  /* one column again: a 220px rail leaves nothing for the text */
  .case-block { grid-template-columns: 1fr; gap: var(--space-4); }
  .case-head { position: static; }
}
@media (max-width: 600px) {
  .case-title { font-size: var(--fs-h2); line-height: var(--lh-h2); }
}

/* scope chips */
.case-chips {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.case-chips li {
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--surface-secondary);
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  color: var(--text-primary);
}

/* numbered challenges, problem beside solution */
.case-body--challenges { gap: var(--space-8); }
.case-challenge {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border-primary);
}
.case-challenge-no {
  font-size: var(--fs-body-s);
  line-height: var(--lh-body-s);
  font-variant-numeric: tabular-nums;
  color: var(--text-tertiary);
}
.case-challenge-pair { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }

/* what to read next */
.case-next { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--space-4); }
.case-next-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-6);
  border-radius: 16px;
  background: var(--surface-secondary);
  transition: background 0.2s ease, transform 0.3s cubic-bezier(0.34, 1.2, 0.64, 1);
}
.case-next-card:hover { background: var(--surface-tertiary); transform: translateY(-4px); }
.case-next-tag { font-size: var(--fs-caption); line-height: var(--lh-caption); color: var(--text-tertiary); }
.case-next-title { font-size: var(--fs-body-l); line-height: 26px; font-weight: 600; }
.case-next-desc { font-size: var(--fs-body-s); line-height: var(--lh-body-s); color: var(--text-secondary); }

@media (max-width: 900px) {
  .case-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .case-challenge-pair,
  .case-next { grid-template-columns: 1fr; }
}

/* ---------- Case study — editorial (cs-*) ----------
   Black, white and one typeface. The page is a reading column with a hanging
   margin: section numbers and labels sit out in the margin, the argument runs
   at a fixed measure, and the data — funnel, segments, prioritisation — is
   drawn in ink rather than screenshotted. */
.case-doc {
  max-width: var(--max-w);
  margin-inline: auto;
  padding: 0 var(--space-12) var(--space-10);
}
/* the case runs in the same content zone as the page head, edge to edge:
   the measure of the running text is capped on the text itself, not here */
.cs-wrap { width: 100%; }
.cs-read { max-width: 66ch; }

/* the opening sits left, like the first page of a chapter */
.cs-hero {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-5);
  padding: var(--space-9) 0 var(--space-8);
}
.cs-title {
  margin: 0;
  max-width: 16ch;
  font-size: clamp(44px, 6vw, 88px);
  line-height: 0.98;
  letter-spacing: -0.04em;
  font-weight: 500;
  text-wrap: balance;
}
/* the product's own icon beside its name, on the same grey tile the work
   cards use, with its white ground multiplied away */
.cs-titlerow { display: flex; align-items: center; gap: var(--space-5); }
.cs-appicon {
  flex: none;
  width: clamp(48px, 6vw, 76px);
  aspect-ratio: 1;
  border-radius: 22%;
  overflow: hidden;
  background: rgba(var(--black), 0.07);
}
.cs-appicon img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  padding: 8%;
  mix-blend-mode: multiply;
}

.cs-sub {
  margin: 0;
  max-width: 44ch;
  font-size: clamp(18px, 1.6vw, 22px);
  line-height: 1.45;
  letter-spacing: -0.01em;
  color: var(--text-secondary);
}
.cs-meta { display: flex; flex-wrap: wrap; gap: var(--space-3); font-size: var(--fs-body-s); line-height: 20px; color: var(--text-tertiary); }
.cs-meta i { font-style: normal; opacity: 0.45; }

/* every section hangs its number and label in the margin */
.cs-sec {
  display: grid;
  grid-template-columns: 180px minmax(0, 1fr);
  gap: var(--space-8);
  padding: var(--space-9) 0;
  /* barely there: the rule separates, it does not divide */
  border-top: 1px solid rgba(var(--black), 0.08);
}
.cs-side { display: flex; flex-direction: column; gap: var(--space-2); position: sticky; top: var(--space-7); }
.cs-no { font-size: var(--fs-body-s); line-height: 20px; font-variant-numeric: tabular-nums; color: var(--text-tertiary); }
.cs-eyebrow { font-size: var(--fs-body-s); line-height: 20px; font-weight: 600; color: var(--text-primary); }
.cs-col { display: flex; flex-direction: column; gap: var(--space-6); }

/* the three sizes of voice: statement, lead, body */
.cs-head {
  margin: 0;
  max-width: 24ch;
  font-size: clamp(26px, 2.6vw, 36px);
  line-height: 1.12;
  letter-spacing: -0.035em;
  font-weight: 500;
  text-wrap: balance;
}
.cs-head--wide { max-width: 32ch; }
.cs-lead {
  margin: 0;
  max-width: 58ch;
  font-size: clamp(19px, 1.5vw, 22px);
  line-height: 1.5;
  letter-spacing: -0.015em;
  color: var(--text-primary);
}
.cs-p { margin: 0; max-width: 66ch; font-size: 17px; line-height: 29px; color: var(--text-secondary); }
.cs-p strong, .cs-lead strong { color: var(--text-primary); font-weight: 500; }
/* an in-text link to another section of the same case */
.cs-link {
  color: var(--text-primary);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: rgba(var(--black), 0.3);
  transition: text-decoration-color 0.2s ease;
}
.cs-link:hover { text-decoration-color: currentColor; }

/* a phrase worth slowing down on, underlined by a hairline rather than a colour */
.cs-key { color: var(--text-primary); font-weight: 500; text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 4px; text-decoration-color: rgba(var(--black), 0.25); }
.cs-finding { margin: var(--space-4) 0 calc(var(--space-2) * -1); font-size: var(--fs-body); line-height: 24px; font-weight: 600; letter-spacing: -0.01em; }
.cs-sub-head { margin: var(--space-4) 0 0; font-size: var(--fs-body-l); line-height: 26px; font-weight: 600; letter-spacing: -0.01em; }
.cs-stack-text { display: flex; flex-direction: column; gap: var(--space-4); }

/* the sentence a section is really about: a short rule, then it speaks */
.cs-pull { margin: var(--space-4) 0; max-width: 720px; display: flex; flex-direction: column; gap: var(--space-5); }
.cs-pull::before { content: ''; width: 72px; height: 2px; background: var(--text-primary); }
.cs-pull p {
  margin: 0;
  font-size: clamp(24px, 2.6vw, 34px);
  line-height: 1.22;
  letter-spacing: -0.03em;
  font-weight: 500;
  text-wrap: balance;
}
.cs-pull--wide { max-width: 980px; }

/* overview beside the brief */
.cs-brief { display: grid; grid-template-columns: minmax(0, 1fr) 240px; gap: var(--space-9); align-items: start; }
.cs-facts { margin: 0; display: flex; flex-direction: column; gap: var(--space-5); }
.cs-facts dt { font-size: var(--fs-body-s); line-height: 20px; color: var(--text-tertiary); }
.cs-facts dd { margin: 4px 0 0; font-size: var(--fs-body-s); line-height: 20px; }

/* short definitions, held by hairlines instead of boxes */
.cs-grid { display: grid; gap: var(--space-7); }
.cs-grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cs-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.cs-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.cs-item { display: flex; flex-direction: column; gap: var(--space-3); padding-top: var(--space-4); border-top: 1px solid rgba(var(--black), 0.22); }
.cs-item--hair { border-top-color: rgba(var(--black), 0.1); }
.cs-item-label {
  font-size: var(--fs-body-s);
  line-height: 20px;
  font-weight: 600;
  color: var(--text-primary);
}
.cs-item h3 { margin: 0; font-size: var(--fs-body); line-height: 22px; font-weight: 600; letter-spacing: -0.01em; }
.cs-item p { margin: 0; font-size: 15px; line-height: 23px; color: var(--text-secondary); }

/* numbers set large enough to carry the argument */
.cs-figures { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--space-6); padding: var(--space-2) 0; }
.cs-figure-stat { display: flex; flex-direction: column; gap: var(--space-3); }
.cs-figure-value { font-size: clamp(32px, 3.4vw, 48px); line-height: 0.95; letter-spacing: -0.04em; font-weight: 500; }
.cs-figure-label { font-size: var(--fs-body-s); line-height: 20px; color: var(--text-secondary); }

/* a list that keeps its numbers out in the margin */
.cs-list { margin: 0; padding: 0; list-style: none; counter-reset: cs-i; max-width: 62ch; }
.cs-list li {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-top: 1px solid var(--border-primary);
  font-size: 17px;
  line-height: 26px;
  color: var(--text-primary);
}
.cs-list li::before {
  content: counter(cs-i, decimal-leading-zero);
  counter-increment: cs-i;
  font-size: var(--fs-body-s);
  line-height: 26px;
  font-variant-numeric: tabular-nums;
  color: var(--text-tertiary);
}

/* the chain of criteria people actually search by */
.cs-chain { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-3); margin: 0; font-size: clamp(18px, 1.7vw, 24px); line-height: 1.4; letter-spacing: -0.02em; }
.cs-chain span { font-weight: 500; }
.cs-chain i { font-style: normal; color: var(--text-tertiary); }

/* prioritisation: the score is a bar as well as a number */
.cs-table { width: 100%; border-collapse: collapse; font-size: 15px; line-height: 22px; }
.cs-table th,
.cs-table td { padding: var(--space-4) var(--space-4); text-align: left; border-bottom: 1px solid var(--border-primary); vertical-align: middle; }
.cs-table thead th {
  padding-bottom: var(--space-3);
  border-bottom: 1px solid rgba(var(--black), 0.22);
  font-size: var(--fs-body-s);
  line-height: 20px;
  font-weight: 500;
  color: var(--text-tertiary);
}
.cs-table td:first-child,
.cs-table th:first-child { padding-left: 0; }
.cs-table td:last-child,
.cs-table th:last-child { padding-right: 0; }
.cs-table .cs-num { text-align: right; font-variant-numeric: tabular-nums; width: 64px; color: var(--text-tertiary); }
.cs-table tbody td { color: var(--text-secondary); }
.cs-table tr.is-picked td { color: var(--text-primary); font-weight: 500; }
.cs-rank { width: 40px; font-variant-numeric: tabular-nums; color: var(--text-tertiary); }
.cs-bar { width: 200px; }
.cs-bar-track { display: block; position: relative; height: 5px; border-radius: 3px; background: var(--surface-secondary); }
.cs-bar-fill { position: absolute; inset: 0 auto 0 0; width: var(--pct, 0%); border-radius: 3px; background: var(--text-tertiary); }
tr.is-picked .cs-bar-fill { background: var(--text-primary); }
.cs-score { font-variant-numeric: tabular-nums; text-align: right; width: 72px; }

/* a product named in a table carries its mark, so the teardown reads as a
   shelf of real products rather than a list of words */
.cs-brand { display: inline-flex; align-items: center; gap: var(--space-3); }
.cs-brand img {
  width: 22px;
  height: 22px;
  border-radius: 5px;
  object-fit: contain;
  flex: none;
}

/* a hypothesis, set as three plain definitions */
.cs-def { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-7); }
.cs-def-col { display: flex; flex-direction: column; gap: var(--space-3); padding-top: var(--space-4); border-top: 1px solid rgba(var(--black), 0.22); }
.cs-def-col p { margin: 0; font-size: 15px; line-height: 23px; color: var(--text-secondary); }
.cs-def-col p strong { color: var(--text-primary); font-weight: 500; }

/* quotes: the opening mark hangs outside the measure, the way it should */
.cs-quotes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-8) var(--space-9); }
.cs-quote { margin: 0; display: flex; flex-direction: column; gap: var(--space-4); }
.cs-quote p {
  margin: 0;
  font-size: clamp(19px, 1.7vw, 23px);
  line-height: 1.38;
  letter-spacing: -0.02em;
  text-indent: -0.42em;
  text-wrap: pretty;
}
.cs-quote footer { display: flex; gap: var(--space-3); font-size: var(--fs-body-s); line-height: 20px; color: var(--text-tertiary); }
.cs-quote footer span:first-child::before { content: '– '; }
.cs-quote--solo { max-width: 34ch; }

/* sources: grouped link lists, small enough to scan and still clickable */
.cs-sources { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-7) var(--space-8); }
.cs-source-group { display: flex; flex-direction: column; gap: var(--space-3); }
.cs-source-group h3 {
  margin: 0;
  padding-bottom: var(--space-2);
  border-bottom: 1px solid rgba(var(--black), 0.22);
  font-size: var(--fs-body-s);
  line-height: 20px;
  font-weight: 600;
}
.cs-source-group ul { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; }
.cs-source-group li { font-size: var(--fs-body-s); line-height: 20px; }
.cs-source-group a {
  color: var(--text-secondary);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  text-decoration-color: rgba(var(--black), 0.2);
  transition: color 0.2s ease, text-decoration-color 0.2s ease;
}
.cs-source-group a:hover { color: var(--text-primary); text-decoration-color: currentColor; }

/* plates: a cover, or an exported screen, with its caption underneath */
.cs-fig { margin: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.cs-fig img,
.cs-fig .cs-box { width: 100%; border-radius: 16px; display: block; }
.cs-fig .cs-box { aspect-ratio: var(--ratio, 16 / 9); background: var(--surface-secondary); }
.cs-fig img { height: auto; }
.cs-fig figcaption {
  display: flex;
  justify-content: space-between;
  gap: var(--space-5);
  font-size: var(--fs-caption);
  line-height: var(--lh-caption);
  color: var(--text-tertiary);
}
.cs-fig figcaption span:last-child { white-space: nowrap; }
.cs-cover { margin-bottom: var(--space-8); }
/* a cover made of screens rather than a photograph: three phones standing in
   the middle of a quiet band, in the order the story runs */
.cs-cover-band {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-8);
  /* a fixed band height rather than a ratio: the screens are sized from it,
     and an intrinsic image height can't stretch the box open */
  height: clamp(360px, 42vw, 620px);
  min-width: 0;
  padding: var(--space-8);
  border-radius: 16px;
  background: var(--surface-secondary);
  overflow: hidden;
}
/* two ways into the same work, side by side */
.cs-actions { display: flex; flex-wrap: wrap; gap: var(--space-4); }

/* landscape screens of a tool rather than a phone: one per row, full width,
   because a desktop interface at half a column is unreadable */
.cs-plates { display: grid; grid-template-columns: 1fr; gap: var(--space-5); }
.cs-plates img,
.cs-plates video {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 16px;
}

/* an empty plate inside the band, waiting for the real screen */
.cs-cover-band .cs-box { height: 100%; aspect-ratio: 9 / 19.5; border-radius: 14px; }

.cs-cover-band img {
  width: auto;
  height: 100%;
  border-radius: 14px;
}
/* a cover photograph keeps the same 2:1 band whatever its own ratio is —
   the child selector matters: a cover built of screens sets its own sizes */
.cs-cover > img { aspect-ratio: 2 / 1; object-fit: cover; }

/* the case keeps the site's own gutter steps, so its content zone is always
   exactly as wide as the page head above it and the footer below */
@media (max-width: 1600px) {
  .case-doc { padding-left: var(--space-10); padding-right: var(--space-10); }
}
@media (max-width: 1100px) {
  .case-doc { padding-left: var(--space-7); padding-right: var(--space-7); }
  .cs-sec { grid-template-columns: 140px minmax(0, 1fr); gap: var(--space-6); }
  .cs-def,
  .cs-grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 900px) {
  .cs-sec { grid-template-columns: 1fr; gap: var(--space-5); }
  .cs-side { position: static; flex-direction: row; align-items: baseline; gap: var(--space-4); }
  .cs-brief { grid-template-columns: 1fr; gap: var(--space-6); }
  .cs-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cs-bar { display: none; }
}
@media (max-width: 600px) {
  .case-doc { padding-left: var(--space-5); padding-right: var(--space-5); }
  /* the band stops pretending to be a landscape plate on a phone */
  /* on a phone the row becomes a swipeable strip: a screen at 78% of the
     viewport is legible, where three side by side were 98px of mush */
  .cs-cover-band {
    height: auto;
    gap: var(--space-4);
    padding: var(--space-4);
    justify-content: flex-start;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .cs-cover-band img {
    flex: 0 0 78%;
    width: 78%;
    height: auto;
    max-height: none;
    scroll-snap-align: center;
  }
  .cs-sec { padding: var(--space-8) 0; }
  .cs-def,
  .cs-grid--2,
  .cs-grid--3,
  .cs-grid--4,
  .cs-quotes,
  .cs-sources { grid-template-columns: 1fr; }
  .cs-table th:nth-child(3),
  .cs-table td:nth-child(3),
  .cs-table th:nth-child(4),
  .cs-table td:nth-child(4),
  .cs-table th:nth-child(5),
  .cs-table td:nth-child(5) { display: none; }
}

/* the contents rail: parked in the left gutter, it tracks where you are.
   It is fixed to the page rather than the column, so it keeps its distance
   from the text no matter how wide the window gets. */
.cs-toc {
  position: fixed;
  top: 50%;
  left: calc(max(0px, (100vw - var(--max-w)) / 2) + var(--space-7));
  transform: translateY(-50%);
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: 150px;
}
.cs-toc-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; }
.cs-toc-list a {
  display: block;
  font-size: var(--fs-body-s);
  line-height: 20px;
  color: var(--text-tertiary);
  transition: color 0.2s ease, transform 0.25s cubic-bezier(0.34, 1.2, 0.64, 1);
}
.cs-toc-list a:hover { color: var(--text-primary); }
/* the section you are in: ink, and nudged a hair out of the list */
.cs-toc-list a.is-current { color: var(--text-primary); transform: translateX(4px); }

/* the rail lives in the gutter, and the gutter only has room for it while the
   page is wide enough to keep its 256px margins */
@media (max-width: 1600px) {
  .cs-toc { display: none; }
}
