/* ============================================================
   CASE PAGE TEMPLATE — Figma system, disciplined onto:
   · an 8px spacing scale (4px only for micro-adjustments)
   · a 4pt typographic baseline (16/24 body, 12/16 labels, 40/48 stats)
   · a 12-column layout grid, 24px gutters, 1192px container
     (rail = cols 1–3 · content = right-aligned 640px, cols ~6–12)
   Internal ≤ external: component padding never exceeds the
   space between components. Borders are strokes, not spacing,
   and stay at their designed widths.
   ============================================================ */

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body.case-page {
  /* spacing tokens — named by px value, all multiples of 8 (4 = micro fallback) */
  --sp-4: 4px;   --sp-8: 8px;   --sp-16: 16px;  --sp-24: 24px;
  --sp-32: 32px; --sp-40: 40px; --sp-48: 48px;  --sp-56: 56px;
  --sp-64: 64px; --sp-88: 88px; --sp-128: 128px;
  --page-gutter: 64px;
  --nav-h: 64px;                    /* the fixed header band; clearances derive from this */

  /* palette — peach default (Figma: case study, enibas) */
  --bg: #ffe5b5;
  --fg: #333333;
  --muted: rgba(51,51,51,.4);        /* rule: nav + meta = ink @ 40% (Figma #b7a17a over peach) */
  --label: rgba(51,51,51,.4);        /* rule: labels = ink @ 40% */
  --sublabel: rgba(51,51,51,.7);
  --border: rgba(51,51,51,.3);       /* rule: outlines = ink @ 30% */
  --rule: rgba(51,51,51,.18);        /* rule: structural marks (spines, dots) = ink @ 18% */
  --border-soft: rgba(51,51,51,.3);
  --rejected: rgba(51,51,51,.5);     /* rule: rejected options = ink @ 50% */
  --chosen: #216759;
  --tile-ground: #861630;            /* work-tile ground behind a cover-cropped screenshot (Figma) */
  --accent: var(--chosen);

  --font-body: "Inter", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "Andale Mono", "Menlo", ui-monospace, monospace;
  --font-hand: "Reenie Beanie", cursive;

  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.5;             /* 24px — on the baseline */
  letter-spacing: -0.02em;
}

/* ---- theme: wine (Figma: conversion) ---- */
body.case-page.theme-wine {
  --bg: #861630;
  --fg: #ffffff;
  --muted: rgba(255,255,255,.4);
  --label: rgba(255,255,255,.4);
  --sublabel: rgba(255,255,255,.7);
  --border: rgba(255,255,255,.3);
  --rule: rgba(255,255,255,.2);
  --border-soft: rgba(255,255,255,.3);
  --rejected: rgba(255,255,255,.5);
  --chosen: #ffffff;
}
body.case-page.theme-wine .case-body a:not(.todo) { color: #fff; text-decoration: underline; }
body.case-page.theme-wine .todo { background: rgba(255,255,255,.12); color: rgba(255,255,255,.7); }
body.case-page.theme-wine .stat-strip .stat span { font-size: 12px; }

/* ---- nav: handwritten brand left, centered mono links ---- */
body.case-page .site-nav {
  border-bottom: 0;
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  background: var(--bg);
  height: var(--nav-h);
}
body.case-page .site-nav .wrap {
  position: relative; height: 100%;
  display: flex; align-items: center; justify-content: center; gap: var(--sp-56);
  padding-top: 0; padding-bottom: 0;
}
body.case-page .site-nav a {
  font-family: var(--font-mono); font-weight: 400;
  font-size: 14px; letter-spacing: -0.04em; text-transform: uppercase;
  color: var(--muted);
}
body.case-page .site-nav a:hover, body.case-page .site-nav a[aria-current="page"] { color: var(--fg); }
/* links may be bare in .wrap or wrapped in span.links (the sky theme draws a pill
   around them); both must lay out identically, so the gap lives on whichever is the
   flex parent. */
body.case-page .site-nav .links { display: flex; align-items: center; gap: var(--sp-56); }
body.case-page .site-nav .brand {
  position: absolute; left: var(--sp-32); top: 50%; transform: translateY(-50%); margin: 0;
  font-family: var(--font-hand); font-weight: 400; text-transform: none;
  font-size: 40px; letter-spacing: .05em; color: var(--fg); line-height: 1.2;
}

/* ---- page frame ---- */
body.case-page main { padding: calc(var(--nav-h) + var(--sp-24)) 0 var(--sp-128); }   /* top clears the fixed nav */
/* Wildish-style frame: no page max-width — one constant outer gutter at every
   size (64/40/24 on the 8-scale), fluid interior, only the text measure capped */
body.case-page .wrap { max-width: none; padding-left: var(--page-gutter); padding-right: var(--page-gutter); }
body.case-page .meta, body.case-page .meta a { font-family: var(--font-mono); font-size: 12px; line-height: 16px; color: var(--muted); text-decoration: none; }
body.case-page .meta a { display: inline-flex; align-items: center; gap: .5em; }
body.case-page .meta a .arw { display: inline-block; line-height: 1; font-size: 1.1em; }
body.case-page .meta a:hover { color: var(--fg); }
body.case-page .kicker { display: none; }

/* ---- hero ---- */
/* Headline only, flush left with the rail below it (both start at the wrap's
   content edge, which is --page-gutter). */
body.case-page .case-hero { margin: var(--sp-40) 0 var(--sp-128); }
body.case-page .case-hero h1 { max-width: 640px; }
body.case-page .case-hero .hero-figure { width: 256px; aspect-ratio: 256 / 208; overflow: hidden; position: relative; flex: none; margin-left: var(--sp-32); }
@media (max-width: 1100px) { body.case-page .case-hero .hero-figure { width: 224px; } }
@media (max-width: 640px)  { body.case-page .case-hero .hero-figure { width: 192px; } }
body.case-page .case-hero .hero-figure img { position: absolute; width: 159.22%; height: 182.16%; left: -37.22%; top: -10.65%; max-width: none; }
body.case-page h1 {
  font-family: var(--font-body); font-weight: 300; text-transform: none;
  font-size: 56px; line-height: 64px;        /* stepped, on the 8px baseline: 56/64 → 40/48 → 32/40 */
  letter-spacing: -0.02em; margin: 0;
}
@media (max-width: 1100px) { body.case-page h1 { font-size: 40px; line-height: 48px; } }
@media (max-width: 640px)  { body.case-page h1 { font-size: 32px; line-height: 40px; } }

/* ---- layout: 12-column grid, 24px gutters ---- */
.case-layout {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--sp-24);
}
.case-toc {
  grid-column: 1 / 4;
  /* The rail settles in the upper quarter of the viewport — high, but a clear
     128 below the nav band so it never reads as part of the header. The box
     hugs its content and the offset does the work, so there is no transform
     and no pre-stick jump (a transform on a sticky element applies at every
     scroll position, not only once stuck). Derived from --nav-h, per the rule
     that no header clearance is ever hardcoded. */
  position: sticky; top: calc(var(--nav-h) + var(--sp-128)); align-self: start;
}
/* short viewports: keep the whole rail on screen rather than the fix point */
@media (max-height: 720px) {
  .case-toc { top: calc(var(--nav-h) + var(--sp-40)); }
}
.case-body {
  grid-column: 7 / -1;   /* the editorial midline — content owns the right half */
  min-width: 0;
}

