/* ============================================================
   MEG'S ROOM · stylesheet
   palette: paper / ink / void
   no rounded corners, no shadows, no gradients
   ============================================================ */

:root {
  --paper:  #FAFAF7;
  --ink:    #0B1A2C;
  --void:   #000000;
  /* secondary text and hairlines are mixed toward the ink by an amount the
     mood engine raises as the room drifts (see js/mood.js). they used to be a
     fixed 55%/18% of a *transparent* ink, which meant the photo wall showed
     straight through the letterforms — survivable on a white page, unreadable
     once the red phase puts them over blood-multiplied photographs. mixing
     toward --paper instead keeps them opaque, so the glyphs stay solid. */
  --whisper-mix: 58%;
  --rule-mix:    20%;
  --rule:   color-mix(in srgb, var(--ink) var(--rule-mix), transparent);
  --whisper:color-mix(in srgb, var(--ink) var(--whisper-mix), var(--paper));
  --blood:  #6b0e0e;

  --serif:  "Cormorant Garamond", "EB Garamond", Georgia, serif;
  --mono:   "Space Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --sans:   "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;

  /* mood engine: shifts white -> blue -> green -> red over 90s, updated by js/mood.js */
  --mood-tint: transparent;
  --mood-tint-strength: 0;
  --blood-strength: 0;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  cursor: crosshair;
  overflow-x: hidden;
}
/* body itself stays transparent so the fixed .mood-bg photo wall (negative
   z-index) can show through the gaps in the layout — the solid paper color
   lives only on html, underneath it */
body { padding-bottom: 46px; } /* clearance for fixed ECG strip */
/* asylum-tile grid behind everything */
html {
  background-color: var(--paper);
  background-image:
    linear-gradient(to right, rgba(11,26,44,0.045) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(11,26,44,0.045) 1px, transparent 1px);
  background-size: 56px 56px;
  background-position: -1px -1px;
}

/* ============ REDUCED MOTION ============ */
/* only applies to visitors who set this at OS level. the room still turns
   red and still gets scratched — what stops is the flashing and the
   perpetual jitter, which is the part that can actually hurt someone. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }
  .blackout { display: none !important; }
}

/* ============ GLOBAL OVERLAYS ============ */

/* film grain */
body::before {
  content: "";
  position: fixed; inset: 0;
  pointer-events: none;
  z-index: 998;
  opacity: 0.09;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  animation: grain-shift 0.5s steps(3) infinite;
}
@keyframes grain-shift {
  0%   { transform: translate(0, 0); }
  33%  { transform: translate(-4px, 3px); }
  66%  { transform: translate(3px, -4px); }
  100% { transform: translate(0, 0); }
}

/* CRT scanlines */
body::after {
  content: "";
  position: fixed; inset: 0;
  pointer-events: none;
  z-index: 997;
  background: repeating-linear-gradient(
    to bottom,
    transparent 0,
    transparent 2px,
    rgba(11,26,44,0.03) 2px,
    rgba(11,26,44,0.03) 3px
  );
}

/* blackout flicker · whole-page dim, brief */
.blackout {
  position: fixed; inset: 0;
  background: var(--void);
  z-index: 995;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.04s ease;
}
.blackout.on { opacity: 0.6; }
.blackout.flicker { background: rgba(180,210,180,0.55); }
.blackout.red { background: rgba(120,16,16,0.55); }

/* mood background wall · a fixed, low-opacity flood of production stills
   sitting behind everything, so the room feels present even where there's
   no photo in the layout. deliberately dim and desaturated so it reads as
   atmosphere, not content — the eye should land on the real photos first */
.mood-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-template-rows: repeat(4, 1fr);
  pointer-events: none;
}
.mood-bg__cell { position: relative; overflow: hidden; }
.mood-bg__cell img {
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0.1;
  filter: grayscale(0.5) contrast(1.1) brightness(0.8);
  transition: opacity 1.5s ease, filter 1.5s ease;
}
/* 4x6 = the same 24 cells js/mood.js builds. a 3x5 grid would strand nine
   of them in implicit rows outside the fixed box, paying for images that
   can never be seen */
@media (max-width: 900px) {
  .mood-bg { grid-template-columns: repeat(4, 1fr); grid-template-rows: repeat(6, 1fr); }
}

/* blood splatters · bloom in as the room slides from green into red,
   as if something has finally broken. 20 slashes and 15 full drops.
   every mark is generated separately, with its own length, taper, curve,
   angle and depth: one shape rotated and repeated reads as pattern rather
   than damage. slashes are deliberately NOT evenly spaced or parallel,
   because tidy line sets read as cat claws. tile is 1200x1600 so the
   repeat is hard to catch at normal viewport widths.
   marks sit at fixed points down the whole page and scroll with it — this
   is NOT a fixed viewport overlay, it's meant to read as marks on the page
   itself. height is set in js/mood.js to match the full document height.
   z-index keeps it BELOW normal content (like the mood-bg wallpaper) so
   it shows through the paper gaps rather than sitting on top of text
   and photos; opaque elements (nav, buttons, photos) naturally mask it
   wherever they overlap, so it never covers a clickable button */
