/* ============================================================
   film.css — filmography list (Film / Music Videos) and film
   detail Template B (BRIEF §5). Values from reference
   film.dc.html / film-detail.dc.html, canvas px × --u.
   ============================================================ */

/* ---- filmography rows ---- */
.films {
  position: relative;
  z-index: 2;
  max-width: calc(1280 * var(--u));
  margin: calc(80 * var(--u)) auto 0;
  padding: 0 calc(64 * var(--u));
}

.film-row {
  display: grid;
  grid-template-columns: 7fr 5fr;
  column-gap: calc(64 * var(--u));
  align-items: center;
  transition: opacity 0.5s ease;
}

.film-row--flip {
  grid-template-columns: 5fr 7fr;
}

.film-row + .film-row {
  margin-top: calc(110 * var(--u));
}

/* Hovering one film dims the others to 0.55 — a focus effect, on BOTH
   lists this file serves (Film index and Music Videos).

   Its history, because it has one. It shipped with the template, was
   REMOVED on 03.09.2026 while hunting why the Chemins hero read weaker
   on the index than the same file does on the film's own page: the
   pointer is over the list the whole time you are reading it, so in
   practice every still except the one under the cursor lived at 55%
   over INK, which lifts the blacks and costs real contrast. RESTORED
   13.09.2026 — the author wants the focus on the film he is pointing
   at, and the "half-grey frames under the cursor" argument is
   overruled. Same 0.55, same 0.5s ease (the transition is on
   .film-row above and was never taken off); no new choreography.

   Dimming is OPACITY, deliberately — it composites, where a filter
   would re-rasterise three large pictures on the same half-second the
   hovered row is zooming. The hovered row is untouched by this rule:
   opacity 1, filter lifted to none, and its loop plays.

   At REST no row is dimmed — :has needs a hovered row to match — so
   the note about Chemins reading flat in the list stands only while
   the pointer is on a different row. */
/* Pointer-only, like every hover on the site (the guard and its
   reasoning are in base.css). This replaces the `@media (hover: none)`
   undo that used to follow the rule: a tap can leave :hover stuck on
   a row and would otherwise freeze the whole list at 0.55. The rule
   is simply not there to stick now. */
@media (hover: hover) and (pointer: fine) {
  .films:has(.film-row:hover) .film-row:not(:hover) {
    opacity: 0.55;
  }
}

.film-row__still {
  grid-column: 1;
  grid-row: 1;
  position: relative;
  display: block;
  aspect-ratio: 2.2 / 1;
  overflow: hidden;
  background: #161a20;
}

.film-row--flip .film-row__still {
  grid-column: 2;
}

.film-row__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: var(--grade-filter);
  transition: transform var(--hover-zoom-time) var(--ease-slide), opacity 0.6s ease;
}

.film-row__img--raw {
  filter: none;
  opacity: 0;
  pointer-events: none;
}

/* PER-FILM grade opt-out (author, 01.08.2026). The site grade stays
   on the filmography by default — it is the §4 language, and the
   01.08 attempt to lift it off the whole Film index was reverted.
   What a film CAN do is opt its own still out, so its tile matches
   its detail page, where the film's frames already render ungraded
   (§6c). Driven by `grade: false` in the film's data, never by page
   or position; absent = graded, so nothing changes for a film that
   does not ask. NO FILM sets it today (author, 14.09.2026): all four
   rows carry the grade at rest again, like every other list on the
   site, and hover lifts it as everywhere. The rule stays because the
   opt-out stays available.

   Note for the record: the grade is not what makes the Chemins tile
   read grey next to its neighbours — it costs that still only
   0.127 → 0.104 saturation while the others sit at 0.33–0.55. This
   is about the tile matching its own detail page, which is what was
   asked; the neighbour gap is a frame-choice question (posterSrc). */
.film-row__img--nograde {
  filter: none;
}

.film-row:focus-within .film-row__img {
  transform: scale(1.025);
}

@media (hover: hover) and (pointer: fine) {
  .film-row:hover .film-row__img {
    transform: scale(1.025);
  }
}

.film-row:focus-within .film-row__img--raw {
  opacity: 1;
}

@media (hover: hover) and (pointer: fine) {
  .film-row:hover .film-row__img--raw {
    opacity: 1;
  }
}

/* the hover loop (base.css .hover-loop) rides the same 1.025 zoom as
   the still under it — created mid-hover, it renders already scaled,
   so there is no snap back when the video fades in (same pattern as
   the category work tiles) */
@media (hover: hover) and (pointer: fine) {
  .film-row__still .hover-loop {
    transition: opacity 0.18s ease, transform var(--hover-zoom-time) var(--ease-slide);
  }

  .film-row:hover .hover-loop,
  .film-row:focus-within .hover-loop {
    transform: scale(1.025);
  }
}

/* ---- BLEED row (BRIEF §6d): the §6c derivation on the index ----
   aspect >= 16:9, so the film is made to fill a screen and fills the
   measure here — still across the full 1280u width, title block
   BELOW it. Nothing over the picture: no scrim, no overlaid type.
   The still keeps its own ratio from the inline style, so the box
   ratio equals the file ratio and object-fit: cover has nothing to
   crop. Hung rows (aspect < 16:9) are untouched above. */