/* ---- rail ---- */
.case-toc ol { list-style: none; margin: 0; padding: 0; }
.case-toc li { margin: 0 0 var(--sp-16); }
.case-toc a {
  display: flex; align-items: flex-start;
  /* Mono at 14/16, the same treatment as the section headings it points at: the
     rail is a list of those headings, not a competing voice. Its own sub-items
     drop to 12 so the two levels still separate on size as well as indent. */
  font-family: var(--font-mono); font-weight: 400;
  font-size: 14px; line-height: 16px; letter-spacing: -0.04em;
  text-transform: uppercase;
  color: var(--muted); text-decoration: none;
  transition: color .3s cubic-bezier(.2,.6,.2,1);
}
.case-toc a::before {
  content: ""; display: block; height: 1px; background: var(--fg);
  width: 0; margin-right: 0; margin-top: 7.5px; flex: none;  /* (16px line-height - 1px rule) / 2, so the marker
     centres on the first line. Retune if the rail's line-height changes. */
  transition: width .35s cubic-bezier(.2,.6,.2,1), margin-right .35s cubic-bezier(.2,.6,.2,1);
}
.case-toc a:hover { color: var(--fg); }
.case-toc a[aria-current="true"] { color: var(--fg); }
.case-toc a[aria-current="true"]::before { width: var(--sp-32); margin-right: var(--sp-16); }
@media (prefers-reduced-motion: reduce) { .case-toc a, .case-toc a::before { transition: none; } }

.case-toc .toc-sub {
  display: block; margin: 0 0 0 var(--sp-48);      /* margins live in the active state, so the collapsed label takes no space */
  font-family: var(--font-mono); font-size: 12px; line-height: 16px; letter-spacing: -0.04em;
  text-transform: uppercase; color: var(--label);
  opacity: 0; max-height: 0; overflow: hidden;
  transition: opacity .35s cubic-bezier(.2,.6,.2,1), max-height .35s cubic-bezier(.2,.6,.2,1), margin .35s cubic-bezier(.2,.6,.2,1);
}
.case-toc .toc-sub.on { opacity: 1; max-height: 4em; margin-top: var(--sp-8); margin-bottom: var(--sp-8); }
@media (prefers-reduced-motion: reduce) { .case-toc .toc-sub { transition: none; } }
/* Looping video is paused by scripts/loop-video.js under reduced motion; the poster shows instead. */