.mood-blood {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  z-index: -1;
  pointer-events: none;
  opacity: var(--blood-strength, 0);
  transition: opacity 2.5s ease;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 1600'><defs><linearGradient id='b' x1='0' y1='0' x2='0.3' y2='1'><stop offset='0%25' stop-color='%23b81419'/><stop offset='55%25' stop-color='%23880f0f'/><stop offset='100%25' stop-color='%233a0505'/></linearGradient></defs><g fill='url(%23b)'><path d='M119.5,226.6 Q153.0,182.5 169.7,129.6 Q145.6,178.7 119.5,226.6 Z' fill-opacity='0.83'/><path d='M130.9,255.3 Q188.2,175.6 220.8,83.0 Q180.3,171.5 130.9,255.3 Z' fill-opacity='0.79'/><path d='M589.3,85.0 Q636.6,95.2 684.6,89.8 Q637.0,86.3 589.3,85.0 Z' fill-opacity='0.64'/><path d='M1002.8,267.2 Q1041.3,261.8 1073.0,239.1 Q1039.1,256.3 1002.8,267.2 Z' fill-opacity='0.9'/><path d='M941.1,340.7 Q997.6,266.0 1021.7,175.5 Q989.4,262.0 941.1,340.7 Z' fill-opacity='0.64'/><path d='M292.2,383.7 Q325.5,466.2 384.3,533.0 Q334.4,460.7 292.2,383.7 Z' fill-opacity='0.73'/><path d='M803.3,630.9 Q873.6,571.8 942.5,511.3 Q868.5,565.9 803.3,630.9 Z' fill-opacity='0.63'/><path d='M841.8,603.8 Q901.2,559.3 952.9,506.1 Q895.0,552.2 841.8,603.8 Z' fill-opacity='0.95'/><path d='M790.8,539.2 Q854.3,542.8 914.3,521.7 Q853.6,538.2 790.8,539.2 Z' fill-opacity='0.95'/><path d='M116.4,668.6 Q146.6,702.4 188.0,720.8 Q152.7,694.0 116.4,668.6 Z' fill-opacity='0.9'/><path d='M103.6,719.4 Q165.9,752.5 229.4,783.4 Q168.6,747.1 103.6,719.4 Z' fill-opacity='0.9'/><path d='M614.6,968.0 Q652.2,908.9 697.8,855.6 Q647.2,905.1 614.6,968.0 Z' fill-opacity='0.88'/><path d='M944.9,934.1 Q1041.0,991.9 1148.6,1023.6 Q1043.8,985.6 944.9,934.1 Z' fill-opacity='0.91'/><path d='M1002.3,875.7 Q1028.5,922.6 1066.6,960.5 Q1033.0,919.2 1002.3,875.7 Z' fill-opacity='0.64'/><path d='M191.8,1193.9 Q259.1,1144.3 315.8,1082.9 Q255.1,1139.8 191.8,1193.9 Z' fill-opacity='0.67'/><path d='M210.9,1143.3 Q294.2,1170.5 381.5,1163.8 Q295.1,1162.8 210.9,1143.3 Z' fill-opacity='0.96'/><path d='M754.3,1274.6 Q762.3,1311.6 779.3,1345.4 Q770.6,1308.7 754.3,1274.6 Z' fill-opacity='0.87'/><path d='M45.2,1400.4 Q142.2,1397.4 237.9,1381.3 Q141.4,1389.6 45.2,1400.4 Z' fill-opacity='0.75'/><path d='M49.5,1356.1 Q145.2,1418.2 252.2,1457.7 Q147.6,1413.4 49.5,1356.1 Z' fill-opacity='0.85'/><path d='M863.7,1530.1 Q967.9,1496.5 1062.8,1441.8 Q965.3,1490.6 863.7,1530.1 Z' fill-opacity='0.88'/><g fill-opacity='0.84'><circle cx='820.7' cy='337.5' r='7.6'/><path d='M820.7,337.5 Q813.4,345.1 814.0,355.7 Q821.3,348.0 820.7,337.5 Z'/></g><g fill-opacity='1.0'><circle cx='827.9' cy='337.6' r='8.4'/><path d='M827.9,337.6 Q822.3,347.0 825.9,357.3 Q831.5,347.9 827.9,337.6 Z'/></g><g fill-opacity='0.89'><circle cx='855.2' cy='340.8' r='9.5'/><path d='M855.2,340.8 Q851.0,354.3 857.2,367.1 Q861.5,353.5 855.2,340.8 Z'/></g><g fill-opacity='0.87'><circle cx='403.8' cy='905.4' r='5.1'/></g><g fill-opacity='0.92'><circle cx='377.3' cy='913.5' r='7.3'/></g><g fill-opacity='0.85'><circle cx='402.7' cy='910.3' r='6.5'/><path d='M402.7,910.3 Q403.1,920.4 410.1,927.7 Q409.7,917.6 402.7,910.3 Z'/></g><g fill-opacity='0.86'><circle cx='400.5' cy='893.2' r='5.4'/><path d='M400.5,893.2 Q400.5,900.9 406.0,906.2 Q406.0,898.5 400.5,893.2 Z'/></g><g fill-opacity='0.94'><circle cx='699.3' cy='1251.7' r='9.8'/><path d='M699.3,1251.7 Q694.7,1267.3 700.9,1282.3 Q705.5,1266.7 699.3,1251.7 Z'/></g><g fill-opacity='0.93'><circle cx='681.1' cy='1233.4' r='5.4'/><path d='M681.1,1233.4 Q674.9,1239.8 674.0,1248.6 Q680.3,1242.3 681.1,1233.4 Z'/></g><g fill-opacity='0.86'><circle cx='712.1' cy='1232.6' r='9.8'/></g><g fill-opacity='0.85'><circle cx='717.5' cy='1222.6' r='6.0'/></g><g fill-opacity='0.96'><circle cx='141.5' cy='994.8' r='5.3'/><path d='M141.5,994.8 Q136.9,1000.2 137.9,1007.2 Q142.5,1001.8 141.5,994.8 Z'/></g><g fill-opacity='0.99'><circle cx='131.7' cy='994.8' r='5.9'/><path d='M131.7,994.8 Q128.2,1003.3 131.3,1011.9 Q134.7,1003.4 131.7,994.8 Z'/></g><g fill-opacity='0.95'><circle cx='139.1' cy='1043.0' r='9.5'/><path d='M139.1,1043.0 Q130.5,1056.3 132.1,1072.2 Q140.7,1058.8 139.1,1043.0 Z'/></g><g fill-opacity='0.91'><circle cx='145.4' cy='1026.9' r='9.0'/><path d='M145.4,1026.9 Q138.4,1038.3 141.1,1051.3 Q148.1,1040.0 145.4,1026.9 Z'/></g></g></svg>");
  background-repeat: repeat;
  background-size: 1200px 1600px;
  mix-blend-mode: multiply;
}

/* mood tint · color-grades every photo container to match the current
   phase (white/blue/green/red); strength is 0 at the start of a session
   so nothing changes until the shift has begun */
.mood-photo { position: relative; }
.mood-photo::before {
  content: "";
  position: absolute; inset: 0;
  z-index: 1;
  background: var(--mood-tint);
  mix-blend-mode: color;
  opacity: var(--mood-tint-strength);
  pointer-events: none;
  transition: opacity 1.2s ease, background 1.2s ease;
}

/* ============ WARNING BANNER (top) ============ */
.warning {
  position: sticky;
  top: 0; left: 0; right: 0;
  z-index: 100;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  padding: 7px 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  border-bottom: 1px solid var(--void);
  overflow: hidden;
  white-space: nowrap;
}
.warning::before, .warning::after {
  content: "";
  width: 9px; height: 9px;
  background: #c8181f;
  flex-shrink: 0;
  animation: rec-blink 1.1s steps(2) infinite;
}
@keyframes rec-blink { 50% { opacity: 0.15; } }
.warning__track {
  overflow: hidden;
  flex: 1;
  position: relative;
}
.warning__track span {
  display: inline-block;
  animation: warning-scroll 60s linear infinite;
  padding-right: 64px;
}

@keyframes warning-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ============ ECG STRIP (bottom) ============ */
.ecg {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 100;
  height: 46px;
  background: #050a14;
  border-top: 1px solid rgba(95,180,140,0.25);
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  padding: 0 18px;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.3em;
  color: rgba(95,180,140,0.7);
  pointer-events: none;
}
.ecg__canvas {
  width: 100%; height: 100%;
  display: block;
}
.ecg__left {
  position: relative;
  height: 100%;
  overflow: hidden;
}
.ecg__readout {
  display: flex;
  gap: 18px;
  text-transform: uppercase;
  align-items: center;
}
.ecg__readout span.bpm {
  color: #5cd6a8;
  animation: bpm-blink 1.15s steps(2) infinite;
}
@keyframes bpm-blink { 50% { opacity: 0.4; } }