.film-row--bleed {
  grid-template-columns: 1fr;
  /* the same 64u the hung row puts BETWEEN still and text as its
     column gap — one token, turned on its side */
  row-gap: calc(64 * var(--u));
  align-items: start;
}

.film-row--bleed .film-row__still {
  grid-column: 1;
  grid-row: 1;
}

.film-row--bleed .film-row__text {
  grid-column: 1;
  grid-row: 2;
  align-items: flex-start;
  text-align: left;
}

.film-row__text {
  grid-column: 2;
  grid-row: 1;
  display: flex;
  flex-direction: column;
  gap: calc(22 * var(--u));
  align-items: flex-start;
  text-align: left;
  min-width: 0;
}

.film-row--flip .film-row__text {
  grid-column: 1;
  align-items: flex-end;
  text-align: right;
}

/* serif italic = film titles (type roles, BRIEF §4) */
.film-row__title {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 500;
  font-size: calc(72 * var(--u));
  line-height: 1.02;
  letter-spacing: 0.01em;
  color: var(--paper);
  text-wrap: balance;
}

/* a two-part title breaks at its comma — the halves are blocks, so the
   line count is exactly 2 and never depends on how wide the column
   happens to be (build: displayTitle) */
.film-row__title-part,
.mount__title-part {
  display: block;
}

/* …and the long form steps down, because at the base 72u the longer
   half ("Parcours Interrompu", ~546px) outruns the 5fr text column
   (~453px at 1440) and would wrap to a third line on its own */
.film-row__title--long {
  font-size: calc(56 * var(--u));
}

.film-row__meta {
  font-family: var(--font-mono);
  font-size: max(calc(10 * var(--u)), 9px);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--secondary);
}

/* ============================================================
   MV project page (BRIEF §6b) — media at full content-column
   width in the work's native ratio (shared .facade, base.css),
   then title block + credits. No synopsis, no lyrics.
   ============================================================ */
.project {
  position: relative;
  z-index: 2;
  max-width: calc(1280 * var(--u));
  margin: calc(52 * var(--u)) auto 0;
  padding: 0 calc(64 * var(--u));
}

.project__media {
  position: relative;
  width: 100%;
  overflow: hidden;
  background: #161a20;
}

.project__media iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* serif italic display line: ARTIST — “Title” */
.project__cols {
  display: grid;
  grid-template-columns: 7fr 5fr;
  column-gap: calc(64 * var(--u));
  align-items: start;
  margin-top: calc(44 * var(--u));
}

.project__title {
  margin: 0;
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 500;
  font-size: calc(56 * var(--u));
  line-height: 1.05;
  letter-spacing: 0.01em;
  color: var(--paper);
  text-wrap: balance;
}

.project__meta {
  margin: calc(20 * var(--u)) 0 0;
  font-family: var(--font-mono);
  font-size: max(calc(10 * var(--u)), 9px);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--secondary);
}

/* credits: [role] Name, one per line, up to 7 lines (BRIEF §6b);
   no heading — the run itself is the section.

   ROLE SECONDARY, NAME PAPER (14.09.2026) — the film detail pages'
   treatment, which this list is supposed to share and did not. It
   coloured the whole line `--secondary`, so the NAMES came out grey
   here and paper three clicks away on a film page; the markup had no
   role element to address, which is why nobody could see it in the
   stylesheet alone. Both emitters are one function now and both emit
   the `.mount-credits__role` span, so the colour below applies to the
   name and the shared role rule takes the bracket back to secondary.
   The context block under this one is NOT crew and keeps its own
   quieter treatment. */
.project__credits {
  --credits-step: calc(10 * var(--u)); /* the list's own rhythm; see .credits-author */
  list-style: none;
  margin: calc(6 * var(--u)) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--credits-step);
  font-family: var(--font-mono);
  font-size: max(calc(9.5 * var(--u)), 8.5px);
  letter-spacing: 0.14em;
  color: var(--paper);
}

/* context: song attribution + place under the credits (BRIEF §6b) —
   not crew, so no brackets; one size step down from the credits,
   dimmed to the numerals gray, a clear pause above, no heading */
.project__context {
  margin-top: calc(30 * var(--u));
  display: flex;
  flex-direction: column;
  gap: calc(8 * var(--u));
  font-family: var(--font-mono);
  font-size: max(calc(8.5 * var(--u)), 8px);
  letter-spacing: 0.14em;
  color: var(--numerals);
}

@media (max-width: 768px) {
  .project {
    margin-top: 24px;
    padding: 0; /* main already carries the 20px page inset */
  }

  .project__cols {
    grid-template-columns: 1fr;
    row-gap: 28px;
    margin-top: 24px;
  }

  .project__title {
    font-size: clamp(26px, 7.5vw, 34px);
  }
}

/* ============================================================
   Film detail — Template B
   ============================================================ */

/* header-over-poster behavior comes from .has-hero-header (base.css) */

/* ---- full-bleed poster ---- */
.poster {
  position: relative;
  z-index: 1;
  height: 78vh;
  min-height: 540px;
  overflow: hidden;
  background: #161a20;
}

/* The picture and its scrim sit in their own box inside the hero.
   On DESKTOP that box IS the hero — absolute, inset 0 — so nothing
   about the full-bleed composition changes; the wrapper exists so
   that on a phone the picture can become a contained frame with the
   title block following it in flow, instead of the title being
   absolutely positioned over a crop. */