/* ---- content column ---- */
.case-body > section { margin: 0 0 var(--sp-128); scroll-margin-top: calc(var(--nav-h) + var(--sp-32)); }
.case-body > section:last-child { margin-bottom: 0; }
.case-body > section > :last-child { margin-bottom: 0; }

@media (min-width: 861px) {
  .case-body section > .role-line {
    position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); white-space: nowrap;               /* titles live in the rail */
  }
}
/* chapter headings: mono eyebrow, tight against the sub-head it introduces */
/* Section heading. Mono eyebrow, one treatment for every section so Overview,
   The problem, Decision 01 and Reflection all read as the same level. The rail
   mirrors these rather than replacing them. */
.case-body section > h2 {
  font-family: var(--font-mono); font-weight: 400; font-size: 14px; line-height: 16px;
  letter-spacing: -0.04em; text-transform: uppercase; color: var(--sublabel);
  margin: 0 0 var(--sp-16);
}
.case-body section > h2 + h3 { margin-top: 0; }

body.case-page p { margin: 0 0 var(--sp-24); }
body.case-page .case-body p { max-width: 640px; }
body.case-page .lede { font-size: 16px; }
body.case-page strong { font-weight: 600; }
body.case-page .case-body a:not(.todo) { color: var(--chosen); }

body.case-page .case-body h3 {
  font-family: var(--font-body); font-weight: 600; font-size: 16px;
  line-height: 24px; letter-spacing: -0.02em; text-transform: none;
  border-bottom: 0; padding-bottom: 0; margin: var(--sp-56) 0 var(--sp-24);
}

/* ---- case-meta: hairline mono rows ---- */
body.case-page .case-meta { margin: var(--sp-56) 0; border-top: 0; }
body.case-page .case-meta .row {
  grid-template-columns: 88px 1fr; gap: var(--sp-16);
  border: .5px solid var(--border); border-bottom: 0; padding: var(--sp-8);
}
body.case-page .case-meta .row:last-child { border-bottom: .5px solid var(--border); }
/* 12/16, the same as the label under a stat numeral. The wine theme used to
   override this to 10px; removed, so all three case studies match. */
body.case-page .case-meta .k, body.case-page .case-meta .v {
  font-family: var(--font-mono); font-weight: 400; font-size: 12px; line-height: 16px;
  letter-spacing: -0.04em; text-transform: uppercase; padding: 0;
}
body.case-page .case-meta .k { color: var(--label); }
body.case-page .case-meta .v { color: var(--fg); }

/* ---- stats ---- */
body.case-page .stat-strip {
  border: 0; padding: 0; margin: var(--sp-56) 0;
  display: flex; gap: 0; width: 100%;
}
body.case-page .stat-strip .stat {
  flex: 1; min-width: 0;
  border: .5px solid var(--border-soft); padding: var(--sp-16);
  display: flex; flex-direction: column; gap: var(--sp-8);
}
body.case-page .stat-strip .stat + .stat { border-left: 0; }  /* shared hairline, not doubled */
@media (max-width: 640px) {
  body.case-page .stat-strip { flex-direction: column; }
  body.case-page .stat-strip .stat + .stat { border-left: .5px solid var(--border-soft); border-top: 0; }
}
body.case-page .stat-strip .stat b {
  font-family: var(--font-mono); font-weight: 400;
  font-size: 32px; line-height: 40px; letter-spacing: -0.04em; margin: 0;
}
body.case-page .stat-strip .stat span {
  font-family: var(--font-mono); font-size: 12px; line-height: 16px; letter-spacing: -0.04em;
  text-transform: uppercase; color: var(--label);
}
body.case-page .stat-solo {
  display: flex; flex-direction: column; gap: var(--sp-8); width: 100%;
  border: .5px solid var(--border-soft); padding: var(--sp-16); margin: var(--sp-56) 0;
}
body.case-page .stat-solo b { font-family: var(--font-mono); font-weight: 400; font-size: 32px; line-height: 40px; letter-spacing: -0.04em; }
body.case-page .stat-solo span { font-family: var(--font-mono); font-size: 12px; line-height: 16px; letter-spacing: -0.04em; text-transform: uppercase; color: var(--label); }

/* ---- figures / placeholders / screenshots ---- */
body.case-page .case-body img { max-width: 100%; }
body.case-page .case-body figure > img { display: block; margin: 0 auto; }
body.case-page figure { margin: var(--sp-56) auto; }
body.case-page figure .placeholder {
  border: .5px solid var(--border-soft); border-radius: 0;
  min-height: 216px; display: flex; align-items: center; justify-content: center;
  padding: var(--sp-8); text-align: center;
  font-family: var(--font-mono); font-size: 10px; letter-spacing: -0.04em;
  text-transform: uppercase; color: var(--muted);
}
body.case-page figure.ph-345 { width: 344px; max-width: 100%; margin: var(--sp-56) auto; }
body.case-page .shot {
  border: 5px solid var(--fg); border-radius: 8px; overflow: hidden;
  width: fit-content; max-width: 100%; margin: var(--sp-40) auto;
}
body.case-page .shot > img { display: block; max-width: 100%; transform: scale(1.015); }  /* crops the screenshot's own light edge */
body.case-page .shot-sm { border-width: 3px; }
/* Case-study images open full size on click (scripts/lightbox.js). The thumbnail
   is for reading past; this is for reading. */
