/* =====================================================================
   style.css — Stavanger talk · "Making Sense of Noise"
   v2 — finished. Image-lecture base. Black ⇄ cream ground rhythm,
   a single silver-halide treatment pass over the whole film, and the
   plate-cut transition (700ms wipe + optional shutter flash).

   Layering, fixed for the 1920×1080 stage:
       z1  image-plate / diagram-ground
       z2  agents canvas — the two living kin
       z3  text + wordmark + diagrams
       z4  silver-halide treatment (grain, vignette, scanline, shutter)
       z10 chrome (HUD), hidden in clean mode
   ===================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300..700&family=JetBrains+Mono:wght@100..800&family=Fraunces:ital,opsz,wght,SOFT,WONK@0,9..144,100..900,0..100,0..1;1,9..144,100..900,0..100,0..1&display=swap');

:root {
  /* palette — the wine-lipped mouth-eye, restrained */
  --ground:     #06050a;     /* not pure black; cooler night */
  --cream:      #FFFFFF;     /* paper register — now pure white per direction */
  --cream-dim:  #d9d4cc;
  --wine:       #8a1a2b;     /* oxblood lip */
  --wine-lo:    #5b0f1d;
  --flesh:      #d68b66;     /* amber-flesh */
  --green:      #B8FF40;     /* live-type / active highlight */
  --red:        #FF2438;
  --ultra:      #1b0fff;     /* sparse — diagram beats only */
  --ash:        #6b6a66;     /* HUD ash */
  --ash-warm:   #a89c83;

  /* type */
  --f-grotesk:  'Space Grotesk', system-ui, sans-serif;
  --f-mono:     'JetBrains Mono', ui-monospace, monospace;
  --f-fraunces: 'Fraunces', Georgia, serif;

  /* stage */
  --stage-w: 1920px;
  --stage-h: 1080px;

  /* treatment dial */
  --tx-strength: 1;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  width: 100%; height: 100%;
  background: #000;
  overflow: hidden;
  color: var(--cream);
  font-family: var(--f-grotesk);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* --- stage: fixed 1920×1080, letterboxed into the viewport --- */
#stage {
  position: absolute;
  top: 50%; left: 50%;
  width: var(--stage-w);
  height: var(--stage-h);
  margin-left: calc(var(--stage-w) / -2);
  margin-top: calc(var(--stage-h) / -2);
  transform-origin: center center;
  background: var(--ground);
  overflow: hidden;
}

/* the agents canvas sits between imagery (z1) and text (z3) */
#agent-canvas {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  z-index: 2;
  display: block;
  pointer-events: none;
}

/* --- beat overlays (text / diagrams) — one per beat ---
   visibility-based toggling (was opacity+transition, which got stuck at 0
   on first paint in some browsers). Children with .rise still cross-fade. */
.beat-overlay {
  position: absolute;
  inset: 0;
  z-index: 3;
  visibility: hidden;
  pointer-events: none;
}
.beat-overlay.active {
  visibility: visible;
  pointer-events: auto;
}

/* --- registers — coexistent, never blended; set --accent only --- */
.reg-a { --accent: var(--flesh); }
.reg-b { --accent: var(--green); }
.reg-c { --accent: var(--green); }
.reg-blueprint { --accent: var(--ultra); }

/* --- type helpers --- */
.f-grotesk  { font-family: var(--f-grotesk); }
.f-mono     { font-family: var(--f-mono); }
.f-fraunces { font-family: var(--f-fraunces); }
.green { color: var(--green); }
.red   { color: var(--red); }
.ultra { color: var(--ultra); }
.cream { color: var(--cream); }
.wine  { color: var(--wine); }

/* =====================================================================
   HUD (chrome) — far quieter than v1. Top-right: a small phase index.
   Bottom: a thin spec line + an 8-dot beat ruler.
   ===================================================================== */