.poster__frame {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

.poster__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: var(--grade-filter);
}

/* the bleed hero is a frame of the film like any other, and a film's
   own frames are shown as the FILM was graded — so the whole composed
   detail page is ungraded (§6c), hero, frames grid and poster alike.
   Unconditional: it is a property of the PAGE, not of the film. The
   per-film `grade` flag opts the INDEX TILE out and reaches nothing
   here (14.09.2026 — the two used to share one switch). */
.poster__img--nograde {
  filter: none;
}

.poster__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(11, 14, 19, 0.66) 0%,
    rgba(11, 14, 19, 0.14) 32%,
    rgba(11, 14, 19, 0.08) 55%,
    rgba(11, 14, 19, 0.82) 100%
  );
}

.poster__titleblock {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(58 * var(--u));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(26 * var(--u));
  text-align: center;
  padding: 0 calc(40 * var(--u));
}

/* serif italic = display lines + film titles */
.poster__title {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 500;
  font-size: calc(118 * var(--u));
  line-height: 0.98;
  letter-spacing: 0.005em;
  color: var(--paper);
  text-wrap: balance;
  text-shadow: 0 2px 40px rgba(11, 14, 19, 0.55);
}

.poster__meta {
  font-family: var(--font-mono);
  font-size: max(calc(10.5 * var(--u)), 9px);
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--tagline-color);
  line-height: 1;
}

/* ---- inline player ---- */
.film-player {
  position: relative;
  z-index: 2;
  max-width: calc(1080 * var(--u));
  margin: calc(76 * var(--u)) auto 0;
  padding: 0 calc(64 * var(--u));
}

.film-player__frame {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  background: #161a20;
  border: 0;
  padding: 0;
  cursor: pointer;
}

.film-player__frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

.film-player__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: var(--grade-filter);
  transform: scale(1);
  transition: transform 0.9s var(--ease-slide), opacity 0.6s ease;
}

.film-player__img--raw {
  filter: none;
  opacity: 0;
  pointer-events: none;
}

.film-player__frame:focus-visible .film-player__img {
  transform: scale(1.02);
}

@media (hover: hover) and (pointer: fine) {
  .film-player__frame:hover .film-player__img {
    transform: scale(1.02);
  }
}

.film-player__frame:focus-visible .film-player__img--raw {
  opacity: 1;
}

@media (hover: hover) and (pointer: fine) {
  .film-player__frame:hover .film-player__img--raw {
    opacity: 1;
  }
}

.film-player__play {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0.85;
  transition: opacity 0.5s ease;
  pointer-events: none;
}

.film-player__frame:hover .film-player__play {
  opacity: 1;
}

.film-player__play::before {
  content: "";
  width: 66px;
  height: 66px;
  border: 1px solid rgba(233, 233, 228, 0.55);
  border-radius: 50%;
}

.film-player__play::after {
  content: "";
  position: absolute;
  width: 0;
  height: 0;
  border-left: 13px solid rgba(233, 233, 228, 0.9);
  border-top: 8px solid transparent;
  border-bottom: 8px solid transparent;
  margin-left: 4px;
}

.film-player__note {
  position: absolute;
  left: calc(22 * var(--u));
  bottom: calc(18 * var(--u));
  font-family: var(--font-mono);
  font-size: max(calc(9.5 * var(--u)), 8.5px);
  letter-spacing: var(--meta-tracking);
  color: rgba(233, 233, 228, 0.75);
  pointer-events: none;
}

/* ---- synopsis & laurels ---- */
.synopsis {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(30 * var(--u));
  margin: calc(72 * var(--u)) auto 0;
  padding: 0 calc(64 * var(--u));
  max-width: calc(1080 * var(--u));
  text-align: center;
}

.synopsis__text {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  font-size: calc(26 * var(--u));
  line-height: 1.45;
  letter-spacing: 0.01em;
  color: var(--tagline-color);
  max-width: 44ch;
  text-wrap: balance;
}

/* ---- synopsis BESIDE the credits (author, 02.08.2026) ----
   The bleed page puts the description and the credits shoulder to
   shoulder instead of stacking them: the §6b column ratio again, text
   on the 7fr and credits on the 5fr, so the film pages and the MV
   project pages keep reading as one system. Left-aligned in both
   columns — the centred synopsis only made sense while it stood alone
   across the page. */
.film-cols {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: 7fr 5fr;
  column-gap: calc(64 * var(--u));
  align-items: start;
  max-width: calc(1280 * var(--u));
  margin: calc(72 * var(--u)) auto 0;
  padding: 0 calc(64 * var(--u));
}

.film-cols__text {
  min-width: 0;
}

/* Beside the credits the synopsis is READING copy, not a display line
   (author, 02.08.2026: much smaller, no italic). It takes the body
   treatment the About statement already established in §7 — Space
   Grotesk, fluid 15–17px, line-height 1.65, dimmed to ~80% paper —
   rather than the Cormorant italic it wore while it stood alone
   across the page. */
.film-cols .synopsis__text {
  max-width: none;
  font-family: var(--font-grotesque);
  font-style: normal;
  font-weight: 400;
  font-size: clamp(15px, 1.15vw, 17px);
  line-height: 1.65;
  letter-spacing: 0;
  color: var(--paper);
  opacity: 0.8;
  text-align: left;
  text-wrap: pretty;
}