body.case-page .case-body img { cursor: zoom-in; }
body.case-page .case-body img:focus-visible { outline: 2px solid var(--fg); outline-offset: 4px; }
.lightbox {
  position: fixed; inset: 0; z-index: 300;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-16); padding: var(--sp-56) var(--page-gutter);
  background: var(--bg);                     /* the theme ground, not a black scrim */
}
.lightbox img {
  max-width: 100%; max-height: calc(100vh - var(--sp-128) - var(--sp-56));
  width: auto; height: auto; cursor: zoom-out;
  border: 5px solid var(--fg); border-radius: 8px;
}
.lightbox-caption {
  font-family: var(--font-mono); font-size: 12px; line-height: 16px;
  letter-spacing: -0.04em; text-transform: uppercase; color: var(--label);
  margin: 0; text-align: center; max-width: 640px;
}
.lightbox-close {
  position: absolute; top: var(--sp-24); right: var(--page-gutter);
  font-family: var(--font-mono); font-size: 12px; line-height: 16px;
  letter-spacing: -0.04em; text-transform: uppercase;
  color: var(--label); background: transparent; border: 0;
  padding: var(--sp-8); cursor: pointer;
}
.lightbox-close:hover, .lightbox-close:focus-visible { color: var(--fg); }
@media (max-width: 640px) { .lightbox { padding: var(--sp-56) var(--sp-24); } }
/* Screenshot inset within the content column: 80% of the column, centred, never
   wider. Fluid, so it holds the same proportion at every size. */
body.case-page .shot-inset { width: 80%; max-width: 100%; margin-left: auto; margin-right: auto; }
body.case-page .shot-inset > img { width: 100%; height: auto; }
/* Stroke outside the whole image: the default .shot scales its img 1.015 inside an
   overflow-clip to hide a screenshot's own light edge, which crops the outer ~1.5%.
   Screenshots whose content runs to the edge use this instead. */
body.case-page .shot-flush > img { transform: none; }
/* Looping product video. The render is cropped to the device itself and carries no ground of its
   own, so the .shot frame is suppressed here: a border would draw a box around a phone that already
   has its own edge. No scale(1.015) either — that exists to crop a screenshot's own light edge, and
   a render has none, so scaling one only crops content.

   Width 233px is the phone at the size it read at when the render still had its beige surround
   (838/1080 of a 300px frame). Cropping to the device made the same 300px frame ~40% bigger.
   The radius is the phone's own outer corner, 143px in the 838px-wide crop, scaled to 233px — it
   clips the four ground slivers left outside the rounded bezel. Both scale with the width: change
   one and you must change the other.

   Two selector shapes because the markup exists in both; they resolve to the same treatment.
   The figure is capped to the text measure and the video centres inside THAT, not inside the wider
   layout column: centred on the column, it sits ~80px right of the text it belongs to. */
body.case-page figure.video-phone,
body.case-page figure:has(> .shot-phone) { max-width: 640px; margin: var(--sp-56) 0; }

body.case-page .shot.shot-phone {
  border: 0; border-radius: 0; overflow: visible; box-shadow: none;
  width: 233px; max-width: 100%; margin: 0 auto;
}
body.case-page figure.video-phone > video,
body.case-page .shot-phone > video {
  display: block; width: 233px; max-width: 100%; height: auto; margin: 0 auto;
  border-radius: 40px;
}
body.case-page .shot-cluster { position: relative; height: 248px; width: 472px; max-width: 100%; margin: var(--sp-56) auto; }
body.case-page .shot-cluster .shot-a { position: absolute; left: 136px; top: var(--sp-24); width: 336px; margin: 0; }
body.case-page .shot-cluster .shot-a > img { width: 100%; height: 192px; object-fit: cover; }
body.case-page .shot-cluster .shot-b { position: absolute; left: 0; top: var(--sp-56); width: 176px; margin: 0; }
body.case-page .shot-cluster .shot-b > img { width: 100%; height: 136px; object-fit: cover; object-position: top; }

/* ---- decision cards + build-log facts (shared hairline-card grammar) ---- */
body.case-page .decisions { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-16); margin: var(--sp-24) 0 var(--sp-56); }
body.case-page .decision {
  border: .5px solid var(--border); border-radius: 0; background: transparent;
  padding: var(--sp-16); display: flex; flex-direction: column; gap: var(--sp-8);
}
body.case-page .decision .verdict {
  font-family: var(--font-mono); font-weight: 400; font-size: 12px; line-height: 16px;
  letter-spacing: -0.04em; text-transform: uppercase; color: var(--label); margin: 0;
}
body.case-page .decision p { font-size: 12px; line-height: 1.5; letter-spacing: -0.02em; color: var(--rejected); margin: 0; }
body.case-page .decision.chosen { border-color: var(--chosen); }
body.case-page .decision.chosen .verdict, body.case-page .decision.chosen p { color: var(--chosen); }

