/* ============================================================================
   DIGBIG STUDIO — visual system
   ----------------------------------------------------------------------------
   Swiss editorial grid, one grotesk, one mono, and red used only as a signal.
   The whole palette is four neutrals and a single red; there is deliberately
   no second red, no gradient and no tint of the accent anywhere in this file.
   ========================================================================== */

/* ─────────────────────────────────────────────────────────────── TOKENS ── */
:root {
  /* Ground */
  /* Every text colour below was checked against the ground it sits on and
     clears WCAG AA. The metadata grey and the red are both a step deeper than
     they first were for exactly that reason — 4.9:1 and 4.9:1 on paper. */
  --paper:  #FAFAF8;   /* off-white — the default surface           */
  --paper-2:#F2F2EE;   /* one step down, for insets and stripes     */
  --ink:    #0B0B0B;   /* near-black — display type and inversions  */
  --char:   #45453F;   /* charcoal — secondary text        9.2:1    */
  --mute:   #6E6E66;   /* metadata and small caps          4.9:1    */
  --mute-d: #85857D;   /* the same role on an inverted band 5.3:1   */
  /* The same signal red, lifted just far enough to stay legible on the dark
     band. One red cannot clear AA on both grounds: #D81E1A reads 4.88 on paper
     but only 3.86 on ink, and the section numbers are 9.5px. This is the
     minimum lift that reaches 4.58 — not a second accent colour, and it is
     used ONLY where red sits on the inverted ground. */
  --red-d:  #E5352F;   /* red on an inverted band          4.6:1    */
  --rule:   #E1E1DB;   /* hairlines                                 */
  --rule-2: #CFCFC7;   /* hairlines that need to be seen            */
  --red:    #D81E1A;   /* the only accent in the system    4.9:1    */

  /* Inversion. A band marked .invert means "the opposite of the page", not
     "black" — so these flip with the theme and the rhythm of light and dark
     bands survives in both. */
  --inv-bg:   #0B0B0B;
  --inv-fg:   #FAFAF8;
  --inv-body: #B4B4AE;
  --inv-rule: #2A2A28;
  --inv-mute: #85857D;
  --inv-dim:  #66665F;
  --inv-meta: #C9C9C3;

  /* A well is a container for media, not a surface: the space behind a video
     stays black in both themes because that is what a frame sits in. */
  --well: #0B0B0B;
  --well-fg: #FAFAF8;   /* type over a media well: the well never changes */
  --well-mute: #85857D;
  /* Artwork was designed on white paper, so the sheet behind a poster stays
     white in both themes. Turning it grey in dark mode would misrepresent it. */
  --sheet: #FFFFFF;
}

/* ───────────────────────────────────────────────────────── DARK THEME ── */
/* Same system, inverted ground. The red is lifted because #D81E1A on near
   black is only 3.1:1 — below AA for the small mono labels it is used on.
   #FF4A3D on the same ground is 5.6:1. It is the same signal colour tuned to
   its background, not a second accent. */
:root[data-theme="dark"] {
  --paper:  #0B0B0B;
  --paper-2:#141412;
  --ink:    #FAFAF8;
  --char:   #B4B4AE;
  --mute:   #8C8C84;
  --mute-d: #6E6E66;
  --rule:   #262624;
  --rule-2: #3A3A36;
  --red:    #FF4A3D;
  /* In dark mode the inverted band is the LIGHT one, so red sitting on it
     needs the deeper value — the opposite swap to light mode. */
  --red-d:  #D81E1A;

  --inv-bg:   #FAFAF8;
  --inv-fg:   #0B0B0B;
  --inv-body: #45453F;
  --inv-rule: #E1E1DB;
  --inv-mute: #6E6E66;
  /* The deliberately recessed word in "LET'S MAKE SOMETHING." A light grey
     that recedes on black has to become a mid grey to recede on white —
     #CFCFC7 there was 1.4:1 and the word simply disappeared. This holds 3.4:1,
     matching what the light theme gives it, which is the bar for display type. */
  --inv-dim:  #8A8A82;
  --inv-meta: #45453F;
}
:root[data-theme="dark"] {
  color-scheme: dark;   /* native form controls and scrollbars follow */
}
:root {
  /* Type */
  --sans: 'Inter Tight', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* Grid */
  --cols: 12;
  --gut: clamp(12px, 1.4vw, 24px);
  --pad: clamp(18px, 4.2vw, 72px);
  --max: 1720px;

  /* Rhythm */
  --sec: clamp(76px, 11vw, 176px);   /* space between major sections */
  --blk: clamp(36px, 5vw, 72px);     /* space between blocks         */

  /* Motion */
  --e: cubic-bezier(.22,.61,.36,1);
  --t: .34s;
}

/* ──────────────────────────────────────────────────────────────── RESET ── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: clamp(15px, .55vw + 13px, 17px);
  line-height: 1.5;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
  font-feature-settings: 'ss01' 1, 'cv05' 1;
}
h1, h2, h3, h4, p, ul, ol, dl, dd, figure, blockquote { margin: 0; }
ul, ol { padding: 0; list-style: none; }
img { display: block; max-width: 100%; height: auto; }
/* <picture> wraps every content image so WebP can be offered with a JPEG
   fallback; display:contents keeps the <img> laying out as if the wrapper
   were not there, so every existing "figure img" rule still applies. */
picture { display: contents; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
::selection { background: var(--red); color: #fff; }

/* Focus: a red bracket, never a browser default halo. */
:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 3px;
  border-radius: 1px;
}

.skip {
  position: fixed; top: 8px; left: 8px; z-index: 200;
  padding: 10px 16px; background: var(--ink); color: var(--paper);
  font: 500 11px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
  transform: translateY(-200%);
}
.skip:focus { transform: none; }

/* ───────────────────────────────────────────────────────────────── GRID ── */
.grid {
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  column-gap: var(--gut);
}
.c1-3  { grid-column: 1 / 4;  }
.c1-4  { grid-column: 1 / 5;  }
.c1-6  { grid-column: 1 / 7;  }
.c1-8  { grid-column: 1 / 9;  }
.c1-12 { grid-column: 1 / -1; }
.c4-6  { grid-column: 4 / 7;  }
.c4-12 { grid-column: 4 / -1; }
.c5-8  { grid-column: 5 / 9;  }
.c7-12 { grid-column: 7 / -1; }
.c8-12 { grid-column: 8 / -1; }
.c9-12 { grid-column: 9 / -1; }
.c10-12{ grid-column: 10 / -1;}
.ta-r  { text-align: right; }

main, .hd-in, .ft-in { max-width: var(--max); margin-inline: auto; }
main { padding-inline: var(--pad); }

/* ───────────────────────────────────────────────────────── TYPE SCALE ── */
.lbl {
  font: 500 clamp(9.5px, .55vw, 11px)/1.3 var(--mono);
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--mute);
}
.lbl--ink { color: var(--ink); }
.lbl--red { color: var(--red); }

h1, h2, h3 { font-weight: 600; letter-spacing: -.03em; line-height: .92; }

.lede {
  font-size: clamp(20px, 2.1vw, 30px);
  line-height: 1.22;
  letter-spacing: -.024em;
  font-weight: 500;
  text-wrap: balance;
}
.body { font-size: clamp(15px, .8vw, 18px); line-height: 1.58; color: var(--char); max-width: 62ch; }
.body-sm { font-size: clamp(14px, .68vw, 15.5px); line-height: 1.6; color: var(--char); max-width: 46ch; }
.body + .body, .body-sm + .body-sm { margin-top: 1.1em; }

/* ────────────────────────────────────────────────────────────── HEADER ── */
.hd {
  position: sticky; top: 0; z-index: 90;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(1.6) blur(14px);
  -webkit-backdrop-filter: saturate(1.6) blur(14px);
}
.hd-in {
  display: flex; align-items: center; gap: var(--gut);
  padding: 14px var(--pad) 13px;
}
.hd-rule { height: 1px; background: var(--rule); }

.wordmark {
  display: flex; gap: .4em; align-items: center; margin-right: auto;
  /* Taller hit area for the home link, without moving the mark. */
  padding-block: 6px; margin-block: -6px;
}
.wm-mark {
  height: clamp(17px, 1.5vw, 21px); width: auto;
  margin-right: .3em;
  transition: transform var(--t) var(--e);
}
.wordmark:hover .wm-mark { transform: rotate(-6deg); }
@media (prefers-reduced-motion: reduce) { .wordmark:hover .wm-mark { transform: none; } }
.wm-a, .wm-b {
  font: 700 clamp(12px, .84vw, 14px)/1 var(--sans);
  letter-spacing: .1em;
}
.wm-b { color: var(--mute); font-weight: 500; }
.wordmark:hover .wm-b { color: var(--red); }

.nav ul { display: flex; gap: clamp(14px, 1.7vw, 34px); }
.nav a {
  display: inline-flex; align-items: baseline; gap: .5em;
  font: 500 clamp(11px, .68vw, 13px)/1 var(--sans);
  letter-spacing: .04em;
  padding: 6px 0;
  position: relative;
  transition: color var(--t) var(--e);
}
.nav a i {
  font: 500 9.5px/1 var(--mono); font-style: normal;
  letter-spacing: .08em; color: var(--mute);
  transition: color var(--t) var(--e);
}
.nav a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px; background: var(--red);
  transform: scaleX(0); transform-origin: left;
  transition: transform var(--t) var(--e);
}
.nav a:hover i, .nav a[aria-current] i { color: var(--red); }
.nav a:hover::after, .nav a[aria-current]::after { transform: scaleX(1); }
.nav a[aria-current] { color: var(--red); }

.hd-end { display: flex; align-items: center; gap: 14px; }
.cv-link {
  font: 500 clamp(11px, .68vw, 13px)/1 var(--sans);
  letter-spacing: .04em;
  border-bottom: 1px solid var(--rule-2);
  padding-bottom: 3px;
  /* Same reasoning as .more — a bigger hit area, no layout shift. */
  padding-block: 12px 3px;
  margin-block: -12px 0;
  transition: color var(--t) var(--e), border-color var(--t) var(--e);
}
.cv-link:hover { color: var(--red); border-color: var(--red); }

/* ───────────────────────────────────────────────────── THEME TOGGLE ── */
/* One mark, drawn in CSS rather than borrowed from an icon font: a circle
   split down the middle, the classic contrast symbol. The filled half swaps
   with the theme, so the icon always shows the state you are in. It is the
   same geometry as the studio mark and needs no glyph to load. */
.theme {
  display: grid; place-items: center;
  width: 26px; height: 26px;
  transition: color var(--t) var(--e);
  color: var(--ink);
}
.theme:hover { color: var(--red); }
.theme i {
  display: block; position: relative;
  width: 15px; height: 15px; border-radius: 50%;
  border: 1.5px solid currentColor;
  overflow: hidden;
}
/* The filled half. In light mode the right side is solid; in dark mode it
   flips to the left, so the icon reads as an inversion of itself. */
