/* ══════════════════════════════════════════════════════════════════════════
   TNAADO — /services/media-production HERO: "THE CONFORM"
   2026-08-09.

   WHAT THIS REPLACES AND WHY
   ──────────────────────────
   The hero was .glow-hero--prod + .fx-conic (a 38s conic turn — 0.1%/s, below
   the threshold of perception) and then, earlier the same night, THE STRIKE
   in css/service-moments.css §1: three gradient lights sequencing in on load.
   THE STRIKE fixed the timing defect and was right about the timing. It is
   still a lighting TREATMENT painted across the frame, not a built object,
   and the standard set on 2026-08-09 for the four heroes rebuilt that night
   is an object: Ethan, on the technology pair — "don't use a photo at all...
   make a custom animation for the page that will jaw drop."

   Note what was NOT removed: this page's content. The four-row production log
   is the real current shoot schedule and the two reserved photo frames are
   honest empty states waiting on Ethan's own shoot images. Nothing below the
   hero is touched by this file.

   THE OBJECT
   ──────────
   A conform: the moment in post where every separate thing that was made for
   a job is laid on one timeline, in sync, and becomes one deliverable. Built
   here as a physical edit deck seen from above — five rails standing at real
   depth on a table, clips as solid slabs with thickness sitting on them, a
   red playhead blade crossing the whole deck, and a MASTER rail underneath
   that is EMPTY ahead of the playhead and solid behind it.

   That last part is the whole idea and it is the page's own sentence, made
   physical. Three sections down the page says: "The look, the cut and the
   sound arrive together." So the four upper rails are picture, motion, grade
   and sound — the page's own four concentrations, in the page's own words —
   and the master fills only where all four have been crossed. You watch the
   deliverable get made out of the four things this practice does.

   WHY THIS AND NOT SOMETHING ELSE
   ───────────────────────────────
   No photograph and no video: the standing rule on this site, and the two
   image slots on this page are reserved for Ethan's own shoot stills, which
   have not landed. No node-and-line network, no particle field — the generic
   cliché ART-GUIDE §3 bans. No lighting rig, three-point or otherwise: that
   is the STRIKE this file replaces, and a key/fill/rim diagram is a stock
   metaphor any agency site can draw.

   It must also not resemble the three other objects shipped the same night:
     /technology            THE ASSEMBLY — a machined enclosure that closes
     /services/tech         THE STACK    — seven plates seating into a slab
     /media                 THE MOVEMENT — a 35mm camera movement, running
   Those first two are vertical, rectilinear, and they assemble and REST.
   THE MOVEMENT is round, optical, vertical and mechanical. This one is
   horizontal, flat, made of edit data rather than metal, and its motion is a
   single traverse rather than a rotation — the post side of the same practice
   whose production side is /media's camera. Camera and cutting room must not
   look like each other, and they do not.

   WHY NO CANVAS / WebGL
   ─────────────────────
   Measured workload: 71 opaque, axis-aligned, flat-shaded quads, no textures,
   no lighting model, no per-pixel work. The compositor draws exactly that for
   free from CSS transforms. A WebGL context would add a shader compile on
   first paint, DPR/resize/context-loss handling and a live GL context on iOS
   to draw geometry the browser already knows how to draw. Labels stay DOM
   text, so they are subpixel-crisp at DPR 1/2/3 for zero texture bytes.

   FRAME BUDGET — the actual claim
   ───────────────────────────────
   Target: 60fps on desktop (16.67ms/frame at 1440×900) and on an iPhone-class
   device at 390×844. Steady-state main-thread cost is ZERO — there is no
   JavaScript in this hero at all. No rAF, no scroll listener, no observer, no
   per-frame style write, no layout read, ever. Every moving property is
   transform or opacity on a declarative CSS animation, so the whole deck runs
   on the compositor. Animating layers in steady state: 1 playhead + 1 master
   fill + 13 clip edges = 15. Zero image bytes; nothing here downloads.

   SYNC WITHOUT A CLOCK. The playhead, the master fill and all thirteen clip
   flashes are separate animations that must agree about where the playhead
   is. They do, because they all run --cf-pass and every clip's delay is
   (its start ÷ deck width) × --cf-pass, computed from the same two numbers
   the geometry uses. No JS scheduler, no drift, and moving a clip in the
   markup moves its flash with it.

   COLOUR AND UNITS, STATED RATHER THAN INHERITED
   ──────────────────────────────────────────────
   Authored in sRGB, locked palette only: ink #0a0a0a, bone rgb(245,241,232)
   at low alpha for lit faces, red #c8102e for the playhead and the seams,
   --red-text #e8455a for small mono type (--red measures 3.37:1 on ink and
   must never carry small text — site.css:14). No new hue: deliberately NOT
   the multi-colour track palette a real NLE uses, which would import four
   hues this brand does not own. Geometry in CSS px inside perspective:1180px;
   angles in deg; type in rem.

   ALWAYS DARK, BOTH THEMES. This site's default theme is LIGHT (the head
   script sets data-theme="light" unless localStorage says otherwise), so a
   hero that pins only its background paints near-black type on near-black.
   The full dark token set is re-declared on the section.

   REDUCED MOTION / NO JS. Every animation is gated behind html.js-motion AND
   inside prefers-reduced-motion: no-preference. The RESTING state is the deck
   fully conformed: playhead parked at 62%, master filled to meet it, clips
   seated. A still of a finished conform, never an empty box.
   ══════════════════════════════════════════════════════════════════════════ */

