/* Cinematic scroll layer. Only this page loads these rules. */
.premiere { --scroll-ease: cubic-bezier(.22, 1, .36, 1); }
.premiere .flicker, .premiere #scratch { display: none; }
.premiere .grain { opacity: .045; animation: none; }
.premiere .marquee { background: linear-gradient(#0d0e12f5, #0d0e1280 70%, transparent); border-bottom: 0; }
.premiere .marquee.solid { background: #0d0e12f5; }
.premiere .marquee:focus-within { opacity: 1; pointer-events: auto; }
.scroll-invitation {
  position: absolute; z-index: 4; inset: auto 4vw 35px;
  display: flex; align-items: center; gap: 20px;
  color: var(--paper); text-decoration: none;
  font: 10px var(--f-type); letter-spacing: .2em; text-transform: uppercase;
}
.scroll-invitation span:last-child { margin-left: auto; }
.scroll-line { width: clamp(40px, 8vw, 130px); height: 1px; background: var(--stamp-lit); }
.scroll-invitation:focus-visible { outline: 2px solid var(--paper); outline-offset: 8px; opacity: 1 !important; }
.reel { height: 600svh; }
.reel-stage {
  --pad: clamp(18px, 4vw, 70px);
  --gw: min(100vw - 2 * var(--pad), (100svh - 190px) * 16 / 9);
  gap: 18px;
}
.reel-canvas {
  display: block; position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; opacity: 0; pointer-events: none;
}
.reel-canvas.is-ready { opacity: 1; }
.gate { outline: none; border-radius: 0; }
.reel-chapter { letter-spacing: .19em; color: var(--stamp-lit); }
.reel-sub { font: clamp(14px, 1.25vw, 19px)/1.5 var(--f-type); color: var(--bone); min-height: 3em; }
.reel-line { display: inline-block; }   /* each caption arrives and leaves by the film's time (premiere.js) */
.reel-strip::after {
  content: ''; position: absolute; left: 0; right: 0; top: -1px; height: 2px;
  background: var(--stamp-lit); transform: scaleX(var(--p, 0)); transform-origin: left;
}
.reel-strip a { min-height: 44px; }
.perfs { opacity: .35; }

/* A second continuous scene carries the film into the product story. The crew's own
   photographs stand on a portrait plate, flush to the marquee above and to the right and
   bottom of the stage; the type and the footer run from one gutter to the plate's edge.
   Nothing rules the scene off: it has no line under it and no edge around it. */
.case-statement {
  --gutter: max(6vw, calc((100vw - 1240px) / 2));
  --gap: clamp(20px, 2.4vw, 44px);
  --plate: min(44vw, calc((100svh - var(--marquee-height)) * .6));
  --copy-right: calc(var(--plate) + var(--gap));
  position: relative; height: 300svh; width: calc(100vw - 16px);
  margin-left: calc((100% - 100vw + 16px) / 2);
  margin-top: calc(-1 * var(--section-y)); margin-bottom: var(--section-y);
  /* No edge below: the ground thins out over its last stretch into the crew's. By then
     premiere.js has taken everything off the stage (--story-exit). */
  background: linear-gradient(180deg, #090a0d calc(100% - 50svh), rgba(9, 10, 13, 0) 100%);
}
.statement-stage { position: sticky; top: 0; height: 100svh; overflow: clip; isolation: isolate; }
.statement-plate {
  position: absolute; inset: var(--marquee-height) 0 0 auto; width: var(--plate); overflow: clip;
  opacity: calc(var(--story-enter, 1) * var(--story-enter, 1) * (1 - var(--story-exit, 0)));
  translate: 0 calc((1 - var(--story-enter, 1)) * 6svh - var(--story-exit, 0) * 5svh);
  /* While the scene is still arriving the photograph's top edge is feathered; once it is
     in place that edge sits on the marquee and the feather has closed to nothing. */
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 calc((1 - var(--story-enter, 1)) * 45%));
  mask-image: linear-gradient(180deg, transparent 0, #000 calc((1 - var(--story-enter, 1)) * 45%));
}
.statement-image {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  filter: grayscale(1) contrast(1.08) brightness(.88);   /* colour snapshots, graded to the reel */
  transform: scale(var(--story-scale, 1)); transform-origin: 50% 12%;   /* the push keeps the hat in frame */
}
.statement-room { object-position: 50% 0%; }
.statement-evidence { opacity: var(--story-crossfade, 0); }
/* The two photographs as one picture (webgl-scenes.js): ink spreads across the first
   and the second is there where it has passed. Pushed in exactly as the images are,
   and graded as they are by the canvas itself (a filter here would grey the ink).
   They stay in the page under it, unseen; where there is no WebGL the crossfade above shows. */
.statement-morph {
  display: none; position: absolute; inset: 0; width: 100%; height: 100%;
  transform: scale(var(--story-scale, 1)); transform-origin: 50% 12%;
}
.statement-plate.is-morphing .statement-morph { display: block; }
.statement-plate.is-morphing .statement-image { opacity: 0; }
/* Only the plate is shaded, and only a little, at its foot. */
.statement-shade { position: absolute; inset: 0; background: linear-gradient(0deg, #090a0db3, transparent 20%); }
.statement-copy { position: absolute; left: var(--gutter); right: var(--copy-right); top: 50%; }
.statement-first { opacity: calc(var(--story-first, 1) * var(--story-enter, 1)); transform: translate3d(0, calc(-50% + var(--story-first-y, 0px)), 0); }
.statement-second { opacity: calc(var(--story-second, 0) * (1 - var(--story-exit, 0))); transform: translate3d(0, calc(-50% + var(--story-second-y, 40px)), 0); }
.statement-copy .label { color: var(--stamp-lit); margin-bottom: 24px; }
/* The longest line is 3.97em wide, so this size runs it from the gutter to the plate. */
.statement-line {
  font: clamp(48px, calc((100vw - 16px - var(--gutter) - var(--copy-right)) / 4.02), 300px)/.88 var(--f-display);
  letter-spacing: -.015em; text-transform: uppercase;
}
.statement-line em { color: var(--stamp-lit); font-style: normal; }
/* The headlines again, in cut stones (premiere-diamond-type.js). The type stays in the
   page and is only put out while its stones are lit. */
.statement-stones {
  position: absolute; max-width: none; pointer-events: none; opacity: 0;
  filter: drop-shadow(0 0 4px rgba(196, 220, 255, .38));
}
.statement-line.in-stones { opacity: 0; transition: opacity 400ms ease-out; }   /* out slowly; back at once when the stones stop */
.statement-foot {
  position: absolute; inset: auto var(--copy-right) 48px var(--gutter); display: flex; justify-content: space-between; gap: 24px;
  font: 10px var(--f-type); letter-spacing: .16em; text-transform: uppercase; color: var(--bone);
  opacity: calc(var(--story-enter, 1) - var(--story-exit, 0) * 1.6);
}
/* JS owns arrival translate/turn/opacity; avoid fighting the older CSS timelines. Each
   file and print is dealt onto the desk a little crooked and settles at its own tilt. */
body.premiere .dossier, body.premiere .paperwork .print {
  animation: none; opacity: 1; transform: none;
  translate: 0 var(--arrival-y, 0px); rotate: calc(var(--tilt, 0deg) + var(--arrival-turn, 0deg));
  transition: rotate 350ms var(--scroll-ease);
}
.premiere .dossier .print img, .premiere .paperwork .print img { opacity: var(--arrival-opacity, 1); }
body.premiere .dossiers::before { animation: none; }
.premiere .board-print { transition: opacity 650ms var(--scroll-ease), transform 800ms var(--scroll-ease); }

@media (max-width: 720px) {
  .scroll-invitation { inset: auto 20px 18px; font-size: 8px; gap: 10px; letter-spacing: .1em; }
  .scroll-invitation > span:first-child { display: none; }
  .reel { height: 430svh; }
  .reel-stage { --gw: calc(100vw - 32px); padding-inline: 16px; gap: 24px; }
  .reel-sub { min-height: 6em; font-size: 15px; }
  .reel-strip { display: flex; justify-content: space-between; gap: 4px; height: auto; }
  .reel-strip li { position: relative; left: auto; }
  .reel-strip li a { font-size: 8px; letter-spacing: 0; padding: 14px 2px; width: auto; height: auto; }
  .reel-strip li.low a { padding-top: 14px; }
  .reel-strip li.low::before { height: 9px; }
  /* On a phone the portrait fills the stage and the type stands on its lower third. */
  .case-statement { height: 240svh; --gutter: 6vw; --copy-right: 6vw; }
  .statement-plate { inset: var(--marquee-height) 0 0; width: auto; }
  .statement-shade { background: linear-gradient(0deg, #090a0d 8%, #090a0de6 32%, #090a0d66 54%, transparent 72%); }
  .statement-evidence { top: -16%; height: 116%; }   /* less ceiling: the face clears the type */
  .statement-copy { top: auto; bottom: 104px; }
  .statement-first { transform: translate3d(0, var(--story-first-y, 0px), 0); }
  .statement-second { transform: translate3d(0, var(--story-second-y, 40px), 0); }
  .statement-foot { font-size: 8px; line-height: 1.7; }
  .statement-foot span { max-width: 45%; }
  .statement-foot span:last-child { text-align: right; }
  .statement-copy .label { font-size: 9px; margin-bottom: 14px; }
  body.premiere.film-static .statement-shade { background: #090a0dc7; }
}

/* ---------- props that answer the scroll (premiere-props.js) ---------- */
/* The string is run from pin to pin as the files land. */
body.premiere .dossiers::before { clip-path: inset(-14px calc((1 - var(--string, 1)) * 100%) -14px -14px); }
/* Each file is stamped once it is down: the kit's slam (noir.css), stroke for stroke, landing
   at this stamp's own strength. It comes from no further out than the kit's does: on a phone
   a stamp sits against the edge of the page and has no room to be any bigger. */
.cine-on .dossier .stamp.ink:not(.landed) { opacity: 0; }
.dossier .stamp.ink.landed { animation: stamp-land var(--dur-stamp) var(--ez-stamp) both; }
@keyframes stamp-land {
  0% { transform: rotate(var(--rot, -6deg)) scale(1.16); opacity: 0; }
  42% { transform: rotate(var(--rot, -6deg)) scale(.988); opacity: .85; }
  64% { transform: rotate(var(--rot, -6deg)) scale(1.018); }
  82% { transform: rotate(var(--rot, -6deg)) scale(.997); }
  100% { transform: rotate(var(--rot, -6deg)); opacity: .85; }
}
/* As the method arrives the files are swept aside, each its own way. */
.dossier:nth-child(1) { --sweep-x: -9%; --sweep-r: -5deg; }
.dossier:nth-child(2) { --sweep-x: 0%; --sweep-r: 2deg; }
.dossier:nth-child(3) { --sweep-x: 9%; --sweep-r: 5deg; }
body.premiere .dossier {
  translate: calc(var(--sweep, 0) * var(--sweep-x, 0%)) var(--arrival-y, 0px);
  rotate: calc(var(--tilt, 0deg) + var(--arrival-turn, 0deg) + var(--sweep, 0) * var(--sweep-r, 0deg));
}
/* The projectionist's cue mark (the kit's .cue), clear of the marquee. */
.premiere .cue { top: calc(var(--marquee-height) + 3vh); right: 4vw; width: 3.2vmin; }

/* ---------- the rover, the wrist and the hat, turned by the scroll (premiere-props.js) ----------
   Photographs taken walking round each, cut to one size with the thing in one place
   (film/build-turn-plates.py), laid one over another in a single print. The scroll
   turns it. Where motion is off, or there is no script, they lie side by side as a
   contact sheet instead (below, and in the page's noscript).
   A second print stands beside the rover: the rover on the job. It is a photograph
   on its own and takes no part in the turn. The other scenes are a pair, a head and
   a print, and every other one is flipped so the print changes sides down the page.
   A scene sets its own length (--turn) and how many plates its sheet has to a row
   (--sheet). */
.turntable { position: relative; height: var(--turn, 340svh); }
.turntable-stage {
  position: sticky; top: 0; height: 100svh; overflow: clip;
  display: grid; align-items: center; padding-top: var(--marquee-height);
}
.turntable-grid { display: grid; grid-template-columns: minmax(0, .72fr) minmax(0, 1fr) minmax(0, .56fr); gap: clamp(24px, 3.2vw, 56px); align-items: center; }
.turntable-main { display: contents; }      /* the head and the turning print: columns of the grid here, the first screen on a phone */
.turntable .section-head { margin-bottom: 0; }
.turntable .section-title { font-size: clamp(48px, 5.6vw, 84px); }
.turntable-print { justify-self: center; width: min(100%, calc(100svh - var(--marquee-height) - 130px)); }
.turntable-field { align-self: end; }
.turntable-field img { aspect-ratio: 4 / 3; }
.turntable-pair .turntable-grid { grid-template-columns: minmax(0, .8fr) minmax(0, 1fr); }
.turntable-flip .turntable-grid { grid-template-columns: minmax(0, 1fr) minmax(0, .92fr); }
.turntable-flip .turntable-print { order: -1; }
.turntable-note { margin-top: 18px; color: var(--ash); }
.plates { list-style: none; position: relative; aspect-ratio: 1; background: #000; }
.plates li { position: absolute; inset: 0; }
.plates li + li { opacity: 0; }      /* the first plate until the scroll says otherwise */
.print .plates img { height: 100%; aspect-ratio: auto; }
/* The desk behind the rover is different in every photograph: its edges are let go a little. */
.plates::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: radial-gradient(ellipse at 50% 54%, transparent 46%, rgba(9, 10, 13, .5) 100%); }
/* Where three columns will not fit: the head and the turning print are the first screen,
   pinned; the second print is under them, and comes up once the turn is done. */
@media (max-width: 860px) {
  .turntable { height: var(--turn-small, 300svh); }
  .turntable-stage { display: block; height: auto; min-height: 100svh; padding-bottom: clamp(32px, 6vh, 56px); }
  .turntable-grid, .turntable-pair .turntable-grid { grid-template-columns: minmax(0, 1fr); gap: 28px; }
  .turntable-main { display: grid; gap: 20px; align-content: center; min-height: calc(100svh - var(--marquee-height)); }
  .turntable .section-title { font-size: 52px; margin-block: 8px 12px; }
  .turntable .section-lede { font-size: 14px; }
  .turntable-print { width: min(100%, calc(100svh - var(--marquee-height) - 320px)); }
  .turntable-field { justify-self: end; width: min(72%, 320px); }
  .turntable-flip .turntable-print { order: 0; }
  .turntable-pair .turntable-print { width: min(100%, calc(100svh - var(--marquee-height) - 360px)); }
  .turntable-wrist .turntable-print { width: min(100%, calc(100svh - var(--marquee-height) - 400px)); }      /* its head has the most to say */
  .turntable-note { margin-top: 10px; }
}

/* The flock (premiere-flock.js) crosses over the page, and under the marquee, the grain and the vignette. */
.flock { position: fixed; inset: 0; z-index: 50; width: 100%; height: 100%; pointer-events: none; }

/* Pause is a complete alternate reading mode, including dynamically toggled preferences. */
body.premiere.film-static .reel { height: auto; }
body.premiere.film-static .reel-stage { position: relative; height: auto; min-height: 0; padding-block: 112px 60px; clip-path: none; }
body.premiere.film-static .reel-canvas { display: none; }
body.premiere.film-static .reel-sub { max-width: 76ch; }
body.premiere.film-static .case-statement { height: auto; background: #090a0d; }
body.premiere.film-static .statement-stage { position: relative; height: auto; min-height: 80svh; padding: 100px var(--copy-right) 100px var(--gutter); }
body.premiere.film-static .statement-copy { position: relative; inset: auto; opacity: 1; transform: none; margin-block: 40px; }
body.premiere.film-static .statement-plate { top: 0; }
body.premiere.film-static .statement-image { transform: none; }
body.premiere.film-static :is(.statement-evidence, .statement-stones) { display: none; }
body.premiere.film-static .turntable { height: auto; padding-block: var(--section-y); }
body.premiere.film-static .turntable-stage { position: relative; height: auto; min-height: 0; padding-top: 0; }
body.premiere.film-static .turntable-main { min-height: 0; }
body.premiere.film-static .plates { aspect-ratio: auto; display: grid; grid-template-columns: repeat(var(--sheet, 3), minmax(0, 1fr)); gap: 6px; background: none; }
body.premiere.film-static .plates li { position: static; opacity: 1; }
body.premiere.film-static .print .plates img { height: auto; aspect-ratio: 1; }
body.premiere.film-static .plates::after { display: none; }
body.premiere.motion-paused *, body.premiere.motion-paused *::before, body.premiere.motion-paused *::after { animation: none !important; transition: none !important; }
body.premiere.motion-paused .scroll-invitation { display: none; }
@media (prefers-reduced-motion: reduce), print {
  .premiere *, .premiere *::before, .premiere *::after { animation: none !important; transition: none !important; }
  .case-statement { height: auto; background: #090a0d; }
  .statement-stage { position: relative; height: auto; padding: 80px var(--copy-right) 80px var(--gutter); }
  .statement-copy { position: relative; inset: auto; opacity: 1; transform: none; margin-block: 40px; }
  .statement-plate { top: 0; }
  .statement-image { transform: none; }
  .statement-evidence, .statement-stones, .statement-morph, .flock { display: none !important; }
  .turntable { height: auto; padding-block: var(--section-y); }
  .turntable-stage { position: relative; height: auto; min-height: 0; padding-top: 0; }
  .turntable-main { min-height: 0; }
  .plates { aspect-ratio: auto; display: grid; grid-template-columns: repeat(var(--sheet, 3), minmax(0, 1fr)); gap: 6px; background: none; }
  .plates li, .plates li + li { position: static; opacity: 1; }
  .print .plates img { height: auto; aspect-ratio: 1; }
  .plates::after { display: none; }
  .statement-plate.is-morphing .statement-room { opacity: 1; }
  .scroll-invitation { display: none; }
}
