/* ROB HELFFERICH, Projection
   The page is a darkened projection room and the work is the only light in it.
   One law runs top to bottom: at any moment exactly one thing is lit, and
   everything else sits back in the dark. Colour does no work here; luminance
   is the whole palette, which is why there is no accent hue anywhere. */

/* ---------------------------------------------------------------- fonts -- */
@font-face {
  font-family: 'Manrope';
  src: url('assets/fonts/Manrope-Variable.woff2') format('woff2-variations');
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('assets/fonts/JetBrainsMono-Regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------------------------------------- tokens -- */
:root {
  --void: #0a0a09;
  --void-2: #121210;
  --light: #ede9df;          /* warm, never pure white */
  --light-60: rgba(237, 233, 223, .6);
  --light-34: rgba(237, 233, 223, .34);
  --light-16: rgba(237, 233, 223, .16);
  --hair: rgba(237, 233, 223, .13);

  --sans: 'Manrope', system-ui, -apple-system, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, 'SF Mono', monospace;

  /* ONE curve, every transition and every tween, CSS and JS alike. */
  --ease: cubic-bezier(0.25, 0.46, 0.45, 0.94);

  --gut: clamp(1.25rem, 4.2vw, 5rem);
  --bar: 52px;
}

/* ---------------------------------------------------------------- reset -- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; background: var(--void); }
body {
  margin: 0;
  background: var(--void);
  color: var(--light);
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.6;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, video, svg, canvas { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
h1, h2, h3, h4, p, figure, blockquote { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
::selection { background: var(--light); color: var(--void); }
:focus-visible { outline: 1px solid var(--light); outline-offset: 4px; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 300;
  background: var(--light); color: var(--void); padding: .75rem 1.25rem;
  font: 400 .75rem/1 var(--mono); letter-spacing: .1em; text-transform: uppercase;
}
.skip:focus { left: 0; }

/* ---------------------------------------------------------- type system -- */
/* Light weights at enormous size: a projected title card, not a bold grotesk.
   Thin faces need the tracking opened, not closed. */
.display {
  font-weight: 250;
  font-size: clamp(2.9rem, 11.4vw, 12rem);
  line-height: 0.94;
  letter-spacing: 0.005em;
  text-transform: uppercase;
}
.display-2 {
  font-weight: 250;
  font-size: clamp(2.2rem, 6.4vw, 6.5rem);
  line-height: 0.98;
  letter-spacing: 0.008em;
  text-transform: uppercase;
}
.lede {
  font-size: clamp(1.1rem, 1.55vw, 1.45rem);
  line-height: 1.52;
  font-weight: 300;
  color: var(--light-60);
  letter-spacing: -0.005em;
}
.meta {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1.5;
  color: var(--light-34);
}
.num {
  font-family: var(--mono);
  font-size: 0.6875rem;
  letter-spacing: 0.1em;
  color: var(--light-34);
  font-variant-numeric: tabular-nums;
}

/* --------------------------------------------------------------- layout -- */
.wrap { padding-inline: var(--gut); }
main { position: relative; z-index: 1; }
section { position: relative; }

.sec-head {
  display: grid;
  gap: 1.2rem;
  padding-block: clamp(5rem, 13vh, 10rem) clamp(2rem, 5vh, 3.5rem);
}
@media (min-width: 900px) {
  .sec-head { grid-template-columns: 16ch minmax(0, 1fr); gap: 3.5rem; align-items: start; }
}
.sec-head__body { max-width: 44ch; }

/* --------------------------------------------------------- the projector */
/* A fixed grain plate plus a vignette: the room, not the picture. Both sit
   above the media and below the type so nothing on the page escapes the room. */
.room {
  position: fixed; inset: 0;
  z-index: 60;
  pointer-events: none;
}
.room::before {
  content: '';
  position: absolute; inset: -60%;
  background-image: var(--grain-url);
  background-size: 170px 170px;
  opacity: .5;
  mix-blend-mode: overlay;
}
.room::after {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(125% 92% at 50% 46%,
    transparent 34%, rgba(0, 0, 0, .42) 78%, rgba(0, 0, 0, .72) 100%);
}

/* ---------------------------------------------------------------- header */
.bar {
  position: fixed; inset: 0 0 auto 0;
  z-index: 120;
  height: var(--bar);
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 1rem;
  padding-inline: var(--gut);
  mix-blend-mode: difference;   /* the bar reads over light footage and dark alike */
}
.wordmark {
  font-family: var(--mono);
  font-size: .75rem;
  letter-spacing: .32em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--light);
}
.bar__right { justify-self: end; display: flex; align-items: center; gap: clamp(1rem, 2.4vw, 2.2rem); }
.bar a, .bar button { color: var(--light); }
.bar__cta {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .2em;
  text-transform: uppercase;
  display: none; align-items: center; min-height: 44px;
  position: relative;
}
.bar__cta::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 13px; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: right;
  transition: transform .55s var(--ease);
}
.bar__cta:focus-visible::after{ transform: scaleX(1); transform-origin: left; }
@media (min-width: 700px) { .bar__cta { display: flex; } }