.cf-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: #0a0a0a;
  /* T-1095: 92svh -> 68svh. The shortest of the five heroes on purpose — this
     is a service page one level down from /media, and it should not open at
     the same weight as the pages above it. See the hero-height note in
     css/media-hero-movement.css. */
  /* T-1108: 68svh plus clamp(7rem,13vw,10rem) of top padding measured 664px =
     90vh at 1440x740, with a 90vh photograph inside it. The min-height was
     never the problem, the padding was. */
  min-height: 58vh;
  min-height: 58svh;
  display: flex;
  align-items: center;
  padding: clamp(5rem, 9vw, 7rem) 0 clamp(3rem, 5vw, 4.5rem);

  /* Full dark token set, re-declared — see header note. */
  --ink: #0a0a0a;
  --on-black: #f5f1e8;
  --on-black-mute: rgba(245,241,232,.58);
  --on-black-faint: rgba(245,241,232,.52);
  --red-text: #e8455a;

  /* ── THE ONE SET OF NUMBERS ────────────────────────────────────────
     --cf-w is the deck's timeline length in px and is the denominator
     for every clip position in the markup. --cf-pass is one traverse.
     Change either and the flashes follow, because the markup expresses
     each clip's delay as a fraction of the same pair. */
  --cf-w: 720px;     /* timeline length, left edge to right edge */
  --cf-pass: 8.64s;  /* one playhead traverse                    */
  /* One scale for the whole deck. The widest thing on it is NOT the table
     (--cf-w + 92px) but the rail tags, which stand a further 92px off its
     left end — the assembly is 858 authored px wide about the deck origin.
     Its SCREEN width is not 858 * --cf-k, though: the deck is pitched inside
     perspective:1180px, so the far edge is magnified and the projected width
     grows faster than the scale does. Every value here and in the responsive
     block was therefore MEASURED with getBoundingClientRect over the whole
     .cf-deck subtree at each breakpoint, not extrapolated — extrapolating
     from one measurement is what put the deck 28px off the right edge at
     1441px on the first attempt. At --cf-k:1 with the deck at left:56% the
     master rail was drawn straight through the lede. */
  --cf-k: .82;
}

.cf-hero .inner {
  position: relative;
  z-index: 3;
  width: 100%;
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 clamp(1.2rem, 4vw, 2.5rem);
}

/* ── AMBIENT GROUND ───────────────────────────────────────────────────
   ONE dominant red radial where the playhead lives, plus a cool key from
   the upper left. Static: the deck carries the motion. */