.theme i::after {
  content: ''; position: absolute; top: -1px; bottom: -1px;
  left: 50%; right: -1px;
  background: currentColor;
  transition: transform var(--t) var(--e);
}
:root[data-theme="dark"] .theme i::after { transform: translateX(-100%); }
.theme:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) { .theme i::after { transition: none; } }

/* The mark is black artwork, so it has to swap with the ground. Both files
   ship; CSS picks. */
.wm-mark.on-dark { display: none; }
:root[data-theme="dark"] .wm-mark.on-light { display: none; }
:root[data-theme="dark"] .wm-mark.on-dark { display: block; }

/* The bars stay 26x18; the button around them is a full 44px square so the
   menu is comfortable to hit on a phone. */
.burger { display: none; width: 44px; height: 44px; position: relative; margin-right: -10px; }
/* The two bars keep their old 26x18 appearance, inset inside the larger
   button: 9px each side centres a 26px bar in 44px, and 13px top and bottom
   leaves the same 18px between them as before. */
.burger i {
  position: absolute; left: 9px; right: 9px; height: 1.5px; background: var(--ink);
  transition: transform var(--t) var(--e), opacity .2s;
}
.burger i:nth-child(1) { top: 13px; }
.burger i:nth-child(2) { bottom: 13px; }
.burger[aria-expanded="true"] i:nth-child(1) { transform: translateY(5px) rotate(45deg); }
.burger[aria-expanded="true"] i:nth-child(2) { transform: translateY(-5px) rotate(-45deg); }

/* ────────────────────────────────────────────────────────────── DRAWER ── */
.drawer {
  position: fixed; inset: 0; z-index: 80;
  background: var(--paper);
  padding: calc(56px + env(safe-area-inset-top)) var(--pad) var(--pad);
  display: flex; flex-direction: column; justify-content: space-between;
  animation: dwIn .3s var(--e);
}
.drawer[hidden] { display: none; }
@keyframes dwIn { from { opacity: 0; transform: translateY(-8px); } }
.dw-nav { display: flex; flex-direction: column; margin-top: auto; }
.dw-nav a {
  display: flex; align-items: baseline; gap: .7em;
  padding: clamp(10px, 2.2vw, 18px) 0;
  border-top: 1px solid var(--rule);
  font-size: clamp(26px, 8vw, 44px);
  font-weight: 600; letter-spacing: -.035em; line-height: 1;
}
.dw-nav a:last-child { border-bottom: 1px solid var(--rule); }
.dw-nav em { font: 500 11px/1 var(--mono); font-style: normal; color: var(--red); }
.dw-foot { display: flex; flex-wrap: wrap; gap: 8px 20px; margin-top: var(--blk); }
.dw-foot a { font: 500 11px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--char); }

/* ──────────────────────────────────────────────────────────────── HERO ── */
.hero { padding-top: clamp(28px, 5vw, 64px); }
.hero-top { padding-bottom: clamp(30px, 6vw, 76px); }

.hero-name {
  display: block;
  margin: 0 0 clamp(22px, 3.4vw, 44px);
  border-top: 1px solid var(--ink);
  padding-top: clamp(8px, 1vw, 16px);
}
.hn {
  display: block;
  font-size: clamp(56px, 18.4vw, 268px);
  font-weight: 700;
  letter-spacing: -.05em;
  line-height: .84;
  text-indent: -.02em;
}
.hn:last-child { color: var(--char); }

.hero-mid { border-top: 1px solid var(--rule); padding-top: clamp(16px, 2vw, 28px); }
.hero-role { position: relative; }
.role-a {
  font-size: clamp(14px, 1.16vw, 21px);
  font-weight: 600; letter-spacing: .04em; line-height: 1.25;
  text-transform: uppercase;
}
.role-x { font: 400 clamp(14px, 1.16vw, 21px)/1.25 var(--mono); color: var(--red); }
.mark {
  display: block; width: 12px; height: 12px; background: var(--red);
  margin-top: clamp(18px, 2.4vw, 34px);
}
.hero-say { align-self: end; }
.hero-say .body-sm { margin-top: 1.1em; }

.disciplines {
  display: flex; flex-wrap: wrap; gap: clamp(14px, 2.6vw, 46px);
  margin: clamp(34px, 5vw, 72px) 0 clamp(18px, 2.4vw, 30px);
  padding-top: 12px;
  border-top: 1px solid var(--rule);
}
.disciplines li {
  font: 500 clamp(10px, .62vw, 12px)/1 var(--mono);
  letter-spacing: .18em; color: var(--char);
}
.disciplines li::before { content: '— '; color: var(--red); }

.hero-fig img {
  width: 100%; aspect-ratio: 16 / 9; object-fit: cover;
  background: var(--paper-2);
}
.hero-fig figcaption { padding-top: 10px; }

/* ─────────────────────────────────────────────────────────── SECTIONS ── */
.sec { padding-block: var(--sec); }
/* Section index — the running numbering a printed document would carry, with
   only the current number in red. This is the survey-marker role the accent
   plays everywhere else on the site. */
.sec-ix {
  font: 500 clamp(9.5px, .55vw, 11px)/1.3 var(--mono);
  letter-spacing: .13em; text-transform: uppercase; color: var(--mute);
  padding-bottom: clamp(10px, 1.2vw, 18px);
}
.sec-ix span { color: var(--red); }
.invert .sec-ix { color: var(--mute-d); }

.sec-head {
  align-items: baseline;
  padding-bottom: clamp(24px, 3.4vw, 52px);
  border-bottom: 1px solid var(--ink);
}
.sec-head h2 { font-size: clamp(30px, 5.2vw, 82px); letter-spacing: -.042em; }
.sec-more { margin-top: clamp(30px, 4vw, 60px); border-top: 1px solid var(--rule); padding-top: 16px; }
.more {
  font: 500 clamp(11px, .66vw, 13px)/1 var(--mono);
  letter-spacing: .12em; text-transform: uppercase;
  display: inline-block;
  transition: color var(--t) var(--e);
  /* An 11px line of type is an 11px tap target, which is well under the 24px
     minimum. The padding grows the hit area and the negative margin takes the
     space back, so the link is easier to hit without moving on the page. */
  padding-block: 11px;
  margin-block: -11px;
}
.more span { display: inline-block; transition: transform var(--t) var(--e); }
.more:hover { color: var(--red); }
.more:hover span { transform: translateX(5px); }

/* Inverted band — used sparingly, twice on the home page at most. */
.invert {
  background: var(--inv-bg);
  color: var(--inv-fg);
  margin-inline: calc(var(--pad) * -1);
  padding-inline: var(--pad);
}
.invert .body, .invert .body-sm { color: var(--inv-body); }
/* Small red type on the dark band uses the lifted red so it stays readable. */
.invert .sec-ix span, .invert .lbl--red, .invert .work-n, .invert .story-n { color: var(--red-d); }
.invert .lbl { color: var(--mute-d); }
.invert .sec-head { border-color: var(--inv-rule); }
.invert .sec-more { border-color: var(--inv-rule); }
.invert ::selection { background: var(--red); color: #fff; }

/* ──────────────────────────────────────────────────── SELECTED WORK ── */
/* Each project is a spread, not a card. Four parts sit on the same 12-column
   grid: an index column carrying the number and a survey-style locator, the
   title band, the visual, and the case for the project. The visual alternates
   margin down the page, so five projects never settle into a rhythm. */
.works { display: block; }

.work { position: relative; padding-block: clamp(30px, 4.4vw, 76px); border-top: 1px solid var(--rule); }
.work:first-child { border-top: 1px solid var(--ink); }
.work:last-child { border-bottom: 1px solid var(--rule); }

.work-hit {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--gut);
  row-gap: clamp(16px, 2.2vw, 34px);
  align-items: start;
}

/* Index column — the survey mark: number over a red tick, the locator beneath,
   and a hairline dropping down the column like a station line on a drawing. */
.work-idx {
  grid-column: 1 / 3; display: flex; flex-direction: column; gap: 8px;
  position: relative;
}
.work-idx::after {
  content: ''; position: absolute; left: 0; top: calc(100% + 14px); bottom: -20px;
  width: 1px; background: var(--rule);
}
.work-n {
  font: 500 clamp(11px, .74vw, 14px)/1 var(--mono);
  letter-spacing: .1em; color: var(--red);
  padding-bottom: 8px; border-bottom: 1px solid var(--red);
  width: max-content; min-width: 3.4em;
}
.work-where { display: block; }

.work-head { grid-column: 3 / -1; display: block; }
.work-title {
  font-size: clamp(28px, 4.4vw, 74px);
  font-weight: 600; letter-spacing: -.042em; line-height: .96;
  transition: transform var(--t) var(--e);
  will-change: transform;
}
.work-meta { display: block; margin-top: .7em; }
.work:hover .work-title { transform: translateX(10px); }

/* Visual and text, alternating sides. */
/* Both sit on the second row, explicitly.
   Left them to auto-placement and the even-numbered entries broke: the figure
   is placed first at columns 8-12, the text then asks for columns 1-7, and
   sparse placement never goes backwards — so the text was pushed onto a row of
   its own, 719px below the top of the artwork, with the whole left half of the
   card left blank. Naming the row costs nothing on the odd entries, which
   already resolved correctly, and makes the rule below true for every card
   rather than every other one. */
.work-fig { grid-column: 1 / 9; grid-row: 2; display: block; overflow: hidden; }
.work-say { grid-column: 9 / -1; grid-row: 2; display: flex; flex-direction: column; gap: clamp(14px, 1.8vw, 24px); align-self: end; }

.work:nth-child(even) .work-fig { grid-column: 5 / -1; }
.work:nth-child(even) .work-say { grid-column: 1 / 5; }

/* Tall artwork gets a narrower measure so showing it whole does not make it
   tower over the rest of the page. */
.work-tall .work-fig { grid-column: 1 / 6; }
.work-tall .work-say { grid-column: 7 / -1; }
.work-tall:nth-child(even) .work-fig { grid-column: 8 / -1; }
.work-tall:nth-child(even) .work-say { grid-column: 1 / 7; }
/* A portrait piece is roughly twice the height of its text, so bottom-aligning
   the text opens a half-metre of dead paper beside the top of the artwork.
   Tall entries read from the top instead; only the wide ones sit on a shared
   baseline with the image. */
.work-tall .work-say { align-self: start; }

.work-fig img {
  width: 100%;
  transition: transform .62s var(--e);
  will-change: transform;
}
/* Photographs crop to a band on purpose; artwork carries its own ratio and is
   never cropped, so there is nothing for object-fit to do. */
.work-photo .work-fig img { aspect-ratio: 16 / 10; height: 100%; object-fit: cover; }
.work-tall .work-fig img, .work-wide .work-fig img,
.work-square .work-fig img, .work-pano .work-fig img {
  height: auto; border: 1px solid var(--rule); background: var(--sheet);
}
.work:hover .work-fig img { transform: scale(1.025); }
.work-cap { display: block; padding-top: 10px; }