.menu-btn {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .2em;
  text-transform: uppercase;
  display: flex; align-items: center; gap: .6rem;
  min-height: 44px;
}
.menu-btn i { display: block; width: 22px; height: 8px; position: relative; }
.menu-btn i::before, .menu-btn i::after {
  content: ''; position: absolute; left: 0; right: 0; height: 1px;
  background: currentColor; transition: transform .5s var(--ease);
}
.menu-btn i::before { top: 0; }
.menu-btn i::after { bottom: 0; }
.menu-btn[aria-expanded='true'] i::before { transform: translateY(3.5px) rotate(12deg); }
.menu-btn[aria-expanded='true'] i::after { transform: translateY(-3.5px) rotate(-12deg); }

/* ------------------------------------------------------------- the sheet */
/* Two columns: where you can go on the left, what there is to watch on the
   right. The same law applies inside the sheet, so the row under the pointer
   is lit and the rest sit back. */
.panel {
  position: fixed; inset: 0; z-index: 110;
  background: var(--void);
  padding: calc(var(--bar) + clamp(1.5rem, 6vh, 4.5rem)) var(--gut) clamp(1.2rem, 4vh, 2.5rem);
  display: grid; grid-template-rows: 1fr auto; gap: clamp(1.5rem, 4vh, 2.5rem);
  clip-path: inset(0 0 100% 0);
  visibility: hidden;
  overflow-y: auto;
}
.panel[data-open='true'] { visibility: visible; }
.panel__cols { display: grid; gap: clamp(2rem, 5vh, 3rem); align-content: start; }
@media (min-width: 900px) {
  .panel__cols {
    grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
    gap: clamp(3rem, 7vw, 7rem); align-items: start;
  }
}
.panel__where { display: grid; align-content: start; gap: .1rem; }
.panel__where .meta { padding-bottom: 1rem; }
.panel__go {
  display: flex; align-items: baseline; gap: .8rem;
  padding-block: .55rem;
  color: var(--light-60);
  font-size: 1.0625rem;
  transition: color .45s var(--ease), transform .55s var(--ease);
}
.panel__go i {
  font-style: normal; font-family: var(--mono); font-size: .625rem;
  letter-spacing: .1em; color: var(--light-16);
  transition: color .45s var(--ease);
}
.panel__go:focus-visible{ color: var(--light); transform: translateX(.5rem); }

.panel__list { display: grid; align-content: start; }
.panel__list .meta { padding-bottom: 1rem; }
.panel__row {
  display: flex; flex-wrap: wrap; gap: .35rem 1.5rem; align-items: baseline;
  padding-block: clamp(.45rem, 1.3vh, .85rem);
  border-top: 1px solid var(--hair);
  color: var(--light-34);
  transition: color .5s var(--ease), transform .6s var(--ease);
}
@media (min-width: 900px) {
  .panel__row {
    display: grid; grid-template-columns: minmax(0, 1fr) 17ch 16ch;
    gap: 1.5rem; align-items: baseline;
  }
  .panel__row .meta:last-child { text-align: right; }
}
.panel__row:last-child { border-bottom: 1px solid var(--hair); }
.panel__row strong {
  font-weight: 250; font-size: clamp(1.25rem, 2.6vw, 2rem);
  letter-spacing: .006em; text-transform: uppercase; line-height: 1.14;
  color: var(--light-60); transition: color .5s var(--ease);
  margin-right: auto;
}
.panel__row:focus-visible{ color: var(--light); transform: translateX(.8rem); }
.panel__row:focus-visible strong{ color: var(--light); }

.panel__foot {
  display: flex; flex-wrap: wrap; gap: .8rem 2.5rem; justify-content: space-between;
  align-items: baseline;
  border-top: 1px solid var(--hair); padding-top: 1.1rem;
}
.panel__foot a { color: var(--light-60); transition: color .45s var(--ease); }

/* ------------------------------------------------------------------ hero */
.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  grid-template-rows: 1fr auto;
  align-items: end;
  overflow: hidden;
}
/* The plate is taller than the hero and lags the page on the way out, so the
   footage dissolves into the room instead of sliding off the bottom edge. */
.hero__plate {
  position: absolute; left: 0; right: 0; top: 0;
  height: 124%;
  z-index: 0;
  will-change: transform;
}
.hero__plate video, .hero__plate img {
  width: 100%; height: 100%; object-fit: cover;
  transform-origin: 50% 46%;
  /* two owners, two properties, so they can never fight over one value:
     --strike is the bulb striking on arrival, --lamp is the exit scrub */
  filter: brightness(calc(var(--lamp, .46) * var(--strike, 1))) contrast(1.06) saturate(.86);
}
.hero__plate::after {
  content: '';
  position: absolute; inset: 0;
  background: linear-gradient(to top,
    var(--void) 2%, rgba(10, 10, 9, .72) 32%, rgba(10, 10, 9, .3) 66%, rgba(10, 10, 9, .5) 100%);
}
.hero__inner {
  position: relative; z-index: 2;
  padding: calc(var(--bar) + clamp(3rem, 12vh, 8rem)) var(--gut) clamp(1.5rem, 4vh, 2.5rem);
  display: grid; gap: clamp(1.6rem, 4vh, 2.6rem);
  align-content: end;
}
.hero h1 { position: relative; }
.hero h1 .line-mask { display: block; }