.cf-hero__ground {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background:
    radial-gradient(ellipse 40% 46% at 62% 62%, rgba(200,16,46,.24) 0%, rgba(200,16,46,.07) 46%, transparent 72%),
    radial-gradient(ellipse 58% 44% at 22% 2%, rgba(245,241,232,.06) 0%, transparent 62%),
    /* T-1086: DIRECTIONAL. There is a photograph under this now, so the scrim
       is spent on the left where the headline, lede and jump links sit, and
       runs out by 80% so the set, the light stand and the two people on the
       right are plainly visible. A flat wash here would put the black box
       straight back. */
    linear-gradient(100deg,
      rgba(10,10,10,.94) 0%, rgba(10,10,10,.84) 27%,
      rgba(10,10,10,.50) 49%, rgba(10,10,10,.18) 67%, transparent 80%),
    linear-gradient(to bottom, rgba(10,10,10,.6) 0%, transparent 26%, transparent 66%, #0a0a0a 100%);
}

/* ── THE HERO PHOTOGRAPH (T-1086, 2026-08-13) ─────────────────────────
   A sibling of .cf-scene, never a child: .cf-stage / .cf-deck must not have
   an ancestor carrying opacity, filter or mask (see the DECK warning below),
   and this element carries all three.

   Anchored RIGHT and feathered at its left edge so it dissolves into the
   page ink instead of ending at a line. Source is 1400x1050 (4:3) and the
   element renders at 74% of the viewport, so at 1920 it draws ~1420px wide —
   native, no upscale.

   HEADS. object-position 70% holds the window over the right of the frame:
   the two people at source x 70-95% land around viewport x 75-95%, far clear
   of the copy column (which ends at ~x 45%), and the camera operator at
   source x 0-15% falls inside the mask feather rather than under the scrim,
   so he softens out rather than being blacked over. Nothing is cropped
   through a head at any width — the vertical window is the full frame
   height at every breakpoint. */
.cf-hero__photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 60% 34%;
  z-index: 0;
  opacity: .80;
  filter: saturate(.92) contrast(1.03);
  pointer-events: none;
}
@media (min-width: 940px) {
  .cf-hero__photo {
    left: auto; right: 0;
    width: 74%;
    -webkit-mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.4) 14%, #000 36%);
            mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.4) 14%, #000 36%);
  }
}
@media (max-width: 939px) {
  /* Narrow: the copy fills the column, so the window is moved onto the empty
     middle of the room — whiteboard, light stand and table — and off both
     faces, rather than scrimming a face to make type readable. */
  .cf-hero__photo { object-position: 38% 40%; opacity: .44; }

  /* T-1120: the lede measured 4.16:1 against real painted pixels at 390 —
     under the 4.5 floor. On narrow the directional 100deg scrim is the wrong
     shape, because the copy is no longer in a left column, it spans the frame.
     A vertical wash instead, deepest where the copy actually sits. Measured
     after: ground moves from rgb(68,67,68) to rgb(52,51,52), taking the lede
     to 5.1:1 without touching the type colour, so the headline/lede hierarchy
     is unchanged. */
  /* Deepest at the TOP, which is where the eyebrow and the headline sit —
     ART-GUIDE's "darkest scrim stop sits behind the densest copy block".
     The eyebrow is `--red-text` and it measured 3.69:1 at 768, because the
     hero photograph has a red practical in it and the eyebrow was landing red
     on red — the ground read rgb(58,37,37), not ink. Red stays the eyebrow
     accent (ART-GUIDE locks that); the GROUND moves instead. The red radial
     is pushed low and right, away from the copy, for the same reason. */
  .cf-hero__ground {
    background:
      radial-gradient(ellipse 60% 36% at 76% 80%, rgba(200,16,46,.18) 0%, transparent 70%),
      linear-gradient(to bottom,
        rgba(10,10,10,.96) 0%, rgba(10,10,10,.92) 22%,
        rgba(10,10,10,.76) 56%, rgba(10,10,10,.90) 88%, #0a0a0a 100%);
  }
}

.cf-hero__grain {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: .045;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ══════════════════════════════════════════════════════════════════════
   THE DECK
   .cf-stage / .cf-deck / .cf-rail / .cf-clip must never carry opacity,
   filter, mask, clip-path, mix-blend-mode or contain:paint — any one of
   them flattens transform-style and the deck collapses to a flat picture.
   Load-bearing, not stylistic.
   ══════════════════════════════════════════════════════════════════════ */

.cf-scene {
  position: absolute;
  z-index: 1;
  inset: auto 0 6% auto;
  width: 100%;
  height: 62%;
  pointer-events: none;
}

.cf-stage {
  position: absolute;
  inset: 0;
  perspective: 1180px;
  perspective-origin: 58% 22%;
}

.cf-deck {
  position: absolute;
  /* 72%, not 56%. The deck is anchored in the right-hand half so the copy
     column is never crossed; see the --cf-k note for the arithmetic. */
  left: 72%;
  top: 46%;
  width: 0; height: 0;
  transform-style: preserve-3d;
  /* SETTLED POSE — what a no-JS / reduced-motion visitor sees, so it is the
     finished pose, not the entry pose. 58° of pitch is the number that makes
     this a table rather than a bar chart: under about 45° the rails stop
     receding and the clips' top faces vanish, which is how a timeline drawn
     flat in 2D looks — and a flat timeline is a screenshot, not an object. */
  transform: rotateX(58deg) rotateZ(-3deg) scale(var(--cf-k));
}

/* The table the rails stand on: a machined surface with a second-by-second
   ruler milled into it. The ruler is a gradient, not elements — 12 ticks of
   gradient cost nothing where 12 divs each cost a box. */
.cf-table {
  position: absolute;
  left: calc(var(--cf-w) / -2 - 46px);
  top: -186px;
  width: calc(var(--cf-w) + 92px);
  height: 396px;
  background:
    repeating-linear-gradient(90deg,
      rgba(245,241,232,.085) 0px, rgba(245,241,232,.085) 1px,
      transparent 1px, transparent 60px),
    linear-gradient(163deg, rgba(245,241,232,.055) 0%, rgba(245,241,232,.012) 44%, rgba(10,10,10,.5) 100%),
    #0d0f12;
  box-shadow:
    inset 0 1px 0 rgba(245,241,232,.16),
    inset 0 -1px 0 rgba(10,10,10,.9),
    0 40px 90px rgba(0,0,0,.8);
}

/* ── ONE RAIL ─────────────────────────────────────────────────────────
   --y is its depth on the table, --d its depth extent. The rail is the
   empty channel a clip drops into, so it reads even where no clip sits. */
.cf-rail {
  position: absolute;
  left: calc(var(--cf-w) / -2);
  top: var(--y);
  width: var(--cf-w);
  height: var(--d, 40px);
  transform-style: preserve-3d;
  background: linear-gradient(180deg, rgba(10,10,10,.72) 0%, rgba(10,10,10,.45) 100%);
  box-shadow: inset 0 0 0 1px rgba(245,241,232,.07);
}

/* ── ONE CLIP ─────────────────────────────────────────────────────────
   --x start, --cw width, both in the same px as --cf-w. A clip is a slab:
   a lit top face on the table plane and a front face standing up from the
   near edge, which is what gives it thickness at this camera. */
.cf-clip {
  position: absolute;
  left: var(--x);
  top: 0;
  width: var(--cw);
  height: 100%;
  transform-style: preserve-3d;
  transform: translateZ(var(--cf-h, 15px));
}

.cf-clip__top {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(168deg, rgba(245,241,232,.30) 0%, rgba(245,241,232,.12) 46%, rgba(245,241,232,.05) 100%),
    #191c22;
  box-shadow: inset 0 0 0 1px rgba(10,10,10,.85), inset 0 1px 0 rgba(245,241,232,.34);
}

/* The front face. Rotated up out of the table at the clip's near edge, so it
   is the surface you actually read the clip's height from. */
.cf-clip__front {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: var(--cf-h, 15px);
  transform-origin: 50% 100%;
  transform: rotateX(-90deg);
  background: linear-gradient(180deg, rgba(245,241,232,.14) 0%, rgba(10,10,10,.86) 100%);
  box-shadow: inset 0 1px 0 rgba(245,241,232,.22);
}

/* THE CUT. A red hairline standing on the clip's leading edge — the point
   where this piece of material begins. Dim at rest; it fires as the playhead
   crosses it, which is what "the playhead crossed a cut" looks like. */
.cf-clip__cut {
  position: absolute;
  left: 0;
  top: 0;
  width: 2px;
  height: 100%;
  transform: translateZ(1px);
  background: var(--red);
  opacity: .34;
}

.cf-clip__label {
  position: absolute;
  left: 7px;
  top: 50%;
  transform: translateY(-50%) translateZ(1px);
  font-family: var(--font-mono);
  font-size: 8px;
  letter-spacing: .16em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(245,241,232,.5);
  pointer-events: none;
}

/* ── MATERIALS PER RAIL ───────────────────────────────────────────────
   Four surfaces, one hue. Picture is the brightest because it is the thing
   everything else is applied to; grade carries the red because grade IS the
   colour pass; sound is dark with the waveform doing the work. */
.cf-rail--picture .cf-clip__top {
  background:
    linear-gradient(168deg, rgba(245,241,232,.42) 0%, rgba(245,241,232,.16) 44%, rgba(245,241,232,.06) 100%),
    #1d2027;
}
.cf-rail--motion .cf-clip__top {
  background:
    repeating-linear-gradient(58deg,
      rgba(245,241,232,.10) 0px, rgba(245,241,232,.10) 2px,
      transparent 2px, transparent 7px),
    linear-gradient(168deg, rgba(245,241,232,.22) 0%, rgba(245,241,232,.07) 60%, rgba(245,241,232,.03) 100%),
    #16191f;
}
.cf-rail--grade .cf-clip__top {
  background:
    linear-gradient(90deg, rgba(200,16,46,.42) 0%, rgba(200,16,46,.14) 42%, rgba(245,241,232,.10) 100%),
    #1a1216;
}
.cf-rail--sound .cf-clip__top {
  background:
    linear-gradient(168deg, rgba(245,241,232,.13) 0%, rgba(245,241,232,.04) 60%, rgba(10,10,10,.5) 100%),
    #12151a;
}

/* THE WAVEFORM. Static geometry: a recorded take has one shape and it does
   not wobble. --h is each bar's amplitude, authored in the markup. */
.cf-wave {
  position: absolute;
  inset: 5px 6px;
  display: flex;
  align-items: center;
  gap: 2px;
  transform: translateZ(1px);
}
.cf-wave i {
  display: block;
  flex: 1 1 auto;
  height: calc(var(--h) * 1%);
  min-width: 1px;
  background: linear-gradient(180deg, rgba(245,241,232,.72) 0%, rgba(245,241,232,.34) 100%);
}

/* ── THE MASTER ───────────────────────────────────────────────────────
   Empty ahead of the playhead, solid behind it. The fill is a scaleX from
   the left edge on the same clock as the playhead, so the two can never
   disagree about where "now" is. */
.cf-master {
  position: absolute;
  left: calc(var(--cf-w) / -2);
  top: 138px;
  width: var(--cf-w);
  height: 54px;
  transform-style: preserve-3d;
  background: linear-gradient(180deg, rgba(10,10,10,.8) 0%, rgba(10,10,10,.5) 100%);
  box-shadow: inset 0 0 0 1px rgba(245,241,232,.12);
}

.cf-master__fill {
  position: absolute;
  inset: 0;
  transform-origin: 0 50%;
  transform: translateZ(11px) scaleX(.62);
  background:
    linear-gradient(168deg, rgba(245,241,232,.5) 0%, rgba(245,241,232,.20) 44%, rgba(245,241,232,.08) 100%),
    #232830;
  box-shadow: inset 0 1px 0 rgba(245,241,232,.44), inset 0 0 0 1px rgba(10,10,10,.8);
}

.cf-master__label {
  position: absolute;
  left: 8px;
  top: 50%;
  transform: translateY(-50%) translateZ(13px);
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: rgba(245,241,232,.62);
}

/* ── THE PLAYHEAD ─────────────────────────────────────────────────────
   A blade standing on the table, crossing every rail. Three parts: the line
   on the surface, the blade standing up out of it, and the flag that carries
   the timecode. All three move as one element. */
.cf-head {
  position: absolute;
  left: calc(var(--cf-w) / -2);
  top: -168px;
  width: 2px;
  height: 372px;
  transform-style: preserve-3d;
  transform: translate3d(calc(var(--cf-w) * .62), 0, 0);
}

.cf-head__line {
  position: absolute;
  inset: 0;
  transform: translateZ(2px);
  background: var(--red);
  box-shadow: 0 0 16px 3px rgba(200,16,46,.6);
}

.cf-head__blade {
  position: absolute;
  left: -1px;
  bottom: 0;
  width: 4px;
  height: 62px;
  transform-origin: 50% 100%;
  transform: rotateX(-90deg);
  background: linear-gradient(180deg, rgba(245,241,232,.9) 0%, var(--red) 44%, rgba(200,16,46,.5) 100%);
  box-shadow: 0 0 22px 4px rgba(200,16,46,.5);
}

.cf-head__flag {
  position: absolute;
  left: -4px;
  top: -30px;
  transform: rotateX(-90deg) translateZ(38px);
  transform-origin: 50% 100%;
  padding: 4px 7px;
  background: var(--red);
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .1em;
  white-space: nowrap;
  color: #fff;
}

/* ── RAIL LABELS ──────────────────────────────────────────────────────
   Standing off the left end of the deck, lifted off the table so they read
   as gear rather than as paint. */
.cf-tag {
  position: absolute;
  left: calc(var(--cf-w) / -2 - 92px);
  top: var(--y);
  width: 86px;
  height: var(--d, 40px);
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-right: 9px;
  transform: translateZ(3px);
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(245,241,232,.42);
  background: linear-gradient(90deg, transparent 0%, rgba(245,241,232,.05) 100%);
  box-shadow: inset -1px 0 0 rgba(245,241,232,.14);
}
.cf-tag b { color: var(--red-text); font-weight: 500; margin-right: 6px; }
.cf-tag--master { color: rgba(245,241,232,.66); }

/* ══════════════════════════════════════════════════════════════════════
   COPY
   ══════════════════════════════════════════════════════════════════════ */

/* 540px, and the LEDE is clamped back to 460 on its own rule below.
   The column is sized by its widest LINE, which is the headline, not the lede.
   Measured at 59.2px display: "Built camera-ready." needs 491px. A 460px column
   is 31px short of that, so the line took the only legal break it had — the
   hyphen inside "camera-ready" — and rendered "Built camera-" / "ready. On day
   one." at every width from 1181 to 1920, i.e. on every desktop.

   Putting max-width:540px on .cf-h1 alone (the previous attempt) does nothing:
   a block child cannot exceed its parent's content box, so the h1 still
   resolved to 460. The constraint has to move to the parent. The lede keeps
   its 460px measure below, which is where a 62-character measure belongs, and
   the deck's clearance from the copy's longest line was re-measured after this
   change at every breakpoint — narrowest is 41px at 1281. */
.cf-copy { max-width: 540px; position: relative; }

.cf-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: 11px;
  line-height: 1;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--red-text);
  margin: 0 0 1.3rem;
}
.cf-eyebrow::before {
  content: "";
  width: 36px; height: 1px;
  background: var(--red);
  display: inline-block;
}