.work-desc {
  display: block;
  font-size: clamp(14.5px, .82vw, 17px); line-height: 1.55;
  color: var(--char); max-width: 42ch;
}
.work-go {
  display: inline-flex; align-items: center; gap: .6em;
  font: 500 clamp(10.5px, .64vw, 12px)/1 var(--mono);
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink);
  padding-top: 12px; border-top: 1px solid var(--rule-2);
  width: max-content;
  transition: color var(--t) var(--e), border-color var(--t) var(--e);
}
.work-go span { display: inline-block; transition: transform var(--t) var(--e); }
.work:hover .work-go { color: var(--red); border-color: var(--red); }
.work:hover .work-go span { transform: translateX(6px); }

/* A red survey tick that draws itself along the top rule on hover. */
.work::after {
  content: ''; position: absolute; left: 0; top: -1px; height: 1px; width: 100%;
  background: var(--red); transform: scaleX(0); transform-origin: left;
  transition: transform .55s var(--e);
}
.work:hover::after { transform: scaleX(1); }

/* ────────────────────────────────────────────────────── POSITIONING ── */
.pos-body { padding-block: clamp(10px, 1.4vw, 20px); }
.pos-line {
  font-size: clamp(26px, 3.9vw, 62px);
  font-weight: 600; letter-spacing: -.04em; line-height: 1.03;
  max-width: 20ch;
  margin-bottom: clamp(22px, 2.6vw, 38px);
}
.pos-line em { font-style: normal; color: var(--red); }

/* The one sentence the section exists to deliver. Set on its own, against a
   red rule, at a size between the headline and the body. */
.pos-punch {
  font-size: clamp(19px, 1.9vw, 30px);
  font-weight: 500; letter-spacing: -.022em; line-height: 1.2;
  color: var(--inv-fg);
  border-left: 2px solid var(--red);
  padding-left: clamp(14px, 1.4vw, 22px);
  margin-bottom: clamp(20px, 2.4vw, 34px);
  max-width: 24ch;
}
.pos-index { margin-top: clamp(44px, 6vw, 92px); row-gap: 1px; }
.pos-row {
  grid-column: 1 / -1;
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gut);
  align-items: baseline;
  padding: clamp(12px, 1.5vw, 20px) 0;
  border-top: 1px solid var(--inv-rule);
}
.pos-row:last-child { border-bottom: 1px solid var(--inv-rule); }
.pos-row > .k { grid-column: 1 / 3; }
.pos-row > .t { grid-column: 3 / 8; font-size: clamp(15px, 1.1vw, 20px); font-weight: 500; letter-spacing: -.02em; }
.pos-row > .d { grid-column: 8 / -1; }
/* Red at 10px on black would fall short of AA, so the hover signal here is a
   red square and a shift to white rather than red type. */
.pos-row > .k::before {
  content: ''; display: inline-block; width: 6px; height: 6px;
  background: var(--red); margin-right: .7em; vertical-align: .04em;
  opacity: 0; transition: opacity var(--t) var(--e);
}
.pos-row:hover > .k { color: var(--inv-fg); }
.pos-row:hover > .k::before { opacity: 1; }

/* ───────────────────────────────────────────────────── ARCHIVE PEEK ── */
.arc-stat { padding-block: clamp(30px, 4vw, 58px); align-items: end; }
.big-num { display: flex; align-items: baseline; gap: .5em; }
.big-num span { font-size: clamp(40px, 6.2vw, 104px); font-weight: 700; letter-spacing: -.05em; line-height: .82; }
.big-num i {
  font: 500 clamp(9.5px, .55vw, 11px)/1.3 var(--mono);
  letter-spacing: .13em; text-transform: uppercase; color: var(--mute); font-style: normal;
}
/* The home page reuses the archive's own story blocks rather than inventing a
   carousel, so a preview looks exactly like the thing it links to. Four
   stories, two large and two small, staggered off the baseline. */
.stories-home { row-gap: clamp(34px, 4.6vw, 72px); }
.stories-home .story.lg:nth-of-type(1) { grid-column: 1 / 7; }
.stories-home .story.sm:nth-of-type(2) { grid-column: 8 / 12; margin-top: clamp(30px, 5vw, 86px); }
.stories-home .story.lg:nth-of-type(3) { grid-column: 6 / -1; }
.stories-home .story.sm:nth-of-type(4) { grid-column: 2 / 6; margin-top: clamp(30px, 5vw, 86px); }

/* ────────────────────────────────────────────────────── MOTION HOME ── */
.mot-grid { align-items: start; padding-bottom: clamp(20px, 2.6vw, 36px); }
.mot-idx { display: flex; flex-direction: column; gap: 8px; }
.mot-title {
  font-size: clamp(26px, 3.6vw, 58px);
  font-weight: 600; letter-spacing: -.04em; line-height: 1;
}
.mot-note { margin-top: 1em; max-width: 54ch; }
.mot-player { max-width: 100%; }

/* ─────────────────────────────────────────────────────── ABOUT HOME ── */
.abo-grid { row-gap: var(--blk); align-items: start; }
.abo-say .body { margin-top: 1.1em; }
.abo-more { display: inline-block; margin-top: clamp(20px, 2.4vw, 32px); }
.abo-cap { border-top: 1px solid var(--ink); padding: 14px 0 18px; }
.abo-cap h3 {
  font: 500 10.5px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase;
  color: var(--red); margin-bottom: 10px;
}
.abo-cap p { color: var(--char); }

/* ══════════════════════════════════════════════════════ ROUTED VIEWS ══ */
.route[hidden] { display: none; }
.view-in { animation: vIn .42s var(--e) both; }
@keyframes vIn { from { opacity: 0; transform: translateY(10px); } }

/* Page masthead used by every routed page. */
.mast { padding-top: clamp(34px, 6vw, 88px); padding-bottom: clamp(28px, 4vw, 56px); }
.mast-top { padding-bottom: clamp(22px, 3vw, 40px); }
.mast h1 {
  grid-column: 1 / -1;
  font-size: clamp(38px, 9.6vw, 148px);
  font-weight: 700; letter-spacing: -.05em; line-height: .86;
  border-top: 1px solid var(--ink);
  padding-top: clamp(8px, 1vw, 16px);
}

/* A case study's title, which is set in mixed case and is long enough to wrap.
   The .86 above is display leading, chosen for the section headings — one
   word, all caps, nothing below the baseline — where tight stacking is the
   point. A wrapped mixed-case title is a different object: "Planning for
   Persons with Disabilities" breaks after "with", and at .86 the g of
   Planning lands on the D of Disabilities. This is the leading that clears a
   descender, and it only applies where a descender can occur. */
.mast h1.case-t { line-height: .98; letter-spacing: -.04em; }
.mast-sub { border-top: 1px solid var(--rule); margin-top: clamp(18px, 2.4vw, 34px); padding-top: 16px; align-items: start; }

/* ─────────────────────────────────────────────────────── INDEX LISTS ── */
.idx { border-top: 1px solid var(--ink); }
.idx-row {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gut);
  align-items: center;
  padding: clamp(16px, 2.1vw, 30px) 0;
  border-bottom: 1px solid var(--rule);
  position: relative;
  /* Film rows are real <button>s, so reset the parts a button brings with it. */
  width: 100%; text-align: left; font: inherit; color: inherit;
}
.idx-row .n { grid-column: 1 / 2; font: 500 clamp(10px, .6vw, 12px)/1 var(--mono); letter-spacing: .1em; color: var(--mute); transition: color var(--t) var(--e); }
.idx-row .t { grid-column: 2 / 7; font-size: clamp(19px, 2.3vw, 38px); font-weight: 600; letter-spacing: -.035em; line-height: 1.02; transition: transform var(--t) var(--e); }
.idx-row .m { grid-column: 7 / 11; }
.idx-row .y { grid-column: 11 / 13; text-align: right; }
.idx-row .go { position: absolute; right: 0; top: 50%; transform: translate(6px, -50%); opacity: 0; transition: opacity var(--t) var(--e), transform var(--t) var(--e); color: var(--red); font: 500 12px/1 var(--mono); }
.idx-row:hover .n { color: var(--red); }
.idx-row:hover .t { transform: translateX(8px); }
.idx-row:hover .go { opacity: 1; transform: translate(0, -50%); }
.idx-row::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 1px;
  background: var(--red); transform: scaleX(0); transform-origin: left;
  transition: transform .45s var(--e);
}
.idx-row:hover::after { transform: scaleX(1); }

/* ─────────────────────────────────────────── PHOTOGRAPHY ARCHIVE UI ── */
.stories { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gut); row-gap: clamp(40px, 6vw, 96px); }
.story {
  display: block; position: relative;
  padding-top: clamp(12px, 1.4vw, 18px);
  border-top: 1px solid var(--ink);
}
/* Asymmetry: large stories take eight columns and alternate side; small ones
   take four and sit against the opposite margin. */
.story.lg:nth-of-type(4n+1) { grid-column: 1 / 8; }
.story.sm:nth-of-type(4n+2) { grid-column: 9 / -1; }
.story.lg:nth-of-type(4n+3) { grid-column: 6 / -1; }
.story.sm:nth-of-type(4n+4) { grid-column: 1 / 4; }

.story-hd { display: flex; align-items: baseline; gap: .8em; margin-bottom: clamp(12px, 1.4vw, 20px); }
.story-n { font: 500 clamp(10px, .6vw, 12px)/1 var(--mono); letter-spacing: .1em; color: var(--red); }
.story-t { font-size: clamp(20px, 2.5vw, 40px); font-weight: 600; letter-spacing: -.035em; line-height: 1; transition: transform var(--t) var(--e); }
.story-c { margin-left: auto; }
.story figure { overflow: hidden; background: var(--paper-2); }
.story.lg figure { aspect-ratio: 4 / 3; }
.story.sm figure { aspect-ratio: 3 / 4; }
.story img { width: 100%; height: 100%; object-fit: cover; transition: transform .62s var(--e); }
.story:hover img { transform: scale(1.03); }
.story:hover .story-t { transform: translateX(7px); }
.story-f { display: flex; justify-content: space-between; gap: 1em; padding-top: 10px; }
.story-note { margin-top: 10px; }

/* ────────────────────────────────────────────── PHOTO STORY VIEWER ── */
/* The measure of a plate follows the photograph's own proportion, set by the
   f-* class the script assigns. No plate crops: each <img> carries the frame's
   real aspect ratio inline, so height simply follows width. */
.plate { padding-block: clamp(30px, 4.4vw, 76px); }
.plate-fig { position: relative; }
.plate img { width: 100%; height: auto; background: var(--paper-2); cursor: zoom-in; }
.plate-cap { display: flex; justify-content: space-between; gap: 1em; padding-top: 12px; }

/* The way in — the strongest frame, full measure, nothing beside it. */
.pl-open { padding-top: clamp(8px, 1.4vw, 20px); padding-bottom: clamp(44px, 7vw, 116px); }
.f-open { grid-column: 1 / -1; }

/* Panoramas and every third landscape break the margins. */
.f-bleed { grid-column: 1 / -1; }
.pl-bleed { padding-block: clamp(36px, 5.4vw, 92px); }

/* Landscapes hang from alternating margins, leaving the other side open. */
.f-large-l { grid-column: 1 / 11; }
.f-large-r { grid-column: 3 / -1; }