/* ============ ROOM CONTROLS ============ */
/* the two controls that hand the room back to the visitor: hold the drift
   where it started, and turn the ambient sound on. they share one fixed stack
   rather than each carrying its own bottom offset, so a label that grows (or a
   third control later) cannot make them overlap. */
.room-controls {
  position: fixed;
  right: 16px;
  bottom: 58px;
  z-index: 101;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
}

/* the audio button used to be a 44px square reading "AMB" in 25%-opacity type
   — unreadable as a word and unnoticeable as a control. both buttons now say
   what a click will DO, at a size and contrast that survives a dark
   photograph behind them. */
.room-btn {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  background: #050a14;
  color: var(--paper);
  border: 1px solid rgba(250,250,247,0.8);
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  cursor: crosshair;
  white-space: nowrap;
  transition: background 0.25s ease, color 0.25s ease, border-color 0.25s ease;
}
.room-btn__dot {
  width: 8px; height: 8px;
  flex: none;
  background: rgba(250,250,247,0.55);
  transition: background 0.25s ease;
}
.room-btn:hover,
.room-btn:focus-visible {
  background: var(--paper);
  color: #050a14;
  border-color: var(--paper);
  outline: none;
}
.room-btn:hover .room-btn__dot,
.room-btn:focus-visible .room-btn__dot { background: #050a14; }

/* ambient sound running · the dot keeps the heartbeat, so the label stays
   legible instead of blinking along with it */
.audio-toggle.is-on { color: #5cd6a8; border-color: #5cd6a8; }
.audio-toggle.is-on .room-btn__dot {
  background: #5cd6a8;
  animation: bpm-blink 1.15s steps(2) infinite;
}
.audio-toggle.is-on:hover { background: #5cd6a8; color: #050a14; }
.audio-toggle.is-on:hover .room-btn__dot { background: #050a14; }

/* drift held at the first stage · amber, because this is the room being kept
   from doing the thing it wants to do */
.mood-toggle.is-held { color: #e8b06a; border-color: #e8b06a; }
.mood-toggle.is-held .room-btn__dot { background: #e8b06a; }
.mood-toggle.is-held:hover { background: #e8b06a; color: #050a14; }
.mood-toggle.is-held:hover .room-btn__dot { background: #050a14; }

/* on a phone the labels would crowd the ECG strip */
@media (max-width: 480px) {
  .room-controls { right: 10px; bottom: 54px; gap: 6px; }
  .room-btn { padding: 10px 12px; font-size: 9px; letter-spacing: 0.14em; }
}

/* whisper marquee · disabled; replaced by ECG strip */
.whisper-band { display: none; }
.whisper-band_DEPRECATED {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  z-index: 100;
  background: var(--paper);
  border-top: 1px solid var(--rule);
  overflow: hidden;
  height: 28px;
  display: flex;
  align-items: center;
  pointer-events: none;
}
.whisper-band__track {
  display: flex;
  white-space: nowrap;
  animation: whisper-scroll 120s linear infinite;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: rgba(11,26,44,0.28);
}
.whisper-band__track span { padding: 0 32px; }
.whisper-band__track span::after { content: " · "; padding-left: 32px; color: rgba(11,26,44,0.18); }
@keyframes whisper-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

a { color: inherit; text-decoration: none; cursor: crosshair; }
img, svg { display: block; max-width: 100%; }

/* ============ NAV ============ */
.nav {
  position: sticky; top: 32px; z-index: 90;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  padding: 18px 32px;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.nav__brand {
  font-family: var(--serif);
  font-size: 18px;
  font-style: italic;
  letter-spacing: 0.02em;
  text-transform: none;
}
.nav__brand.is-flicker { animation: flicker 0.32s steps(6); }
@keyframes flicker {
  0%, 100% { opacity: 1; }
  10% { opacity: 0.2; }
  20% { opacity: 1; }
  35% { opacity: 0.4; }
  50% { opacity: 1; }
  65% { opacity: 0.1; }
  80% { opacity: 1; }
}
/* the brand + switch group took the left column, so the case-file line moved
   into the centre — it keeps the nav in three parts and puts the switch at
   the same corner of the page as the one on the company front door */
.nav__meta { color: var(--whisper); justify-self: center; }
.nav__links { display: flex; gap: 22px; justify-self: end; }
.nav__links a {
  position: relative;
  padding-bottom: 2px;
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s ease;
}
.nav__links a:hover,
.nav__links a[aria-current="page"] { border-bottom-color: var(--ink); }
.nav__links a:hover { animation: tremor 0.4s steps(2) infinite; }

/* ============ LAYOUT PRIMITIVES ============ */
.wrap { max-width: 1320px; margin: 0 auto; padding: 0 32px; }
.label {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--whisper);
}
.rule { border-top: 1px solid var(--rule); }
.rule--ink { border-top: 1px solid var(--ink); }

/* ============ HERO (home) ============ */
.hero {
  display: grid;
  grid-template-columns: 60px 1.6fr 0.7fr;
  gap: 40px;
  padding: 64px 32px 48px;
  border-bottom: 1px solid var(--ink);
  position: relative;
  align-items: stretch;
}
.hero__photo {
  position: relative;
  border: 1px solid var(--ink);
  overflow: hidden;
  background: var(--ink);
  min-height: 360px;
  max-height: 480px;
  align-self: end;
}
.hero__photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: contrast(1.05) brightness(0.92);
  transition: filter 1.4s ease, transform 8s ease, opacity 0.8s ease;
  animation: breathe 9s ease-in-out infinite;
}
.hero__photo:hover img { filter: contrast(1.15) brightness(1); transform: scale(1.02); }
.hero__photo::after {
  content: "";
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.4' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.55'/></svg>");
  mix-blend-mode: overlay;
  opacity: 0.4;
  pointer-events: none;
  animation: grain-shift 0.5s steps(3) infinite;
}
.hero__photo__caption {
  position: absolute;
  bottom: 16px; left: 16px;
  font-family: var(--mono);
  font-size: 9px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--paper);
  z-index: 2;
  background: rgba(0,0,0,0.5);
  padding: 6px 10px;
}
.hero__col { display: flex; flex-direction: column; justify-content: space-between; gap: 32px; }
.hero__rail {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: var(--whisper);
  align-self: end;
  padding-bottom: 4px;
}
.hero__title {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(72px, 12vw, 184px);
  line-height: 0.88;
  letter-spacing: -0.02em;
  position: relative;
}
.hero__title em {
  font-style: italic;
  font-weight: 400;
  display: block;
  font-size: clamp(18px, 1.5vw, 22px);
  line-height: 1.4;
  color: var(--whisper);
  letter-spacing: 0;
  margin-top: 28px;
  max-width: 28ch;
}
.hero__title.is-glitch {
  animation: glitch 0.45s steps(3);
  text-shadow:
    -2px 0 var(--blood),
     2px 0 cyan;
}
@keyframes glitch {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(-3px, 1px) skewX(-2deg); }
  40%  { transform: translate(2px, -2px) skewX(1deg); }
  60%  { transform: translate(-1px, 2px) skewX(-1deg); }
  80%  { transform: translate(2px, 0) skewX(0deg); }
  100% { transform: translate(0, 0); }
}
.hero__synopsis {
  align-self: end;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(18px, 1.5vw, 22px);
  line-height: 1.4;
  max-width: 38ch;
  color: var(--ink);
}
.hero__synopsis::before {
  content: "/ a performance /";
  display: block;
  font-family: var(--mono);
  font-style: normal;
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--whisper);
  margin-bottom: 16px;
}

/* ============ INFO STRIP ============ */
.strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-bottom: 1px solid var(--rule);
}
.strip__cell {
  padding: 24px 28px;
  border-right: 1px solid var(--rule);
  transition: background 0.3s ease, color 0.3s ease;
}
.strip__cell:hover { background: var(--ink); color: var(--paper); }
.strip__cell:hover .strip__label,
.strip__cell:hover .strip__value small { color: rgba(250,250,247,0.6); }
.strip__cell:last-child { border-right: none; }
.strip__label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--whisper);
  margin-bottom: 10px;
  transition: color 0.3s ease;
}
.strip__value {
  font-family: var(--serif);
  font-size: 24px;
  font-weight: 500;
  line-height: 1.15;
}
.strip__value small {
  display: block;
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 400;
  color: var(--whisper);
  margin-top: 4px;
  letter-spacing: 0.02em;
  transition: color 0.3s ease;
}

/* ============ PULL QUOTES ============ */
.quote-block {
  display: grid;
  grid-template-columns: 0.7fr 1.3fr;
  gap: 56px;
  padding: 80px 32px;
  align-items: start;
}
.quote-block__art {
  position: relative;
  aspect-ratio: 1 / 1.35;
  max-height: 480px;
  border: 1px solid var(--ink);
  overflow: hidden;
  background: var(--ink);
  animation: breathe 8s ease-in-out infinite;
}
@keyframes breathe {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.015); }
}
.quote-block__art svg { width: 100%; height: 100%; }
.quote-block__art::after {
  content: "";
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.4' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.4'/></svg>");
  mix-blend-mode: overlay;
  opacity: 0.5;
  pointer-events: none;
  animation: grain-shift 0.4s steps(3) infinite;
}
.quote-block__text { padding-top: 24px; }
.quote-block__text q {
  display: block;
  font-family: var(--serif);
  font-size: clamp(28px, 3.2vw, 44px);
  line-height: 1.18;
  font-style: italic;
  font-weight: 400;
  quotes: none;
  margin-bottom: 32px;
}
.quote-block__text q::before { content: ""; }
.quote-block__text q::after  { content: ""; }
.quote-block__text p {
  font-size: 15px;
  line-height: 1.7;
  max-width: 52ch;
  color: var(--ink);
  margin-bottom: 16px;
}