body.case-page .fact-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(216px, 1fr)); gap: var(--sp-16); margin: var(--sp-24) 0 var(--sp-56); }
body.case-page .fact {
  border: .5px solid var(--border); padding: var(--sp-16); text-align: left;
  display: flex; flex-direction: column; gap: var(--sp-8);
}
body.case-page .fact b {
  font-family: var(--font-mono); font-weight: 400; font-size: 12px; line-height: 16px;
  letter-spacing: -0.04em; text-transform: uppercase; color: var(--label); margin: 0;
}
body.case-page .fact span { font-size: 12px; line-height: 1.5; letter-spacing: -0.02em; color: var(--fg); }

/* ---- todo markers ---- */
body.case-page .todo {
  background: rgba(51,51,51,.06); color: var(--label);
  font-family: var(--font-mono); font-size: 11px;
}

/* ---- next-project links: top back-link style, well clear of content ---- */
body.case-page .case-next { margin-top: var(--sp-128); text-align: right; }
body.case-page .case-next a { color: var(--muted); text-decoration: none; font-family: var(--font-mono); font-size: 12px; line-height: 16px; }
body.case-page .case-next a:hover { color: var(--fg); }

/* ---- footer ---- */
body.case-page .site-foot { border-top: .5px solid var(--border); }
body.case-page .site-foot, body.case-page .site-foot a { color: var(--muted); }
body.case-page .site-foot a { font-family: var(--font-mono); font-size: 12px; text-transform: uppercase; letter-spacing: -0.04em; }

/* ---- responsive ---- */
@media (max-width: 1100px) {
  .case-toc { grid-column: 1 / 4; }
  .case-body { grid-column: 4 / -1; }
}
@media (max-width: 768px) { body.case-page { --page-gutter: 40px; } }
@media (max-width: 500px) { body.case-page { --page-gutter: 24px; } }

@media (max-width: 860px) {
  .case-layout { display: block; }
  .case-toc { display: none; }
  .case-body { width: auto; max-width: none; }
  .case-body > section { border-top: 0; padding-top: 0; margin-bottom: var(--sp-88); }
  .case-body section > .role-line {
    font-family: var(--font-mono); font-size: 12px; line-height: 16px; letter-spacing: -0.04em;
    text-transform: uppercase; color: var(--sublabel); margin: 0 0 var(--sp-24);
  }
  body.case-page .case-hero { display: block; margin: var(--sp-24) 0 var(--sp-56); }
  body.case-page .case-hero .hero-figure { margin-bottom: var(--sp-24); margin-left: 0; }
  /* Conventional mobile header: one 64px band, brand left, links right. It was a
     112px two-row band, which ate the top of every page. The brand stays absolutely
     positioned and vertically centred so the scroll handover animation still works
     (that animation owns translateY(-50%); making the brand static would fight it). */
  body.case-page .site-nav .wrap { justify-content: flex-end; align-items: center; padding-bottom: 0; gap: var(--sp-24); }
  body.case-page .site-nav .brand { font-size: 28px; }
  body.case-page .site-nav .links { gap: var(--sp-24); }
  body.case-page .site-nav a { font-size: 12px; }   /* label step on the ramp */
  body.case-page .decisions { grid-template-columns: 1fr; }
  body.case-page .shot-cluster { height: auto; }
  body.case-page .shot-cluster .shot-a, body.case-page .shot-cluster .shot-b {
    position: static; width: 100%; margin: 0 0 var(--sp-16); }
  body.case-page .shot-cluster .shot-a > img, body.case-page .shot-cluster .shot-b > img { height: auto; }
}

/* On a case study the brand is always visible, so it shares the nav row with the links.
   At 375px that clears by ~15px and a 360px phone would collide — step both down. */
@media (max-width: 500px) {
  body.case-page .site-nav .brand { font-size: 24px; }
  body.case-page .site-nav .links { gap: var(--sp-16); }
  body.case-page .site-nav .wrap { gap: var(--sp-16); }
  body.case-page .site-nav a { font-size: 10px; }   /* micro step on the ramp */
}

/* ---- homepage: the name hands over from the hero to the nav ----------------
   The hero wordmark and the nav brand are already the SAME type: Reenie Beanie,
   40px, .05em, --fg. So this is a handover, not a morph — the nav copy rises into
   the slot behind a mask exactly as the hero copy leaves, and because the glyphs
   match it reads as one name moving rather than two elements swapping.

   Driven by a scroll-driven view timeline on the hero, so it scrubs with the
   scroll off the main thread. scripts/brand-handover.js covers the browsers that
   do not have it yet; it checks for support and stays out of the way otherwise. */