.cf-h1 {
  /* Inherits the column's 540px. The width alone fixes the hyphen break at
     every width this page is used at; the U+2060 WORD JOINER after the hyphen
     in the markup is the guarantee, so a font that loads at a different metric
     can never reintroduce "Built camera-" / "ready." Below ~330px of measure
     the joiner makes the line wrap to "Built" / "camera-ready." instead —
     three lines, but never a word split at a hyphen. */
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.3rem, 5vw, 3.7rem);
  line-height: 1.04;
  letter-spacing: -.02em;
  color: var(--on-black);
  margin: 0 0 1.2rem;
  text-shadow: 0 2px 30px rgba(10,10,10,.85);
}
/* "On day one." is the designed second line, so it moves as one unit. Without
   this it split as "...ready. On" / "day one." at 1024.
   T-1245 — "it cannot overflow" was true of THAT phrase and not of the rule.
   /services/media-production's em is "from our own crew in Toronto." and
   measures 463.5px against a 353px column at 390, so nowrap truncated the H1
   mid-word: "Video production / from our own crew in To". The nowrap is worth
   having where the column is wide enough to honour it and is actively harmful
   below that, so it now stops at the breakpoint where the widest em still
   fits. A phrase wrapping on a phone is a cosmetic loss; a headline cut
   mid-word is not.
   Then: the phrase it was protecting is GONE. "On day one." appears nowhere on
   the site, and .cf-h1 is used on exactly one page whose em is the long one
   above — so a breakpointed nowrap still overflowed 632px into a 540px column
   at 1024 and 717px at 1440. The rule has no remaining beneficiary and every
   width it applies at is a width it breaks. Removed rather than narrowed. */