.film-cols__credits {
  min-width: 0;
  text-align: left;
}

.film-cols__credits .mount-label {
  text-align: left;
  margin-bottom: calc(14 * var(--u));
}

.film-cols__credits .mount-credits__list {
  --credits-lh: 1.95;
  font-size: max(calc(9.5 * var(--u)), 8.5px);
  line-height: var(--credits-lh);
}

.film-cols__credits .mount-context {
  margin-top: calc(30 * var(--u));
  font-size: max(calc(9 * var(--u)), 8px);
  line-height: 1.9;
}

.synopsis__laurels {
  font-family: var(--font-mono);
  font-size: max(calc(9.5 * var(--u)), 8.5px);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--numerals);
  line-height: 2;
}

/* prev / next rail (.film-nav) lives in base.css — shared with case pages */

/* ============================================================
   Mobile (≤768px): the staggered composition drops. Per film:
   full-width 16:9 still, serif italic title clamped to always
   fit the viewport, ONE metadata line. Left-aligned block,
   consistent rhythm. Desktop untouched.
   ============================================================ */
@media (max-width: 768px) {
  .films {
    margin-top: 40px;
    padding: 0; /* main already carries the 20px page inset */
  }

  .film-row,
  .film-row--flip {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 16px;
  }

  .film-row + .film-row {
    margin-top: 52px;
  }

  .film-row__still {
    width: 100%;
    aspect-ratio: 16 / 9;
  }

  .film-row__text,
  .film-row--flip .film-row__text {
    align-items: flex-start;
    text-align: left;
    gap: 10px;
  }

  /* clamp keeps long titles inside the viewport; words wrap */
  .film-row__title {
    font-size: clamp(30px, 10.5vw, 54px);
    line-height: 1.05;
  }

  .film-row__meta {
    font-size: 9px;
    letter-spacing: 0.18em;
  }
}

/* ============================================================
   Film detail — MOUNT mode (BRIEF §5: aspect < 16:9). The frame
   hangs whole, centered on INK — the aspect is sacred, no crop in
   any viewport: the frame width is min(ideal, container) and the
   height derives from the data aspect-ratio. Everything below is
   one centered composition (approved mockup). Bleed pages
   (aspect >= 16:9) keep Template B above — untouched.
   ============================================================ */

/* Mount — ASIDE composition (01.08.2026, borrowed from the MV project
   page §6b): the frame is no longer centred. It hangs RIGHT, with the
   title and credits standing to its left, right-aligned against it —
   the same hand as this film's row on the Film index, which is a
   flipped row (author's reason for choosing this side). The synopsis
   is NOT in this column: it stays centred below the composition. Supersedes the centred
   composition described in BRIEF §6c — the brief is NOT updated until
   the author approves this.

   Same column ratio as .project__cols (7fr 5fr) so the two page types
   read as one system. The frame takes its width from its column and
   its height from the data aspect, so the still is still never
   cropped — the old min(68vh, 620px) height cap is what made the
   composition centred, and it is gone here. */
.mount {
  display: flex;
  justify-content: center;
  margin-top: calc(56 * var(--u));
}

.mount--aside {
  display: grid;
  grid-template-columns: 5fr 7fr; /* text 5fr left · frame 7fr right */
  column-gap: calc(64 * var(--u));
  align-items: start;
  max-width: calc(1280 * var(--u));
  margin: calc(52 * var(--u)) auto 0;
  padding: 0 calc(64 * var(--u));
}

.mount__frame {
  position: relative;
  /* --mount-w = min(68vh, 620px) × aspect, set inline from data */
  width: min(var(--mount-w), 100%);
  background: #161a20;
}

/* the frame keeps DOM order (it comes first, so it leads on a phone)
   and is placed into the right column explicitly */
.mount--aside .mount__frame {
  width: 100%;
  grid-column: 2;
  grid-row: 1;
}

/* the aside column: title, meta, credits, context — right-aligned so
   the type hangs against the frame's edge, exactly as a flipped row
   behaves in the filmography */
.mount__aside {
  min-width: 0;
  grid-column: 1;
  grid-row: 1;
  text-align: right;
}

/* the title is sized to its COLUMN here, not to the viewport: at the
   centred layout's clamp(44px, 6.5vw, 84px) the longer half of a
   two-part title overruns a 5fr column several times over */
.mount--aside .mount__title {
  font-size: calc(56 * var(--u));
}

.mount--aside .mount__title--long {
  font-size: calc(44 * var(--u));
}

.mount--aside .mount__subtitle {
  font-size: clamp(18px, 2.2vw, 26px);
}

/* credits sit under the meta line in the same column — the label keeps
   the film page's museum grammar (§6c), aligned with its column */
.mount__credits {
  margin-top: calc(52 * var(--u));
}

.mount__credits .mount-label {
  text-align: right;
  margin-bottom: calc(14 * var(--u));
}

.mount__credits .mount-credits__list {
  --credits-lh: 1.95;
  font-size: max(calc(9.5 * var(--u)), 8.5px);
  line-height: var(--credits-lh);
}

.mount__credits .mount-context {
  margin-top: calc(30 * var(--u));
  font-size: max(calc(9 * var(--u)), 8px);
  line-height: 1.9;
}