/* ============ FRAGMENTS (home) ============ */
.fragments {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border-top: 1px solid var(--ink);
}
.fragment {
  padding: 48px 32px 56px;
  border-right: 1px solid var(--rule);
  min-height: 320px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  transition: background 0.4s ease, color 0.4s ease;
}
.fragment:hover { background: var(--ink); color: var(--paper); }
.fragment:hover .fragment__num { color: rgba(250,250,247,0.5); }
.fragment:last-child { border-right: none; }
.fragment__num {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.3em;
  color: var(--whisper);
  margin-bottom: 48px;
  transition: color 0.4s ease;
}
.fragment__q {
  font-family: var(--serif);
  font-size: 28px;
  line-height: 1.2;
  font-style: italic;
  font-weight: 400;
}

/* the answer half of the FAQ cards. this used to carry its colour as an inline
   style, and an inline style outranks .fragment:hover — so on hover the card
   turned dark, the answer stayed dark with it, and the text disappeared. as a
   class it inverts along with everything else in the card. */
.fragment__a {
  font-size: 14px;
  line-height: 1.6;
  color: var(--whisper);
  margin-top: 16px;
  transition: color 0.4s ease;
}
.fragment:hover .fragment__a { color: rgba(250, 250, 247, 0.75); }

/* ============ MEDIA WALL · contact-sheet filmstrip ============ */
/* three across rather than six: at six, each still was a ~240px sliver on a
   wide screen and the faces were being cropped out of them. rows are auto and
   the cells carry an aspect-ratio, so a cell keeps the same shape at every
   screen width instead of turning from a landscape box into a portrait one
   as the window narrows. */
.media-wall {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: auto;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
  background: var(--ink);
  gap: 1px;
}
.media-wall__head {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 80px 1fr auto;
  gap: 32px;
  align-items: end;
  padding: 48px 32px 32px;
  border-bottom: 1px solid var(--rule);
}
.media-wall__head h2 {
  font-family: var(--serif);
  font-size: clamp(40px, 5vw, 64px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.01em;
}
.media-wall__head h2 em { font-style: italic; color: var(--whisper); }
.media-wall__head .rail {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: var(--whisper);
  align-self: end;
}
.media-cell {
  background: var(--ink);
  color: var(--paper);
  position: relative;
  overflow: hidden;
  cursor: crosshair;
  display: block;
  aspect-ratio: 4 / 3;
  grid-column: span 1;
  grid-row: span 1;
}
.media-cell--wide { grid-column: span 2; }
.media-cell--tall { grid-row: span 2; }
.media-cell--big  { grid-column: span 2; grid-row: span 1; }
.media-cell::after {
  content: "";
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.6' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/></svg>");
  mix-blend-mode: overlay;
  opacity: 0.6;
  pointer-events: none;
  animation: grain-shift 0.5s steps(3) infinite;
}
.media-cell svg, .media-cell img, .media-cell video {
  width: 100%; height: 100%; object-fit: cover;
}
.media-cell img, .media-cell video {
  filter: contrast(1.05) brightness(0.85) saturate(0.85);
  transition: filter 0.6s ease, transform 6s ease, opacity 0.6s ease;
}
.media-cell:hover img, .media-cell:hover video { filter: contrast(1.15) brightness(1) saturate(1); transform: scale(1.03); }
.media-cell.has-media svg { display: none; }

/* ============ ESSAY PHOTO (about page accent inserts) ============ */
/* was height:38vh, which keys off the window's HEIGHT — so a short wide window
   gave a letterbox sliver and a tall phone gave a deep block, neither related
   to how wide the picture actually is. an aspect-ratio keys off the width
   instead, which is what decides how much of the frame you see. */
.essay-photo {
  position: relative;
  width: 100%;
  aspect-ratio: 21 / 9;
  min-height: 240px;
  max-height: 460px;
  overflow: hidden;
  background: var(--ink);
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
}
.essay-photo img {
  width: 100%; height: 100%; object-fit: cover;
  filter: contrast(1.05) brightness(0.88);
  animation: breathe 12s ease-in-out infinite;
  transition: opacity 0.6s ease;
}
.essay-photo::after {
  content: "";
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.5' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.55'/></svg>");
  mix-blend-mode: overlay;
  opacity: 0.45;
  pointer-events: none;
  animation: grain-shift 0.5s steps(3) infinite;
}
.essay-photo__caption {
  position: absolute;
  bottom: 24px; left: 32px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--paper);
  z-index: 2;
  max-width: 50ch;
}
.essay-photo__caption em {
  display: block;
  font-family: var(--serif);
  font-size: 22px;
  font-style: italic;
  letter-spacing: 0.01em;
  text-transform: none;
  margin-top: 8px;
  color: rgba(250,250,247,0.85);
}