body.home .site-nav .brand {
  clip-path: inset(-20% -20% 100% -20%);
  transform: translateY(-50%) translateY(0.5em);
  opacity: 0;
}
body.home.brand-in .site-nav .brand {
  clip-path: inset(-20% -20% -20% -20%);
  transform: translateY(-50%);
  opacity: 1;
  transition: clip-path .5s cubic-bezier(.22,1,.36,1),
              transform .5s cubic-bezier(.22,1,.36,1),
              opacity .35s ease;
}
@supports (animation-range: exit) {
  @media (prefers-reduced-motion: no-preference) {
    /* the nav is a SIBLING of the hero, and a named view timeline is only visible to the
       declaring element's descendants — timeline-scope hoists it so the nav can read it */
    body.home { timeline-scope: --wordmark; }
    body.home .home-hero .home-id { view-timeline-name: --wordmark; }
    body.home .site-nav .brand {
      animation: brand-handover auto linear both;
      animation-timeline: --wordmark;
      /* starts as the wordmark begins to leave, lands before it is fully gone */
      animation-range: exit 15% exit 85%;
      transition: none;
    }
  }
}
@keyframes brand-handover {
  from { clip-path: inset(-20% -20% 100% -20%); transform: translateY(-50%) translateY(0.5em); opacity: 0; }
  to   { clip-path: inset(-20% -20% -20% -20%); transform: translateY(-50%);                   opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  body.home .site-nav .brand { transition: none; }
}

/* ---- theme: sky (Figma: linguease, node 4590:102165) ---- */
body.case-page.theme-sky {
  --bg: #d4e2ff;
  --fg: #333333;
  --muted: rgba(51,51,51,.4);
  --label: rgba(51,51,51,.4);
  --sublabel: rgba(51,51,51,.7);
}
/* descendant, not child: the links sit inside span.links, so `.wrap > a` never matched them and
   they fell through to --muted (ink @ 40%) on the #333 pill — dark on dark, invisible. */
/* The sky theme used to draw a #333 pill behind the links, with #c2ad7d text on it. Both were
   literals outside the one-ink rule, and the pill read as a black box sitting on the page. The nav
   now takes the system treatment like the other two themes: ink at 40%, ink at 100% on hover. */
body.case-page.theme-sky figure .placeholder { color: #c2ad7d; }

/* ============================================================
   HOMEPAGE HERO (Figma node 4598:103338), on the system:
   full-viewport hero — signature wordmark + mono kicker left,
   illustration right, client-logo strip at the bottom.
   ============================================================ */
body.case-page .home-hero {
  /* short of a full screen on purpose: the work cards should break the fold almost as soon as
     you scroll, so the hero gives back a token's worth of height rather than filling it */
  min-height: calc(100vh - var(--nav-h) - var(--sp-56));
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: var(--sp-24);
  grid-template-rows: 1fr;
  align-items: center;
}
body.case-page .home-hero .home-id { grid-column: 2 / 10; grid-row: 1; align-self: start; padding-top: var(--sp-88); padding-left: var(--sp-32); }
body.case-page .home-hero .wordmark {
  font-family: var(--font-hand); font-weight: 400;
  font-size: 40px; line-height: 1.2; letter-spacing: .05em;
  color: var(--fg); margin: 0 0 var(--sp-16);
}
/* hover/focus the name block → work history drops down */
body.case-page .home-hero .home-id { width: fit-content; outline: none; }
body.case-page .home-history {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows .55s cubic-bezier(.2,.7,.2,1);
}
body.case-page .home-history > ul {
  overflow: hidden; list-style: none; margin: 0; padding: var(--sp-24) 0 0 var(--sp-32);
  position: relative;
}
/* the timeline spine, drawn between the first and last dot */
body.case-page .home-history > ul::before {
  content: ""; position: absolute; left: 2px;
  top: calc(var(--sp-24) + 20px); bottom: 20px; width: 1px;
  background: var(--rule);                  /* structural marks sit below every text tone */
}
body.case-page .home-history li {
  position: relative; display: flex; align-items: center; min-height: var(--sp-40);
  font-family: var(--font-mono); font-size: 14px; line-height: 16px;
  letter-spacing: -0.04em; text-transform: uppercase; color: var(--label);
  opacity: 0; transform: translateY(6px);
  transition: opacity .4s cubic-bezier(.2,.7,.2,1), transform .4s cubic-bezier(.2,.7,.2,1);
}
body.case-page .home-history li::before {                 /* node on the spine */
  content: ""; position: absolute; left: -32px; top: 50%; transform: translateY(-50%);
  width: 5px; height: 5px; border-radius: 50%; background: var(--rule);
}
body.case-page .home-history li .yr { min-width: 72px; flex: none; }
body.case-page .home-history li .co { min-width: 176px; flex: none; }
body.case-page .home-history li .ro { flex: none; min-width: 184px; white-space: nowrap; }
body.case-page .home-id:hover .home-history,
body.case-page .home-id:focus-visible .home-history,
body.case-page .home-id:focus-within .home-history { grid-template-rows: 1fr; }
body.case-page .home-id:hover .home-history li,
body.case-page .home-id:focus-visible .home-history li,
body.case-page .home-id:focus-within .home-history li { opacity: 1; transform: none; }
body.case-page .home-history li:nth-child(1) { transition-delay: .06s; }
body.case-page .home-history li:nth-child(2) { transition-delay: .12s; }
body.case-page .home-history li:nth-child(3) { transition-delay: .18s; }
body.case-page .home-history li:nth-child(4) { transition-delay: .24s; }
/* the name block reads as interactive */
body.case-page .home-hero .wordmark, body.case-page .home-hero .home-kicker { cursor: default; transition: color .3s ease; }
@media (hover: none) {                      /* touch: no hover to give, so show it */
  body.case-page .home-history { grid-template-rows: 1fr; }
  body.case-page .home-history li { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  body.case-page .home-history, body.case-page .home-history li { transition: none; }
}

body.case-page .home-hero .home-kicker {
  font-family: var(--font-mono); font-size: 14px; line-height: 16px;
  letter-spacing: -0.04em; text-transform: uppercase; color: var(--label); margin: 0;
}
body.case-page .home-hero .hero-figure {
  grid-column: 8 / 11; grid-row: 1; align-self: start;
  margin-top: calc(var(--sp-128) + var(--sp-128));   /* mock: image sits well under the signature line */
  margin-left: var(--sp-32);
  width: 280px; max-width: 100%; aspect-ratio: 256 / 208;
  overflow: hidden; position: relative;
}
body.case-page .home-hero .hero-figure img {
  position: absolute; width: 159.22%; height: 182.16%; left: -37.22%; top: -10.65%; max-width: none;
}
@media (max-width: 860px) {
  /* Name first, illustration under it and close by. Source order puts the figure first
     for the desktop grid, so order flips it here. The desktop padding-top of 88 was
     still applying and was most of the wasted height above the name. */
  body.case-page .home-hero { display: flex; flex-direction: column; align-items: flex-start; min-height: 0; }
  body.case-page .home-hero .home-id { order: -1; padding: 0; margin: var(--sp-16) 0 var(--sp-16); }
  /* the desktop rule drops the figure 256px to sit under the signature line, and indents
     it 32 for the grid; stacked, both just push it away from the name */
  body.case-page .home-hero .hero-figure { width: 224px; margin: 0 0 var(--sp-40); }
  /* the work history is a hover/focus reveal, which has no affordance on touch */
  body.case-page .home-history { display: none; }
}
/* narrow: the three fixed-width history columns (72+176+184 + 32 indent) exceed
   the viewport, so the role drops to its own line instead of running off-screen */
@media (max-width: 640px) {
  body.case-page .home-history li {
    flex-wrap: wrap; align-items: baseline;
    column-gap: var(--sp-16); row-gap: var(--sp-4);
    min-height: 0; padding: var(--sp-8) 0;
  }
  body.case-page .home-history li::before { top: calc(var(--sp-8) + 8px); transform: none; }
  body.case-page .home-history li .yr { min-width: 48px; }
  body.case-page .home-history li .co { min-width: 0; }
  body.case-page .home-history li .ro { min-width: 0; flex-basis: 100%; white-space: normal; }
}

/* ============================================================
   HOMEPAGE — MY WORK (Figma node 4807:18397), on the system:
   80/96 display title, then a 3-up row of numbered work cards.
   Figma frame 1512: 60px gutter, 24px gaps, 448px columns,
   21px mono caption, 24px to a 448x334 tile (4:3 within 2px).
   Gutter uses --page-gutter (64) rather than the mock's 60 —
   the 8-scale is the rule, the mock is the reference.
   ============================================================ */
/* 48, not 128: the hero is min-height 100vh - --nav-h, so this margin IS the
   distance the work section sits below the fold. 48 leaves it just out of
   view — a scroll-hint rather than a whole empty screen. The 88 at <=860 is
   ordinary section rhythm, not a fold offset: the hero drops to min-height 0
   there, so nothing is being tucked under a fold. */
body.case-page .home-work { margin-top: var(--sp-48); scroll-margin-top: calc(var(--nav-h) + var(--sp-32)); }
body.case-page .home-work h2 {
  font-family: var(--font-body); font-weight: 300; text-transform: none;
  font-size: 80px; line-height: 96px; letter-spacing: -0.02em;   /* steps to 56/64 then 40/48 — never clamp() */
  color: var(--fg); margin: 0 0 var(--sp-56); text-wrap: balance;
}
/* two explicit rows so every card's caption and tile line up across the row,
   however many lines a caption wraps to */
body.case-page .work-grid {
  display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: auto 1fr;
  gap: var(--sp-24); list-style: none; margin: 0; padding: 0;
}
body.case-page .work-grid > li { display: contents; }
body.case-page .work-card {
  grid-row: span 2; display: grid; grid-template-rows: subgrid; row-gap: var(--sp-24);
  text-decoration: none; color: inherit;
}
body.case-page .work-cap {
  font-family: var(--font-mono); font-weight: 400;
  font-size: 14px; line-height: 16px; letter-spacing: -0.04em;   /* sub-label step on the ramp */
  text-transform: uppercase; color: var(--fg); margin: 0;
  transition: color .3s ease;
}
/* Closing note under the work grid. A fourth card would orphan onto a second row, so the
   "there is more" signal is a line instead. Reuses the work-cap sub-label spec — only the
   ink level and the block gap differ, so the type ramp stays defined in one place. */
body.case-page .work-more { color: var(--muted); margin-top: var(--sp-56); }

/* The Tommy cover carries this navy itself and is opaque, so the ground only shows while the image
   loads — matching it here avoids a flash of the wine default behind a navy cover. */
body.case-page .work-shot.ground-th { --tile-ground: #01194E; }
body.case-page .work-shot {
  aspect-ratio: 4 / 3; background: var(--tile-ground);
  overflow: hidden; position: relative;
}
body.case-page .work-shot img {
  position: absolute; inset: 0; width: 100%; height: 100%; max-width: none;
  object-fit: cover; object-position: center top;
  transform: scale(1.015);                       /* crops the screenshot's own light edge, as .shot does */
  transition: transform .5s cubic-bezier(.2,.7,.2,1);
}
body.case-page .work-card:hover .work-shot img,
body.case-page .work-card:focus-visible .work-shot img { transform: scale(1.05); }
body.case-page .work-card:focus-visible { outline: 2px solid var(--fg); outline-offset: var(--sp-4); }
/* tile with no screenshot yet — same grammar as the .todo markers on case pages */
body.case-page .work-shot.is-pending {
  display: flex; align-items: center; justify-content: center; padding: var(--sp-16);
}
body.case-page .work-shot.is-pending .todo {
  background: rgba(255,255,255,.12); color: rgba(255,255,255,.7);
  font-family: var(--font-mono); font-size: 11px; letter-spacing: -0.04em;
  text-transform: uppercase; text-align: center;
}
@media (prefers-reduced-motion: reduce) {
  body.case-page .work-shot img { transition: none; }
  body.case-page .work-card:hover .work-shot img { transform: scale(1.015); }
}
@media (max-width: 1100px) {
  body.case-page .home-work h2 { font-size: 56px; line-height: 64px; }
  body.case-page .work-cap { font-size: 12px; }          /* label size — 3-up columns get tight here */
}
/* 860 is the system's single-column breakpoint; 2-up would orphan the third card */
@media (max-width: 860px) {
  body.case-page .home-work { margin-top: var(--sp-88); }
  body.case-page .work-grid { grid-template-columns: 1fr; grid-template-rows: none; gap: var(--sp-56); }
  body.case-page .work-grid > li { display: block; }
  body.case-page .work-card { grid-row: auto; grid-template-rows: none; }
}
@media (max-width: 640px) {
  body.case-page .home-work h2 { font-size: 40px; line-height: 48px; margin-bottom: var(--sp-40); }
}

/* ============================================================
   VERTICAL RHYTHM
   One system for the case body. Every block is spaced by its
   relationship to what precedes it, so the same pair always gets
   the same gap wherever it appears.

      8  heading to a table              (a table is the heading's own data)
     16  after a heading                 (a heading binds to its content)
     24  paragraph to paragraph          (body rhythm)
     40  to or from a block object       (stat strip, decision cards)
     56  before a heading                (the break for a new topic)
     56  around an image                 (a picture needs room on both sides)
    128  section to section              (set on .case-body > section)

   The type lists sit in :where() so every rule here carries the same
   specificity and source order alone resolves them. That is what lets
   "after a heading" beat "block object" for an h3 followed by cards.
   ============================================================ */
body.case-page .case-body section > * { margin: 0; }
body.case-page .case-body section > * + *                { margin-top: var(--sp-24); }
body.case-page .case-body section > * + :where(.case-meta, .stat-strip, .stat-solo, .decisions) { margin-top: var(--sp-40); }
body.case-page .case-body section > :where(.case-meta, .stat-strip, .stat-solo, .decisions) + * { margin-top: var(--sp-40); }
body.case-page .case-body section > * + :where(.shot, .shot-cluster, figure) { margin-top: var(--sp-56); }
body.case-page .case-body section > :where(.shot, .shot-cluster, figure) + * { margin-top: var(--sp-56); }
body.case-page .case-body section > * + :where(h2, h3)   { margin-top: var(--sp-56); }
body.case-page .case-body section > :where(h2, h3) + *   { margin-top: var(--sp-16); }
body.case-page .case-body section > :where(h2, h3) + .case-meta { margin-top: var(--sp-8); }