/* A square sits inset — smaller than a landscape, so it reads as a beat. */
.f-sq { grid-column: 4 / 10; }

/* A lone portrait is narrow and offset, with the page deliberately left empty
   beside it. */
.f-port-l { grid-column: 2 / 6; }
.f-port-r { grid-column: 8 / 12; }

/* Two portraits become one spread. This is what rescues the portrait-heavy
   stories from being a single narrow column all the way down. */
.pl-pair .f-pair:first-of-type { grid-column: 2 / 7; }
.pl-pair .f-pair:last-of-type  { grid-column: 7 / 12; align-self: end; }

.pager { display: flex; justify-content: space-between; align-items: center; gap: 2em;
         border-top: 1px solid var(--ink); padding-top: clamp(18px, 2.2vw, 30px); margin-top: var(--blk); }
.pager a { display: block; }
.pager .pg-lbl { display: block; margin-bottom: 6px; }
.pager .pg-t { font-size: clamp(18px, 2.2vw, 34px); font-weight: 600; letter-spacing: -.032em; line-height: 1; transition: color var(--t) var(--e); }
.pager a:hover .pg-t { color: var(--red); }

/* ───────────────────────────────────────────────────── CASE STUDIES ── */
.case-hero { margin-top: clamp(20px, 2.6vw, 36px); }
.case-hero-fig { display: flex; justify-content: center; }
/* The inline aspect-ratio on the <img> is the artwork's own, so the piece is
   always complete. max-height is what keeps a tall cover on one screen: it caps
   the height and, because the ratio is fixed, the width follows. */
/* Sized by both constraints at once, never by a box it has to fit inside:
   width and height are auto, so the artwork keeps its ratio, and max-width /
   max-height shrink it until it clears both the measure and the viewport.
   object-fit is deliberately absent — there is no box to fit into, so there is
   nothing to crop and no bars to letterbox with. */
.case-hero img {
  width: auto; height: auto;
  max-width: 100%;
  max-height: 78vh;
  background: var(--sheet);
  border: 1px solid var(--rule);
  cursor: zoom-in;
}

/* Placeholder for a project whose visuals have not been archived yet. Reads as
   a deliberate index card — hairline rule, survey mark, field-note type — not
   as a missing image. */
.arc-note { margin-top: clamp(20px, 2.6vw, 36px); }
.arc-note-in {
  border: 1px solid var(--rule);
  background: var(--paper-2);
  padding: clamp(30px, 5vw, 72px) clamp(20px, 3vw, 48px);
  text-align: center;
}
.arc-mark {
  display: block; width: 10px; height: 10px; background: var(--red);
  margin: 0 auto clamp(16px, 2vw, 26px);
}
.arc-note-t {
  font: 500 clamp(10px, .6vw, 12px)/1 var(--mono);
  letter-spacing: .22em; text-transform: uppercase; color: var(--ink);
  margin-bottom: 10px;
}
.arc-note-b { margin: clamp(14px, 1.8vw, 22px) auto 0; max-width: 46ch; }

.facts { border-top: 1px solid var(--ink); margin-top: clamp(28px, 3.6vw, 52px); }
.facts div { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: var(--gut);
             padding: 11px 0; border-bottom: 1px solid var(--rule); }
.facts dt { font: 500 10px/1.3 var(--mono); letter-spacing: .13em; text-transform: uppercase; color: var(--mute); }
.facts dd { margin: 0; font-size: clamp(13.5px, .74vw, 15.5px); }

.chap { padding-top: clamp(34px, 5vw, 80px); }
.chap h2 {
  font: 500 clamp(9.5px, .55vw, 11px)/1.3 var(--mono);
  letter-spacing: .16em; text-transform: uppercase; color: var(--red);
  padding-bottom: 14px; border-bottom: 1px solid var(--rule); margin-bottom: clamp(16px, 2vw, 26px);
}
.chap .body { max-width: none; }

.sheet { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gut); row-gap: clamp(20px, 2.8vw, 42px); }
/* Spans chosen so that every shape lands at roughly the same rendered height.
   A 0.7 pamphlet on three columns and a 3:1 banner on twelve both come out near
   450px, which is what keeps the sheet even without cropping a single piece. */
.sheet-item        { grid-column: span 4; }   /* square-ish */
.sheet-item.sh-tall{ grid-column: span 3; }
.sheet-item.sh-wide{ grid-column: span 6; }
.sheet-item.sh-pano{ grid-column: 1 / -1; }
.sheet-item figure { overflow: hidden; }
.sheet-item img {
  width: 100%; height: auto;          /* ratio comes from the inline style */
  background: var(--sheet);
  border: 1px solid var(--rule);
  cursor: zoom-in;
  transition: transform .5s var(--e);
}
.sheet-item:hover img { transform: scale(1.015); }
.sheet-item .cap { display: flex; justify-content: space-between; gap: 1em; padding-top: 10px; border-top: 1px solid var(--rule); margin-top: 10px; }

/* ────────────────────────────────────────────────────────── MOTION ── */
/* ── Films: one independent player per film ──────────────────────────────── */

.film-stage { position: relative; background: var(--ink); aspect-ratio: 16 / 9; overflow: hidden; }
.film-mount { position: absolute; inset: 0; z-index: 1; }
.film-mount iframe { width: 100%; height: 100%; border: 0; display: block; }

/* The poster is a real button covering the stage, and it is taken out of the
   pointer's way the moment the film mounts — it can never sit over a playing
   picture. */
.film-poster {
  position: absolute; inset: 0; z-index: 2;
  width: 100%; height: 100%; padding: 0; border: 0;
  display: block; cursor: pointer; background: var(--ink);
}
.film-poster img { width: 100%; height: 100%; object-fit: cover; opacity: .84;
                   transition: opacity var(--t) var(--e), transform .6s var(--e); }
.film-poster:hover img { opacity: 1; transform: scale(1.015); }
.film-stage.is-playing .film-poster { display: none; }

.film-play {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  display: flex; align-items: center; gap: 12px;
  background: var(--paper); color: var(--ink);
  padding: 13px 22px;
  font: 500 11px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  transition: background var(--t) var(--e), color var(--t) var(--e);
}
.film-poster:hover .film-play { background: var(--red); color: #fff; }
.film-play i { width: 0; height: 0; border: 5px solid transparent; border-left-color: currentColor; border-right: 0; }

.film-msg {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 3;
  padding: 10px clamp(12px, 1.6vw, 22px);
  font: 500 10px/1.4 var(--mono); letter-spacing: .12em; text-transform: uppercase;
  color: #FAFAF8; background: rgba(0,0,0,.55);
  pointer-events: none;
}
.film-msg:empty { display: none; }

.film-bar { display: flex; flex-wrap: wrap; gap: 10px; padding-top: 14px; }
.film-btn {
  font: 500 clamp(10px, .6vw, 11.5px)/1 var(--mono);
  letter-spacing: .13em; text-transform: uppercase;
  padding: 11px 16px; border: 1px solid var(--rule-2); color: var(--ink);
  background: none; cursor: pointer; text-decoration: none;
  transition: color var(--t) var(--e), border-color var(--t) var(--e), background var(--t) var(--e);
}
.film-btn:hover { color: #fff; background: var(--red); border-color: var(--red); }
/* A stage in fullscreen fills it, rather than keeping a 16:9 box inside. */
.film-stage:fullscreen { aspect-ratio: auto; width: 100vw; height: 100vh; }
.film-stage:-webkit-full-screen { aspect-ratio: auto; width: 100vw; height: 100vh; }

/* The list under the player. The film currently loaded is marked in red. */
.film-meta { padding-top: 14px; }
.film-list { margin-top: clamp(24px, 3vw, 40px); }
.film-pick { width: 100%; text-align: left; }
.film-pick.is-current .n { color: var(--red); }
.film-pick.is-current .t { color: var(--red); }
.film-pick.is-current .go { opacity: 1; transform: translate(0, -50%); color: var(--red); }

@media (max-width: 760px) {
  .film-btn { flex: 1 1 auto; text-align: center; padding: 13px 12px; }
}

.film-hero { position: relative; background: var(--well); aspect-ratio: 16 / 9; overflow: hidden; cursor: pointer; }
/* z-index, not just DOM order: the player must sit above anything the card or
   the fallback leaves behind, in every browser, not only the ones that happen
   to paint later elements on top. */
/* Poster frame. Layer order is explicit so nothing can ever end up on top of
   the picture: poster 0, scrim 1, title card 2, player 3. */
/* contain, not cover. Most of these films are shot wide — the Kathputli frame
   is 2.64:1 — and filling a 16:9 box with a 2.64:1 still meant cropping away
   two thirds of the frame and landing on a face in extreme close-up. Fitting it
   shows the shot as it was composed; the bars top and bottom are the film's own
   aspect ratio against the black of the player, which is what a widescreen film
   looks like in a 16:9 frame. */
.film-hero img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; z-index: 0;
  transition: transform .7s var(--e);
}
.film-hero:hover img { transform: scale(1.02); }
/* A scrim, not a black box — the frame stays visible, the type stays legible. */
.film-hero::after {
  content: ''; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(to top,
    rgba(11,11,11,.90) 0%, rgba(11,11,11,.45) 42%, rgba(11,11,11,.12) 100%);
}
.film-card { z-index: 2; }
/* Scoped to .film-hero on purpose. Unscoped, this z-index:3 also matched the
   per-film players further up the file and lifted their EMPTY mount above the
   poster button — which silently swallowed every click on films 2-7 while
   film 1 (the hero) still worked. */
.film-hero .film-mount { position: absolute; inset: 0; z-index: 3; }
.film-hero .film-mount iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.film-hero iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; z-index: 3; }

/* While the player is fetching, the poster stays put and a line of type says
   what is happening — never a blank rectangle. */
.film-hero.is-loading img, .film-hero.is-loading::after { display: block; }
.film-hero.is-loading .film-mount { opacity: 0; }
.film-hero.is-blocked img, .film-hero.is-blocked::after,
.film-hero.is-error img,   .film-hero.is-error::after { display: block; }

.film-state {
  position: absolute; inset: 0; z-index: 4;
  display: none; place-items: center;
  pointer-events: none;
}
.film-hero.is-loading .film-state,
.film-hero.is-blocked .film-state,
.film-hero.is-error .film-state { display: grid; }
.film-state span {
  background: var(--well-fg); color: var(--well);
  padding: 12px 20px;
  font: 500 11px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
}
.film-hero.is-error .film-state span { background: var(--red); color: #fff; }
/* The three states share one element; only the matching line is shown. */
.film-state .s-load, .film-state .s-blocked, .film-state .s-error { display: none; }
.film-hero.is-loading  .film-state .s-load    { display: block; }
.film-hero.is-blocked  .film-state .s-blocked { display: block; }
.film-hero.is-error    .film-state .s-error   { display: block; }

/* The row for whatever is playing. */
.idx-row[aria-current] .n { color: var(--red); }
.idx-row[aria-current] .t { color: var(--red); }
/* Once the player is in, the poster and scrim have no business being there. */
.film-hero.is-playing img, .film-hero.is-playing::after { display: none; }
@media (prefers-reduced-motion: reduce) { .film-hero:hover img { transform: none; } }

/* Sits underneath the iframe and is only ever seen if the embed fails to
   paint. Never visible during normal playback. */
.film-fallback {
  position: absolute; inset: 0; z-index: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  text-align: center; padding: var(--pad);
}
.film-fallback .lbl { color: var(--well-mute); }
.film-fallback-go {
  font: 500 12px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--well-fg); border-bottom: 1px solid var(--red); padding-bottom: 6px;
}
.film-fallback:hover .film-fallback-go { color: var(--red); }