.hud {
  position: absolute;
  top: 26px; right: 32px;
  z-index: 20;
  font-family: var(--f-mono);
  font-size: 11.5px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ash);
  display: flex; gap: 18px; align-items: center;
  pointer-events: none;
}
.hud .dot {
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--green); opacity: .9;
  animation: pulse 2.2s ease-in-out infinite;
}
@keyframes pulse { 0%,100% { opacity:.25; transform:scale(.85); } 50% { opacity:.9; transform:scale(1.15); } }
.hud .blink { animation: blink 1.1s steps(1) infinite; }
@keyframes blink { 50% { opacity: 0; } }

.beat-hud {
  position: absolute;
  bottom: 22px; left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  font-family: var(--f-mono);
  font-size: 10.5px; letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ash);
  opacity: 0.55;
  pointer-events: none;
}

body.clean .hud,
body.clean .beat-hud { display: none; }
body.clean .tx-shutter { display: none; }

/* =====================================================================
   Shared content typography — sized for the 1920×1080 stage.
   ===================================================================== */
.layer { position: absolute; inset: 0; }
.pad   { padding: 110px 130px; }

.kicker {
  font-family: var(--f-mono);
  font-size: 21px; letter-spacing: 0.14em; text-transform: lowercase;
  color: var(--accent, var(--green));
}
.headline {
  font-family: var(--f-grotesk);
  font-weight: 600; font-size: 100px; line-height: 1.0;
  letter-spacing: -0.025em; color: var(--cream);
}
.headline .em  { color: var(--accent, var(--green)); }
.headline .red { color: var(--red); }
.statement {
  font-family: var(--f-grotesk); font-weight: 400;
  font-size: 56px; line-height: 1.14; letter-spacing: -0.01em;
  color: var(--cream);
}
.statement em { font-style: normal; color: var(--accent, var(--green)); }
.lede {
  font-family: var(--f-grotesk); font-weight: 300;
  font-size: 35px; line-height: 1.42; color: var(--cream);
}
.quote {
  font-family: var(--f-fraunces); font-style: italic;
  font-weight: 380; font-size: 48px; line-height: 1.26;
  color: var(--cream); font-variation-settings: "SOFT" 60, "opsz" 120;
}
.attrib {
  font-family: var(--f-mono); font-size: 19px;
  letter-spacing: 0.05em; color: var(--ash);
}
.mono-note {
  font-family: var(--f-mono); font-size: 20px; line-height: 1.62;
  letter-spacing: 0.02em; color: var(--ash);
}

/* per-beat reveal — children with .rise lift in when the beat activates */
.rise {
  opacity: 0; transform: translateY(22px);
  transition: opacity 900ms cubic-bezier(.2,.7,.2,1),
              transform 900ms cubic-bezier(.2,.7,.2,1);
}
.beat-overlay.active .rise { opacity: 1; transform: none; }
.beat-overlay.active .rise.d1 { transition-delay: 180ms; }
.beat-overlay.active .rise.d2 { transition-delay: 380ms; }
.beat-overlay.active .rise.d3 { transition-delay: 580ms; }
.beat-overlay.active .rise.d4 { transition-delay: 820ms; }

/* =====================================================================
   The morphing wordmark — MAKING → SENSE → NOISE — three-typeface
   clip mashup, continuously re-cut.
   ===================================================================== */
.wm        { display: flex; align-items: flex-start; }
.wm-slot   { position: relative; display: inline-block; margin-right: 0.04em; }
.wm-spacer { visibility: hidden; font-family: var(--f-mono); font-weight: 700; }
.wm-layer  {
  position: absolute; top: 0; left: 0; white-space: pre;
  will-change: clip-path, transform;
}
.wm-layer.f-grotesk  { font-family: var(--f-grotesk);  font-weight: 700; }
.wm-layer.f-mono     { font-family: var(--f-mono);     font-weight: 700; }
.wm-layer.f-fraunces { font-family: var(--f-fraunces); font-weight: 640; font-style: italic; }