.mount__frame > img,
.mount__frame > .facade {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

/* the frame ratio equals the still's own ratio — cover never crops.
   NO GRADE (author, 01.08.2026): a film's own frames are shown as the
   film was graded, not as the site grades imagery. The site grade
   costs this material real punch — measured on these stills it takes
   ~6% off brightness AND contrast and 18–36% off saturation, which on
   an already near-monochrome frame reads as grey. The rest/hover
   pairing does not exist here anyway: nothing on this page is
   hoverable. */
.mount__frame > img {
  object-fit: cover;
  filter: none;
}

/* …and the same when the frame is a player facade: with a video the
   still sits INSIDE the button, so the direct-child selector above
   misses it and the shared .facade grade (base.css) would put the
   site grade back on a film's own frame */
.mount__frame .facade img {
  filter: none;
}

/* The facade swaps itself for an iframe (yt-facade.js), and nothing
   was sizing it — the player rendered at the browser default 300×150
   in the corner of the frame. MV project pages have this rule on
   .project__media; the film frame never got one. */
.mount__frame > iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* and the frame opens to 16:9 once the film is playing — see the note
   in yt-facade.js. !important is load-bearing here: the still's ratio
   is an INLINE style written from the film's data, and an inline
   declaration outranks any class. */
.mount__frame--playing {
  aspect-ratio: 16 / 9 !important;
}

.mount__title {
  margin: 0;
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 500;
  font-size: clamp(44px, 6.5vw, 84px);
  line-height: 1.02;
  color: var(--paper);
  /* balance still helps single-part titles that happen to wrap; a
     two-part title is broken explicitly at its comma instead (the
     -part blocks above), so its line count does not depend on the
     viewport at all. */
  text-wrap: balance;
}

.mount__subtitle {
  margin: 6px 0 0;
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(22px, 3vw, 36px);
  color: var(--paper);
  opacity: 0.85;
}

.mount__meta {
  margin: calc(22 * var(--u)) 0 0;
  font-family: var(--font-mono);
  font-size: max(calc(11 * var(--u)), 9.5px);
  letter-spacing: var(--meta-tracking);
  text-transform: uppercase;
  color: var(--secondary);
}

/* centered mono label shared by the mount sections */
.mount-label {
  margin: 0 0 18px;
  font-family: var(--font-mono);
  font-size: max(calc(10 * var(--u)), 9px);
  letter-spacing: 0.26em;
  color: var(--numerals);
  text-align: center;
}

/* synopsis reuses the shared component. It used to step the measure
   down to ~620px, quieter than bleed — but on the page that reads as
   a hole: the frames grid runs the full 1152u measure and the credits
   and context hang off its left edge, while the description floated
   centred at 524px, aligned to nothing on either side. It now takes
   the page's own measure, the same box the frames grid uses, so the
   description starts and ends where the screenshots do (author,
   12.09.2026). Centred, as it always was — only the width changed. */
.synopsis--mount {
  margin-top: 96px;
  max-width: calc(1280 * var(--u));
  padding: 0 calc(64 * var(--u));
}

/* same reading treatment as the bleed page's column (author,
   02.08.2026) so both film-page types speak in one voice; only the
   centring differs here */
.synopsis--mount .synopsis__text {
  font-family: var(--font-grotesque);
  font-style: normal;
  font-weight: 400;
  font-size: clamp(15px, 1.15vw, 17px);
  line-height: 1.65;
  letter-spacing: 0;
  color: var(--paper);
  opacity: 0.8;
  /* max-width: none, exactly as the bleed page's column does it. Two
     caps were holding this line in: the 62ch that used to sit here,
     and the base rule's 44ch underneath it — dropping only the first
     left the block wide and the words still at 467px. The measure is
     the page's now, by the author's instruction; it is a long line by
     typographic convention and that was his call to make. */
  max-width: none;
  text-wrap: pretty;
}

/* ON PHOTOGRAPHY — reserved section (BRIEF: renders only when the
   film carries onPhotography text; null on all films today) */
.onphoto {
  max-width: calc(560px + 2 * var(--page-pad));
  margin: 84px auto 0;
  padding: 0 var(--page-pad);
  text-align: center;
}

.onphoto__text {
  font-family: var(--font-grotesque);
  font-weight: 400;
  font-size: 15px;
  line-height: 1.75;
  color: var(--paper);
  opacity: 0.92;
}

/* frames: 2-column grid of stills in the film's own ratio — no
   captions, no hover choreography */
.mount-frames {
  max-width: calc(980px + 2 * var(--page-pad));
  margin: 110px auto 0;
  padding: 0 var(--page-pad);
}

.mount-frames__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}

/* Both grids widen to the page's own 1280u measure so the frames do
   not end up as strips: at the old 980px measure three scope frames
   were 317px, here they are ~374px. */
.mount-frames:has(.mount-frames__grid--3up),
.mount-frames:has(.mount-frames__grid--4up) {
  max-width: calc(1280 * var(--u));
  padding: 0 calc(64 * var(--u));
}

/* wide frames (ratio >= 2): three to a row */
.mount-frames__grid--3up {
  grid-template-columns: repeat(3, 1fr);
}

/* narrower frames: four, since each needs less width — ~277px, and a
   5:4 still comes out 277×222, still taller than a 3-up scope frame */
.mount-frames__grid--4up {
  grid-template-columns: repeat(4, 1fr);
}