/* The title card. A hairline box inset from the edge gives it the feel of a
   leader slide rather than an empty black rectangle. */
.film-card {
  position: absolute; inset: clamp(14px, 2vw, 30px);
  border: 1px solid var(--inv-rule);
  display: flex; flex-direction: column; justify-content: flex-end;
  padding: clamp(16px, 2.4vw, 38px);
  transition: border-color var(--t) var(--e);
}
.film-hero:hover .film-card { border-color: var(--red); }
.film-kind { color: var(--well-mute); }
.film-title {
  color: var(--well-fg);
  font-size: clamp(24px, 4.4vw, 68px);
  font-weight: 600; letter-spacing: -.042em; line-height: .96;
  margin-top: .35em; max-width: 18ch;
  text-wrap: balance;
}
.play {
  position: absolute; right: clamp(16px, 2.4vw, 38px); top: clamp(16px, 2.4vw, 38px);
  display: flex; align-items: center; gap: 12px;
  background: var(--well-fg); color: var(--well);
  padding: 13px 22px;
  font: 500 11px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
  transition: background var(--t) var(--e), color var(--t) var(--e);
}
.film-hero:hover .play { background: var(--red); color: #fff; }
.play::before { content: ''; width: 0; height: 0; border: 5px solid transparent; border-left-color: currentColor; border-right: 0; }

.reels {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(min(52vw, 250px), 1fr);
  gap: var(--gut); overflow-x: auto; scroll-snap-type: x mandatory;
  overscroll-behavior-x: contain; padding-bottom: 14px;
}
.reel { scroll-snap-align: start; position: relative; }
.reel-fig { aspect-ratio: 9 / 16; background: var(--well); overflow: hidden; position: relative; }
.reel-fig img, .reel-fig video { width: 100%; height: 100%; object-fit: cover; }
.reel-fig video { position: absolute; inset: 0; opacity: 0; transition: opacity .3s; }
.reel.playing .reel-fig video { opacity: 1; }
.reel .cap { display: flex; justify-content: space-between; padding-top: 9px; }
.reel { cursor: pointer; }

/* A small red play mark, so a clip reads as playable without being hovered.
   It is the only thing that told a desktop visitor these were videos at all. */
.reel-play {
  position: absolute; left: 12px; bottom: 12px; z-index: 2;
  width: 26px; height: 26px; display: grid; place-items: center;
  background: var(--red);
  transition: opacity var(--t) var(--e), transform var(--t) var(--e);
}
.reel-play::after {
  content: ''; width: 0; height: 0;
  border: 6px solid transparent; border-left-color: #fff; border-right: 0;
  margin-left: 3px;
}
.reel:hover .reel-play { transform: scale(1.08); }
/* The mark stays through the silent hover preview: it is what says the clip
   opens into a player with sound and fullscreen. */
.reel.playing .reel-play { opacity: .75; }
.reel:focus-visible { outline: 2px solid var(--red); outline-offset: 3px; }

/* ─────────────────────────────────────────────────── CITY REPORTS ── */
.cities { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: var(--gut); }
.city {
  display: flex; flex-direction: column; gap: 10px;
  border-top: 1px solid var(--ink); padding-top: 14px;
}
.city-n { color: var(--red); }
.city-name { font-size: clamp(20px, 2.2vw, 32px); font-weight: 600; letter-spacing: -.032em; line-height: 1; }
.city-go {
  font: 500 clamp(10px, .62vw, 12px)/1 var(--mono);
  letter-spacing: .13em; text-transform: uppercase;
  margin-top: 6px; padding-top: 12px; border-top: 1px solid var(--rule-2);
  transition: color var(--t) var(--e), border-color var(--t) var(--e);
}
.city-go:hover { color: var(--red); border-color: var(--red); }
/* A city whose report is not in hand states that, rather than borrowing one. */
.city-none { margin-top: 6px; padding-top: 12px; border-top: 1px dashed var(--rule-2); }

/* ────────────────────────────────────────────────────── INSTITUTIONS ── */
/* The planning index is a disclosure tree, not a list. Three rows arrive; the
   reader opens what they want. On a phone the previous version printed every
   category heading and all fourteen projects before anything had been asked
   for, which is what made the page feel endless.

   Red does more work here than elsewhere on the site: the index number, the
   open state and the disclosure mark are all interaction, and interaction is
   what the accent is for. Titles and body copy stay black. */

.plan-tree { border-top: 1px solid var(--ink); }

.inst { border-bottom: 1px solid var(--rule-2); }

.inst-sum {
  display: grid;
  grid-template-columns: 3.4em minmax(0, 1fr) auto auto 1.5em;
  align-items: baseline;
  gap: clamp(10px, 1.6vw, 26px);
  padding: clamp(20px, 2.6vw, 34px) 0;
  cursor: pointer; list-style: none;
  transition: color var(--t) var(--e);
}
.inst-sum::-webkit-details-marker { display: none; }
.inst-n {
  font: 500 clamp(10px, .66vw, 13px)/1 var(--mono);
  letter-spacing: .1em; color: var(--red);
}
.inst-t {
  font-size: clamp(22px, 3.2vw, 50px);
  font-weight: 600; letter-spacing: -.04em; line-height: 1;
  transition: transform var(--t) var(--e);
}
.inst-c { justify-self: end; }
/* "Open" is the affordance; it turns to "Active" in red once the panel is up. */
.inst-state { justify-self: end; color: var(--mute); }
.inst-sum:hover .inst-t { transform: translateX(6px); }
.inst-sum:hover .inst-state { color: var(--red); }
details[open] > .inst-sum .inst-state { color: var(--red); }
details[open] > .inst-sum .inst-state::after { content: ' ·'; }
details[open] > .inst-sum { color: var(--ink); }

/* The disclosure mark: a plus that becomes a minus. */
.disc-i { position: relative; justify-self: end; align-self: center; width: 12px; height: 12px; }
.disc-i::before, .disc-i::after {
  content: ''; position: absolute; left: 0; top: 5px; width: 12px; height: 1.5px;
  background: var(--red); transition: transform var(--t) var(--e), opacity var(--t) var(--e);
}
.disc-i::after { transform: rotate(90deg); }
details[open] > summary .disc-i::after { transform: rotate(0deg); opacity: 0; }

.inst-body { padding-bottom: clamp(22px, 3vw, 44px); }
.inst-meta { padding-bottom: clamp(16px, 2.2vw, 30px); }
.inst-full {
  font: 500 clamp(10px, .6vw, 11.5px)/1.4 var(--mono);
  letter-spacing: .1em; text-transform: uppercase; color: var(--red);
}
.inst-note { max-width: 52ch; }
.inst-body > .idx { border-top: 1px solid var(--rule); }

/* ───────────────────────────────────────── AIILSG CATEGORY LEVEL ── */
/* Quieter than the institution above it — a category is a shelf label. */
.cat { border-top: 1px solid var(--rule); }
.cat:first-of-type { border-top: 1px solid var(--ink); }
.cat-sum {
  display: grid;
  grid-template-columns: 3.4em minmax(0, 1fr) auto 1.5em;
  align-items: baseline;
  gap: clamp(10px, 1.4vw, 22px);
  padding: clamp(13px, 1.5vw, 19px) 0;
  cursor: pointer; list-style: none;
  transition: color var(--t) var(--e);
}
.cat-sum::-webkit-details-marker { display: none; }
.cat-n {
  font: 500 clamp(9.5px, .58vw, 11px)/1 var(--mono);
  letter-spacing: .1em; color: var(--red);
}
.cat-t {
  font-size: clamp(12.5px, .88vw, 15.5px); font-weight: 600;
  letter-spacing: .06em; line-height: 1.3; text-transform: uppercase;
}
.cat-c { justify-self: end; color: var(--mute); }
.cat-sum:hover .cat-t { color: var(--red); }
details[open] > .cat-sum .cat-t { color: var(--red); }
.cat .idx { border-top: 0; padding-bottom: clamp(8px, 1.2vw, 16px); }
.cat .disc-i { width: 10px; height: 10px; }
.cat .disc-i::before, .cat .disc-i::after { width: 10px; top: 4px; }

/* Rows inside a category sit in from the number column. */
.cat .idx-row .n { color: var(--red); }

@media (max-width: 760px) {
  /* Compact on a phone: number and title on one line, the rest beneath. The
     whole summary stays one tap target and clears 44px comfortably.

     Sizes and padding were both a step too generous here. The project title
     had been 19px against a 22px institution and a 12.5px category, so the
     deepest level in the tree was competing with the shallowest and the
     hierarchy read flat. Each level now steps down clearly, and the padding
     comes in about 15% so a category of five projects is not a screen and a
     half of mostly air. Nothing is made small — the section heading is
     untouched and the smallest label here is still 12.5px. */
  .inst-sum {
    grid-template-columns: 2.6em minmax(0, 1fr) 1.4em;
    row-gap: 4px; padding: 15px 0;
  }
  .inst-t { font-size: clamp(18px, 5.1vw, 20px); }        /* was 22px */
  .inst-c { grid-column: 2; justify-self: start; }
  .inst-state { grid-column: 2; justify-self: start; }
  .inst-sum:hover .inst-t { transform: none; }

  .cat-sum { grid-template-columns: 2.4em minmax(0, 1fr) 1.3em; row-gap: 3px; padding: 12px 0; }
  /* The project row is where the vertical bulk was: 110px each, mostly
     padding around a title that wrapped to two lines. */
  /* project row type and spacing are set in the later mobile block, with
     the rest of the .idx-row overrides — one place, not two */
  .cat-c { grid-column: 2; justify-self: start; }

  .inst-full, .inst-note { margin-top: 8px; }
}

/* ─────────────────────────────────────── ARCHIVED PROJECT COVER ── */
/* A drawing title block, drawn in CSS. It stands in for the hero image on a
   project whose drawings are not here yet — built only from metadata the page
   already states, so it invents nothing and cannot fall out of step. */
.cover { margin-top: clamp(20px, 2.6vw, 36px); }
.cover-in {
  position: relative;
  background: var(--ink);
  color: var(--paper);
  aspect-ratio: 16 / 9;
  padding: clamp(20px, 3vw, 52px);
  display: flex; flex-direction: column; justify-content: space-between;
  overflow: hidden;
}
/* The faint sheet grid a drawing is set out on. */
.cover-in::before {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(to right, rgba(255,255,255,.05) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,.05) 1px, transparent 1px);
  background-size: clamp(34px, 4.4vw, 72px) clamp(34px, 4.4vw, 72px);
}
.cover-in > * { position: relative; z-index: 1; }

