/* ==========================================================================
   Home film sequence — scroll-driven architectural study.

   The 6s photoreal render (720x720 on desktop, 720x1280 cropped for mobile,
   both on a white ground) is drawn right-anchored on a matching paper surface,
   so film and page share one continuous white and copy owns the true negative
   space. Interface vocabulary borrows the site's drawing-sheet HUD (sheet
   numbers, revision codes, survey dimensions). Frames are built by
   scripts/extract_film_frames.py — never by hand.

   Deliberately theme-fixed: the section is a sheet of drafting paper and stays
   paper in dark mode, so every color here is a literal — not a semantic token
   that would re-theme underneath the fixed footage. Brand green matches the
   light-theme --color-brand.

   Motion: everything eases on cubic-bezier(0.16, 1, 0.3, 1) — the same
   --ease-out-expo the rest of the site uses.
   ========================================================================== */

.film-scope {
  --film-paper: #f5f5f4;
  --film-ink: #26282e;
  --film-ink-muted: #4a4e60;
  --film-survey: #66799e;
  --film-brand: #128759;
  --film-brand-strong: #0e6d47;
  --film-line: rgba(38, 40, 46, 0.16);
  --film-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --film-gutter: clamp(20px, 4.2vw, 72px);
  --film-progress: 0;
  --film-intro-opacity: 1;
}

.film-sequence {
  position: relative;
  height: 520vh;
  background: var(--film-paper);
}

.film-stage {
  position: sticky;
  top: 0;
  width: 100%;
  height: 100svh;
  overflow: hidden;
  background: var(--film-paper);
  isolation: isolate;
}

.film-canvas {
  position: absolute;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
}

/* Survey grid — a drawing sheet, not a screen effect. */
.film-grid {
  position: absolute;
  inset: 0 var(--film-gutter);
  z-index: 2;
  background-image: repeating-linear-gradient(
    90deg,
    transparent 0,
    transparent calc(8.333% - 1px),
    rgba(38, 40, 46, 0.05) calc(8.333% - 1px),
    rgba(38, 40, 46, 0.05) 8.333%
  );
  mask-image: linear-gradient(180deg, transparent, black 14%, black 82%, transparent);
  opacity: 0.6;
  pointer-events: none;
}

/* --------------------------------------------------------------------------
   Drafting overlay: dimension lines draw themselves on arrival.
   Stroke-dashoffset, 1200ms, 200ms stagger — no animation library needed.
   -------------------------------------------------------------------------- */
.film-draft {
  position: absolute;
  z-index: 3;
  top: 0;
  right: 0;
  height: 100%;
  aspect-ratio: 1 / 1;
  max-width: 100%;
  opacity: var(--film-intro-opacity);
  transition: opacity 400ms ease;
  pointer-events: none;
}

.film-draft path,
.film-draft circle {
  stroke: var(--film-survey);
  stroke-width: 1.4;
  fill: none;
  vector-effect: non-scaling-stroke;
}

.film-draft [pathLength] {
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 1200ms var(--film-ease);
}

.film-scope.is-ready .film-draft [pathLength] { stroke-dashoffset: 0; }

.film-draft .film-d1 { transition-delay: 200ms; }
.film-draft .film-d2 { transition-delay: 400ms; }
.film-draft .film-d3 { transition-delay: 600ms; }
.film-draft .film-d4 { transition-delay: 800ms; }

.film-draft text {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 9px;
  letter-spacing: 0.08em;
  fill: var(--film-survey);
  stroke: none;
  opacity: 0;
  transition: opacity 600ms 1100ms ease;
}

.film-scope.is-ready .film-draft text { opacity: 1; }

@media (max-width: 1100px) {
  .film-draft { display: none; }
}

/* --------------------------------------------------------------------------
   Chapters
   -------------------------------------------------------------------------- */
.film-chapters {
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
}

.film-chapter {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  align-content: center;
  column-gap: clamp(10px, 1.2vw, 20px);
  padding: 96px var(--film-gutter) 104px;
  visibility: hidden;
}

.film-chapter.is-visible { visibility: visible; }

.film-chapter__copy {
  position: relative;
  align-self: center;
}