/* a count that is not a multiple of three leaves one frame alone on
   the last row — 10 frames give 3·3+1. Left where it falls it hugs the
   left edge with two empty columns beside it; centred it reads as a
   closing note. Only the single-orphan case: two trailing frames
   balance on their own. */
.mount-frames__grid--3up .mount-frames__cell:last-child:nth-child(3n + 1) {
  grid-column: 2;
}

/* same courtesy in the four-column grid: a lone trailing frame spans
   the two middle columns at ONE column's width, which puts it on the
   container's centre line rather than against the left edge */
.mount-frames__grid--4up > .mount-frames__cell:last-child:nth-child(4n + 1) {
  grid-column: 2 / span 2;
  width: calc((100% - 3 * 14px) / 4);
  justify-self: center;
}

/* and in the plain two-column grid, if a film ever uses it */
.mount-frames__grid:not(.mount-frames__grid--3up):not(.mount-frames__grid--4up)
  > .mount-frames__cell:last-child:nth-child(odd) {
  grid-column: 1 / -1;
  width: calc((100% - 14px) / 2);
  justify-self: center;
}

/* every cell is a button — click or Enter opens it full screen
   (frames-view.js); it must not look like UI, so the button chrome is
   stripped back to the plain frame it was */
.mount-frames__cell {
  position: relative;
  overflow: hidden;
  background: #161a20;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  border-radius: 0;
  cursor: zoom-in;
  -webkit-appearance: none;
  appearance: none;
}

.mount-frames__cell:focus-visible {
  outline: 1px solid var(--rule);
  outline-offset: 3px;
}

/* FRAMES carry no grade either — same reason as the hero above */
.mount-frames__cell img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover; /* cell ratio equals the still's ratio — no crop */
  filter: none;
}

/* credits: [role] NAME, centered, cap 7 (BRIEF §6b grammar) */
/* Standalone centred credits section. The hung-frame page carries its
   credits inside the aside column (.mount__credits); the full-bleed
   page has no aside, so there they stand on their own, centred, as
   §6c originally described. Both share the __list / __role rules. */
.mount-credits {
  margin: 120px auto 0;
  padding: 0 var(--page-pad);
  text-align: center;
}

.mount-credits__list {
  --credits-lh: 2.2; /* one line box IS this list's rhythm; see .credits-author */
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--font-mono);
  font-size: max(calc(11 * var(--u)), 9.5px);
  letter-spacing: 0.14em;
  line-height: var(--credits-lh);
  color: var(--paper);
}

/* The author's own line leads a CREDITS block (BRIEF §6b/§6c) and is
   followed by a pause: above-the-line, a beat, then the crew. The
   pause is ONE STEP of whichever list it is in — a line box on the
   film pages, the flex gap on an MV page — so it stays in rhythm if
   either is ever retuned, and it is never a number typed here.

   The film list has no gap of its own, so the step is expressed as
   `1lh`, with the line-height token × 1em as the fallback for engines
   without `lh` (the same pair the category caption reserve uses). */
.mount-credits__list .credits-author {
  margin-bottom: calc(var(--credits-lh) * 1em);
  margin-bottom: 1lh;
}

.project__credits .credits-author {
  margin-bottom: var(--credits-step);
}

.mount-credits__role {
  color: var(--secondary);
}

/* context: quieter by one step, under the credits — no brackets */
.mount-context {
  margin-top: 56px;
  font-family: var(--font-mono);
  font-size: max(calc(10.5 * var(--u)), 9px);
  letter-spacing: 0.14em;
  line-height: 2;
  color: var(--numerals);
}

.mount-context p {
  margin: 0;
}

/* poster: hung as an object — contained, never upscaled */
.mount-poster {
  margin: 120px auto 0;
  padding: 0 var(--page-pad);
  text-align: center;
}

.mount-poster__img {
  display: block;
  margin: 0 auto;
  max-height: min(72vh, 660px);
  max-width: 88vw;
  width: auto;
  height: auto;
}

.mount-poster__credit {
  margin: 14px 0 0;
  font-family: var(--font-mono);
  font-size: max(calc(9.5 * var(--u)), 8.5px);
  letter-spacing: 0.14em;
  color: var(--numerals);
}