.cover-top { display: flex; justify-content: space-between; gap: 1em;
             border-bottom: 1px solid #2A2A28; padding-bottom: 12px; }
.cover-top .lbl { color: var(--mute-d); }

.cover-mid { display: flex; align-items: flex-start; gap: clamp(12px, 1.8vw, 28px); }
.cover-n {
  font: 500 clamp(10px, .68vw, 13px)/1 var(--mono);
  letter-spacing: .1em; color: var(--red);
  padding-bottom: 7px; border-bottom: 1px solid var(--red);
  flex: 0 0 auto;
}
.cover-t {
  font-size: clamp(20px, 3.3vw, 52px);
  font-weight: 600; letter-spacing: -.038em; line-height: 1.02;
  max-width: 20ch; text-wrap: balance;
}

.cover-foot { display: flex; flex-wrap: wrap; align-items: baseline;
              justify-content: space-between; gap: 10px 1.4em;
              border-top: 1px solid #2A2A28; padding-top: 12px; }
.cover-disc { color: var(--paper); }
.cover-tags { display: flex; flex-wrap: wrap; gap: 6px 8px; }
.cover-tag { color: var(--mute-d); }
.cover-tag::before { content: '· '; }
.cover-tag:first-child::before { content: ''; }

/* Corner registration marks. */
.cover-reg { position: absolute; width: 14px; height: 14px; z-index: 1; }
.cover-reg::before, .cover-reg::after { content: ''; position: absolute; background: var(--red); }
.cover-reg::before { left: 0; top: 6px; width: 14px; height: 1px; }
.cover-reg::after  { left: 6px; top: 0; width: 1px; height: 14px; }
.cover-reg-tl { left: clamp(8px, 1.1vw, 18px); top: clamp(8px, 1.1vw, 18px); }
.cover-reg-br { right: clamp(8px, 1.1vw, 18px); bottom: clamp(8px, 1.1vw, 18px); }

.cover-cap { display: block; padding-top: 10px; }

@media (max-width: 760px) {
  .cover-in { aspect-ratio: 4 / 3; }
  .cover-mid { flex-direction: column; gap: 10px; }
  .cover-foot { flex-direction: column; align-items: flex-start; }
}

/* ────────────────────────────────────── PROJECT ARCHIVE NOTICE ── */
/* Shown on a project that is named but whose drawings are not yet here. It has
   to read as a deliberate state, not as a failure — so it is set like a caption
   block with a red rule, and never uses the language of an error. */
.arch-note {
  border-top: 1px solid var(--ink);
  border-left: 2px solid var(--red);
  padding: clamp(18px, 2.2vw, 30px) 0 clamp(18px, 2.2vw, 30px) clamp(16px, 1.6vw, 26px);
  max-width: 56ch;
}
.arch-note-k { color: var(--red); }
.arch-note-t {
  font-size: clamp(19px, 1.9vw, 30px); font-weight: 500;
  letter-spacing: -.022em; line-height: 1.2;
  margin: .5em 0 .4em;
}
.arch-note-b { color: var(--char); }

@media (max-width: 760px) {
  .cat-hd { grid-template-columns: 3em minmax(0, 1fr); row-gap: 4px; }
  .cat-hd .ta-r { display: none; }
}

/* ───────────────────────────────────────────────────────── ARCHIVE ── */
/* A reference shelf. Each document is a cover, a title and a way in — sized
   so a group reads as a shelf rather than a list of links. */
.arc-inst { padding-top: clamp(40px, 6vw, 96px); }
.arc-inst-hd { border-top: 1px solid var(--ink); padding-top: clamp(12px, 1.4vw, 18px);
               align-items: baseline; padding-bottom: clamp(14px, 1.8vw, 24px); }

/* Each group is a closed <details>: a row you open, not a wall you scroll. */
.arc-grp { border-top: 1px solid var(--rule); }
.arc-grp:last-of-type { border-bottom: 1px solid var(--rule); }
.arc-sum {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto 1.6em;
  align-items: baseline; gap: clamp(10px, 1.6vw, 26px);
  padding: clamp(14px, 1.7vw, 22px) 0;
  cursor: pointer; list-style: none;
  transition: color var(--t) var(--e);
}
.arc-sum::-webkit-details-marker { display: none; }
.arc-sum:hover { color: var(--red); }
.arc-sum-t { font-size: clamp(15px, 1.15vw, 21px); font-weight: 600; letter-spacing: -.024em; }
.arc-sum-i { position: relative; justify-self: end; align-self: center; width: 11px; height: 11px; }
.arc-sum-i::before, .arc-sum-i::after {
  content: ''; position: absolute; left: 0; top: 5px; width: 11px; height: 1px;
  background: currentColor; transition: transform var(--t) var(--e);
}
.arc-sum-i::after { transform: rotate(90deg); }
details[open] > .arc-sum { color: var(--red); }
details[open] > .arc-sum .arc-sum-i::after { transform: rotate(0deg); }
.arc-grp-in { padding-bottom: clamp(24px, 3vw, 44px); }
.arc-grp-n { max-width: 62ch; margin-bottom: clamp(18px, 2.2vw, 30px); }

@media (max-width: 760px) {
  .arc-sum { grid-template-columns: minmax(0, 1fr) 1.4em; row-gap: 6px; }
  .arc-sum-t { grid-column: 1; }
  .arc-sum-i { grid-column: 2; grid-row: 1; }
  .arc-sum-m, .arc-sum-c { grid-column: 1; }
}

.arc-docs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 250px), 1fr));
  gap: clamp(22px, 2.6vw, 40px) var(--gut);
  margin-top: clamp(26px, 3.4vw, 46px);
}
.arc-doc { display: flex; flex-direction: column; gap: 14px; }
.arc-doc-fig {
  display: block; overflow: hidden;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  aspect-ratio: 1 / 1.28;
}
.arc-doc-fig img {
  width: 100%; height: 100%; object-fit: cover; object-position: top center;
  transition: transform .6s var(--e);
}
.arc-doc:hover .arc-doc-fig img { transform: scale(1.03); }
.arc-doc:hover .arc-doc-fig { border-color: var(--red); }
.arc-doc-body { display: flex; flex-direction: column; gap: 7px; }
.arc-doc-t { font-size: clamp(15px, .95vw, 18px); font-weight: 600; letter-spacing: -.022em; line-height: 1.2; }
.arc-doc-n { font-size: clamp(13px, .72vw, 14.5px); line-height: 1.45; color: var(--char); }
.arc-doc-m { display: block; }
.arc-doc-go {
  font: 500 clamp(9.5px, .58vw, 11px)/1 var(--mono);
  letter-spacing: .13em; text-transform: uppercase;
  margin-top: 4px; padding-top: 10px; border-top: 1px solid var(--rule-2);
  transition: color var(--t) var(--e), border-color var(--t) var(--e);
}
.arc-doc:hover .arc-doc-go { color: var(--red); border-color: var(--red); }

@media (max-width: 760px) {
  .arc-docs { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px var(--gut); }
  .arc-doc-n { display: none; }   /* the title and the page count carry it */
}

/* ─────────────────────────────────────────────────────────── ABOUT ── */
.tl { border-top: 1px solid var(--ink); }
.tl-row {
  display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gut);
  padding: clamp(14px, 1.9vw, 26px) 0; border-bottom: 1px solid var(--rule);
  align-items: baseline;
}
.tl-row .k { grid-column: 1 / 3; }
.tl-row .t { grid-column: 3 / 7; font-size: clamp(16px, 1.4vw, 24px); font-weight: 600; letter-spacing: -.028em; }
.tl-row .d { grid-column: 7 / -1; }
.tl-row .t::before { content: ''; display: inline-block; width: 6px; height: 6px; background: var(--red); margin-right: .6em; vertical-align: .12em; }

.caps { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); column-gap: var(--gut); row-gap: var(--blk); }
.caps > div { grid-column: span 4; border-top: 1px solid var(--ink); padding-top: 14px; }
.caps h3 { font: 500 11px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--red); margin-bottom: 16px; }
.caps li { padding: 8px 0; border-bottom: 1px solid var(--rule); font-size: clamp(14px, .82vw, 16.5px); }

/* Square, because the photograph is square — forcing it into a 3:4 box would
   crop the model and the drawings that give the picture its context. */
.portrait { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; background: var(--paper-2); }

/* ───────────────────────────────────────────────────────────── TOOLS ── */
.tools-route { padding-bottom: clamp(18px, 2.4vw, 30px); }
.tools-route span { color: var(--red); padding: 0 .3em; }
/* Five stages, so the row holds five. This was a 12-column grid with each tool
   spanning 3, which fitted four and left the fifth stranded on a row of its
   own at a quarter width. The container spans the full measure either way, so
   the outer edges still line up with the page grid. */
.tools {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
  column-gap: var(--gut); row-gap: var(--blk);
}
.tool { grid-column: auto; border-top: 1px solid var(--ink); padding-top: 14px; position: relative; }
.tool-n { display: block; color: var(--red); margin-bottom: 10px; }
.tool h3 { font-size: clamp(17px, 1.3vw, 23px); font-weight: 600; letter-spacing: -.028em; }
/* Room for two lines whether or not this one needs them. At five columns the
   longest subtitle wraps and the one below it started a line lower than the
   other four, which is the kind of half-line drift this grid exists to stop.
   Reserving the space keeps every list starting on the same baseline, and
   keeps it that way the next time a subtitle is reworded. */
.tool-sub { display: block; margin: 6px 0 14px; line-height: 1.3; min-height: 2.6em; }
.tool li {
  padding: 7px 0; border-bottom: 1px solid var(--rule);
  font-size: clamp(13.5px, .76vw, 15.5px); color: var(--char);
}
/* Three then one, rather than two — five items across two columns strands one
   again, which is the thing this is avoiding. */