/* the gate: two halves of the room meeting at a centre line, retracting to
   the edges once. Present in the markup so there is no flash of hero first. */
.hero__gate { position: absolute; inset: 0; z-index: 5; pointer-events: none; }
.hero__bar {
  position: absolute; left: 0; right: 0; height: 50.4%;
  background: var(--void);
  will-change: transform;
}
.hero__bar--t { top: 0; transform-origin: 50% 0; }
.hero__bar--b { bottom: 0; transform-origin: 50% 100%; }
/* A beam travelling through the letterforms: the one place on the page where
   light is inside the type rather than behind it. */
.hero h1 .ln {
  display: block;
  background-image: linear-gradient(100deg,
    var(--light-60) 0%, var(--light-60) 34%,
    #fffdf7 46%, #fffdf7 54%,
    var(--light-60) 66%, var(--light-60) 100%);
  background-size: 280% 100%;
  background-position: var(--beam, 100%) 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.hero__foot {
  position: relative; z-index: 2;
  display: grid; gap: 1.6rem;
  padding: 0 var(--gut) clamp(1.6rem, 5vh, 3rem);
}
@media (min-width: 860px) {
  .hero__foot { grid-template-columns: minmax(0, 1fr) minmax(0, 30rem); gap: 3rem; align-items: end; }
}
.hero__say { display: grid; gap: 1.4rem; justify-items: start; }

/* The call to action, built as a slit of light that opens under the words.
   Same mechanism as the room itself, at the size of a link. */
.cta {
  position: relative;
  display: inline-flex; align-items: center; gap: .9rem;
  padding: .6rem 0 .85rem;
  font-size: clamp(1.05rem, 1.5vw, 1.3rem);
  font-weight: 300;
  color: var(--light);
  letter-spacing: -.005em;
}
.cta::before {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--light-16);
}
.cta::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--light);
  box-shadow: 0 0 14px 1px rgba(237, 233, 223, .34);
  transform: scaleX(0); transform-origin: left;
  transition: transform .7s var(--ease);
}
.cta:focus-visible::after{ transform: scaleX(1); }
.cta i {
  font-style: normal; display: block; width: 40px; height: 1px;
  position: relative;
}
.cta i::before {
  content: ''; position: absolute; inset: 0;
  background: currentColor;
  transform: scaleX(.62); transform-origin: 100% 50%;
  transition: transform .55s var(--ease);
}
.cta i::after {
  content: ''; position: absolute; right: 0; top: -3px;
  width: 7px; height: 7px;
  border-top: 1px solid currentColor; border-right: 1px solid currentColor;
  transform: rotate(45deg); transform-origin: top right;
}
.cta:focus-visible i::before{ transform: scaleX(1); }
.cta--quiet { color: var(--light-60); font-size: 1rem; }

/* ------------------------------------------------------------- the index */
/* The flood: nine titles in the dark, and the one under the reader's attention
   floods the whole room with its own film. */
.index { position: relative; }
.index__flood {
  position: fixed; inset: 0; z-index: 0;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
}
.index__flood video {
  position: relative; z-index: 0;
  width: 100%; height: 100%; object-fit: cover;
  /* the highlights come down further than the shadows do, so a white sky
     stops competing with the type without the whole film going flat */
  filter: brightness(.5) contrast(.88) saturate(.86);
}
/* The gate's shadow. Exactly one title is lit, so the room throws a soft band
   of dark under that one title and nowhere else. It follows whatever is lit,
   which is why the type never has to fight whatever the film is doing: the
   ground arrives with the title. */
.index__flood::before {
  content: '';
  position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(to bottom,
    rgba(10, 10, 9, 0) calc((var(--gate, 50) - 26) * 1%),
    rgba(10, 10, 9, .58) calc((var(--gate, 50) - 12) * 1%),
    rgba(10, 10, 9, .76) calc(var(--gate, 50) * 1%),
    rgba(10, 10, 9, .58) calc((var(--gate, 50) + 12) * 1%),
    rgba(10, 10, 9, 0) calc((var(--gate, 50) + 26) * 1%));
}
.index__flood::after {
  content: '';
  position: absolute; inset: 0; z-index: 2;
  background: radial-gradient(120% 80% at 50% 50%, rgba(10,10,9,.25) 0%, rgba(10,10,9,.78) 100%);
}
.index__list { position: relative; z-index: 2; }

.row {
  position: relative;
  display: block; width: 100%;
  padding: clamp(1.1rem, 2.6vh, 2rem) 0;
  border-top: 1px solid var(--hair);
  text-align: left;
  color: inherit;
}
.index__list li:last-child .row { border-bottom: 1px solid var(--hair); }
.row__in {
  display: grid; gap: .5rem;
  transform: translateX(var(--push, 0));
  transition: transform .7s var(--ease);
}
.row__meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: .3rem .9rem; }
@media (min-width: 760px) {
  .row__in {
    grid-template-columns: 4ch minmax(0, 1fr) auto;
    align-items: baseline; gap: 2rem;
  }
  .row__meta { justify-content: flex-end; gap: 1.8rem; min-width: 24ch; }
}
.row__t {
  font-weight: 250;
  font-size: clamp(1.8rem, 6.2vw, 5.4rem);
  line-height: 1;
  letter-spacing: .006em;
  text-transform: uppercase;
  color: var(--light-34);
  transition: color .6s var(--ease), opacity .6s var(--ease);
}
.row__c, .row__k, .row__y { color: var(--light-34); transition: color .6s var(--ease); }
.row__c { font-size: .9375rem; }