/* =====================================================================
   Image-plate — one generated image per beat (z1).
   Now uses a clip-path wipe between beats rather than opacity, and a
   subtle film tone (slight saturation lift + warm contrast).
   A plate with no image stays black — that's the correct placeholder.
   ===================================================================== */
.plate, .plate-grid {
  position: absolute; inset: 0; z-index: 1;
  opacity: 0;
  background: var(--ground);
  transition: opacity 760ms cubic-bezier(.5,.05,.2,1),
              clip-path 760ms cubic-bezier(.5,.05,.2,1),
              filter   760ms cubic-bezier(.5,.05,.2,1);
  clip-path: inset(0% 0% 0% 0%);
  filter: saturate(1.08) contrast(1.05);
}
.plate.active, .plate-grid.active {
  opacity: 1;
  clip-path: inset(0% 0% 0% 0%);
}
.plate { background-position: center; background-size: cover; background-repeat: no-repeat; }
.plate.contain   { background-size: contain; background-repeat: no-repeat; background-color: var(--ground); }
.plate.centred   { background-size: 56% auto; background-repeat: no-repeat; }
.plate.cream-bg  { background-color: var(--cream); }

/* --- the wipe variants — choose per beat via class --- */
.plate.wipe-r:not(.active), .plate-grid.wipe-r:not(.active) { clip-path: inset(0 100% 0 0); }
.plate.wipe-l:not(.active), .plate-grid.wipe-l:not(.active) { clip-path: inset(0 0 0 100%); }
.plate.wipe-d:not(.active), .plate-grid.wipe-d:not(.active) { clip-path: inset(0 0 100% 0); }
.plate.wipe-u:not(.active), .plate-grid.wipe-u:not(.active) { clip-path: inset(100% 0 0 0); }
.plate.wipe-iris:not(.active), .plate-grid.wipe-iris:not(.active) {
  clip-path: inset(50% 50% 50% 50%);
}

/* --- placeholder hint when image fails or is absent (no broken icon) --- */
.plate[data-src=""], .plate.placeholder { background: var(--ground); }
.plate.placeholder::after {
  content: attr(data-hint);
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  font-family: var(--f-mono); font-size: 12px;
  letter-spacing: 0.32em; text-transform: uppercase;
  color: var(--ash); opacity: .35;
  white-space: nowrap;
}

.plate-grid       { display: grid; gap: 6px; padding: 90px; background: var(--ground); }
.plate-grid.g2x2  { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; }
.plate-grid.g1x2  { grid-template-columns: 1fr 1fr; }
.plate-grid img   {
  width: 100%; height: 100%; object-fit: cover;
  filter: saturate(1.05) contrast(1.04);
  background: #111;
}

/* a beat rendered in code (agenda, the Flusser ladder, the R&D split) */
.diagram {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  padding: 110px;
}

/* =====================================================================
   The cream ground — used on the title beat, the agenda, the close.
   Sparingly. When body.cream-ground is set OR a .beat-overlay carries
   the .cream class, this gives us the paper register: warm, breathable,
   the inverse of the wine night.
   ===================================================================== */
.beat-overlay.cream {
  background: var(--cream);
}
.beat-overlay.cream .headline,
.beat-overlay.cream .statement,
.beat-overlay.cream .lede,
.beat-overlay.cream .quote,
.beat-overlay.cream .cream { color: var(--wine-lo); }
.beat-overlay.cream .kicker { color: var(--wine); }
.beat-overlay.cream .mono-note,
.beat-overlay.cream .attrib { color: var(--ash-warm); }
.beat-overlay.cream .green { color: var(--wine); }

/* =====================================================================
   THE SIGNATURE TREATMENT — the silver-halide pass.
   Grain · vignette · warm veil · faint scanline · shutter wipe.
   All z4, above content but below HUD. Pointer-events off.
   ===================================================================== */
.tx-layer {
  position: absolute; inset: 0; z-index: 4;
  pointer-events: none;
  --tx-strength: 1;
}