@media (max-width: 1080px) { .tools { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 620px)  { .tools { grid-template-columns: 1fr; } }

/* ────────────────────────────────────────────────────────── FOOTER ── */
.ft { background: var(--inv-bg); color: var(--inv-fg); margin-top: var(--sec); }
.ft-in { padding: clamp(56px, 8vw, 130px) var(--pad) clamp(24px, 3vw, 44px); }
.ft-big { display: block; margin-bottom: clamp(40px, 6vw, 92px); }
/* Two blocks, each free to wrap. The size is a shade smaller than the old
   one-word-per-line setting because the sentence is now five words: at the
   previous scale it filled a phone screen on its own. */
.ft-big span {
  display: block;
  font-size: clamp(34px, 9.4vw, 150px);
  font-weight: 700; letter-spacing: -.05em; line-height: .9;
  text-wrap: balance;
}
.ft-big span:nth-child(2) { color: var(--inv-dim); }
.ft-big span:nth-child(2)::after { content: ''; display: inline-block; width: clamp(10px, 1.2vw, 20px); height: clamp(10px, 1.2vw, 20px); background: var(--red); margin-left: .3em; vertical-align: .04em; }

.ft-grid { border-top: 1px solid var(--inv-rule); padding-top: clamp(22px, 3vw, 40px); row-gap: var(--blk); }
.ft-list li, .ft-links li { padding: 7px 0; }
.ft-list li { font: 500 11px/1 var(--mono); letter-spacing: .13em; text-transform: uppercase; color: var(--mute-d); }
.ft-links a {
  font-size: clamp(17px, 1.5vw, 26px); font-weight: 600; letter-spacing: -.028em;
  transition: color var(--t) var(--e); display: inline-block;
  padding-block: 6px; margin-block: -6px;
}
.ft-links a:hover { color: var(--red); }
.ft-meta div { display: flex; justify-content: space-between; gap: 1em; padding: 7px 0; border-bottom: 1px solid var(--inv-rule); }
.ft-meta dt { font: 500 10px/1.4 var(--mono); letter-spacing: .13em; text-transform: uppercase; color: var(--mute-d); }
.ft-meta dd { margin: 0; font: 500 11px/1.4 var(--mono); letter-spacing: .06em; color: var(--inv-meta); }
.ft-base { margin-top: clamp(44px, 6vw, 92px); border-top: 1px solid var(--inv-rule); padding-top: 16px; align-items: center; row-gap: 18px; }
.ft-mark { height: clamp(26px, 2.6vw, 38px); width: auto; }
/* Inverted bands run opposite to the page, so the footer mark does too. */
.ft-mark.on-inv-light { display: none; }
:root[data-theme="dark"] .ft-mark.on-inv-dark { display: none; }
:root[data-theme="dark"] .ft-mark.on-inv-light { display: block; }
.ft .lbl { color: var(--mute-d); }

/* ──────────────────────────────────────────────────────── LIGHTBOX ── */
.lb {
  position: fixed; inset: 0; z-index: 150;
  background: var(--paper);
  display: grid; grid-template-rows: auto 1fr auto;
  animation: lbIn .26s var(--e);
}
.lb[hidden] { display: none; }
@keyframes lbIn { from { opacity: 0; } }
.lb-bar {
  display: flex; align-items: center; gap: 1.4em;
  padding: 16px var(--pad); border-bottom: 1px solid var(--rule);
}
.lb-bar .lbl:first-child { color: var(--ink); }
.lb-x { margin-left: auto; font: 500 11px/1 var(--mono); letter-spacing: .13em; }
.lb-x:hover { color: var(--red); }
.lb-fig { display: grid; place-items: center; padding: clamp(16px, 3vw, 48px) var(--pad); min-height: 0; overflow: hidden; }
/* max-height:100% here silently did nothing — a percentage on a replaced grid
   item does not reliably resolve against the grid area, so a tall photograph
   rendered at its full intrinsic height and ran off a viewer that cannot
   scroll. Viewport units resolve unconditionally. The subtracted space is the
   title bar, the caption and this element's own padding; dvh keeps it honest
   when mobile browser chrome slides in and out. */
.lb-fig img {
  max-width: 100%;
  max-height: calc(100vh - 170px);
  max-height: calc(100dvh - 170px);
  object-fit: contain;
}
@media (max-width: 760px) {
  /* the previous/next buttons sit along the bottom on a phone */
  .lb-fig img { max-height: calc(100dvh - 210px); }
}
.lb-cap { padding: 0 var(--pad) 18px; text-align: center; }
.lb-nav {
  position: fixed; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 52px; height: 52px; display: grid; place-items: center;
  background: var(--paper); border: 1px solid var(--rule);
  font-size: 18px; transition: border-color var(--t) var(--e), color var(--t) var(--e);
}
.lb-nav:hover { border-color: var(--red); color: var(--red); }
.lb-prev { left: clamp(8px, 1.6vw, 24px); }
.lb-next { right: clamp(8px, 1.6vw, 24px); }

/* ───────────────────────────────────────────────────── REEL VIEWER ── */
/* NOTE: this class must not be called .rv — that is the site-wide reveal
   class, and naming the viewer the same turned every revealed block into a
   fixed full-screen overlay. */
.reelview {
  position: fixed; inset: 0; z-index: 160;
  background: var(--well);
  display: grid; grid-template-rows: auto 1fr auto;
  animation: lbIn .26s var(--e);
}
.reelview[hidden] { display: none; }
.rv-bar {
  display: flex; align-items: center; gap: 1.4em;
  padding: 16px var(--pad); border-bottom: 1px solid #222;
}
.rv-bar .lbl { color: var(--well-mute); }
.rv-bar .lbl:first-child { color: var(--well-fg); }
.rv-x { margin-left: auto; font: 500 11px/1 var(--mono); letter-spacing: .13em; color: var(--well-fg); }
.rv-x:hover { color: var(--red); }

.rv-stage {
  position: relative; min-height: 0;
  display: grid; place-items: center;
  padding: clamp(10px, 2vw, 28px) var(--pad);
  background: var(--well);
}
/* Fitted, not filled: these clips are 9:16 and the composition is the point. */
#rvVideo {
  max-width: 100%;
  max-height: calc(100vh - 210px);
  max-height: calc(100dvh - 210px);
  width: auto; height: auto;
  object-fit: contain;
  background: #000;
  cursor: pointer;
}
/* In real fullscreen the browser gives us the whole screen — use all of it. */
.rv-stage:fullscreen { padding: 0; }
.rv-stage:fullscreen #rvVideo { max-height: 100vh; max-width: 100vw; }
.rv-stage:-webkit-full-screen #rvVideo { max-height: 100vh; max-width: 100vw; }

.rv-spin {
  position: absolute; width: 26px; height: 26px; border-radius: 50%;
  border: 2px solid #333; border-top-color: var(--red);
  animation: rvSpin .8s linear infinite;
}
.rv-spin[hidden] { display: none; }
@keyframes rvSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .rv-spin { animation-duration: 2.4s; } }
.rv-err { position: absolute; color: var(--red); }

.rv-nav {
  position: fixed; top: 50%; transform: translateY(-50%); z-index: 2;
  width: 52px; height: 52px; display: grid; place-items: center;
  background: transparent; border: 1px solid #333; color: var(--well-fg);
  font-size: 18px;
  transition: border-color var(--t) var(--e), color var(--t) var(--e);
}
.rv-nav:hover { border-color: var(--red); color: var(--red); }
.rv-prev { left: clamp(8px, 1.6vw, 24px); }
.rv-next { right: clamp(8px, 1.6vw, 24px); }

.rv-ctl {
  display: flex; justify-content: center; gap: clamp(10px, 2vw, 28px);
  padding: 16px var(--pad) calc(16px + env(safe-area-inset-bottom));
  border-top: 1px solid #222;
}
.rv-btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 11px 16px;
  border: 1px solid #333; color: var(--well-fg);
  font: 500 10px/1 var(--mono); letter-spacing: .13em; text-transform: uppercase;
  transition: border-color var(--t) var(--e), color var(--t) var(--e);
  min-height: 44px;                       /* touch target */
}
.rv-btn:hover { border-color: var(--red); color: var(--red); }
.rv-btn span { display: block; width: 11px; height: 11px; position: relative; }
/* Icons drawn in CSS — no icon font to load, and they inherit the text colour. */
.ic-play::before { content: ''; position: absolute; inset: 0;
  border: 6px solid transparent; border-left-color: currentColor; border-right: 0; }
.ic-pause::before, .ic-pause::after { content: ''; position: absolute; top: 0; bottom: 0;
  width: 3px; background: currentColor; }
.ic-pause::before { left: 1px; } .ic-pause::after { right: 1px; }
.ic-snd::before { content: ''; position: absolute; left: 0; top: 2px; bottom: 2px;
  width: 5px; background: currentColor; }
.ic-snd::after { content: ''; position: absolute; right: 0; top: 0; bottom: 0; width: 5px;
  border: 2px solid currentColor; border-left: 0; border-radius: 0 6px 6px 0; }
.ic-mute::before { content: ''; position: absolute; left: 0; top: 2px; bottom: 2px;
  width: 5px; background: currentColor; }
.ic-mute::after { content: ''; position: absolute; right: -1px; top: 50%;
  width: 9px; height: 1.5px; background: currentColor; transform: rotate(-45deg); }
.ic-full::before { content: ''; position: absolute; inset: 0;
  border: 1.5px solid currentColor; border-radius: 1px; }

/* The swipe nudge, shown once per visit on touch devices. */
.rv-hint {
  position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%);
  background: rgba(0,0,0,.72); color: var(--well-fg);
  padding: 9px 14px; white-space: nowrap;
  animation: rvHint .3s var(--e);
}
.rv-hint[hidden] { display: none; }
@keyframes rvHint { from { opacity: 0; transform: translate(-50%, 6px); } }

@media (max-width: 760px) {
  .rv-btn em { display: none; }          /* icons only where space is tight */
  .rv-btn { padding: 11px 15px; }
  /* Arrows are a pointer affordance. On a touch screen the gesture is the
     control, so they are removed rather than shrunk — they only stole room
     from the picture. */
  .rv-nav { display: none; }
  #rvVideo { max-height: calc(100dvh - 200px); }
}

/* Any coarse pointer, whatever the width — a tablet is still a touch screen. */
@media (hover: none) and (pointer: coarse) {
  .rv-nav { display: none; }
}

/* ────────────────────────────────────────────────────── CURSOR TAG ── */
.cursor {
  position: fixed; z-index: 140; top: 0; left: 0; pointer-events: none;
  transform: translate(-50%, -50%) scale(.6);
  opacity: 0;
  background: var(--red); color: #fff;
  padding: 8px 12px;
  font: 500 10px/1 var(--mono); letter-spacing: .14em;
  transition: opacity .22s var(--e), transform .22s var(--e);
}
.cursor.on { opacity: 1; transform: translate(-50%, -50%) scale(1); }

/* ───────────────────────────────────────────────────────── REVEALS ── */
.rv { opacity: 0; transform: translateY(14px); transition: opacity .6s var(--e), transform .6s var(--e); }
.rv.in { opacity: 1; transform: none; }

/* ══════════════════════════════════════════════════════════ MOBILE ══ */
/* The grid does not simply collapse: sections are re-composed for one hand. */
@media (max-width: 1080px) {
  .nav { display: none; }
  .burger { display: block; }
  .idx-row .m { grid-column: 7 / 13; }
  .idx-row .y { display: none; }
  .caps > div { grid-column: span 6; }
}