/* lit state, set by JS so the touch build can drive the same two properties */
.row.is-lit { --push: clamp(.5rem, 1.6vw, 1.6rem); }
.row.is-lit .row__t { color: var(--light); }
.row.is-lit .row__c, .row.is-lit .row__k, .row.is-lit .row__y { color: var(--light-60); }
/* everything that is not lit falls further back, so only one thing is lit */
.index__list.has-lit .row:not(.is-lit) .row__t { opacity: .42; }

.index__foot {
  display: flex; flex-wrap: wrap; gap: 1rem 2rem; justify-content: space-between;
  padding-top: clamp(1.5rem, 4vh, 2.5rem);
}

/* ---------------------------------------------------------- the statement */
/* The sentence is about two worlds that intertwine, so the layout is two
   worlds that intertwine: two blocks that share columns 6 and 7 but not the
   same line, tied by a hairline running from one into the other. The light
   sweeps word by word straight through both, which is the only thing that
   makes it read as one sentence rather than two headlines. */
.statement { padding-block: clamp(6rem, 16vh, 13rem) clamp(5rem, 12vh, 9rem); }
.statement__lead { display: grid; gap: .9rem; max-width: 34ch; }

.statement__two {
  display: grid;
  gap: clamp(2.2rem, 6vh, 4rem);
  margin-top: clamp(2.5rem, 7vh, 5rem);
  font-weight: 250;
  letter-spacing: .004em;
  text-transform: uppercase;
}
.statement__half { display: block; }
.statement__half i {
  display: block; font-style: normal;
  padding-bottom: .7rem; margin-bottom: 1.1rem;
  border-bottom: 1px solid var(--hair);
  width: max-content; min-width: 8ch;
}
.statement__t {
  display: block;
  font-size: clamp(1.75rem, 4.7vw, 4.7rem);
  line-height: 1.03;
}
.statement__t .w { display: inline-block; }

@media (min-width: 900px) {
  .statement__two { grid-template-columns: repeat(12, 1fr); column-gap: clamp(1.5rem, 3vw, 3rem); }
  .statement__half--a { grid-column: 1 / span 7; grid-row: 1; }
  /* the overlap is the point: b starts inside a's last two columns */
  .statement__half--b {
    grid-column: 6 / span 7; grid-row: 2;
    position: relative;
    margin-top: clamp(1rem, 4vh, 3rem);
  }
  /* the hairline that carries one world into the other */
  .statement__half--b::before {
    content: '';
    position: absolute; left: 0; bottom: calc(100% + .2rem);
    width: 1px; height: clamp(2rem, 7vh, 5rem);
    background: linear-gradient(to bottom, transparent, var(--hair));
  }
}

.statement__spread {
  display: grid; gap: clamp(2.5rem, 6vh, 3.5rem);
  margin-top: clamp(4rem, 11vh, 9rem);
}
@media (min-width: 960px) {
  /* two panels, side by side, both shorter than a screen. The plate bleeds
     off the left page edge; the text starts at the same line it does. */
  .statement__spread {
    grid-template-columns: minmax(0, .82fr) minmax(0, 1fr);
    column-gap: clamp(3rem, 7vw, 7rem);
    align-items: start;
  }
  .statement__portrait { margin-left: calc(var(--gut) * -1); }
  .statement__prose { padding-top: clamp(.5rem, 2.5vh, 2rem); }
}
.statement__portrait {
  position: relative;
  aspect-ratio: 4 / 5;
  max-height: 74svh;
  background: var(--void-2);
  overflow: hidden; overflow: clip;
}
.statement__portrait figcaption {
  position: absolute; left: 0; bottom: 0; right: 0; z-index: 2;
  padding: 3.5rem 1.1rem .9rem;
  background: linear-gradient(to top, rgba(10, 10, 9, .82), transparent);
}
@media (min-width: 960px) { .statement__portrait figcaption { padding-left: calc(var(--gut) + 1.1rem); } }

/* The plate is grey until it is all the way into the room. Colour fills it
   from the bottom as it arrives, holds while it is fully on screen, and
   drains again as it leaves: the same law, read off the viewport itself. */
.ps__base { filter: grayscale(1) brightness(.8) contrast(1.08); }
.ps__lit {
  position: absolute; inset: 0; z-index: 1;
  -webkit-mask-image: linear-gradient(to top,
    #000 0%,
    #000 calc(var(--fill, 0) * 122% - 20%),
    transparent calc(var(--fill, 0) * 122% - 2%));
  mask-image: linear-gradient(to top,
    #000 0%,
    #000 calc(var(--fill, 0) * 122% - 20%),
    transparent calc(var(--fill, 0) * 122% - 2%));
}
.ps__lit img { width: 100%; height: 100%; object-fit: cover; filter: brightness(1.02) contrast(1.02); }