/* ============ COMPANY GALLERY (cast page) ============ */
/* six cells, six columns. the count matters: this grid paints its own dark
   background and shows it through any slot the cells do not fill, so a row
   that does not divide evenly reads as a blank photo frame rather than as
   empty space. six divides by 6, 3, 2 and 1 — every column count this grid
   steps down through — so the last row is always full. do not add a seventh
   photo here without revisiting the breakpoints. */
.company {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  grid-auto-rows: auto;
  background: var(--ink);
  gap: 1px;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
}
.company__head {
  grid-column: 1 / -1;
  background: var(--paper);
  display: grid;
  grid-template-columns: 80px 1fr;
  gap: 32px;
  padding: 48px 32px 32px;
  align-items: end;
}
.company__head h2 {
  font-family: var(--serif);
  font-size: clamp(40px, 5vw, 64px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.01em;
}
.company__head h2 em { font-style: italic; color: var(--whisper); }
.company__head .rail {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: var(--whisper);
  align-self: end;
}
.company__cell {
  position: relative;
  overflow: hidden;
  background: var(--ink);
  aspect-ratio: 3 / 4; /* these are standing figures — portrait, not letterbox */
}
.company__cell--wide { grid-column: span 1; }
.company__cell img {
  width: 100%; height: 100%; object-fit: cover;
  filter: contrast(1.05) brightness(0.92) saturate(0.9);
  transition: filter 0.6s ease, transform 6s ease;
}
.company__cell:hover img { filter: contrast(1.15) brightness(1) saturate(1.05); transform: scale(1.03); }
.company__cell::after {
  content: "";
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.5' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/></svg>");
  mix-blend-mode: overlay;
  opacity: 0.4;
  pointer-events: none;
}

/* ============ TICKETS BACKDROP PHOTO ============ */
.ticket-backdrop {
  position: relative;
  background: var(--ink);
  color: var(--paper);
  padding: 56px 32px;
  overflow: hidden;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
  display: grid;
  grid-template-columns: 80px 1fr 1fr;
  gap: 32px;
  align-items: end;
}
.ticket-backdrop__bg {
  position: absolute; inset: 0;
  z-index: 0;
}
.ticket-backdrop__bg img {
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0.28;
  filter: contrast(1.1) brightness(0.7);
  animation: breathe 10s ease-in-out infinite;
  transition: opacity 0.8s ease;
}
.ticket-backdrop__bg::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(11,26,44,0.6) 0%, rgba(11,26,44,0.9) 100%);
}
/* :not() here matters: without it this also matches .ticket-backdrop__bg
   itself (also a direct child), knocking its position back to relative
   and collapsing the full-bleed photo down to a tiny box */
.ticket-backdrop > *:not(.ticket-backdrop__bg) { position: relative; z-index: 1; }
.ticket-backdrop h3 {
  font-family: var(--serif);
  font-size: clamp(36px, 5vw, 56px);
  font-weight: 500;
  line-height: 1;
  font-style: italic;
}
.ticket-backdrop p {
  font-size: 14px;
  line-height: 1.7;
  max-width: 38ch;
  color: rgba(250,250,247,0.78);
}
.ticket-backdrop .rail {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: rgba(250,250,247,0.5);
  align-self: end;
}

/* ============ INSTAGRAM EMBED SECTION ============ */
.ig-section {
  display: grid;
  grid-template-columns: 80px 1fr 1fr;
  gap: 32px;
  padding: 80px 32px;
  background: var(--ink);
  color: var(--paper);
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
  position: relative;
}
.ig-section::before {
  content: "";
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.5' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/></svg>");
  mix-blend-mode: overlay;
  opacity: 0.35;
  pointer-events: none;
  animation: grain-shift 0.5s steps(3) infinite;
}
.ig-section__rail {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: rgba(250,250,247,0.5);
  align-self: end;
  position: relative;
}
.ig-section__head {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 80px 1fr auto;
  gap: 32px;
  align-items: end;
  margin-bottom: 32px;
  position: relative;
}
.ig-section__head h2 {
  font-family: var(--serif);
  font-size: clamp(40px, 5vw, 64px);
  font-weight: 500;
  line-height: 1;
  letter-spacing: -0.01em;
}
.ig-section__head h2 em { font-style: italic; color: rgba(250,250,247,0.5); }
.ig-embed {
  border: 1px solid rgba(250,250,247,0.18);
  padding: 16px;
  background: var(--paper);
  position: relative;
  z-index: 2;
}
.ig-embed iframe {
  width: 100%;
  min-height: 540px;
  border: none;
  display: block;
}

@media (max-width: 900px) {
  .ig-section { grid-template-columns: 1fr; padding: 56px 20px; }
  .ig-section__rail { display: none; }
  .ig-section__head { grid-template-columns: 1fr; }
}

/* ============ BIG CTA STRIP ============ */
.cta-strip {
  background: var(--ink);
  color: var(--paper);
  padding: 80px 32px;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 32px;
  position: relative;
  overflow: hidden;
}
.cta-strip::before {
  content: "";
  position: absolute; inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.2' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.6'/></svg>");
  mix-blend-mode: overlay;
  opacity: 0.4;
  pointer-events: none;
}
.cta-strip h2 {
  font-family: var(--serif);
  font-size: clamp(40px, 5vw, 72px);
  font-weight: 400;
  line-height: 1;
  letter-spacing: -0.01em;
  position: relative;
}
.cta-strip h2 em { font-style: italic; color: rgba(250,250,247,0.55); }
.cta-strip .btn { background: var(--paper); color: var(--ink); position: relative; }