/* 1 — animated grain (SVG turbulence), additive, low alpha */
.tx-grain {
  position: absolute; inset: 0;
  opacity: calc(0.22 * var(--tx-strength));
  mix-blend-mode: overlay;
}
.tx-grain svg { width: 100%; height: 100%; display: block; }

/* 2 — vignette: a soft 4:3-feel darkening at the corners */
.tx-vignette {
  position: absolute; inset: 0;
  background: radial-gradient(ellipse 90% 80% at center,
              transparent 35%,
              rgba(0,0,0,0.18) 65%,
              rgba(0,0,0,0.55) 100%);
  mix-blend-mode: multiply;
  opacity: calc(0.85 * var(--tx-strength));
}

/* 3 — a warm filmic veil over the whole thing (ektachrome-ish) */
.tx-veil {
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
              rgba(255, 220, 180, 0.05) 0%,
              rgba(180, 60, 50,  0.04) 50%,
              rgba(30,  10,  0,  0.10) 100%);
  mix-blend-mode: soft-light;
  opacity: calc(0.85 * var(--tx-strength));
}

/* 4 — barely-there scanlines (3px), keeps the "screening" feel honest */
.tx-scanlines {
  position: absolute; inset: 0;
  background: repeating-linear-gradient(0deg,
              rgba(0,0,0,0.05) 0px, rgba(0,0,0,0.05) 1px,
              transparent 1px, transparent 3px);
  mix-blend-mode: multiply;
  opacity: calc(0.45 * var(--tx-strength));
}

/* 5 — the shutter wipe, normally invisible. JS adds .go to fire. */
.tx-shutter {
  --shutter-color: var(--cream);
  --shutter-dur: 420ms;
  position: absolute; inset: 0;
  background: var(--shutter-color);
  pointer-events: none;
  transform: translateX(-101%);
}
.tx-shutter[data-dir="diagonal"]   { transform: translate(-101%, -101%) rotate(-8deg); }
.tx-shutter[data-dir="horizontal"] { transform: translateX(-101%); }
.tx-shutter[data-dir="vertical"]   { transform: translateY(-101%); }
.tx-shutter.go {
  animation: shutter-sweep var(--shutter-dur) cubic-bezier(.4,0,.2,1) forwards;
}
@keyframes shutter-sweep {
  0%   { transform: translate(-101%, 0); }
  45%  { transform: translate(0%, 0); }
  55%  { transform: translate(0%, 0); }
  100% { transform: translate(101%, 0); }
}

/* When a beat opts out of treatment (e.g. the closing thank-you, the
   cream agenda), it can carry data-tx="quiet" on the stage; we knock
   strength down. */
#stage[data-tx="quiet"]  .tx-layer { --tx-strength: 0.55; }
#stage[data-tx="full"]   .tx-layer { --tx-strength: 1.10; }

/* =====================================================================
   Diagram shared utilities — picked up by 05/08 page-level styles too.
   ===================================================================== */
.diagram-frame {
  position: relative;
  padding: 56px 72px;
  background: var(--ground);
}
.diagram-frame::before {
  /* faint registration crosshair, top-left */
  content: ""; position: absolute; top: 18px; left: 18px;
  width: 22px; height: 22px;
  border-top: 1px solid var(--ash);
  border-left: 1px solid var(--ash);
  opacity: .4;
}
.diagram-frame::after {
  content: ""; position: absolute; bottom: 18px; right: 18px;
  width: 22px; height: 22px;
  border-bottom: 1px solid var(--ash);
  border-right: 1px solid var(--ash);
  opacity: .4;
}

/* generic full-bleed text frame (used as cream paper) */
.paper {
  position: absolute; inset: 0;
  background: var(--cream);
  color: var(--wine-lo);
  z-index: 1;
  opacity: 0;
  transition: opacity 800ms cubic-bezier(.5,.05,.2,1);
}
.paper.active { opacity: 1; }