.statement__prose { display: grid; align-content: start; gap: clamp(1.4rem, 3.5vh, 2.2rem); }
.statement__open { display: grid; gap: .9rem; }
.statement__big {
  font-weight: 300;
  font-size: clamp(1.2rem, 1.95vw, 1.85rem);
  line-height: 1.36;
  letter-spacing: -.008em;
  color: var(--light);
  max-width: 24ch;
}
.statement__notes {
  display: grid; gap: 1.2rem; justify-items: start;
  padding-top: clamp(1.2rem, 3vh, 2rem);
  border-top: 1px solid var(--hair);
}
.statement__notes p { color: var(--light-60); font-size: .96875rem; line-height: 1.6; max-width: 44ch; }
@media (min-width: 1180px) {
  .statement__notes { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.6rem 2.5rem; }
  .statement__notes .cta { grid-column: 1 / -1; }
}
.statement__notes .cta { margin-top: .2rem; }

/* ------------------------------------------------------------- the plates */
/* A sequence in a projector: the plate at the gate is lit, the rest wait in
   the dark on either side of it. */
.plates { padding-bottom: clamp(4rem, 10vh, 8rem); }
.plates__stage {
  height: 100svh;
  padding-top: var(--bar);
  display: flex; flex-direction: column; justify-content: center;
  gap: clamp(1.2rem, 3.5vh, 2.4rem);
  overflow: hidden;
}
.plates__track {
  display: flex; align-items: center;
  gap: clamp(.8rem, 2vw, 2.2rem);
  padding-inline: var(--gut);
  will-change: transform;
}
.plate {
  position: relative;
  flex: 0 0 auto;
  height: clamp(210px, 52svh, 560px);
  aspect-ratio: 4 / 5;
  background: var(--void-2);
  padding: 0;
  overflow: hidden;
}
.plate img {
  width: 100%; height: 100%; object-fit: cover;
  filter: brightness(var(--lit, .3)) saturate(var(--sat, .3)) contrast(1.04);
  transform: scale(var(--sc, 1));
  transition: filter .8s var(--ease), transform 1.25s var(--ease);
}
.plate.is-lit { --lit: 1; --sat: 1; --sc: 1.03; }
.plate:focus-visible { --lit: 1; --sat: 1; }
.plates__foot {
  display: flex; flex-wrap: wrap; gap: .9rem 2rem; justify-content: space-between;
  align-items: center; padding-inline: var(--gut);
}
.plates__read { display: flex; align-items: baseline; gap: .6rem; font-family: var(--mono); }
.plates__read b {
  font-weight: 400; font-size: clamp(1.5rem, 2.8vw, 2.4rem);
  letter-spacing: -.02em; color: var(--light); line-height: 1;
  font-variant-numeric: tabular-nums;
}
.plates__read span { font-size: .6875rem; letter-spacing: .18em; text-transform: uppercase; color: var(--light-34); }

/* ------------------------------------------------------------- the method */
.method { padding-block: clamp(5rem, 13vh, 10rem); }
.beats { display: grid; gap: clamp(3rem, 9vh, 7rem); }
@media (min-width: 900px) {
  .beats { grid-template-columns: repeat(12, 1fr); gap: clamp(3rem, 9vh, 6rem) 2rem; }
  .beat--1 { grid-column: 1 / span 7; }
  .beat--2 { grid-column: 6 / span 7; }
  .beat--3 { grid-column: 2 / span 7; }
  .beat--1 h3 { font-size: clamp(1.9rem, 3.4vw, 3.2rem); }
}
.beat { display: grid; gap: 1rem; align-content: start; }
.beat__n {
  font-family: var(--mono); font-size: .75rem; letter-spacing: .22em;
  color: var(--light-34);
  padding-bottom: .9rem; border-bottom: 1px solid var(--hair);
}
.beat h3 {
  font-weight: 250; font-size: clamp(1.5rem, 2.3vw, 2.2rem);
  letter-spacing: .006em; line-height: 1.04; text-transform: uppercase;
}
.beat p { color: var(--light-60); font-size: .96875rem; max-width: 46ch; }

/* ------------------------------------------------------------- the voices */
.voices { padding-block: clamp(5rem, 13vh, 10rem); }
.voices__grid { display: grid; gap: clamp(2.5rem, 6vh, 4rem); }
@media (min-width: 760px) { .voices__grid { grid-template-columns: repeat(2, 1fr); gap: clamp(2.5rem, 5vw, 5rem); } }
@media (min-width: 1200px) { .voices__grid { grid-template-columns: repeat(3, 1fr); } }
.voice { display: grid; gap: 1.1rem; align-content: start; }
.voice blockquote {
  font-size: clamp(1rem, 1.3vw, 1.15rem); line-height: 1.5;
  font-weight: 300; color: var(--light-60);
}
.voice__by {
  display: grid; gap: .2rem;
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .16em; text-transform: uppercase;
  padding-top: .9rem; border-top: 1px solid var(--hair);
}
.voice__by b { font-weight: 400; color: var(--light); }
.voice__by span { color: var(--light-34); }

/* ------------------------------------------------------------- the foot -- */
/* The closing move, and the only contact block on the page. The name rises out
   of the floor as the house lights come up, and the address sits in front of
   it as the one thing at full brightness. */
