/* ==========================================================================
   FILMOGRAPHY — the optical console.

   Ported from mocks/console.css. The page is one fixed frame (css/frame.css)
   bounded below by the nav rail; js/work-filter.js drives three states inside
   it: the aperture mosaic, the record, and every credit.

   LAYOUT LAW (inherited from the mock, and the reason the old page leaked)
   1. The page is a fixed frame bounded below by the rail.
   2. Every region is a laid-out grid row. Nothing that carries content is
      position:absolute — absolute positioning is what put credits under the
      rail and slashed the toggles. The mosaic shards are the one exception,
      and they are pinned inside a row that is itself laid out.
   3. Exactly one row is flexible (minmax(0,1fr)) and that row is the
      designated scroll region. A fixed frame may never become a trap: if
      content still exceeds the frame it scrolls, it does not vanish.
   ========================================================================== */

.page-work {
  background: var(--ground-deep);
  color: var(--paper);
  font-family: var(--font-body);
}

/* hidden means hidden: the regions below set `display` in their own rules,
   which silently beats the UA [hidden] rule. */
.page-work [hidden] { display: none !important; }

/* ---- the console: head / chips / stage / foot ---------------------------- */
.film-console {
  /* THE TYPE SCALE. Six steps, tuned to the frame, not to the document. */
  --fs-display: clamp(2.1rem, 4.5cqw, 3.4rem);
  --fs-sub: 1.35rem;
  --fs-lead: 1rem;
  --fs-body: 0.9rem;
  --fs-meta: 0.8rem;
  --fs-micro: 0.75rem;
  --measure: 34rem;
  --gap: clamp(0.55rem, 1.5cqh, 1.05rem);

  display: grid;
  grid-template-rows: min-content min-content minmax(0, 1fr) min-content;
  align-content: stretch;
  gap: var(--gap);
  outline: none;
}

/* ---- head ---------------------------------------------------------------- */
.film-head {
  display: grid;
  grid-template-columns: min-content minmax(0, 1fr);
  align-items: center;
  gap: 0.2rem clamp(0.9rem, 2.4cqw, 1.8rem);
}

.film-wordmark {
  grid-row: 1 / span 2;
  display: block;
  width: clamp(5.2rem, 8cqw, 8rem);
  line-height: 0;
}

.film-wordmark img { width: 100%; height: auto; }

.film-wordmark:focus-visible {
  outline: 3px solid var(--coral);
  outline-offset: 4px;
}

.film-console h1 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-display);
  font-weight: 680;
  font-variation-settings: "wdth" 92, "wght" 680;
  line-height: 0.9;
  letter-spacing: -0.035em;
}

.film-dek {
  margin: 0;
  max-width: 46ch;
  color: var(--paper-dim);
  font-size: var(--fs-lead);
  line-height: 1.45;
}

/* The accent has one job: it is the hyphen. */
.mh-hy {
  color: var(--coral);
  font-style: normal;
}

/* ---- filter chips: the primary instrument -------------------------------- */
.film-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.film-chips button {
  display: inline-flex;
  align-items: baseline;
  gap: 0.42rem;
  padding: 0.38rem 0.8rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: rgb(8 11 10 / 0.85);
  color: rgb(244 236 224 / 0.78);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  transition:
    background var(--dur-fast) linear,
    color var(--dur-fast) linear,
    border-color var(--dur-fast) linear;
}

.film-chips .fm-chip-n {
  color: var(--gold);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
}

.film-chips button:hover {
  color: #fff3e2;
  border-color: var(--paper-dim);
}

.film-chips button[aria-pressed="true"] {
  background: var(--coral);
  border-color: var(--coral);
  color: #080b0a;
  font-weight: 700;
}

.film-chips button[aria-pressed="true"] .fm-chip-n { color: rgb(8 11 10 / 0.88); }

.film-chips button:focus-visible,
.fm-step:focus-visible,
.fm-toggle:focus-visible,
.fm-close:focus-visible,
.fm-row--open:focus-visible {
  outline: 3px solid var(--paper);
  outline-offset: 2px;
}

/* ---- the body: the one flexible row. The mosaic, the credit list and the
   record all occupy it, so the record can open over either state and nothing
   is ever laid out below the rail. ---------------------------------------- */
.film-body {
  position: relative;
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  min-height: 0;
}