.cf-h1 em { font-style: italic; color: var(--red); }

.cf-lede {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1rem, 1.5vw, 1.22rem);
  line-height: 1.58;
  color: var(--on-black-mute);
  margin: 0 0 1.8rem;
  max-width: 460px;
  text-shadow: 0 1px 18px rgba(10,10,10,.9);
}
.cf-lede em { font-style: italic; color: var(--on-black); }

.cf-jump { display: flex; flex-wrap: wrap; gap: .5rem 1.4rem; }
.cf-jump a {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(245,241,232,.6);
  text-decoration: none;
  padding-bottom: 3px;
  border-bottom: 1px solid rgba(245,241,232,.22);
  transition: color .2s var(--ease-out-expo), border-color .2s var(--ease-out-expo);
}
.cf-jump a:hover { color: var(--on-black); border-bottom-color: var(--red); }

/* ══════════════════════════════════════════════════════════════════════
   MOTION
   ══════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: no-preference) {

  /* ── ENTRY. Black at t=0; a deck with everything on it by t≈1.7s, and the
     playhead is already travelling before the last clip lands. ────────── */

  html.js-motion .cf-deck {
    animation: cfCrane 1.9s cubic-bezier(.2,.66,.22,1) both;
  }
  @keyframes cfCrane {
    from { transform: rotateX(74deg) rotateZ(-7deg) scale(calc(var(--cf-k) * .86)); }
    to   { transform: rotateX(58deg) rotateZ(-3deg) scale(var(--cf-k)); }
  }

  html.js-motion .cf-table { animation: cfWipe .72s cubic-bezier(.2,.8,.25,1) both; }
  @keyframes cfWipe {
    from { opacity: 0; transform: scaleX(.2); }
    to   { opacity: 1; transform: scaleX(1); }
  }
  html.js-motion .cf-table { transform-origin: 0 50%; }

  html.js-motion .cf-rail,
  html.js-motion .cf-master { animation: cfRailIn .5s cubic-bezier(.2,.8,.25,1) both; transform-origin: 0 50%; }
  html.js-motion .cf-rail--picture { animation-delay: .22s; }
  html.js-motion .cf-rail--motion  { animation-delay: .30s; }
  html.js-motion .cf-rail--grade   { animation-delay: .38s; }
  html.js-motion .cf-rail--sound   { animation-delay: .46s; }
  html.js-motion .cf-master        { animation-delay: .54s; }
  @keyframes cfRailIn {
    from { opacity: 0; transform: scaleX(.06); }
    to   { opacity: 1; transform: scaleX(1); }
  }

  html.js-motion .cf-tag { animation: cfTagIn .44s ease-out both; }
  html.js-motion .cf-tag--picture { animation-delay: .34s; }
  html.js-motion .cf-tag--motion  { animation-delay: .42s; }
  html.js-motion .cf-tag--grade   { animation-delay: .50s; }
  html.js-motion .cf-tag--sound   { animation-delay: .58s; }
  html.js-motion .cf-tag--master  { animation-delay: .66s; }
  @keyframes cfTagIn {
    from { opacity: 0; transform: translate3d(-14px,0,3px); }
    to   { opacity: 1; transform: translate3d(0,0,3px); }
  }

  /* THE CLIPS LAND. Each drops onto its rail from above; --dl is authored in
     the markup as its own position on the timeline, so the material arrives
     left to right, in cut order. */
  html.js-motion .cf-clip {
    animation: cfDrop .62s cubic-bezier(.18,.86,.24,1) both;
    /* --dl is a clip's position in PLAYHEAD seconds, so it runs to ~7.95s at
       the right-hand end of the deck. At the * .5 this was authored with, the
       last clip did not land until ~5.1s — the playhead (which starts at
       1.15s) would have crossed three-quarters of an empty deck before its
       material showed up, and the entry claim at the top of this file ("a
       deck with everything on it by t≈1.7s ... the playhead is already
       travelling before the last clip lands") was false in both halves.
       * .07 compresses the ripple to 0.56s: last clip seated at
       .52 + .56 + .62 = 1.70s, first movement of the head at 1.15s. Both
       sentences are now true, and the build still reads left-to-right in
       cut order rather than landing all at once. */
    animation-delay: calc(.52s + var(--dl, 0s) * .07);
  }
  @keyframes cfDrop {
    from { opacity: 0; transform: translateZ(210px); }
    to   { opacity: 1; transform: translateZ(var(--cf-h, 15px)); }
  }

  /* ── STEADY STATE ─────────────────────────────────────────────────── */

  /* THE TRAVERSE. Linear, forever. Everything else on this deck is a
     function of where this element is. */
  html.js-motion .cf-head {
    animation: cfPass var(--cf-pass) linear infinite;
    animation-delay: 1.15s;
  }
  @keyframes cfPass {
    0%   { transform: translate3d(0, 0, 0); opacity: 1; }
    92%  { transform: translate3d(var(--cf-w), 0, 0); opacity: 1; }
    96%  { transform: translate3d(var(--cf-w), 0, 0); opacity: 0; }
    97%  { transform: translate3d(0, 0, 0); opacity: 0; }
    100% { transform: translate3d(0, 0, 0); opacity: 1; }
  }

  /* THE MASTER FILLS behind it. Same curve, same clock, so the fill edge and
     the blade are the same pixel for the whole traverse. */
  html.js-motion .cf-master__fill {
    animation: cfFill var(--cf-pass) linear infinite;
    animation-delay: 1.15s;
  }
  @keyframes cfFill {
    0%   { transform: translateZ(11px) scaleX(.001); }
    92%  { transform: translateZ(11px) scaleX(1); }
    96%  { transform: translateZ(11px) scaleX(1); }
    97%  { transform: translateZ(11px) scaleX(.001); }
    100% { transform: translateZ(11px) scaleX(.001); }
  }

  /* THE CUTS FIRE as the head crosses them. --dl is the clip's own start
     expressed as a fraction of the traverse, authored once in the markup and
     reused by both the drop and this. A clip cannot be in the wrong place. */
  html.js-motion .cf-clip__cut {
    animation: cfCut var(--cf-pass) linear infinite;
    animation-delay: calc(1.15s + var(--dl, 0s));
  }
  @keyframes cfCut {
    0%   { opacity: 1; box-shadow: 0 0 18px 5px rgba(200,16,46,.85); }
    5%   { opacity: .34; box-shadow: 0 0 0 0 rgba(200,16,46,0); }
    100% { opacity: .34; box-shadow: 0 0 0 0 rgba(200,16,46,0); }
  }

  /* Copy arrives with the deck, not after it. */
  html.js-motion .cf-copy > * { animation: cfCopyIn .8s cubic-bezier(.16,1,.3,1) both; }
  html.js-motion .cf-eyebrow { animation-delay: .08s; }
  html.js-motion .cf-h1      { animation-delay: .22s; }
  html.js-motion .cf-lede    { animation-delay: .38s; }
  html.js-motion .cf-jump    { animation-delay: .54s; }
  @keyframes cfCopyIn {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: none; }
  }
}