footer.foot {
  position: relative;
  margin-top: clamp(5rem, 15vh, 12rem);
  padding: clamp(4rem, 13vh, 9rem) var(--gut) clamp(1.2rem, 3vh, 1.8rem);
  border-top: 1px solid var(--hair);
  overflow: hidden; overflow: clip;
  isolation: isolate;
}
/* the house lights: a wash that only exists at the very bottom of the page */
footer.foot::before {
  content: '';
  position: absolute; left: 0; right: 0; bottom: 0;
  height: 62%;
  background: radial-gradient(120% 100% at 50% 122%,
    rgba(237, 233, 223, .13) 0%, rgba(237, 233, 223, .04) 42%, transparent 72%);
  opacity: var(--house, 0);
  pointer-events: none;
  z-index: -1;
}
.foot__eyebrow { margin-bottom: clamp(1rem, 2.5vh, 1.6rem); }

.foot__mail {
  display: block;
  font-weight: 250;
  font-size: clamp(1.55rem, 6.2vw, 6rem);
  letter-spacing: .002em; line-height: 1.06;
  text-transform: uppercase;
  overflow-wrap: anywhere;
  color: var(--light);
  position: relative;
  width: max-content; max-width: 100%;
}
.foot__mail .line-mask { display: block; }
.foot__mail::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -.1em; height: 1px;
  background: var(--light);
  box-shadow: 0 0 18px 1px rgba(237, 233, 223, .3);
  transform: scaleX(0); transform-origin: left;
  transition: transform .85s var(--ease);
}
.foot__mail:focus-visible::after{ transform: scaleX(1); }

.foot__cols {
  display: grid; gap: clamp(1.8rem, 4.5vh, 2.6rem);
  margin-top: clamp(3rem, 9vh, 6rem);
}
@media (min-width: 620px) { .foot__cols { grid-template-columns: repeat(2, 1fr); gap: 2.2rem 3rem; } }
@media (min-width: 1000px) { .foot__cols { grid-template-columns: repeat(4, 1fr); gap: clamp(2rem, 4vw, 4rem); } }
.foot__col { display: grid; gap: .4rem; align-content: start; }
.foot__col .meta { padding-bottom: .5rem; }
.foot__col p { color: var(--light-60); font-size: 1rem; line-height: 1.5; }
.foot__col a {
  color: var(--light-60); font-size: 1rem; width: max-content;
  transition: color .45s var(--ease); position: relative;
}
.foot__col a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -2px; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: right;
  transition: transform .5s var(--ease);
}
.foot__col a:focus-visible{ color: var(--light); }
.foot__col a:focus-visible::after{ transform: scaleX(1); transform-origin: left; }

/* the name rising out of the floor: a mask clipped to the line box, and the
   word itself travelling up inside it while a beam runs through the letters */
.foot__markbox {
  display: block;
  margin-top: clamp(3rem, 10vh, 7rem);
  overflow: hidden; overflow: clip;
  overflow-clip-margin: .12em;
}
.foot__mark {
  display: block;
  font-weight: 250;
  font-size: clamp(1.6rem, 8.9vw, 9.4rem);
  line-height: .92;
  letter-spacing: .004em;
  text-transform: uppercase;
  white-space: nowrap;
  color: transparent;
  background-image: linear-gradient(96deg,
    rgba(237, 233, 223, .13) 0%, rgba(237, 233, 223, .13) 30%,
    rgba(237, 233, 223, .82) 48%, rgba(237, 233, 223, .82) 52%,
    rgba(237, 233, 223, .13) 70%, rgba(237, 233, 223, .13) 100%);
  background-size: 260% 100%;
  background-position: var(--beam, 118%) 0;
  -webkit-background-clip: text;
  background-clip: text;
  will-change: transform;
}
.foot__rule {
  display: flex; flex-wrap: wrap; gap: .6rem 2rem; justify-content: space-between;
  margin-top: clamp(1.2rem, 3.5vh, 2rem);
  padding-top: 1.1rem;
  border-top: 1px solid var(--hair);
}