.film-micro {
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 10px;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.film-chapter__eyebrow {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 22px;
  color: var(--film-ink-muted);
}

.film-chapter__eyebrow::before {
  content: "";
  width: 26px;
  height: 2px;
  background: var(--film-brand);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 900ms 100ms var(--film-ease);
}

.film-chapter.is-visible .film-chapter__eyebrow::before { transform: scaleX(1); }

.film-reveal {
  overflow: hidden;
  padding-bottom: 0.08em;
}

.film-reveal > span {
  display: block;
  transform: translateY(112%);
  transition: transform 1100ms var(--film-ease);
}

.film-reveal:nth-child(3) > span { transition-delay: 200ms; }
.film-reveal:nth-child(4) > span { transition-delay: 400ms; }
.film-chapter.is-visible .film-reveal > span { transform: translateY(0); }

.film-chapter__title {
  /* Pay back the leading this title borrows.
     line-height: 0.86 makes the element's box shorter than the glyphs it
     contains, so the last line's ink overhangs the box by ~0.09em — measured
     at 7.8px on the 86px titles, 10.6px on the 104px hero. Everything below is
     laid out from the box, not the ink, so the deck's nominal 24px margin-top
     rendered as a real gap of 13-17px and the type read as crowded.

     This is padding, not margin, deliberately: a margin-bottom here collapses
     against the deck's larger margin-top and changes nothing at all (tried it
     — the measured gap did not move). Padding cannot collapse, so the box
     genuinely grows and the deck is pushed clear.

     It also supersedes .film-reveal's own 0.08em padding-bottom on this
     element, which is safe because it is strictly more room inside the same
     overflow:hidden clip box. 0.18em is measured, not guessed: the ink sits
     0.17em below the content box (0.08em of it already covered by the reveal
     padding), so this contains the last line completely and hands the deck its
     full 24px. Keep it paired with line-height — change one, re-measure. */
  margin: 0;
  padding-bottom: 0.18em;
  color: var(--film-ink);
  /* Explicit family: the site's heading styles are serif (Playfair) — the
     drawing sheet is set in the precision grotesk, whatever the page uses. */
  font-family: "Inter", system-ui, sans-serif;
  font-size: clamp(44px, 6vw, 96px);
  font-weight: 740;
  letter-spacing: -0.055em;
  line-height: 0.86;
  text-transform: uppercase;
  text-wrap: balance;
}

.film-chapter__deck {
  max-width: 30rem;
  margin: 24px 0 0;
  color: var(--film-ink-muted);
  font-family: "Inter", system-ui, sans-serif;
  font-size: clamp(17px, 1.5vw, 23px);
  font-weight: 450;
  line-height: 1.3;
  letter-spacing: -0.02em;
  text-wrap: balance;
}

.film-chapter__fact {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 14px;
  align-items: baseline;
  margin-top: 30px;
  padding-top: 12px;
  border-top: 1px solid var(--film-line);
  color: var(--film-survey);
  max-width: 30rem;
}

.film-chapter__fact .film-num { color: var(--film-brand-strong); }

.film-chapter--hero { align-content: end; }
.film-chapter--hero .film-chapter__copy { grid-column: 1 / 9; padding-bottom: 5vh; }

.film-chapter--hero .film-chapter__title {
  font-size: clamp(52px, 7.2vw, 120px);
  line-height: 0.84;
  letter-spacing: -0.06em;
}

.film-chapter--hero .film-chapter__deck { max-width: 26rem; }

.film-chapter__actions { margin-top: 34px; }

/* The reveal span is the moving element; it also lays out the CTA pair. */
.film-chapter__actions > span {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}

.film-chapter--left .film-chapter__copy { grid-column: 1 / 6; }
.film-chapter--wide .film-chapter__copy { grid-column: 1 / 7; }

/* Wide chapters carry the longest single words ("stakeholder",
   "full-lifecycle") — step the display size down so no word can outgrow
   its column and get clipped by the reveal's overflow:hidden. */
.film-chapter--wide .film-chapter__title { font-size: clamp(40px, 5.2vw, 84px); }

.film-chapter--index { align-content: center; }
.film-chapter--index .film-chapter__copy { grid-column: 1 / 6; z-index: 2; }

.film-chapter__giant-index {
  position: absolute;
  z-index: -1;
  right: var(--film-gutter);
  top: 50%;
  color: transparent;
  font-family: "Inter", system-ui, sans-serif;
  font-size: clamp(260px, 40vw, 640px);
  font-weight: 800;
  letter-spacing: -0.09em;
  line-height: 0.7;
  -webkit-text-stroke: 1px rgba(38, 40, 46, 0.18);
  transform: translateY(-48%);
  opacity: 0;
  transition: opacity 800ms ease, letter-spacing 1400ms var(--film-ease);
}

.film-chapter.is-visible .film-chapter__giant-index {
  opacity: 1;
  letter-spacing: -0.04em;
}

.film-chapter--final { align-content: end; }

.film-chapter--final .film-chapter__copy {
  grid-column: 1 / 13;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  gap: 32px;
  padding-bottom: 4vh;
}

.film-chapter--final .film-chapter__title {
  max-width: 13ch;
  font-size: clamp(52px, 7.4vw, 128px);
}

.film-cta {
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 40px;
  min-width: min(100%, 280px);
  min-height: 54px;
  padding: 0 18px;
  border: 1px solid var(--film-ink);
  background: rgba(245, 245, 244, 0.6);
  color: var(--film-ink);
  font-family: "JetBrains Mono", ui-monospace, monospace;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-decoration: none;
  text-transform: uppercase;
  transition: color 250ms ease, background 250ms ease, border-color 250ms ease;
}

.film-cta::after { content: "↗"; font-size: 16px; }

.film-cta:hover {
  background: var(--film-brand);
  border-color: var(--film-brand);
  color: #fff;
}

.film-cta--ghost {
  border-color: rgba(38, 40, 46, 0.34);
  min-width: 0;
  gap: 20px;
}

/* --------------------------------------------------------------------------
   Telemetry — the sheet's title block
   -------------------------------------------------------------------------- */
.film-telemetry {
  position: absolute;
  inset: auto var(--film-gutter) max(18px, env(safe-area-inset-bottom));
  z-index: 8;
  display: grid;
  grid-template-columns: auto minmax(100px, 1fr) auto auto auto;
  align-items: center;
  gap: 18px;
  color: var(--film-ink-muted);
  pointer-events: none;
}

.film-telemetry__track {
  position: relative;
  height: 1px;
  overflow: hidden;
  background: rgba(38, 40, 46, 0.18);
}

.film-telemetry__fill {
  position: absolute;
  inset: 0;
  background: var(--film-brand);
  transform: scaleX(var(--film-progress));
  transform-origin: left;
  will-change: transform;
}

.film-telemetry__chapter { min-width: 15ch; }
.film-telemetry__frame { color: var(--film-survey); }

.film-telemetry__rev {
  color: var(--film-survey);
  border: 1px solid var(--film-line);
  padding: 3px 8px;
}

/* "Scroll to drive" is an invitation, not a status readout: it belongs to the
   opening and has nothing left to say once the film is running, yet it used to
   sit in the title block at full strength all the way to the CTA. It now rides
   the same --film-intro-opacity as the drafting overlay, so both retire over
   the first 10% of the sequence. No a11y handling needed — the whole telemetry
   block is already aria-hidden and pointer-events:none. */
.film-scroll-cue {
  display: inline-grid;
  grid-template-columns: auto 18px;
  align-items: center;
  gap: 9px;
  color: var(--film-ink);
  opacity: var(--film-intro-opacity);
  transition: opacity 400ms ease;
}

.film-scroll-cue::after {
  content: "";
  width: 18px;
  height: 18px;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: rotate(45deg) translate(-3px, 3px);
  animation: film-cue 1.8s ease-in-out infinite;
}

@keyframes film-cue {
  0%, 100% { transform: rotate(45deg) translate(-3px, 3px); opacity: 0.35; }
  50% { transform: rotate(45deg) translate(1px, 7px); opacity: 1; }
}

/* --------------------------------------------------------------------------
   Portrait art direction — phones, and any window taller than it is wide.

   The query must stay byte-identical to MOBILE_QUERY in home-film.js: that
   file picks the frame set (square vs portrait crop) and this one lays the
   chapters out to match. If they drift apart the engine draws a full-bleed
   portrait film under a layout still reserving a left copy column, or the
   reverse.
   -------------------------------------------------------------------------- */
@media (max-width: 780px), (max-aspect-ratio: 9 / 10) {
  .film-scope { --film-gutter: 20px; }

  .film-sequence { height: 460vh; }
  /* The film is full-bleed on mobile, so the survey grid now overlays the
     building rather than mostly paper — keep it faint so it reads as a
     drafting overlay, not clutter. */
  .film-grid { opacity: 0.22; }

  .film-chapter {
    grid-template-columns: repeat(6, minmax(0, 1fr));
    align-content: end;
    padding: 76px var(--film-gutter) 100px;
  }

  .film-chapter__copy,
  .film-chapter--hero .film-chapter__copy,
  .film-chapter--left .film-chapter__copy,
  .film-chapter--wide .film-chapter__copy,
  .film-chapter--index .film-chapter__copy,
  .film-chapter--final .film-chapter__copy {
    grid-column: 1 / 7;
  }

  .film-chapter__eyebrow { margin-bottom: 14px; }
  .film-chapter__title { font-size: clamp(42px, 12.5vw, 72px); line-height: 0.88; }
  .film-chapter__deck { max-width: 24rem; margin-top: 14px; font-size: 16px; }
  .film-chapter__fact { margin-top: 16px; }

  .film-chapter--hero .film-chapter__copy { padding-bottom: 2vh; }
  .film-chapter--hero .film-chapter__title { font-size: clamp(36px, 10.8vw, 60px); }
  .film-chapter--hero .film-chapter__deck { max-width: 19rem; }
  .film-chapter__actions { margin-top: 22px; }

  .film-chapter__giant-index {
    right: -5vw;
    top: 11vh;
    font-size: 56vw;
    transform: none;
  }

  .film-chapter--final .film-chapter__copy { display: block; }
  .film-chapter--final .film-chapter__title { max-width: 10ch; }
  .film-chapter--final .film-cta { margin-top: 22px; }

  .film-telemetry {
    grid-template-columns: auto 1fr auto;
    gap: 12px;
  }

  .film-telemetry__chapter { min-width: 9ch; }
  .film-telemetry__rev,
  .film-scroll-cue { display: none; }
}

/* --------------------------------------------------------------------------
   No-JS: the scroll theatre needs the engine, so without it the section
   collapses into a plain stacked hero — every chapter fully readable.
   (base.html adds .js to <html> pre-paint.)

   .film-scope.is-failed takes the same route at runtime. home-film.js sets it
   when no frame can be fetched at all — a deploy that dropped static/film/, an
   offline repeat visit. The chapters are already in the DOM and the copy is
   the real hero content, so stacking them costs nothing and beats the
   alternative: five screens of blank paper with the <h1> hidden inside it.
   -------------------------------------------------------------------------- */
html:not(.js) .film-sequence,
.film-scope.is-failed .film-sequence { height: auto; }

html:not(.js) .film-stage,
.film-scope.is-failed .film-stage {
  position: static;
  height: auto;
  overflow: visible;
}

html:not(.js) .film-canvas,
html:not(.js) .film-draft,
html:not(.js) .film-grid,
html:not(.js) .film-telemetry,
.film-scope.is-failed .film-canvas,
.film-scope.is-failed .film-draft,
.film-scope.is-failed .film-grid,
.film-scope.is-failed .film-telemetry { display: none; }

html:not(.js) .film-chapter,
.film-scope.is-failed .film-chapter {
  position: static;
  visibility: visible;
  padding: 64px var(--film-gutter);
}

html:not(.js) .film-reveal > span,
.film-scope.is-failed .film-reveal > span { transform: translateY(0); }

html:not(.js) .film-chapter__eyebrow::before,
.film-scope.is-failed .film-chapter__eyebrow::before { transform: scaleX(1); }

html:not(.js) .film-chapter__giant-index,
.film-scope.is-failed .film-chapter__giant-index { display: none; }

/* --------------------------------------------------------------------------
   Reduced motion: a stable poster composition, no scroll theatre.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .film-sequence { height: 100svh; }
  .film-chapter:not(.film-chapter--hero) { display: none; }
  .film-chapter--hero { visibility: visible; }
  .film-chapter--hero .film-reveal > span { transform: translateY(0); }
  .film-chapter--hero .film-chapter__eyebrow::before { transform: scaleX(1); }
  .film-draft [pathLength] { stroke-dashoffset: 0; transition: none; }
  .film-draft text { opacity: 1; transition: none; }
  .film-scroll-cue::after { animation: none; }
  .film-telemetry { display: none; }
}