@media (max-width: 768px) {
  .mount {
    margin-top: 24px;
  }

  .mount__title {
    font-size: clamp(34px, 10vw, 44px);
  }

  /* the long form drops its floor: at 320px the longer half wants
     258px at 34px inside a 240px column, so the 34px minimum would
     force a third line on the narrowest phones */
  .mount__title--long {
    font-size: clamp(28px, 9vw, 44px);
  }

  /* the aside stacks: frame first, then the whole text column at full
     width — same collapse as .project__cols. The explicit column/row
     placement MUST be reset here: left in place, grid-column 2 would
     conjure an implicit second column out of a 1fr grid. Alignment
     goes back to left — right-aligned type only makes sense while it
     is hanging against the frame. */
  .mount--aside {
    grid-template-columns: 1fr;
    row-gap: 28px;
    margin-top: 24px;
    padding: 0; /* main already carries the 20px page inset */
  }

  .mount--aside .mount__frame,
  .mount--aside .mount__aside {
    grid-column: 1;
    grid-row: auto;
  }

  .mount--aside .mount__aside,
  .mount--aside .mount__credits .mount-label {
    text-align: left;
  }

  .mount--aside .mount__title,
  .mount--aside .mount__title--long {
    font-size: clamp(28px, 9vw, 44px);
  }

  .mount__credits {
    margin-top: 40px;
  }

  .mount__subtitle {
    font-size: clamp(19px, 5.5vw, 22px);
  }

  /* the desktop rule carries the page measure and its 64u inset;
     on a phone main already supplies the inset, so both come off.
     padding goes to 0 rather than back to --page-pad, which is what
     it used to be: with the inset applied twice the description sat
     20px narrower than the hero and the frames on either side of it,
     the same not-lining-up-with-anything the desktop fix is about. */
  .synopsis--mount {
    margin-top: 64px;
    max-width: none;
    padding: 0;
  }

  .onphoto {
    margin-top: 56px;
  }

  /* ---------------------------------------------------------------
     BLEED HERO ON A PHONE (author, 14.09.2026) — a contained frame,
     not a crop.

     The desktop composition is a full-bleed hero at 78vh with the
     title over it, and it is right there: a 2.20:1 frame across a
     landscape screen is the film's own shape, near enough. In a
     375×812 portrait viewport the same rule asks a 2.20:1 picture to
     fill a 540px-tall box, and object-fit: cover answers by keeping a
     375-wide slice of a frame that is 2.2 times wider than it is
     tall — roughly a quarter of the picture, with the widescreen
     composition (the thing the hero exists to show) thrown away. That
     is the one thing §6c forbids anywhere: the aspect is sacred.

     So on a phone the hero is the film's frame at the film's ratio,
     full width, and the title block follows it in flow — the shape
     the HUNG-frame page already takes at this width, which is why
     the two now read alike on a phone and differently on a desktop,
     as the hero modes are meant to.
     --------------------------------------------------------------- */

  /* header back into the flow so it does not sit over a short band —
     the same move About makes at this width, for the same reason */
  .page-film-detail.has-hero-header .site-header {
    position: static;
  }

  .has-hero-header .poster {
    height: auto;
    min-height: 0;
    overflow: visible;
    background: none;
    margin-top: 18px;
  }

  /* the picture's box takes the film's own ratio, handed down from
     the data as --hero-ar. CONTAINED, never cover: the declared
     aspect and the delivered raster agree to within a tenth of a
     percent here (2.20:1 against 1920×872 and 4096×1860), and
     contain keeps it that way if a re-export ever lands that does
     not agree. */
  .has-hero-header .poster__frame {
    position: relative;
    inset: auto;
    display: block;
    width: 100%;
    aspect-ratio: var(--hero-ar);
    background: #161a20;
  }

  .has-hero-header .poster__img {
    object-fit: contain;
  }

  /* the scrim existed to make the overlaid title readable; with the
     title below the frame there is nothing to lift it off */
  .has-hero-header .poster__scrim {
    display: none;
  }

  /* title block below the frame, left-aligned, on the page inset —
     main strips its padding on a bleed page so the hero can reach
     the screen edges, so this block carries its own, exactly as
     .film-cols and the frames grid do below. Sizes are the mount
     page's, so the two hero modes set their titles alike here. */
  .has-hero-header .poster__titleblock {
    position: static;
    align-items: flex-start;
    text-align: left;
    padding: 22px var(--page-pad) 0;
    gap: 14px;
  }

  .has-hero-header .poster__title {
    font-size: clamp(34px, 10vw, 44px);
    text-shadow: none;
  }

  .has-hero-header .poster__meta {
    letter-spacing: 0.2em;
  }

  .mount-frames {
    margin-top: 72px;
  }

  /* one frame per row on a phone — three columns even more so than
     two: at 375px a 2.20:1 frame would be 102×46. Full width it is
     335×152, and the viewer is one tap away. */
  .mount-frames__grid,
  .mount-frames__grid--3up,
  .mount-frames__grid--4up {
    grid-template-columns: 1fr;
  }

  /* and every centred-orphan rule MUST be undone here: an explicit
     grid-column inside a one-column grid conjures implicit columns
     and collapses the real one to nothing. The selectors are repeated
     in full on purpose — a shorter one loses on specificity to the
     :last-child:nth-child pair above and the reset silently fails. */
  .mount-frames__grid--3up .mount-frames__cell:last-child:nth-child(3n + 1),
  .mount-frames__grid--4up > .mount-frames__cell:last-child:nth-child(4n + 1),
  .mount-frames__grid:not(.mount-frames__grid--3up):not(.mount-frames__grid--4up)
    > .mount-frames__cell:last-child:nth-child(odd) {
    grid-column: auto;
    width: 100%;
  }

  .mount-frames:has(.mount-frames__grid--3up),
  .mount-frames:has(.mount-frames__grid--4up) {
    padding: 0 var(--page-pad);
  }

  /* a hung-frame page keeps main's inset, so the grid must NOT add its
     own on top — the frames were landing 295px wide under a 335px
     hero. A bleed page strips main's padding, so there the rule above
     supplies it instead. */
  .page-film-mount .mount-frames,
  .page-film-mount .mount-poster {
    padding: 0;
  }

  /* the two columns stack: description first, then the credits. The
     inset has to be carried here — a bleed page strips main's padding
     so the hero can reach the screen edges. */
  .film-cols {
    grid-template-columns: 1fr;
    row-gap: 32px;
    margin-top: 40px;
    padding: 0 var(--page-pad);
  }

  .mount-credits {
    margin-top: 80px;
  }

  .mount-context {
    margin-top: 40px;
  }

  .mount-poster {
    margin-top: 80px;
  }

  /* ---------------------------------------------------------------
     ONE READING ORDER FOR BOTH HERO MODES (author, 14.09.2026).

     At this width a bleed page stacked hero → title → meta →
     synopsis → credits → context, and a hung-frame page stacked
     hero → title → meta → credits → context → synopsis, with the
     synopsis centred on top of that. Two page types of the same
     thing, read two different ways, on the width where there is no
     composition left to justify the difference.

     Both now read hero → title → meta → SYNOPSIS → CREDITS →
     context, left-aligned on the page inset. The bleed page already
     did — .film-cols simply stacks — so the work is on the hung
     page, where the two wrappers of the desktop composition stop
     being boxes here and their children become the page's own flow,
     ordered. The spacings above the synopsis (40px) and above the
     credits (32px) are .film-cols' own margin and row-gap, so the
     two page types keep the same rhythm as well as the same order.

     The DESKTOP composition is untouched on both modes: this is the
     ≤768 block, and every built page is byte-identical at 1440 apart
     from the synopsis data. What that costs is that the DOM order on
     a hung page still ends on the synopsis — the order here is
     visual. Moving it in the DOM would mean rebuilding the desktop
     two-column composition, which this pass was told not to touch.
     --------------------------------------------------------------- */
  .page-film-mount main {
    display: flex;
    flex-direction: column;
  }

  /* `margin-inline: 0` is load-bearing, not tidiness. Several of
     these blocks carry `margin: <top> auto 0` for their desktop
     centring, and an auto cross-axis margin BEATS the flex
     container's `align-items: stretch`: the item stops filling the
     width and sizes to its content instead. The frames grid is a
     one-column grid of cells whose only width comes from the
     container, so it resolved to 0×0 — eleven invisible cells and a
     140px hole in the page — the moment main became a flex column. */
  .page-film-mount main > * {
    order: 7;
    margin-inline: 0;
  }

  .page-film-mount .mount--aside,
  .page-film-mount .mount__aside {
    display: contents;
  }

  .page-film-mount .mount__frame {
    order: 1;
    margin-top: 24px; /* was .mount--aside's own margin */
  }

  .page-film-mount .mount__title {
    order: 2;
    margin-top: 28px; /* was the grid's row-gap */
  }

  .page-film-mount .mount__subtitle {
    order: 3;
  }

  .page-film-mount .mount__meta {
    order: 4;
  }

  .page-film-mount .synopsis--mount {
    order: 5;
    margin-top: 40px;
  }

  .page-film-mount .mount__credits {
    order: 6;
    margin-top: 32px;
  }

  /* the synopsis is left-aligned on BOTH page types here — its
     centring on a hung page is a desktop composition and stays
     there. (.film-cols already left-aligns the bleed one.) */
  .synopsis {
    align-items: flex-start;
    text-align: left;
  }
}