/* ------------------------------------------------------------- the player */
.player {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(4, 4, 4, .96);
  display: grid; place-items: center;
  padding: clamp(1rem, 4vw, 3rem);
  opacity: 0; visibility: hidden;
  transition: opacity .5s var(--ease), visibility .5s;
}
.player[data-open='true'] { opacity: 1; visibility: visible; }
.player__box { width: min(100%, 1200px); display: grid; gap: 1rem; }
.player__frame { position: relative; aspect-ratio: 16 / 9; background: #000; }
.player__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.player__bar { display: flex; justify-content: space-between; gap: 1.5rem; align-items: baseline; }
.player__close {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .2em; text-transform: uppercase;
  min-height: 44px; display: flex; align-items: center; color: var(--light-60);
}

/* ------------------------------------------------------------- lightbox -- */
.lightbox {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(4, 4, 4, .97);
  display: grid; place-items: center; gap: 1rem;
  padding: clamp(1rem, 4vw, 3rem);
  opacity: 0; visibility: hidden;
  transition: opacity .45s var(--ease), visibility .45s;
}
.lightbox[data-open='true'] { opacity: 1; visibility: visible; }
.lightbox img { max-height: 80svh; width: auto; object-fit: contain; }
.lightbox__bar {
  display: flex; gap: 1.5rem; align-items: center; justify-content: space-between;
  width: min(100%, 1100px);
}
.lightbox__right { display: flex; gap: 1.5rem; }
.lightbox__bar button {
  min-height: 44px; min-width: 44px; color: var(--light-60);
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .18em; text-transform: uppercase;
}

/* ------------------------------------------------------------- case page */
.case__hero { padding-top: calc(var(--bar) + clamp(2rem, 7vh, 4.5rem)); }
.case__title { padding-block: clamp(1.5rem, 4vh, 2.5rem) clamp(2rem, 5vh, 3rem); }
.case__client { margin-top: 1rem; }
.case__player { position: relative; aspect-ratio: 16 / 9; background: #000; }
.case__player iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.case__body { display: grid; gap: clamp(2.5rem, 6vh, 4rem); padding-block: clamp(3rem, 8vh, 6rem); }
@media (min-width: 900px) {
  .case__body { grid-template-columns: minmax(0, 19rem) minmax(0, 1fr); gap: clamp(3rem, 7vw, 6rem); align-items: start; }
}
.case__credits { display: grid; gap: 1.1rem; align-content: start; }
.case__credit { display: grid; gap: .3rem; padding-bottom: 1.1rem; border-bottom: 1px solid var(--hair); }
.case__credit p:last-child { color: var(--light-60); font-size: .96875rem; }
.case__prose { display: grid; gap: 1.3rem; max-width: 58ch; }
.case__prose h2 {
  font-weight: 250; font-size: clamp(1.3rem, 2.2vw, 2rem);
  letter-spacing: .006em; text-transform: uppercase; line-height: 1.04;
}
.case__prose p { color: var(--light-60); }
.case__prose .pull {
  font-weight: 250; font-size: clamp(1.4rem, 3vw, 2.6rem);
  letter-spacing: .006em; line-height: 1.1; color: var(--light);
  text-transform: uppercase; max-width: 20ch;
}
.case__nav {
  display: flex; flex-wrap: wrap; gap: 1.5rem; justify-content: space-between;
  padding-block: clamp(2rem, 5vh, 3.5rem); border-top: 1px solid var(--hair);
}
.case__nav a { display: grid; gap: .4rem; color: var(--light-60); transition: color .5s var(--ease); }
.case__nav strong {
  font-weight: 250; font-size: clamp(1.1rem, 1.9vw, 1.6rem);
  letter-spacing: .006em; text-transform: uppercase;
}
.case__next { text-align: right; justify-items: end; }

/* -------------------------------------------------------- shared crops -- */
/* Two speeds: the frame clips at one rate, the media inside travels at another. */
.crop {
  display: block; position: relative;
  width: 100%; height: 100%;
  overflow: hidden; overflow: clip;
}
.crop > * { width: 100%; height: 100%; object-fit: cover; will-change: transform; }

.line-mask {
  overflow: hidden; overflow: clip; overflow-clip-margin: .3em;
}

/* ------------------------------------------------------------ the phone -- */
/* Not the desktop layout narrowed. A phone gets its own reading of the same
   law: bigger display type because the screen is small, one film per thumb
   rather than five competing, and the plates handed back to the reader as a
   strip they swipe instead of nine screens of pinned scroll. */
@media (max-width: 859px) {
  :root { --bar: 48px; }

  /* display type carries more of the page when there is less of it */
  .display { font-size: 13.4vw; line-height: .96; }
  .lede { font-size: 1.0625rem; }
  .hero__foot { gap: 1.2rem; }
  .hero__say { gap: 1.1rem; }

  /* the index: one film at a time, and the lit one holds the room long
     enough to be watched rather than flickering past under the thumb */
  .row { padding-block: clamp(1.7rem, 4.8vh, 2.8rem); }
  .row__in { grid-template-columns: 1fr; gap: .5rem; }
  .row__n { font-size: .625rem; letter-spacing: .16em; }
  .row__t { font-size: 9vw; line-height: 1.02; }
  .row__c {
    font-family: var(--mono); font-size: .625rem; letter-spacing: .14em;
    text-transform: uppercase;
  }
  .row__k, .row__y { font-size: .625rem; letter-spacing: .14em; text-transform: uppercase; }
  .row__k::after { content: ','; }
  .row__meta { gap: .3rem .5rem; }
  .row__c::after { content: '\00b7'; margin-left: .9rem; color: var(--light-16); }
  .index__list.has-lit .row:not(.is-lit) .row__t { opacity: .24; }
  .row.is-lit { --push: .5rem; }
  /* a small dark screen swallows the flood, so it runs brighter here */
  .index__flood video { filter: brightness(.58) contrast(.9) saturate(.92); }
  .index__flood::after {
    background: radial-gradient(130% 78% at 50% 46%, rgba(10,10,9,.1) 0%, rgba(10,10,9,.66) 100%);
  }
  /* a phone screen is small and held close, so the band runs tighter and darker */
  .index__flood::before {
    background: linear-gradient(to bottom,
      rgba(10, 10, 9, 0) calc((var(--gate, 50) - 20) * 1%),
      rgba(10, 10, 9, .66) calc((var(--gate, 50) - 9) * 1%),
      rgba(10, 10, 9, .84) calc(var(--gate, 50) * 1%),
      rgba(10, 10, 9, .66) calc((var(--gate, 50) + 9) * 1%),
      rgba(10, 10, 9, 0) calc((var(--gate, 50) + 20) * 1%));
  }
  .index__foot { gap: .5rem 1.5rem; }

  /* the statement: the plate takes the whole width, the two halves step in */
  .statement__t { font-size: 8.2vw; }
  .statement__half--b { margin-left: 1.5rem; }
  .statement__half i { min-width: 6ch; }
  .statement__portrait {
    margin-inline: calc(var(--gut) * -1);
    max-height: none; aspect-ratio: 4 / 5;
  }
  .statement__portrait figcaption { padding-left: calc(var(--gut) + .2rem); }
  .statement__big { font-size: 1.2rem; line-height: 1.4; max-width: none; }
  .statement__notes p { font-size: .9375rem; }

  /* the plates: a strip the reader swipes, one screen tall, snapping to the
     gate. The pin is a desktop idea and costs nine screens on a phone. */
  .plates__stage { height: auto; padding-top: 0; gap: 1.1rem; overflow: visible; }
  .plates__track {
    overflow-x: auto; overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    padding-inline: calc(50vw - min(41vw, 210px));
    gap: .8rem;
  }
  .plates__track::-webkit-scrollbar { display: none; }
  .plate {
    width: min(82vw, 420px); height: auto;
    scroll-snap-align: center;
  }
  /* nothing is un-lit off-gate on a touch screen at rest, only dimmer */
  .plate img { transition: filter .5s var(--ease), transform .8s var(--ease); }
  .plates__foot { gap: .4rem 1.2rem; }

  /* method and voices */
  .beat h3 { font-size: 1.5rem; }
  .voice blockquote { font-size: 1rem; }

  /* the menu: a title line and one line of facts, never three */
  .panel { padding-top: calc(var(--bar) + 2rem); }
  .panel__go { padding-block: .7rem; font-size: 1.15rem; }
  .panel__row { display: grid; gap: .3rem; padding-block: .8rem; }
  .panel__row strong { font-size: 1.5rem; }
  .panel__row .meta { display: inline; }
  .panel__row .meta:first-of-type::after { content: '\00b7'; margin-inline: .5rem; color: var(--light-16); }
  .panel__foot { gap: .5rem 1.5rem; }

  /* the two link lists sit side by side so the close is one screen, not two */
  .foot__cols { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.8rem 1.5rem; }
  .foot__col:nth-child(1), .foot__col:nth-child(2) { grid-column: 1 / -1; }

  /* the close: the name breaks to two lines so it can be big enough to land */
  .foot__mail { font-size: 8.4vw; }
  .foot__markbox { margin-top: 3rem; }
  .foot__mark { white-space: normal; font-size: 12.6vw; line-height: .94; }
  /* every link in the footer is a thumb target, not a line of text */
  .foot__col a { min-height: 44px; display: flex; align-items: center; }
  .foot__col { gap: 0; }
  .foot__col p { padding-block: .3rem; }

  /* the wordmark is a link, so it gets a thumb's worth of bar to be tapped in */
  .wordmark { display: flex; align-items: center; min-height: 44px; }
}

@media (max-width: 520px) {
  .wordmark { letter-spacing: .2em; font-size: .6875rem; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  .room::before { display: none; }
  .hero__plate video, .hero__plate img { filter: brightness(.42) contrast(1.06) saturate(.86); }
  .hero h1 .ln { background: none; color: var(--light); }
  .hero__gate { display: none; }
  .plate img { filter: brightness(.85) saturate(.9); }
  .ps__base { filter: none; }
  .ps__lit { display: none; }
}

/* ------------------------------------------------------------ hover only -- */
/* Every hover state lives behind the capability that produces it. A finger
   cannot hover, and a rule that only fires on hover is a rule a phone can
   never reach, so none of them are allowed to be the only way to see state. */
@media (hover: hover) and (pointer: fine) {
  .bar__cta:hover::after {transform: scaleX(1); transform-origin: left; }
  .panel__go:hover {color: var(--light); transform: translateX(.5rem); }
  .panel__go:hover i {color: var(--light-34); }
  .panel__row:hover {color: var(--light); transform: translateX(.8rem); }
  .panel__row:hover strong {color: var(--light); }
  /* one lit at a time, here too */
  .panel__list:hover .panel__row:not(:hover) strong { color: var(--light-34); }
  .panel__foot a:hover {color: var(--light); }
  .cta:hover::after {transform: scaleX(1); }
  .cta:hover i::before {transform: scaleX(1); }
  .cta--quiet:hover {color: var(--light); }
  .foot__mail:hover::after {transform: scaleX(1); }
  .foot__col a:hover {color: var(--light); }
  .foot__col a:hover::after {transform: scaleX(1); transform-origin: left; }
  .player__close:hover {color: var(--light); }
  .lightbox__bar button:hover {color: var(--light); }
  .case__nav a:hover {color: var(--light); }
}