@media (max-width: 760px) {
  :root { --cols: 6; }
  .c1-3, .c1-4, .c1-6, .c1-8, .c1-12, .c4-12, .c5-8, .c7-12, .c8-12, .c9-12, .c10-12 { grid-column: 1 / -1; }
  .c4-6 { grid-column: 1 / -1; }
  .ta-r { text-align: left; }
  .hide-sm { display: none; }

  /* Everything that sat side by side is now stacked, so the columns need a
     vertical gap they never needed horizontally. */
  .mast-sub { row-gap: 18px; }
  .sec-head { row-gap: 7px; }
  .sec-more { row-gap: 10px; }
  .ft-base { row-gap: 6px; }
  .mast-sub .c1-6 > .lbl + .lbl { margin-top: 4px; }

  .hero-top { display: flex; justify-content: space-between; }
  .hero-top .lbl { grid-column: auto; }
  .hero-mid { row-gap: clamp(22px, 5vw, 34px); }
  .hero-role { display: flex; align-items: baseline; flex-wrap: wrap; gap: .6em; }
  .mark { margin-top: 0; align-self: center; width: 10px; height: 10px; }
  .hero-fig img { aspect-ratio: 4 / 5; }
  .disciplines { gap: 12px 22px; }

  /* Selected work becomes a single column, but keeps its reading order:
     number and locator, title, visual, then the case and the link. The number
     sits beside the title rather than above it, to save a whole line. */
  .work-hit { row-gap: clamp(12px, 3vw, 20px); }
  .work-idx, .work-head, .work-fig, .work-say,
  .work:nth-child(even) .work-fig, .work:nth-child(even) .work-say,
  .work-tall .work-fig, .work-tall .work-say,
  .work-tall:nth-child(even) .work-fig, .work-tall:nth-child(even) .work-say { grid-column: 1 / -1; }
  /* One column here, so the named row above would lay the text over the
     artwork instead of under it. */
  .work-fig, .work-say { grid-row: auto; }
  .work-idx { flex-direction: row; align-items: baseline; gap: 1em; }
  .work-n { padding-bottom: 4px; min-width: 0; }
  /* Tall artwork is inset so a pamphlet does not fill the screen top to bottom
     just to be seen whole. */
  .work-tall .work-fig img { max-width: 76%; }
  .work-photo .work-fig img { aspect-ratio: 4 / 3; }
  .work:hover .work-title { transform: none; }
  .work-desc { max-width: none; }

  /* Photography previews: one column, alternating proportion kept. */
  .stories-home .story.lg:nth-of-type(1), .stories-home .story.sm:nth-of-type(2),
  .stories-home .story.lg:nth-of-type(3), .stories-home .story.sm:nth-of-type(4) {
    grid-column: 1 / -1; margin-top: 0;
  }

  .mot-idx { flex-direction: row; align-items: baseline; gap: 1em; }

  .pos-row { row-gap: 6px; }
  .pos-row > .k { grid-column: 1 / -1; }
  .pos-row > .t { grid-column: 1 / -1; }
  .pos-row > .d { grid-column: 1 / -1; }

  .arc-stat { row-gap: 22px; }

  /* The row was 112px on a phone: 36 of padding, 18 of gaps and a title at
     19px that wrapped to two lines. Trimmed on all three counts. */
  .idx-row { row-gap: 5px; padding: 15px 0; }
  .idx-row .t { font-size: clamp(15px, 4.3vw, 16.5px); line-height: 1.16; }
  .idx-row .n { grid-column: 1 / -1; }
  .idx-row .t { grid-column: 1 / -1; }
  .idx-row .m { grid-column: 1 / -1; }
  .idx-row .go { display: none; }
  .idx-row:hover .t { transform: none; }

  /* Stories become one column, but keep alternating image proportion so the
     page still has a rhythm on a phone. */
  .story, .story.lg, .story.sm { grid-column: 1 / -1 !important; }
  .story.lg figure { aspect-ratio: 4 / 3; }
  .story.sm figure { aspect-ratio: 1 / 1; }
  .stories { row-gap: clamp(34px, 9vw, 56px); }

  /* One column on a phone, but the rhythm survives: lone portraits stay inset
     so they do not fill the screen, and paired portraits stay paired — a
     two-up spread reads well at this width and keeps the editorial pacing. */
  .f-open, .f-bleed, .f-large-l, .f-large-r, .f-sq { grid-column: 1 / -1; }
  .f-port-l, .f-port-r { grid-column: 1 / 6; }
  .f-port-r { grid-column: 2 / -1; }
  .pl-pair .f-pair:first-of-type { grid-column: 1 / 4; }
  .pl-pair .f-pair:last-of-type  { grid-column: 4 / -1; }
  .plate { padding-block: clamp(20px, 5vw, 40px); }
  .pl-open { padding-bottom: clamp(28px, 8vw, 52px); }

  .sheet-item, .sheet-item.sh-tall, .sheet-item.sh-wide { grid-column: span 3; }
  .sheet-item.sh-pano { grid-column: 1 / -1; }
  .case-hero img { max-height: 68vh; }

  .tl-row { row-gap: 4px; }
  .tl-row .k, .tl-row .t, .tl-row .d { grid-column: 1 / -1; }
  .caps > div { grid-column: 1 / -1; }

  .facts div { grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr); }

  .ft-grid { row-gap: 30px; }
  .lb-nav { top: auto; bottom: 68px; transform: none; width: 46px; height: 46px; }
  .lb-cap { text-align: left; }
  .cursor { display: none; }
}

@media (max-width: 420px) {
  .sheet-item, .sheet-item.sh-tall, .sheet-item.sh-wide { grid-column: 1 / -1; }
}

/* Coarse pointers never get hover-only affordances. */
@media (hover: none) {
  .cursor { display: none; }
  .work:hover .work-title, .story:hover .story-t, .idx-row:hover .t { transform: none; }
}

/* ─────────────────────────────────────────────────── REDUCED MOTION ── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .rv { opacity: 1; transform: none; }
}

/* ─────────────────────────────────────────────────────────── PRINT ── */
@media print {
  .hd, .drawer, .cursor, .lb, .sec-more, .burger { display: none !important; }
  body { background: #fff; color: #000; }
  .invert, .ft { background: #fff; color: #000; }
}

/* ─────────────────────────────────── ABOUT — RED AS NAVIGATION ── */
/* The accent does more work in About than it did: the section indices, the
   institution names in the timeline, the tool-group labels and the timeline
   markers. Names, body copy and the display type stay black — red marks
   structure and metadata, never prose. */
.tl-row .k { color: var(--red); }                 /* the year on each row      */
.tl-row .t::before { background: var(--red); }    /* the marker (already red)  */
.abo-cap h3 { color: var(--red); }                /* tool-group label          */
.tools-g > h3 { color: var(--red); }
.about-inst { color: var(--red); }                /* AIILSG / NIUA / SPA       */
.facts dt { color: var(--red); }                  /* fact keys on project pages*/

/* The × between the two roles was already red; give it a little more presence
   without changing its size relative to the words either side. */
.role-x { font-weight: 500; }

/* A semester with no project entry yet. Same notice as an archived project,
   set inside the disclosure rather than on a page of its own, plus a way
   through to the documents that do exist. */
.cat-note {
  border-left: 2px solid var(--red);
  padding: clamp(14px, 1.8vw, 22px) 0 clamp(16px, 2vw, 24px) clamp(14px, 1.4vw, 22px);
  margin-bottom: clamp(10px, 1.4vw, 18px);
  max-width: 54ch;
}
.cat-note .arch-note-t { font-size: clamp(16px, 1.4vw, 22px); margin: .45em 0 .35em; }
.cat-note-go { display: inline-block; margin-top: clamp(12px, 1.4vw, 18px); }
/* An empty category reads a shade quieter until it is opened. */
.cat-empty > .cat-sum .cat-t { color: var(--char); }
.cat-empty > .cat-sum .cat-c { color: var(--mute); }
details.cat-empty[open] > .cat-sum .cat-t { color: var(--red); }

/* Documents shown inside a semester in the planning index. Tighter than the
   Archive page's grid — this is a panel inside a panel, not a page. */
.cat-docs { padding: clamp(6px, 1vw, 12px) 0 clamp(18px, 2.2vw, 28px); }
.cat-docs-k { color: var(--red); margin-bottom: clamp(12px, 1.6vw, 20px); }
.cat-docs .arc-docs {
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr));
  gap: clamp(18px, 2.2vw, 30px) var(--gut);
  margin-top: 0;
}
@media (max-width: 760px) {
  .cat-docs .arc-docs { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 20px var(--gut); }
}

/* ─────────────────────────────────────────────────────── VISUALISATION ── */
/* A chart is neither artwork nor a photograph — it is a figure, so it is
   numbered like one.

   It sits on white in both themes, for the same reason the poster sheet does:
   a Flourish embed brings its own white ground with it, and inverting the page
   around it would only produce a bright rectangle with a dark rim. The white
   is the chart's paper, not the site's surface.

   The frame's height is set from the message Flourish posts back, so there is
   no ratio here to keep in step with the chart. Before that message arrives
   the min-height below is holding the space — it is a floor, never the final
   height. */

.viz-group > .viz:first-of-type { margin-top: clamp(20px, 2.6vw, 34px); }
.viz { margin-bottom: clamp(34px, 4.4vw, 68px); }
.viz:last-child { margin-bottom: 0; }

.viz-cap {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--gut);
  padding-bottom: 10px; margin-bottom: clamp(12px, 1.4vw, 18px);
  border-bottom: 1px solid var(--rule);
}
.viz-t {
  font: 500 clamp(15px, .92vw, 19px)/1.35 var(--sans);
  color: var(--ink); letter-spacing: -.01em;
}
.viz-n { white-space: nowrap; }

.viz-frame {
  position: relative;
  min-height: 320px;
  background: var(--sheet);
  border: 1px solid var(--rule);
  transition: height .25s ease;
}
.viz-frame iframe { display: block; width: 100%; height: 100%; border: 0; }

/* Until the chart reports back, the frame is an empty white field with the
   hairline of a figure. Deliberately not a spinner: the charts arrive in well
   under a second on a normal connection, and a spinner per figure on a page of
   twenty-four would be its own kind of noise. */
.viz-frame[data-state="loading"]::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(var(--paper-2), var(--paper-2));
  opacity: .55; pointer-events: none;
}
.viz-frame[data-state="ok"] { min-height: 0; }
.viz-frame[data-state="ok"]::after { display: none; }

/* The honest failure. A chart that is not published yet — or is blocked, or
   has been deleted — shows where it went instead of an empty rectangle. */
.viz-off {
  display: none;
  position: absolute; inset: 0;
  flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  margin: 0; padding: 0 24px; text-align: center;
  color: var(--mute);
}
.viz-frame[data-state="stalled"] { min-height: 180px; height: auto !important; }
.viz-frame[data-state="stalled"] iframe { display: none; }
.viz-frame[data-state="stalled"] .viz-off { display: flex; }
.viz-off a { color: var(--red); text-decoration: none; border-bottom: 1px solid currentColor; }
.viz-off a:hover { color: var(--ink); }

@media (max-width: 760px) {
  .viz-cap { flex-direction: column; align-items: flex-start; gap: 4px; }
  .viz-frame { min-height: 380px; }
}

@media (prefers-reduced-motion: reduce) {
  .viz-frame { transition: none; }
}

/* ─────────────────────────────────────── VISUALISATION ON THE HOME PAGE ── */
/* One live chart and the three studies under it. The chart keeps the frame
   rules from the study pages — white ground in both themes, hairline, height
   set from the service's own resize message — and only needs its margins
   setting here. */

.viz-home { margin-top: clamp(20px, 2.6vw, 34px); }
.viz-home-fig { margin-bottom: clamp(26px, 3.4vw, 44px); }
.viz-home-idx { margin-top: 0; }