/* ============================================================
   Frames viewer (02.08.2026) — any FRAMES cell opens full screen.
   Same grammar as the overlay player (§6): INK scrim, mono CLOSE
   top-right, PREV/NEXT, ESC and a scrim click both close. The
   picture is CONTAINED, never cropped and never upscaled past its
   own pixels — the whole point is to see the frame whole.
   ============================================================ */

.frames-view[hidden] {
  display: none;
}

.frames-view {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(14, 17, 22, 0.94);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: calc(64 * var(--u)) calc(72 * var(--u));
  animation: frames-view-in 0.3s ease both;
}

@keyframes frames-view-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.frames-view__img {
  display: block;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  /* a film's own frame, shown as the film was graded (§6c) */
  filter: none;
}

.frames-view__close {
  position: absolute;
  top: calc(26 * var(--u));
  right: calc(34 * var(--u));
  font-family: var(--font-mono);
  font-size: max(calc(10 * var(--u)), 9px);
  letter-spacing: 0.22em;
  color: var(--secondary);
  background: none;
  border: 0;
  padding: 6px;
  cursor: pointer;
}

.frames-view__counter {
  position: absolute;
  bottom: calc(26 * var(--u));
  left: 50%;
  transform: translateX(-50%);
  font-family: var(--font-mono);
  font-size: max(calc(9.5 * var(--u)), 8.5px);
  letter-spacing: 0.22em;
  color: var(--numerals);
}

.frames-view__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--font-mono);
  font-size: max(calc(15 * var(--u)), 13px);
  color: var(--secondary);
  background: none;
  border: 0;
  padding: 12px;
  cursor: pointer;
}

.frames-view__arrow--prev { left: calc(22 * var(--u)); }
.frames-view__arrow--next { right: calc(22 * var(--u)); }

.frames-view__arrow[hidden] { display: none; }

.frames-view__close:hover,
.frames-view__close:focus-visible,
.frames-view__arrow:hover,
.frames-view__arrow:focus-visible {
  color: var(--paper);
}

@media (max-width: 768px) {
  .frames-view {
    padding: 56px 16px;
  }

  .frames-view__arrow--prev { left: 4px; }
  .frames-view__arrow--next { right: 4px; }
}