/* ============ BUTTONS ============ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 18px 28px;
  border: 1px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  cursor: crosshair;
  transition: background 0.2s ease, color 0.2s ease;
  position: relative;
}
.btn:hover { background: var(--ink); color: var(--paper); }
.btn--invert {
  background: var(--ink);
  color: var(--paper);
  border-color: var(--paper);
  box-shadow:
    0 0 0 2px rgba(250,250,247,0.10),
    0 0 28px rgba(255,250,235,0.55),
    0 0 72px rgba(255,240,210,0.28);
  animation: heartbeat 2.2s ease-in-out infinite, beacon 2.6s ease-in-out infinite;
}
.btn--invert:hover {
  background: var(--paper);
  color: var(--ink);
  animation: none;
  box-shadow: 0 0 36px rgba(255,250,235,0.85), 0 0 96px rgba(255,240,210,0.45);
}
@keyframes heartbeat {
  0%, 30%, 100% { transform: scale(1); }
  10%           { transform: scale(1.025); }
  20%           { transform: scale(1); }
}
@keyframes beacon {
  0%, 100% {
    box-shadow:
      0 0 0 2px rgba(250,250,247,0.10),
      0 0 28px rgba(255,250,235,0.55),
      0 0 72px rgba(255,240,210,0.28);
  }
  50% {
    box-shadow:
      0 0 0 2px rgba(250,250,247,0.20),
      0 0 48px rgba(255,250,235,0.85),
      0 0 110px rgba(255,240,210,0.45);
  }
}
.btn__arrow { font-size: 14px; transition: transform 0.2s ease; }
.btn:hover .btn__arrow { transform: translateX(4px); }

/* ============ PAGE HEADER (interior pages) ============ */
.page-head {
  display: grid;
  grid-template-columns: 80px 1fr;
  gap: 32px;
  padding: 72px 32px 56px;
  border-bottom: 1px solid var(--ink);
}
.page-head__rail {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: var(--whisper);
  align-self: end;
}
.page-head h1 {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(56px, 9vw, 144px);
  line-height: 0.9;
  letter-spacing: -0.02em;
}
.page-head h1 em {
  display: block;
  font-style: italic;
  font-size: clamp(18px, 1.5vw, 22px);
  line-height: 1.4;
  color: var(--whisper);
  letter-spacing: 0;
  margin-top: 28px;
  font-weight: 400;
  max-width: 40ch;
}

/* ============ LONG-FORM (about) ============ */
.essay {
  display: grid;
  grid-template-columns: 80px 1fr 1fr;
  gap: 32px;
  padding: 80px 32px;
  border-bottom: 1px solid var(--rule);
}
.essay__num { font-family: var(--mono); font-size: 11px; letter-spacing: 0.3em; color: var(--whisper); }
.essay__head {
  font-family: var(--serif);
  font-size: clamp(28px, 3vw, 40px);
  line-height: 1.15;
  font-style: italic;
  font-weight: 400;
}
.essay__body p {
  font-size: 16px;
  line-height: 1.75;
  margin-bottom: 18px;
  max-width: 56ch;
}
.essay__body p:first-of-type {
  font-family: var(--serif);
  font-size: 19px;
  line-height: 1.55;
  color: var(--ink);
}

/* ============ CAST GRID ============ */
.cast {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  border-top: 1px solid var(--ink);
}
.cast__card {
  display: grid;
  grid-template-columns: 60px 1fr;
  gap: 24px;
  padding: 40px 32px;
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  align-items: start;
  transition: background 0.4s ease, color 0.4s ease;
}
.cast__card:hover { background: var(--ink); color: var(--paper); }
.cast__card:hover .cast__num,
.cast__card:hover .cast__role { color: rgba(250,250,247,0.5); }
.cast__card:nth-child(2n) { border-right: none; }
.cast__num {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--whisper);
  padding-top: 8px;
  transition: color 0.4s ease;
}
.cast__role {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--whisper);
  margin-bottom: 8px;
  transition: color 0.4s ease;
}
.cast__name {
  font-family: var(--serif);
  font-size: clamp(28px, 3vw, 40px);
  font-weight: 500;
  line-height: 1.05;
  margin-bottom: 14px;
}
.crew {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  padding: 64px 32px;
  gap: 40px;
  border-top: 1px solid var(--ink);
}
.crew__item { display: flex; flex-direction: column; gap: 8px; }
.crew__role {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--whisper);
}
.crew__name {
  font-family: var(--serif);
  font-size: 22px;
  font-weight: 500;
}

/* ============ TICKETS ============ */
.tickets {
  padding: 64px 32px;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 64px;
  border-bottom: 1px solid var(--rule);
}
.show-list { display: flex; flex-direction: column; }
.show {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 24px;
  padding: 28px 0;
  border-bottom: 1px solid var(--rule);
}
.show:last-child { border-bottom: none; }
.show__date {
  font-family: var(--serif);
  font-size: 32px;
  font-weight: 500;
  line-height: 1.1;
}
.show__date small {
  display: block;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  color: var(--whisper);
  font-weight: 400;
  margin-top: 4px;
}
.show__venue { font-size: 13px; color: var(--whisper); margin-top: 4px; }

.ticket-stub {
  border: 1px solid var(--ink);
  padding: 32px;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 24px;
  align-self: start;
}
.ticket-stub::before,
.ticket-stub::after {
  content: "";
  position: absolute;
  width: 1px;
  background: var(--ink);
  left: 70%;
  height: 16px;
}
.ticket-stub::before { top: 0; }
.ticket-stub::after { bottom: 0; }
.ticket-stub__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
  padding-bottom: 18px;
  border-bottom: 1px dashed var(--rule);
}
.ticket-stub__row:last-of-type { border-bottom: none; padding-bottom: 0; }
.ticket-stub__field { display: flex; flex-direction: column; gap: 4px; }
.ticket-stub__k {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--whisper);
}
.ticket-stub__v {
  font-family: var(--serif);
  font-size: 20px;
  font-weight: 500;
}

.venue-block {
  padding: 64px 32px;
  display: grid;
  grid-template-columns: 80px 1fr 1fr;
  gap: 32px;
  border-bottom: 1px solid var(--rule);
}
.venue-block h3 {
  font-family: var(--serif);
  font-size: 36px;
  font-weight: 500;
}
.venue-block address {
  font-style: normal;
  font-size: 15px;
  line-height: 1.7;
  margin-top: 12px;
}

/* ============ FOOTER ============ */
.foot {
  padding: 56px 32px 60px;
  border-top: 1px solid var(--ink);
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: 32px;
  font-size: 13px;
}
.foot__brand {
  font-family: var(--serif);
  font-size: 32px;
  font-style: italic;
  font-weight: 500;
  line-height: 1;
  margin-bottom: 14px;
}
.foot__col h4 {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--whisper);
  margin-bottom: 14px;
  font-weight: 400;
}
.foot__col a { display: block; padding: 4px 0; }
.foot__col a:hover { font-style: italic; }
.foot__bottom {
  grid-column: 1 / -1;
  display: flex;
  justify-content: space-between;
  border-top: 1px solid var(--rule);
  padding-top: 20px;
  margin-top: 20px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--whisper);
}

/* ============ SCRAMBLE / GLITCH HOVER ============ */
.glitch { position: relative; display: inline-block; }
.glitch:hover { animation: tremor 0.4s steps(2) infinite; }
@keyframes tremor {
  0%   { transform: translate(0, 0); }
  25%  { transform: translate(-1px, 1px); }
  50%  { transform: translate(1px, -1px); }
  75%  { transform: translate(-1px, -1px); }
  100% { transform: translate(0, 0); }
}

/* ============ SCROLL REVEAL ============ */
/* the hidden state is gated on html.js, which the inline head snippet sets.
   main.js is a single IIFE, so a throw anywhere in it would stop the reveal
   observer ever running and leave the tickets, cast and quote blocks
   invisible for good. gated this way, no js means simply no animation. */
.reveal { transition: opacity 0.8s ease, transform 0.8s ease; }
html.js .reveal { opacity: 0; transform: translateY(16px); }
html.js .reveal.is-in { opacity: 1; transform: translateY(0); }

/* ============ RESPONSIVE ============ */