/* ══════════════════════════════════════════════════════════════════════
   RESPONSIVE — real geometry in px, so it scales with ONE number.
   ══════════════════════════════════════════════════════════════════════ */

/* MEASURED, not eyeballed. Under perspective the assembly's screen width is
   973px per unit of --cf-k, running 472px left and 500px right of the deck
   origin at 72%. Each step below is the largest --cf-k that keeps the deck's
   left edge clear of the copy's longest text line AND its right edge inside
   the viewport. Both constraints were failing at every width from 1180 to
   1440 before this: the deck was overrunning the right edge by 15-41px and
   touching or crossing the lede.

   Each tier is evaluated at the NARROW end of its own range, because that is
   where it is worst — a tier that only fits at its widest width is a tier
   that clips for most of the widths it covers, which is exactly how the
   first pass failed. Binding constraint is the right edge:
   --cf-k <= (0.28 * W - 24) / 500. */
@media (max-width: 1600px) { .cf-hero { --cf-k: .68; } }  /* worst case 1521 */
@media (max-width: 1520px) { .cf-hero { --cf-k: .66; } }  /* worst case 1281 */
@media (max-width: 1280px) { .cf-hero { --cf-k: .60; } }  /* worst case 1181 */
@media (max-width: 1180px) { .cf-hero { --cf-k: .55; } }  /* worst case 1081 */