.film-body > .film-stage,
.film-body > .film-credits {
  grid-area: 1 / 1;
  min-height: 0;
}

/* ---- the stage: the apertures, and the record that replaces them ---------- */
.film-stage {
  position: relative;
  min-height: 0;
}

.film-mosaic {
  position: absolute;
  inset: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  transition: opacity var(--dur-slow) ease, filter var(--dur-slow) ease;
}

.film-console.is-open .film-mosaic {
  opacity: 0.5;
  filter: saturate(0.5);
}

.fm-glyph {
  position: absolute;
  margin: 0;
  overflow: hidden;
  transition:
    inset 420ms cubic-bezier(0.32, 0.72, 0, 1),
    clip-path 520ms cubic-bezier(0.32, 0.72, 0, 1);
}

/* ---- aperture geometry. One set per surviving shard count, so a sparse
   filter collapses the mosaic instead of leaving a flat empty slab. ----

   Every aperture also declares where its caption is SAFE: --lx/--rx/--ly are
   the local percentages the polygon eats out of the box at caption height.
   The caption then sits a fixed 12px inside the *visible* edge in all of them
   — which is what "all five match" has to mean once the edges are angled. */

/* n=5 — the approved geometry */
.film-mosaic[data-n="5"] .fm-glyph--0 { inset: 0 66% 45% 0;   --cut: polygon(0 0, 100% 0, 88.2% 100%, 0 87.3%); --rx: 12%; --ly: 13%; }
.film-mosaic[data-n="5"] .fm-glyph--1 { inset: 0 32% 45% 30%; --cut: polygon(10.5% 0, 100% 0, 89.5% 94.5%, 0 100%); --lx: 2%; --rx: 11%; --ly: 6%; }
.film-mosaic[data-n="5"] .fm-glyph--2 { inset: 0 0 48% 64%;   --cut: polygon(11.1% 0, 100% 0, 100% 88.5%, 0 100%); --lx: 2%; --rx: 2%; --ly: 9%; }
.film-mosaic[data-n="5"] .fm-glyph--3 { inset: 48% 36% 0 0;   --cut: polygon(0 0, 46.9% 13.5%, 100% 7.7%, 90.6% 100%, 0 100%); --rx: 10%; }
.film-mosaic[data-n="5"] .fm-glyph--4 { inset: 46% 0 0 58%;   --cut: polygon(14.3% 11.1%, 100% 0, 100% 100%, 0 100%); --lx: 2%; }

/* n=4 — four angled slabs */
.film-mosaic[data-n="4"] .fm-glyph--0 { inset: 0 70% 0 0;   --cut: polygon(0 0, 86.67% 0, 76.67% 100%, 0 100%); --rx: 24%; }
.film-mosaic[data-n="4"] .fm-glyph--1 { inset: 0 45% 0 20%; --cut: polygon(17.14% 0, 88.57% 0, 80% 100%, 8.57% 100%); --lx: 10%; --rx: 21%; }
.film-mosaic[data-n="4"] .fm-glyph--2 { inset: 0 20% 0 45%; --cut: polygon(17.14% 0, 88.57% 0, 80% 100%, 8.57% 100%); --lx: 10%; --rx: 21%; }
.film-mosaic[data-n="4"] .fm-glyph--3 { inset: 0 0 0 70%;   --cut: polygon(20% 0, 100% 0, 100% 100%, 10% 100%); --lx: 12%; }

/* n=3 */
.film-mosaic[data-n="3"] .fm-glyph--0 { inset: 0 62% 0 0;   --cut: polygon(0 0, 89.47% 0, 78.95% 100%, 0 100%); --rx: 21%; }
.film-mosaic[data-n="3"] .fm-glyph--1 { inset: 0 28% 0 26%; --cut: polygon(17.39% 0, 91.3% 0, 80.43% 100%, 8.7% 100%); --lx: 10%; --rx: 20%; }
.film-mosaic[data-n="3"] .fm-glyph--2 { inset: 0 0 0 60%;   --cut: polygon(20% 0, 100% 0, 100% 100%, 7.5% 100%); --lx: 10%; }

/* n=2 */
.film-mosaic[data-n="2"] .fm-glyph--0 { inset: 0 44% 0 0; --cut: polygon(0 0, 92.86% 0, 82.14% 100%, 0 100%); --rx: 18%; }
.film-mosaic[data-n="2"] .fm-glyph--1 { inset: 0 0 0 44%; --cut: polygon(14.29% 0, 100% 0, 100% 100%, 3.57% 100%); --lx: 5%; }