/* the photo grids step down a column at a time so a still never has to carry
   the full width of a desktop window, and never gets squeezed to a stamp.
   the cells keep their aspect-ratio throughout, so only the count changes. */
@media (max-width: 1080px) {
  .company { grid-template-columns: repeat(3, 1fr); }
}
@media (max-width: 860px) {
  .media-wall { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 680px) {
  .company { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .media-wall { grid-template-columns: 1fr; }
  .media-cell { aspect-ratio: 3 / 2; } /* a touch wider once it is alone on the row */
}

@media (max-width: 900px) {
  /* the rigid three-column grid has nothing left to give down here, so the
     nav becomes a wrapping flex row: the logo+switch group holds the first
     line and the links drop onto their own line when they stop fitting,
     rather than being squeezed or pushed off the edge */
  .nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px 18px;
    padding: 14px 20px;
  }
  .nav__meta { display: none; }
  .nav__mid { flex: 0 0 auto; }
  .nav__links { flex: 1 1 auto; justify-content: flex-end; gap: 16px; }

  .hero { grid-template-columns: 1fr; padding: 40px 20px; gap: 24px; }
  .hero__rail { display: none; }
  /* aspect-ratio rather than a flat 360px, so the hero still scales with the
     phone it is on instead of being the same height on every device */
  .hero__photo { order: -1; aspect-ratio: 4 / 3; min-height: 0; max-height: none; }

  .strip { grid-template-columns: repeat(2, 1fr); }
  .strip__cell { border-right: none; border-bottom: 1px solid var(--rule); }
  .strip__cell:nth-child(odd) { border-right: 1px solid var(--rule); }

  .quote-block { grid-template-columns: 1fr; padding: 48px 20px; gap: 32px; }
  .fragments { grid-template-columns: 1fr; }
  .fragment { border-right: none; border-bottom: 1px solid var(--rule); min-height: 220px; }

  .media-wall__head { grid-template-columns: 1fr; padding: 32px 20px; }
  .company__head { grid-template-columns: 1fr; padding: 32px 20px; }

  .ticket-backdrop { grid-template-columns: 1fr; padding: 56px 20px; }
  .ticket-backdrop .rail { display: none; }
  .essay-photo { aspect-ratio: 3 / 2; min-height: 0; max-height: none; }
  .essay-photo__caption { left: 20px; bottom: 16px; }

  .cta-strip { grid-template-columns: 1fr; padding: 56px 20px; }

  .page-head { grid-template-columns: 1fr; padding: 48px 20px; }
  .page-head__rail { display: none; }

  .essay { grid-template-columns: 1fr; padding: 48px 20px; gap: 24px; }

  .cast { grid-template-columns: 1fr; }
  .cast__card { border-right: none; }

  .crew { grid-template-columns: 1fr; padding: 40px 20px; gap: 28px; }

  .tickets { grid-template-columns: 1fr; padding: 40px 20px; gap: 40px; }
  .venue-block { grid-template-columns: 1fr; padding: 40px 20px; }
  .venue-block__rail { display: none; }

  .foot { grid-template-columns: 1fr; padding: 40px 20px 70px; }

  .whisper-band { display: none; }
}

/* ============ INSIDE THE ROOM ============ */

/* was three inline-styled grid columns (rail · heading · button). at 360px the
   button ran 77px off the right edge, and an inline style cannot be reached by
   a media query, so it moved in here. */
.inside-head {
  max-width: 1320px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 80px 1fr auto;
  gap: 32px;
  align-items: end;
}
.inside-head__rail {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: var(--whisper);
  align-self: end;
}

/* the vertical rail is decoration and the button needs the whole width */
@media (max-width: 760px) {
  .inside-head { grid-template-columns: 1fr; gap: 20px; }
  .inside-head__rail { display: none; }
  .inside-head .btn { justify-self: start; }
}

/* the tracking on an 11px mono label is what pushes it over on small phones */
@media (max-width: 420px) {
  .btn { padding: 15px 18px; letter-spacing: 0.16em; gap: 10px; }
}

/* ============ PARENT BRAND ============ */

/* "The Coven Theatre" above the switch, in this show's voice: the same
   letterspaced mono the case-file lines use, so it reads as a stamp on the
   dossier rather than as a logo bolted on. built only from the custom
   properties, like the switch, so mood.js drags it through the drift too. */
.nav .coven__name {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--whisper);
  border-bottom: 1px solid transparent;
  padding-bottom: 1px;
  transition: color 0.25s ease, border-color 0.25s ease;
}
.nav .coven__name:hover,
.nav .coven__name:focus-visible {
  color: var(--ink);
  border-bottom-color: var(--rule);
}

/* ============ SHOW SWITCH ============ */
/* structure lives in ../../shared/switch.css. everything here is colour, and
   every value is a custom property on purpose: mood.js rewrites --ink and
   --paper on :root every 150ms, so the switch bleeds blue, then green, then
   red along with the rest of the room without being told to. do not put a
   hex value in this block. */

/* the brand and the switch travel together as one group in the nav's centre
   column, so the switch always sits immediately to the right of the logo */
.nav__mid {
  display: flex;
  align-items: center;
  gap: 16px;
  justify-self: start;
}

.nav .show-switch {
  border: 1px solid color-mix(in srgb, var(--ink) 32%, transparent);
}

.nav .show-switch__opt {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--whisper);
}

.nav .show-switch__opt + .show-switch__opt {
  border-left: 1px solid var(--rule);
}

.nav .show-switch__opt:hover {
  color: var(--ink);
}

/* the side you are standing in is filled, not just underlined — at a glance
   the control should read as two states, not as two more nav links */
.nav .show-switch__opt[aria-current="true"] {
  color: var(--ink);
  background: color-mix(in srgb, var(--ink) 8%, transparent);
}

/* the room is a crosshair everywhere else; the switch is no exception */
.nav .show-switch__opt { cursor: crosshair; }

.nav .show-switch__opt:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 2px;
}

.nav .show-switch__marker {
  background: var(--ink);
}

/* ============ COMING-SOON PLAQUE ============ */
/* the right half of the switch is a plaque rather than a link — the next
   production has no pages to point at yet, so nothing here is clickable and
   switch.js never sees it (it only listens for .show-switch__opt). it copies
   the live half's geometry exactly so the control still reads as two shows
   side by side instead of one lonely tab.
   the sigil sits BEHIND the words, watermark-style: it costs no height, so
   the nav does not grow, and it is drawn as a mask filled with var(--ink),
   which means mood.js drags it through the blue/green/red drift along with
   everything else. do not give it a hex value. */
.nav .show-switch__soon {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  text-align: center;
  white-space: nowrap;
  padding: 8px 20px 10px;
  border-left: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--whisper) 78%, transparent);
  cursor: default;
  -webkit-user-select: none;
  user-select: none;
}

/* the words ride above the watermark */
.nav .show-switch__soon > span:not(.show-switch__sigil) {
  position: relative;
  z-index: 1;
}