/* ── STACKED, from 1080px down ─────────────────────────────────────────
   Below this the two-column arrangement stops being a judgement call and
   becomes arithmetic: the copy needs ~500px of measure and the deck needs
   ~600px to stay legible, and 1080 cannot give both. So the deck moves to
   its own full-width band above the copy, where it can be BIGGER than the
   side-by-side version rather than smaller. This threshold used to be
   900px, which left three breakpoints' worth of collision above it. */
@media (max-width: 1080px) {
  .cf-hero {
    display: block;
    min-height: 0;
    padding: clamp(5.5rem, 18vw, 7rem) 0 clamp(3rem, 9vw, 4rem);
    /* Full width is available here, so the deck grows rather than shrinks.
       973px per unit k against 1080 * .92 of usable width allows up to ~1.02;
       .70 keeps a comfortable margin at 1080 and still fits 900. */
    --cf-k: .70;
  }
  .cf-scene {
    position: relative;
    inset: auto;
    width: 100%;
    height: 40svh;
    min-height: 280px;
    margin: 0 0 1.4rem;
  }
  .cf-stage { perspective: 900px; perspective-origin: 50% 26%; }
  .cf-deck { left: 50%; top: 48%; }
  /* NOT max-width:none. The deck moved to its own band, so nothing competes
     with the copy for horizontal room — but "none" let the headline run the
     full 944px of content width at 1024 while the lede stayed at its own
     460px, which reads as two unrelated blocks. Keeping the column at its
     desktop 540 holds the composed two-line headline over the lede. */
  .cf-copy { max-width: 540px; }
  /* T-1120. This rule, not the 939px one above it, is what actually paints
     every stacked viewport — same specificity, later in the file, so it wins.
     Two measured faults, both in this one declaration:
       1. the red radial sat at 50% 22%, which is exactly where the eyebrow
          lands once the hero stacks. The eyebrow is `--red-text`, so it was
          red type on a red glow: 3.83:1 at 390 and 3.66:1 at 768, against a
          4.5 floor. The glow moves down and right, off the copy entirely.
       2. the vertical wash went transparent from 22% to 74%, so between those
          stops the only thing under the type was the photograph — which has a
          red practical in it. The top stop now carries through the copy block
          instead of vanishing behind it.
     Red is still the eyebrow accent; the ground moved, not the type. */
  .cf-hero__ground {
    background:
      radial-gradient(ellipse 66% 30% at 74% 82%, rgba(200,16,46,.20) 0%, rgba(200,16,46,.05) 48%, transparent 76%),
      linear-gradient(to bottom,
        rgba(10,10,10,.93) 0%, rgba(10,10,10,.88) 26%,
        rgba(10,10,10,.66) 58%, rgba(10,10,10,.88) 86%, #0a0a0a 100%);
  }
}

/* Stacked still, but 900 and below cannot carry .70 across the full width. */
@media (max-width: 900px) { .cf-hero { --cf-k: .56; } }

@media (max-width: 560px) {
  .cf-hero { --cf-k: .40; }
  .cf-scene { height: 32svh; min-height: 232px; }
  /* At this scale the clip labels and the tags are 3px of type. Illegible
     detail is noise; both are decorative and aria-hidden, so nothing is lost. */
  .cf-clip__label, .cf-tag { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   LIGHT THEME — dark in both, same rule as .page-hero / .sv-close.
   ══════════════════════════════════════════════════════════════════════ */
[data-theme="light"] .cf-hero { background: #0a0a0a; }
[data-theme="light"] .cf-hero .cf-h1 { color: #f5f1e8; }
[data-theme="light"] .cf-hero .cf-lede { color: rgba(245,241,232,.58); }
[data-theme="light"] .cf-hero .cf-eyebrow { color: #e8455a; }
[data-theme="light"] .cf-hero .cf-jump a { color: rgba(245,241,232,.6); border-bottom-color: rgba(245,241,232,.22); }
[data-theme="light"] .cf-hero .cf-jump a:hover { color: #f5f1e8; }