/* n=1 */
.film-mosaic[data-n="1"] .fm-glyph--0 { inset: 0; --cut: polygon(0 1.6%, 100% 0, 100% 98.4%, 0 100%); --rx: 1%; --ly: 2%; }

.film-mosaic[data-n="0"] {
  display: grid;
  place-content: center;
}

.fm-empty {
  margin: 0;
  color: rgb(244 236 224 / 0.6);
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.fm-cut {
  position: absolute;
  inset: 0;
  display: block;
  overflow: hidden;
  clip-path: var(--cut);
  /* This was --teal-accent (#0d5155), a good deal brighter than the page
     ground (#062b30) — so every shard that had not yet painted flashed teal
     against the frame. Matched to the ground, an unloaded shard reads as part
     of the page rather than as a light coming on. */
  background: var(--ground, #062b30);
  cursor: pointer;
  text-decoration: none;
  opacity: 1;
  transition: opacity 560ms cubic-bezier(0.32, 0.72, 0, 1);
}

/* The still and the clip share one box. The still is ~20KB against the clip's
   60-500KB, so it lands first and the shard is never empty — before this, the
   crossfade began the instant the element was appended and you saw the frame's
   own teal through it while the video was still on the wire. */
.fm-cut video,
.fm-cut .fm-still {
  position: absolute;
  inset: -7%;
  width: 114%;
  height: 114%;
  max-width: none;
  object-fit: cover;
  filter: contrast(1.06) saturate(1.04);
  transition: filter 420ms cubic-bezier(0.32, 0.72, 0, 1);
}

.fm-cut .fm-still { z-index: 0; }

/* The clip simply replaces its still the moment it can play. No transition:
   a dissolve here reads as a rendering error, not as motion. */
.fm-cut video {
  z-index: 1;
  opacity: 0;
}

.fm-cut video.is-ready { opacity: 1; }

/* Motion off: the still is the shard. */
@media (prefers-reduced-motion: reduce) {
  .fm-cut video { display: none; }
}

.fm-cut:hover video,
.fm-cut:focus-visible video {
  filter: contrast(1.12) saturate(1.16) brightness(1.08);
}

/* halftone, under the scrim */
.fm-cut::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background-image: radial-gradient(circle, rgb(2 5 4 / 0.82) 0 0.48px, transparent 0.7px);
  background-size: 2.4px 2.4px;
  mix-blend-mode: multiply;
  opacity: 0.2;
}

/* base scrim: the cinematic weight along the bottom of the aperture */
.fm-cut::before {
  content: "";
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 2;
  height: min(150px, 74%);
  pointer-events: none;
  background: linear-gradient(
    to top,
    rgb(4 20 22 / 0.85) 0%,
    rgb(4 20 22 / 0.52) 42%,
    rgb(4 20 22 / 0) 100%);
}

.fm-cut:focus-visible {
  outline: 3px solid var(--coral);
  outline-offset: -3px;
}

/* THE CAPTION. Its own plate, so contrast is a constant, not a lottery played
   against whatever frame the video happens to be on. 11:1 over pure white. */
.fm-label {
  position: absolute;
  z-index: 3;
  left: calc(var(--lx, 0%) + 12px);
  bottom: calc(var(--ly, 0%) + 12px);
  max-width: calc(100% - var(--lx, 0%) - var(--rx, 0%) - 24px);
  width: max-content;
  display: grid;
  gap: 2px;
  padding: 9px 13px 10px;
  background: linear-gradient(
    to top,
    rgb(4 20 22 / 0.95) 0%,
    rgb(4 20 22 / 0.9) 64%,
    rgb(4 20 22 / 0.74) 100%);
  font-family: var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.fm-label-t {
  color: var(--paper);
  font-size: var(--fs-meta);
  font-weight: 600;
  line-height: 1.2;
}

.fm-label-y {
  color: rgb(244 236 224 / 0.86);
  font-size: var(--fs-micro);
  line-height: 1.2;
}

/* ---- the record: full-frame over the stage ------------------------------- */
.film-detail {
  position: absolute;
  inset: 0;
  z-index: 20;
  display: grid;
  grid-template-rows: min-content minmax(0, 1fr);
  padding: clamp(1rem, 2.6cqw, 2rem);
  background: rgb(4 20 22 / 0.95);
  border: 1px solid var(--line-strong);
}

.fm-detail-head {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
}

.fm-detail-head h2 {
  margin: 0 0 0.25rem;
  font-family: var(--font-display);
  font-size: var(--fs-sub);
  font-weight: 680;
  font-variation-settings: "wdth" 94, "wght" 680;
  line-height: 1.05;
  letter-spacing: -0.01em;
}

.fm-detail-meta,
.fm-detail-roles {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.fm-detail-meta { color: var(--gold); }
.fm-detail-roles { margin-top: 0.2rem; color: rgb(244 236 224 / 0.8); }

.fm-close {
  margin-left: auto;
  flex: none;
  width: 2.2rem;
  height: 2.2rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: none;
  color: rgb(244 236 224 / 0.82);
  cursor: pointer;
  font-size: var(--fs-lead);
  line-height: 1;
}

.fm-close:hover {
  background: var(--coral);
  border-color: var(--coral);
  color: #080b0a;
}

.fm-detail-body {
  display: grid;
  align-content: start;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  padding-top: 0.7rem;
  scrollbar-width: thin;
}

/* Wide frames set the record in two columns, so a long laurel list is read
   rather than scrolled. The frame is the container: `cqw` and this query both
   measure it, not the document. */
@container (min-width: 56rem) {
  .fm-detail-body {
    grid-template-columns: minmax(0, var(--measure)) minmax(0, 1fr);
    align-items: start;
    column-gap: clamp(1.5rem, 4cqw, 3.5rem);
  }

  .fm-awards { margin-top: 0; }

  .fm-aw-head {
    padding-top: 0;
    border-top: 0;
  }
}

.fm-detail-body p {
  margin: 0 0 0.6rem;
  max-width: var(--measure);
  color: var(--paper-dim);
  font-size: var(--fs-lead);
  line-height: 1.5;
}

.fm-watch a {
  color: var(--gold);
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  text-decoration: none;
  border-bottom: 1px solid var(--coral);
}

.fm-watch a:hover { color: #fff3e2; }

.fm-watch a:focus-visible {
  outline: 3px solid var(--paper);
  outline-offset: 3px;
}

.fm-awards { margin-top: 0.55rem; }

.fm-aw-head,
.fm-aw-label {
  margin: 0 0 0.25rem;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.fm-aw-head {
  padding-top: 0.5rem;
  border-top: 1px solid var(--line);
  color: var(--coral);
}

.fm-aw-label { color: rgb(244 236 224 / 0.55); }

.fm-aw-group { margin-bottom: 0.5rem; }

.fm-awards ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.16rem;
}

.fm-awards li {
  color: rgb(244 236 224 / 0.76);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  line-height: 1.35;
  letter-spacing: 0.03em;
}

/* A region that had to fall back to scrolling has to SAY so — an invisible
   overlay scrollbar on a frame that otherwise never scrolls reads as
   "this is all there is". */
.can-scroll {
  scrollbar-gutter: stable;
  mask-image: linear-gradient(to bottom, #000 calc(100% - 42px), transparent 100%);
}

.can-scroll.at-end { mask-image: none; }

/* ---- every credit: paginated, never under the rail ----------------------- */
.film-credits {
  display: grid;
  grid-template-rows: minmax(0, 1fr) min-content;
  gap: 0.5rem;
  min-height: 0;
}

.fm-credit-scroll {
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;
}

.fm-credit-list {
  display: grid;
  gap: 1px;
  align-content: start;
  margin: 0;
  padding: 0;
  list-style: none;
}

.fm-row {
  display: grid;
  grid-template-columns: 3.6rem minmax(0, 1fr) auto;
  gap: 0.9rem;
  align-items: baseline;
  width: 100%;
  padding: 0.3rem 0;
  border: 0;
  border-bottom: 1px solid var(--line);
  background: none;
  color: var(--paper);
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: 0.04em;
  text-align: left;
}

.fm-row--open {
  grid-template-columns: 3.6rem minmax(0, 1fr) auto min-content;
  cursor: pointer;
  transition: background var(--dur-fast) linear;
}

.fm-row--open:hover { background: rgb(232 121 69 / 0.12); }

.fm-row-mark {
  color: var(--coral);
  font-size: 0.62rem;
}

.fm-y { color: var(--coral); }
.fm-t { color: var(--paper); }
.fm-r { color: rgb(244 236 224 / 0.62); text-align: right; }
.fm-row em { color: rgb(244 236 224 / 0.45); font-style: normal; }

.fm-pager {
  display: flex;
  align-items: center;
  gap: 0.8rem;
}

.fm-pager-label,
.fm-count,
.fm-flow-label {
  color: rgb(244 236 224 / 0.62);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* shared stepper, used by the credit pager and the aperture flow */
.fm-step {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.66rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: rgb(8 11 10 / 0.85);
  color: rgb(244 236 224 / 0.82);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.12em;
  line-height: 1.1;
  text-transform: uppercase;
  transition:
    background var(--dur-fast) linear,
    color var(--dur-fast) linear,
    border-color var(--dur-fast) linear;
}

.fm-step:hover:not(:disabled) {
  background: var(--coral);
  border-color: var(--coral);
  color: #080b0a;
}

.fm-step:disabled {
  opacity: 0.34;
  cursor: default;
}

/* ---- foot: a laid-out row of the console grid, NOT absolute -------------- */
.film-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem clamp(0.9rem, 2.4cqw, 1.5rem);
  padding-top: 0.35rem;
  border-top: 1px solid var(--line);
}

.fm-viewtabs {
  display: flex;
  gap: clamp(0.8rem, 2cqw, 1.2rem);
}

.fm-toggle {
  padding: 0.2rem 0;
  border: 0;
  border-bottom: 2px solid transparent;
  background: none;
  color: rgb(244 236 224 / 0.6);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.fm-toggle[aria-pressed="true"] {
  color: var(--paper);
  border-bottom-color: var(--coral);
}

.fm-flow {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin-left: auto;
}

.fm-flow-label {
  min-width: 8.4em;
  text-align: center;
}

/* The colophon rides in the foot so it never becomes a fifth row. */
.film-colophon {
  display: flex;
  gap: 0.9rem;
  margin-left: auto;
  color: rgb(244 236 224 / 0.42);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.film-colophon a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--line);
}

.film-colophon a:hover { color: var(--paper); border-bottom-color: var(--coral); }

.film-colophon a:focus-visible {
  outline: 3px solid var(--paper);
  outline-offset: 2px;
}

.fm-flow ~ .film-colophon { margin-left: 0; }

/* ==========================================================================
   NARROW — 700/600px and below
   ========================================================================== */
@media (max-width: 700px) {
  .film-head {
    grid-template-columns: minmax(0, 1fr);
    gap: 0.35rem;
  }

  .film-wordmark {
    grid-row: auto;
    width: clamp(4.6rem, 22vw, 6.4rem);
  }

  .film-dek { font-size: var(--fs-body); }

  /* A narrow frame cannot afford to hold the standfirst and three rows of
     chips open behind a record it has pushed into a 250px slot. Reading the
     record is the state; the filter comes back the moment it closes.

     The chips COLLAPSE rather than `display: none`, because removing a grid
     item shifts every later item up a track — which handed the flexible row
     to the foot and squeezed the record into min-content. */
  .film-console.is-open .film-chips {
    height: 0;
    overflow: hidden;
    visibility: hidden;
  }

  .film-console.is-open .film-dek { display: none; }
}

@media (max-width: 600px) {
  .film-console { --fs-sub: 1.2rem; }

  /* Credit rows stack instead of squeezing three columns into 22 characters.
     Every cell is placed explicitly: auto-placement puts the roles and the
     open marker in the same slot as the title and they collide. */
  .fm-row,
  .fm-row--open {
    grid-template-columns: 2.9rem minmax(0, 1fr) min-content;
    gap: 0.1rem 0.6rem;
    padding: 0.32rem 0;
    font-size: var(--fs-micro);
    letter-spacing: 0.02em;
  }

  .fm-y { grid-area: 1 / 1 / span 2 / 2; }
  .fm-t { grid-area: 1 / 2 / 2 / 3; }

  .fm-r {
    grid-area: 2 / 2 / 3 / 4;
    text-align: left;
    color: rgb(244 236 224 / 0.55);
  }

  .fm-row-mark {
    grid-area: 1 / 3 / 2 / 4;
    align-self: center;
  }

  .film-chips button { padding: 0.34rem 0.62rem; letter-spacing: 0.1em; }

  .fm-flow { margin-left: 0; }
  .fm-flow-label { min-width: 0; }
  .film-colophon { margin-left: 0; }
  .fm-label { left: 12px; right: 12px; bottom: 10px; }
}

/* ---- narrow apertures: stacked bands, so captions stay legible ----
   The bands deliberately overlap so the diagonals never leave a gap, which
   means each shard's bottom strip is painted over by the one after it. A
   caption anchored to the bottom therefore lands under its own successor.
   `--ty` is the top-edge slope, the mirror of `--ly`: every shard's top is
   the part that is doing the covering, so it is always the visible part. */
@media (max-width: 600px) {
  .film-mosaic[data-n="3"] .fm-glyph--0 { inset: 0 0 62% 0;   --cut: polygon(0 0, 100% 0, 100% 78.95%, 0 89.47%); --lx: 0%; --rx: 2%; --ly: 18%; --ty: 0%; }
  .film-mosaic[data-n="3"] .fm-glyph--1 { inset: 26% 0 28% 0; --cut: polygon(0 17.39%, 100% 8.7%, 100% 80.43%, 0 89.13%); --lx: 0%; --rx: 2%; --ly: 17%; --ty: 18%; }
  .film-mosaic[data-n="3"] .fm-glyph--2 { inset: 60% 0 0 0;   --cut: polygon(0 17.5%, 100% 7.5%, 100% 100%, 0 100%); --lx: 0%; --rx: 0%; --ly: 0%; --ty: 18%; }
  .film-mosaic[data-n="2"] .fm-glyph--0 { inset: 0 0 48% 0;   --cut: polygon(0 0, 100% 0, 100% 84.6%, 0 96.2%); --lx: 0%; --rx: 2%; --ly: 12%; --ty: 0%; }
  .film-mosaic[data-n="2"] .fm-glyph--1 { inset: 46% 0 0 0;   --cut: polygon(0 11.1%, 100% 0, 100% 100%, 0 100%); --lx: 0%; --rx: 0%; --ly: 0%; --ty: 12%; }

  /* Only the shards that have a successor are at risk; the last one keeps the
     bottom anchor, which is where a caption belongs when nothing covers it. */
  .film-mosaic > li:not(:last-child) .fm-label {
    top: calc(var(--ty, 0%) + 12px);
    bottom: auto;
  }
}

/* ---- no JavaScript: the page is simply the full filmography --------------
   The console's states are all script-driven, so with no script the static
   list becomes the flexible row and the empty stage collapses out of it. */
.film-console:has(.film-static) {
  grid-template-rows: min-content minmax(0, 1fr);
}

/* Chips, apertures, pager and view toggles are all script. With none of them
   working there is nothing for them to say, so the list is the whole page.
   js/work-filter.js removes the fallback the moment it takes over. */
.film-console:has(.film-static) .film-body,
.film-console:has(.film-static) .film-chips,
.film-console:has(.film-static) .film-foot { display: none; }

.film-static {
  display: grid;
  gap: 0.6rem;
  padding-top: 0.4rem;
}

.film-static h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--fs-sub);
  font-weight: 680;
}

.film-static ul {
  display: grid;
  gap: 1px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.film-static li {
  display: grid;
  grid-template-columns: 3.6rem minmax(0, 1fr) auto;
  gap: 0.9rem;
  align-items: baseline;
  padding: 0.24rem 0;
  border-bottom: 1px solid var(--line);
  font-family: var(--font-mono);
  font-size: var(--fs-meta);
}

/* ==========================================================================
   MOTION
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .fm-glyph,
  .fm-cut,
  .film-mosaic {
    transition-duration: 1ms !important;
  }
}

@media (forced-colors: active) {
  .fm-cut:focus-visible,
  .film-chips button:focus-visible,
  .fm-step:focus-visible,
  .fm-toggle:focus-visible,
  .fm-close:focus-visible,
  .fm-row--open:focus-visible {
    outline: 3px solid CanvasText;
  }

  .film-detail { border-color: CanvasText; }
}

/* The dek is one sentence and it should read as one line on a desktop frame;
   wrapping it before "from 2010 to now" orphans the date onto its own row. */
@media (min-width: 900px) {
  .film-dek {
    max-width: none;
    white-space: nowrap;
  }
}