.nav .show-switch__sigil {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 34px;
  height: 34px;
  background: var(--ink);
  -webkit-mask: url(../assets/sigil.svg) center / contain no-repeat;
  mask: url(../assets/sigil.svg) center / contain no-repeat;
  opacity: 0.2;
  pointer-events: none;
  transition: opacity 0.5s ease;
}

/* hovering the switch stirs it — the only sign that something is behind it */
.nav .show-switch:hover .show-switch__sigil { opacity: 0.42; }

@media (prefers-reduced-motion: reduce) {
  .nav .show-switch__sigil { transition: none; }
}

/* the nav is a 1fr auto 1fr grid, so the brand+switch column only gets half
   the width left over after the centred case-file line. that line is longest
   on cast.html ("DRAMATIS PERSONAE"), which is the page that runs out of room
   first, so the breakpoint is set from that page rather than this one */
@media (max-width: 1220px) {
  .nav .show-switch__full { display: none; }
  .nav .show-switch__abbr { display: inline; }
  .nav .show-switch__opt,
  .nav .show-switch__soon { padding: 10px 15px 12px; }
  .nav .show-switch__sigil { width: 28px; height: 28px; }
}

/* below this the brand, four links and the switch stop fitting on one line */
@media (max-width: 560px) {
  .nav { justify-content: center; text-align: center; }
  .nav__mid { flex: 1 1 100%; justify-content: center; }
  .nav__links { flex: 1 1 100%; justify-content: center; flex-wrap: wrap; }
}

/* the logo and the switch stop sharing a line before the switch itself has
   to shrink, so they stack rather than the switch getting cramped */
@media (max-width: 430px) {
  .nav__mid { flex-direction: column; gap: 10px; }
}

/* ============ THE TRAILER ============ */

/* the film is 4:3 and it stays 4:3. the frame carries a fixed aspect-ratio and
   the video sits inside it with object-fit: contain, so whatever geometry the
   source file happens to have it gets letterboxed into the frame rather than
   stretched, cropped or laid on its side. black bars are the correct answer
   here; a distorted face is not. */
.reel {
  background: var(--void);
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
  padding: 72px 32px 80px;
  display: grid;
  /* three columns, two children: the rail takes the first, the film takes the
     second, and the empty third mirrors the rail's width so the middle column
     is centred on the PAGE rather than on the space left over beside the rail.
     without the mirror column the frame sits visibly off-centre to the right. */
  grid-template-columns: 120px minmax(0, 1fr) 120px;
  gap: 32px;
}
.reel__rail {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: rgba(250, 250, 247, 0.45);
  align-self: end;
}
.reel__body { width: 100%; max-width: 1080px; margin: 0 auto; }
.reel__head { margin-bottom: 28px; }
.reel__label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: rgba(250, 250, 247, 0.5);
}
.reel__head h2 {
  margin-top: 14px;
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(34px, 4.4vw, 56px);
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--paper);
}
.reel__head h2 em { font-style: italic; color: rgba(250, 250, 247, 0.55); }

.reel__frame {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--void);
  border: 1px solid rgba(250, 250, 247, 0.35);
  overflow: hidden;
}
.reel__frame video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: var(--void);
}

/* the poster is a real button so it is reachable by keyboard and announces
   itself; it covers the whole frame and gets dropped once the film starts */
.reel__cover {
  position: absolute;
  inset: 0;
  display: block;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--void);
  cursor: crosshair;
  z-index: 3;
}
.reel__cover[hidden] { display: none; }
.reel__cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: contrast(1.05) brightness(0.7);
  transition: filter 0.4s ease;
}
.reel__cover:hover img,
.reel__cover:focus-visible img { filter: contrast(1.1) brightness(0.88); }
.reel__cover:focus-visible { outline: 1px solid var(--paper); outline-offset: -6px; }

/* house grain, over the still only — once the film is running it is the
   film's own grain that should be doing this work */
.reel__cover::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.5' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)' opacity='0.55'/></svg>");
  mix-blend-mode: overlay;
  opacity: 0.4;
  pointer-events: none;
  animation: grain-shift 0.5s steps(3) infinite;
  z-index: 1;
}
.reel__play {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  pointer-events: none;
  z-index: 2;
}
.reel__play__mark {
  width: 74px;
  height: 74px;
  border: 1px solid var(--paper);
  display: grid;
  place-items: center;
  transition: background 0.25s ease;
}
.reel__cover:hover .reel__play__mark,
.reel__cover:focus-visible .reel__play__mark { background: rgba(250, 250, 247, 0.16); }
.reel__play__mark::before {
  content: "";
  width: 0;
  height: 0;
  margin-left: 5px;
  border-left: 15px solid var(--paper);
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
}
.reel__play__label {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--paper);
}

.reel__meta {
  margin-top: 16px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 8px 28px;
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: rgba(250, 250, 247, 0.5);
}

@media (max-width: 900px) {
  .reel { grid-template-columns: 1fr; padding: 56px 20px 64px; gap: 0; }
  .reel__rail { display: none; }
  .reel__play__mark { width: 58px; height: 58px; }
  .reel__meta { justify-content: flex-start; }
}

/* the cast cards carry names only now, so the name has nothing left to sit
   above: drop its trailing margin, and give the card a floor so the 2x2 grid
   keeps its weight instead of collapsing to four thin strips */
.cast__card { min-height: 190px; }
.cast__name:last-child { margin-bottom: 0; }

/* ============ SMALL-TYPE READABILITY ============ */
/* the mono labels ran 9-11px at regular weight with 0.25-0.3em tracking. that
   reads as texture rather than as words: wide tracking pulls letters apart
   faster than small type can afford, and it collapses entirely once the room
   turns red and the ground behind the type is a mottled photograph. so the
   tracking comes in, the weight goes up to the 700 already being loaded, and
   the smallest sizes gain a point. */
.label,
.hero__rail,
.hero__photo__caption,
.hero__synopsis::before,
.strip__label,
.fragment__num,
.essay__num,
.cast__num,
.cast__role,
.crew__role,
.show__date small,
.ticket-stub__k,
.foot__col h4,
.foot__bottom,
.page-head__rail,
.inside-head__rail,
.media-wall__head .rail,
.company__head .rail,
.essay-photo__caption,
.reel__rail,
.reel__label,
.reel__meta,
.reel__play__label {
  font-weight: 700;
  letter-spacing: 0.2em;
}

/* a point up on everything that was sitting at 9-10px */
.hero__photo__caption,
.strip__label,
.cast__role,
.crew__role,
.ticket-stub__k,
.foot__col h4,
.foot__bottom,
.page-head__rail,
.inside-head__rail,
.media-wall__head .rail,
.company__head .rail,
.essay-photo__caption,
.reel__rail,
.reel__label,
.reel__meta,
.reel__play__label {
  font-size: 11px;
}

/* the pull-quote inside a photo caption is serif, and it should stay in book
   weight — the 700 above is meant for the mono slug that sits above it */
.essay-photo__caption em { font-weight: 400; letter-spacing: 0.01em; }

/* secondary body copy: 13px of 55%-opacity ink was the least legible text on
   the site once the room turned */
.show__venue,
.strip__value small { font-size: 14px; }
