/* ==========================================================================
   NITRATE — THE LANDING PAGES  (MOVIES · SERIES)
   Owned by the landing agent.  Pairs with landing.js.  Nothing else.

   Form: a film-lab job ticket.  A ruled ledger at the top, then sections
   announced by a small caption and a hairline that runs to the margin.
   No cards, no accent bars, no gradients.  Colour is only ever severity.
   Every token comes from tokens.css; none are redefined here.
   ========================================================================== */

.lnd {
  /* 2026-08-23 — John: the Movies / Series / Anime fronts must run edge to edge
     like the foyer. This was the ONLY capped panel in the app: .hm, .scr, .nw,
     .sg-page and .dsc are all full-bleed already, so the 1560 cap here was the
     outlier, not the rule. Gutter stays --pad (16px) rather than the foyer's
     --pad-x: blocks mounted INSIDE this wrap (.an, .cour, .nxc) already add
     var(--pad-x) themselves, and switching the wrap too would double the
     gutter to ~104px on a wide screen. */
  padding: 18px var(--pad) 72px;
  max-width: none;
  margin: 0 auto;
  width: 100%;
}

/* ------------------------------------------------------------------ slate */
.lnd-slate {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin-bottom: 10px;
}
.lnd-slate h2 {
  font-size: 30px;
  letter-spacing: -.035em;
}
.lnd-slate-sub {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;   /* a flex item floors at min-content without this */
}

/* --------------------------------------------------- THE FILM FIGURES
   John, 2026-08-12: the flat one-line strip that used to sit low on this
   page "should be on top below hero deck (so it's consistent with series
   and anime and make the styling similar but for movies stats)."

   ⭐ THIS IS DELIBERATELY NOT A NEW COMPONENT — it is the third page of an
   instrument that already exists twice.  `.an-mast` / `.an-figs` in
   anime.css set the composition (prose left, a bordered stat grid right, a
   summary sentence under both); series.css §I records that it copied every
   value from there for #/series; this copies the same values again for
   #/movies — the 1.15fr : 1fr split, the 44px gutter, the 11px mono label,
   the clamp(26px, 3vw, 38px) marquee value, the 11px muted caption, the
   collapse at 1080.  The class names are ours because a shared class across
   module boundaries is a shared fate; the VALUES are theirs.  If the anime
   masthead is retuned, retune both of these with it.

   ⛔ WHAT WENT AWAY: `.lnd-ledger` / `.lnd-fig`, the flat strip of hairline-
   separated figures.  Nothing else in the site used either class — they were
   built by landing.js :: ledger() and by nothing else — so they are deleted
   rather than left as dead selectors that look like a live component.     */
.lnd-led {
  margin: 0 0 34px;
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 8px 44px;
  align-items: start;
}
.lnd-led-l { min-width: 0; }

/* The headline stacks: a numeral and its phrase as siblings on one baseline
   is what wrapped "…END TO / END" mid-phrase on the twin block.  Stacked,
   the phrase gets the column's whole width. */
.lnd-led-big { display: block; }
.lnd-led-fig {
  display: block;
  font-family: var(--font-marquee, var(--font-display));
  font-variant-numeric: tabular-nums;
  font-size: clamp(56px, 7.8vw, 116px);
  font-weight: 800;
  line-height: .8;
  letter-spacing: -.035em;
  color: var(--ink);
}
.lnd-led-unit {
  display: block;
  margin-top: 6px;
  font-family: var(--font-marquee, var(--font-display));
  font-size: clamp(16px, 1.9vw, 27px);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .01em;
  line-height: 1.04;
  color: var(--ink-2);
}
.lnd-led-lede {
  margin: 13px 0 0;
  max-width: 62ch;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-2);
}
.lnd-led-lede b { color: var(--ink); font-weight: 700; }

/* FOUR cards carrying six figures.  A caption is for a figure that MODIFIES
   the one above it; a card is for a figure that stands beside the others. */
.lnd-led-reg {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0;
  border-top: var(--hair) solid var(--rule);
  border-left: var(--hair) solid var(--rule);
}
.lnd-led-cell {
  border-right: var(--hair) solid var(--rule);
  border-bottom: var(--hair) solid var(--rule);
  padding: 9px 12px 10px;
  min-width: 0;
}
.lnd-led-k {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}
.lnd-led-v {
  margin: 2px 0 0;
  font-family: var(--font-marquee, var(--font-display));
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: clamp(26px, 3vw, 38px);
  line-height: 1;
  letter-spacing: 0;
  color: var(--ink);
}
.lnd-led-s {
  margin: 3px 0 0;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.35;
  color: var(--muted);
}
/* The foot carries the rule so it spans BOTH columns, exactly as `.an-prop`
   does; the sentence inside keeps a reading measure.  A max-width on the
   paragraph itself draws a rule that stops two thirds of the way across. */
.lnd-led-foot {
  grid-column: 1 / -1;
  margin-top: 20px;
  border-top: var(--hair) solid var(--rule);
  padding-top: 11px;
}
.lnd-led-say {
  margin: 0;
  max-width: 82ch;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-2);
}

/* The two columns become one where the anime masthead's do, at the same
   width, for the same reason: below this the prose column can no longer hold
   a 62ch measure beside a grid of four numbers.  1080 is not a new
   breakpoint — it is the one anime.css and series.css already collapse at,
   and this block has to collapse with them or the three pages disagree. */
@media (max-width: 1080px) {
  .lnd-led { grid-template-columns: minmax(0, 1fr); gap: 20px; }
}

/* ---------------------------------------------------------------- section */
/* SAFARICSS_20260905 — RENDER ONLY WHAT IS ON SCREEN. John: "the website not
   as responsive as chrome" (Safari). Measured in WebKit at 1440 on #/movies:
   1.5 animation frames/s and a 20-step scroll of 12.9 s before; with every
   section skipping layout and paint while off-screen, 7 frames/s and 2.2 s —
   and 14 frames/s / 1.2 s once the rolling rail also keeps its layout and paint
   to itself (below). Chromium was never this bad but gains too. `auto` keeps
   the real height once a section has painted, the number is only the guess
   before it has. ⚠️ Children of a skipped section measure 0: the rolling
   rail re-measures from its ResizeObserver and the shelf/wire rails fall back
   to a fixed step and re-sync on scroll, so nothing here reads a stale 0. */
.lnd-sec { margin-bottom: 34px; content-visibility: auto; contain-intrinsic-size: auto 1px 480px; }
.lnd-sec-hd {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 12px;
}
.lnd-sec-hd h3 {
  font-size: 12px;
  letter-spacing: .13em;
  white-space: nowrap;
  color: var(--ink);
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lnd-rule {
  flex: 1 1 auto;
  min-width: 16px;
  height: 0;
  border-top: var(--hair) solid var(--rule);
  transform: translateY(-4px);
}
.lnd-sec-meta {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 10.5px;
  color: var(--muted);
  white-space: nowrap;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* the route into the screener */
.lnd-jump {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  border: 0;
  padding: 2px 0 2px 10px;
  white-space: nowrap;
}
.lnd-jump:hover { color: var(--accent); }
.lnd-jump::after { content: " \2192"; }

/* --------------------------------------------------------------- calendar
   COMING SOON.  A date gutter on the left, rows to the right.  Grouped by
   the server's pre-formatted air_date so a day never splits at midnight UTC. */
.lnd-cal { border-top: var(--hair) solid var(--rule); }
.lnd-day { display: flex; align-items: flex-start; }
.lnd-day + .lnd-day { border-top: var(--hair) solid var(--rule); }
.lnd-day-hd {
  flex: 0 0 128px;
  padding: 7px 12px 8px 0;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 11px;
  line-height: 1.3;
}
.lnd-day-d { display: block; color: var(--ink); letter-spacing: .04em; }
.lnd-day-rel {
  display: block;
  font-size: 9.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 1px;
}
.lnd-day.is-today .lnd-day-d { color: var(--accent); }
.lnd-day.is-today .lnd-day-rel { color: var(--accent); }
.lnd-day-rows { flex: 1 1 auto; min-width: 0; }

.lnd-up {
  appearance: none;
  background: transparent;
  display: grid;
  grid-template-columns: 30px 74px minmax(130px, .8fr) minmax(0, 2.4fr) 116px 84px;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  border: 0;
  padding: 5px 6px 5px 0;
  min-height: 34px;
}
.lnd-up + .lnd-up { border-top: var(--hair) solid var(--rule); }
.lnd-up.is-link { cursor: pointer; }
.lnd-up.is-link:hover { background: var(--panel); }
.lnd-up:not(.is-link) { cursor: default; }

/* display:block matters — a bare <span> is inline, and an inline box ignores
   width/aspect-ratio.  Inside .lnd-up it was blockified by the grid and looked
   fine; inside the poster strip it was not, and every card sized itself to the
   poster's natural width. */
.lnd-art {
  display: block;
  position: relative;
  overflow: hidden;
  background: var(--panel-2);
  aspect-ratio: 2 / 3;
  width: 30px;
}
/* absolute, so DOM order decides: the poster covers the initials plate.  A
   static img would paint UNDER the positioned plate whatever the order. */
.lnd-art img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.lnd-art-txt {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono);
  font-size: 9px; font-weight: 700;
  color: var(--ink);
  opacity: .55;
  letter-spacing: .04em;
}

.lnd-up-code {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 10.5px;
  letter-spacing: .06em;
  color: var(--ink-2);
  white-space: nowrap;
}
.lnd-up-name {
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.lnd-up-sub {
  color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.lnd-up-net {
  font-size: 10.5px;
  color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.lnd-up-mark {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .1em;
  text-transform: uppercase;
  text-align: right;
  color: var(--muted);
  white-space: nowrap;
}
.lnd-up-mark.is-have { color: var(--ok); }
.lnd-up-mark.is-missing { color: var(--accent); }

/* release window: cinema / physical / digital */
.lnd-win {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-2);
  border: var(--hair) solid var(--rule);
  padding: 1px 5px;
  white-space: nowrap;
}

/* ------------------------------------------------------------------ strip
   RECENTLY ADDED.  A contact sheet that scrolls sideways.               */
.lnd-strip {
  display: flex;
  gap: 14px;
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 10px;
  scroll-snap-type: x proximity;
}
.lnd-card {
  flex: 0 0 128px;
  /* without this the flex item floors at min-content, and the nowrap caption
     line ("2026 · 24 ep · 45.1 GiB · 4d ago") drags every card 50px wider */
  min-width: 0;
  border: 0;
  padding: 0;
  text-align: left;
  cursor: pointer;
  scroll-snap-align: start;
}
.lnd-card .lnd-art { width: 128px; }
.lnd-card:hover { outline: var(--hair) solid var(--rule); outline-offset: 3px; }
.lnd-card-t {
  width: 128px;
  margin-top: 6px;
  font-weight: 600;
  color: var(--ink);
  line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.lnd-card-m {
  display: block;
  width: 128px;
  margin-top: 2px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 10px;
  line-height: 1.35;
  color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.lnd-card-m + .lnd-card-m { margin-top: 0; }

/* ------------------------------------------------------------------ table */
/* fixed layout + declared <col> widths: a long title ellipses inside its own
   cell instead of shouldering the table off the page */
.lnd-tbl { width: 100%; table-layout: fixed; }
.lnd-tbl th {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: left;
  padding: 0 8px 5px 0;
  border-bottom: var(--hair) solid var(--rule);
  white-space: nowrap;
}
.lnd-tbl td {
  padding: 5px 8px 5px 0;
  border-bottom: var(--hair) solid var(--rule);
  vertical-align: baseline;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lnd-tbl th.num, .lnd-tbl td.num {
  text-align: right;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  padding-right: 16px;
}
.lnd-tbl td.mono {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 10.5px;
  color: var(--ink-2);
  white-space: nowrap;
}
.lnd-tbl td.wrapy { white-space: normal; overflow: visible; }
.lnd-flagname { font-weight: 700; }
/* hover fill, matching the screener's row convention — not a zebra stripe */
.lnd-tbl tbody tr.is-link { cursor: pointer; }
.lnd-tbl tbody tr.is-link:hover > td { background: var(--panel); }
.lnd-tbl .t-name { color: var(--ink); font-weight: 600; }
.lnd-tbl td.dim { color: var(--muted); }

.lnd-scroll {
  max-height: 456px;
  overflow-y: auto;
  overscroll-behavior: contain;
  border-bottom: var(--hair) solid var(--rule);
}
.lnd-scroll .lnd-tbl thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--ground);
}

/* the kind marker: series / anime */
.lnd-kind {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ------------------------------------------------------------------- bars */
.lnd-bar {
  display: block;
  height: 4px;
  background: var(--panel-2);
  width: 100%;
  min-width: 60px;
}
.lnd-bar i { display: block; height: 100%; background: var(--muted); }
.lnd-bar.sev-crit i { background: var(--crit); }
.lnd-bar.sev-warn i { background: var(--warn); }
.lnd-bar.sev-info i { background: var(--muted); }
td.lnd-barcell { width: 26%; padding-right: 0; }

/* ------------------------------------------------------- actionable flags */
.lnd-todo { margin-top: 14px; }
.lnd-todo-hd {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
  padding-bottom: 4px;
  border-bottom: var(--hair) solid var(--rule);
  margin-bottom: 6px;
}
.lnd-todo-hd b { color: var(--ink); font-weight: 700; }
.lnd-names { display: flex; flex-wrap: wrap; gap: 0 6px; margin-bottom: 16px; }
.lnd-names:last-child { margin-bottom: 0; }
.lnd-name {
  border: 0;
  padding: 2px 0;
  cursor: pointer;
  color: var(--ink-2);
  text-align: left;
  max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lnd-name:hover { color: var(--accent); }
.lnd-name::after { content: " \00b7"; color: var(--rule); padding-left: 5px; }
.lnd-name:last-child::after { content: ""; }
.lnd-more {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--muted);
  border: 0;
  padding: 2px 0;
  cursor: pointer;
}
.lnd-more:hover { color: var(--accent); }

/* ------------------------------------------------------------------- grid */
.lnd-cols {
  display: grid;
  gap: 34px;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  align-items: start;
}
.lnd-panel h4 {
  font-size: 10px;
  letter-spacing: .14em;
  color: var(--muted);
  font-weight: 700;
  padding-bottom: 6px;
  margin-bottom: 8px;
  border-bottom: var(--hair) solid var(--rule);
}

/* ------------------------------------------------------------------ notes */
.lnd-note {
  font-size: 10.5px;
  color: var(--muted);
  margin-top: 8px;
  max-width: 74ch;
}
/* A note that hangs directly off a section body is a caption under a
   full-width table: on #/series the three gap notes are 444px of prose with
   965px of nothing beside them — the void John pointed at on NEW PRINTS.
   Those get the house caption grid (tokens.css --cap-col), whose column at
   this size lands within a few px of the 74ch measure they already had.
   ⛔ Scoped to the direct children on purpose: a .lnd-note inside a
   .lnd-panel is already in a grid column ~700px wide and has no void to
   fill — columning it would only split a one-line note across a gutter. */
.lnd-sec-body > .lnd-note {
  max-width: none;
  columns: var(--cap-col);
  column-gap: var(--cap-gap);
  orphans: 2;
  widows: 2;
}
.lnd-empty {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
  padding: 14px 0;
  border-top: var(--hair) solid var(--rule);
}
.lnd-empty.is-err { color: var(--crit); text-transform: none; letter-spacing: 0; }

/* ------------------------------------------------------------ responsive */
@media (max-width: 1180px) {
  .lnd-up { grid-template-columns: 30px 74px minmax(120px, 1.2fr) minmax(0, 1.5fr) 84px; }
  .lnd-up-net { display: none; }
}
@media (max-width: 860px) {
  .lnd-up { grid-template-columns: 30px 70px minmax(0, 1fr) 78px; }
  .lnd-up-sub { display: none; }
  .lnd-day-hd { flex-basis: 96px; }
  .lnd-slate h2 { font-size: 22px; }
  /* the section caption, its rule and its meta stop competing for one line */
  .lnd-sec-hd { flex-wrap: wrap; row-gap: 2px; }
  .lnd-sec-hd h3 { flex: 0 0 auto; }
  .lnd-rule { order: 3; flex-basis: 100%; transform: none; margin-top: 5px; }
  .lnd-sec-meta { white-space: normal; }
}
/* ⛔ 620 USED TO BE HERE.  Folded into the 760 tier below (MOBILE_SPEC §1) —
   its three rules now live at the foot of THE HAND, marked "folded from 620".
   ⛔ 1180 and 860 above are ≥ 820 and stay exactly as they are: desktop is
   finished, and normalising means folding what is BELOW 760, not touching it. */

/* ─────────────────────────────────────────────────────────────────────────
   2026-08-10 redesign. The page opens with a decision, not an inventory:
   one film, big enough to look at, with the rule that chose it stated.
   The ambient wash is that title's OWN extracted poster tint - the only
   site in the world that can colour its page from this collection.
   ───────────────────────────────────────────────────────────────────── */
.lnd-hero{
  position:relative; margin:0 0 6px; padding:30px 18px 26px; overflow:hidden;
  border-bottom:1px solid var(--rule);
}
.lnd-hero::before{
  content:''; position:absolute; inset:0;
  background:radial-gradient(120% 140% at 12% 0%, var(--tint) 0%, transparent 62%);
  opacity:.30; pointer-events:none;
}
.lnd-hero-eye{
  position:relative; font-family:ui-monospace,Menlo,Consolas,monospace;
  font-size:10px; letter-spacing:.22em; text-transform:uppercase;
  color:var(--accent); font-weight:700; margin-bottom:16px;
}
.lnd-hero-body{position:relative; display:flex; gap:24px; align-items:flex-start}
.lnd-hero-art{flex:0 0 auto; border-radius:2px; overflow:hidden; border:1px solid var(--rule)}
.lnd-hero-art img{display:block; width:100%}
.lnd-hero-txt{min-width:0; flex:1 1 auto; padding-top:2px}
.lnd-hero-title{
  font-size:clamp(30px,4.4vw,52px); font-weight:800; letter-spacing:-.035em;
  line-height:.98; margin:0 0 10px; color:var(--ink); text-wrap:balance;
}
.lnd-hero-meta{
  display:flex; flex-wrap:wrap; gap:7px; align-items:baseline;
  font-family:ui-monospace,Menlo,monospace; font-size:11.5px; color:var(--muted);
  letter-spacing:.04em; margin-bottom:12px;
}
.lnd-hero-dot{opacity:.5}
.lnd-hero-sum{
  margin:0 0 16px; font-size:14px; line-height:1.6; color:var(--ink-2); max-width:62ch;
}
.lnd-hero-acts{display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin-bottom:14px}
.lnd-hero-more{
  font:inherit; font-size:12.5px; letter-spacing:.02em;
  background:transparent; color:var(--ink-2);
  border:1px solid var(--rule); border-radius:2px; padding:7px 14px; cursor:pointer;
}
.lnd-hero-more:hover{color:var(--ink); outline:1px solid var(--rule)}
.lnd-hero-why{
  margin:0; font-family:ui-monospace,Menlo,monospace; font-size:11px;
  color:var(--muted); display:flex; align-items:baseline; gap:6px; flex-wrap:wrap;
}
.lnd-hero-score{
  font-size:15px; font-weight:700; color:var(--accent);
  font-variant-numeric:tabular-nums;
}

/* rails — the collection, scannable, at a size worth looking at */
/* ⚠️ --rail-gap, not a literal: a rolling rail lays its cards out inside a
   track and has to reproduce this exact number as the sequence's own gap and
   trailing pad.  One declaration, read in both places, so the two cannot drift
   when the mobile tier changes it. */
.lnd-railwrap{margin:0 0 4px}
.lnd-rail{
  --rail-gap:12px;
  display:flex; gap:var(--rail-gap); overflow-x:auto; padding:4px 18px 18px;
  scroll-snap-type:x proximity; scrollbar-width:thin;
}
.lnd-rail::-webkit-scrollbar{height:7px}
.lnd-rail::-webkit-scrollbar-thumb{background:var(--rule); border-radius:4px}
.lnd-card{
  flex:0 0 132px; scroll-snap-align:start; display:flex; flex-direction:column; gap:5px;
  background:none; border:0; padding:0; cursor:pointer; text-align:left; font:inherit;
}
.lnd-card .lnd-art{
  width:132px; height:198px; border-radius:2px; overflow:hidden;
  border:1px solid var(--rule); display:block;
}
.lnd-card .lnd-art img{width:100%; height:100%; object-fit:cover; display:block}
.lnd-card:hover .lnd-art{outline:2px solid var(--accent); outline-offset:-1px}
.lnd-card-t{
  font-size:12px; color:var(--ink); line-height:1.3; font-weight:600;
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
.lnd-card-s{
  font-family:ui-monospace,Menlo,monospace; font-size:10.5px; color:var(--muted);
  font-variant-numeric:tabular-nums;
}
.lnd-card-when{
  font-family:ui-monospace,Menlo,monospace; font-size:10px; letter-spacing:.08em;
  text-transform:uppercase; color:var(--accent); font-weight:700;
}
.lnd-rail-empty{margin:0 18px 18px; font-size:13px; color:var(--muted)}

/* ── THE ROLLING RAILS ────────────────────────────────────────────────────
   John, 2026-08-12: "want the coming soon rail to be rolling (moving)
   continously (loop) to the right direction and recently released rail move
   to the left direction so that the page does not feel too static."

   The rail is STILL the scroll container and the cards are still its snap
   targets — nothing about swiping or dragging changes.  What is new is one
   flex track inside it holding the cards TWICE, translated by exactly one
   copy.  Because a transform does not move a scroll offset, the two compose:
   the reader's scroll and the drift are independent, and the reader's stops.

   🔴 THE COPY IS IN FRONT, AT NEGATIVE x, AND THAT IS LOAD-BEARING.  With
   the copy behind and the track translating left, a rail dragged to its right
   end showed 2,327px of nothing — measured on the live page.  A scroll
   container's range comes from LAYOUT and a transform moves the content out
   of it, so any leftward translate uncovers exactly that much at the far end,
   at every speed.  In LTR, overflow to the LEFT of the scroll origin is not
   scrollable and does not count towards scrollWidth: putting the copy at
   [-C, 0] therefore leaves the rail's scrollable width at ONE copy, exactly
   what it was before today, and the track translates RIGHT to pull the copy
   across the front.  Direction of travel is which end the keyframes start at.

   ⚠️ THE GAP LIVES INSIDE THE SEQUENCE, as padding-right, not between the two
   sequences as a track gap.  The copies must be exactly equal in width or the
   loop wraps onto a different phase and twitches every cycle; the negative
   margin set in JS is the sequence's own offsetWidth, which is only the right
   number because the trailing gap is inside it.  With that, translateX(100%)
   — the track's own width — is exactly one copy, and no measured pixel value
   ever has to be written into the animation.

   ⭐ NO will-change.  An element with a running transform animation is
   promoted by the compositor anyway; declaring it would keep a ~3,500 × 260px
   layer alive for the whole session, on the phone this most needs to be cheap
   on.  See landing.js :: makeRolling for the rest of the reasoning.        */
/* 🔴 A RAIL THAT MOVES ON ITS OWN MUST NOT ALSO INSIST ON PARKING.  The
   track's transform changes the rail's scrollable width continuously, so
   Chromium re-evaluates scroll-snap against the new layout and nudges
   scrollLeft a pixel at a time — measured idle, with nothing touching the
   page: 6 s, scrollLeft 16 → 13, and a `scroll` handler firing throughout.
   Snap exists to make a FLICK land tidily; against a rail that is already
   walking it is two mechanisms arguing about where the cards should sit.
   Scoped to .is-roll, so every other rail on the site still snaps. */
.lnd-rail.is-roll{ scroll-snap-type:none }
/* SAFARICSS_20260905 — the rolling track's transform moves the rail's
   scrollable overflow every frame, and WebKit answered by re-laying-out the
   page around it: with sections already contained, this alone took the
   movies page from 7 to 14 frames/s in WebKit. Layout + paint containment
   keeps the roll's consequences inside the rail's own box. ⛔ NOT
   will-change on the track — measured 1.5 frames/s, the giant promoted layer
   the comment above already warns about. */
.lnd-rail.is-roll{ contain:layout paint }

.lnd-roll-track{
  display:flex; gap:0; width:max-content;
  animation-name:none;                 /* until JS has measured the duration */
  animation-duration:120s;
  animation-timing-function:linear;
  animation-iteration-count:infinite;
  animation-play-state:running;
}
.lnd-roll-seq{
  display:flex;
  gap:var(--rail-gap, 12px);
  padding-right:var(--rail-gap, 12px);
}
/* Both directions run over the same range — 0 is "the real cards where they
   were laid out", 100% is "one copy further right, so the front copy stands
   exactly where the real ones did".  The two are pixel-identical content, so
   whichever end a rail starts from, starting is invisible. */
.lnd-rail.is-roll.is-rolling.is-roll-left  .lnd-roll-track{ animation-name:lnd-roll-l }
.lnd-rail.is-roll.is-rolling.is-roll-right .lnd-roll-track{ animation-name:lnd-roll-r }
@keyframes lnd-roll-l{ from{transform:translateX(100%)} to{transform:translateX(0)} }
@keyframes lnd-roll-r{ from{transform:translateX(0)}    to{transform:translateX(100%)} }

/* 🔴 THE VIEWER WINS.  These set only play-state, so they never fight the
   rules above for the animation NAME and cannot be out-specified by them.
   .is-held is pointer / touch / wheel, held 2.5s past the last one; .is-off
   is scrolled out of sight; .is-focus is the keyboard, which has no hover.
   ⚠️ .is-focus, NOT :focus-within — a tapped <button> stays focused on
   Android and the rail would never move again.  landing.js :: focusIn(). */
.lnd-rail.is-held  .lnd-roll-track,
.lnd-rail.is-off   .lnd-roll-track,
.lnd-rail.is-focus .lnd-roll-track{ animation-play-state:paused }
/* ⚠️ Gated on a real hover pointer — MOBILE_SPEC §10.3.  A phone that leaves
   a phantom :hover on the last thing tapped would otherwise stop the rail for
   good, and "it moves until you touch it, once" is worse than not moving. */
@media (hover: hover){
  .lnd-rail.is-roll:hover .lnd-roll-track{ animation-play-state:paused }
}

/* 🔴 The second belt.  makeRolling() returns before building any of this when
   the preference is set, so normally there is nothing here to switch off;
   this catches the preference being turned on after the page was drawn.
   tokens.css already flattens every animation under this query — what it
   cannot do is take the duplicate cards back out, and a rail that silently
   holds the library twice is a bug in its own right. */
@media (prefers-reduced-motion: reduce){
  .lnd-roll-seq.is-dup{ display:none }
  .lnd-rail.is-roll .lnd-roll-track{ animation-name:none; transform:none }
}

/* ── the arrivals board's reserved slot ───────────────────────────────────
   ⚠️ THE ANIME HERO IS THE ONLY ASYNC BLOCK ON THIS PAGE THAT IS A BOARD.
   Every other one is a section with a heading, so its placeholder is a line
   of text and the page grows by almost nothing when the fetch lands.  A 706px
   board dropping into a slot of zero height moves the whole page under the
   reader — the exact complaint that got renderLanding's scroll-keeping
   written.  So the empty slot holds a floor while it waits.

   The floor is set BELOW the board's real height at EVERY tier (measured
   2026-08-12: 706px at 1440×900, 603px at 390×844, 576px at 430×932 — note it
   is the SHORTEST at the widest phone, which is why the cap is 560 and not
   600) so it can never leave a strip of dead ground under a board that has
   already landed, and it is released the moment the slot has a child —
   `:empty`, not `:has()`, because this has to work on whatever Safari is on
   the phone in his hand.

   `.is-void` is the other direction: the block declined to render at all,
   which is what an older server with no /api/arrivals gets.  A reserved
   height with nothing in it would be worse than no block. */
.lnd-slot-arrhero:empty{min-height:min(62vh, 560px)}
.lnd-slot.is-void{display:none}

/* ⚠️ A BOARD THAT CHANGES HEIGHT MOVES THE WHOLE PAGE — the same finding
   home.js records above .hm-title, and the reason a long TITLE is set smaller
   there rather than allowed a third line.  Every frame of this board lives in
   one grid cell, so the stage is as tall as its tallest frame, and this line
   is the only one whose length is out of our hands: it is an episode title
   straight from Plex, and they run from "Turn Up" to "A Nightmarish Game -
   The Dark Plot of the Knights of God".  Two lines, then it stops.  Scoped to
   this board so the foyer's blurb, which is prose and wants its four lines,
   is untouched. */
.lnd-arrboard .hm-sum{
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical;
  overflow:hidden;
}
/* 🔴 …AND THE CLAMP MUST NOT UNDO home.css's OWN DROP.  `.hm-sum{display:none}`
   at ≤760 is one class; the rule above is two, so it silently WON and put the
   blurb back on the phone — measured 2026-08-12: the board grew to 672px and
   swung 49px between frames, on the device this whole normalisation exists to
   fix.  Restated here at the same tier rather than weakened above, because the
   clamp is genuinely wanted on a desk. */
@media (max-width: 760px){
  .lnd-arrboard .hm-sum{ display:none }
  /* Two lines of the board's own measurement type, always — 2 × 18px plus the
     7px row gap `.hm-meta` sets, measured at 390px.  The figures are the whole
     content of this slide on a phone and they take one line or two depending
     on the show ("S03E31 · 153 on the shelf" against "2 episodes · S01E1171,
     S23E1173 · aired 9 Aug · 1,173 on the shelf").  Without a floor the board
     changes height every 9 seconds and everything under it walks up and down
     the page — the exact failure home.js records above .hm-title. */
  .lnd-arrboard .hm-meta{ min-height:43px }
}

@media (prefers-reduced-motion:reduce){ .lnd-rail{scroll-behavior:auto} }

/* ⛔ A SECOND @media (max-width:760px) USED TO SIT HERE, holding the hero and
   the rail-card sizes.  It has been merged into THE HAND below — nothing but
   comments stood between the two blocks, so the cascade is unchanged, and the
   file now states its mobile rules in exactly two places: 760, then 430. */

/* ═════════════════════════════════════════════════════════════════════════
   THE HAND.  2026-08-10.
   Below 760px this page is read one thumb at a time, and three things about
   the desktop sheet stop being true:

   1. A GUTTER IS PAID TWICE.  .lnd already gutters at --pad, and every block
      it hosts (the field, the shortlist, the register, the anime shelf) adds
      the foyer's --pad-x on top.  On a 390px screen that is 68px — 17% of the
      glass — spent on nothing.  Each block drops its own gutter here and
      inherits this one; the rule lives in that block's own file.

   2. A SIX-COLUMN TABLE IS NOT A TABLE.  "Needs attention" prints flag,
      meaning, count, share, bar and a route into the Screener.  At 390px the
      route's cell is 46px wide and the button inside it is 78px, so it hung
      out over the page with nothing to scroll it back.  Here the row stops
      pretending to be a row: three lines, the sentence given its own, and the
      route a real 44px control at the foot.  Nothing else on the page uses
      .lnd-jump, which is what :has() is keying on.

   3. A CONTROL IS A FINGERTIP, NOT A POINTER.  The named titles under a flag
      were 22px tall and 6px apart.  They keep flowing as a sentence — 35 of
      them, one per line, would be a page of its own — but each is 42px tall
      with 14px of clear air beside it.

   Nothing here applies at 1000px and above.

   ─────────────────────────── 2026-08-11, and what changed under it ───────
   MOST OF THIS BLOCK IS NOW DORMANT, AND THAT IS DELIBERATE.  The ledger,
   "Needs attention" and "The shelf" no longer REACH a phone at all — they are
   filtered out of BLOCKS[] in landing.js, which is the one place a block is
   dropped.  Their mobile rules are kept here, unchanged and paid for, so that
   flipping `mobile: true` on any of them is still a one-word decision and not
   a re-do.  ⛔ Do not delete them to "clean up": that would quietly turn a
   one-word flag back into an afternoon.

   What a phone actually renders on these pages is: the marquee, one browse
   room (the bill / the racks / the run), the shortlist, the accessions and
   the Coming soon rail.  Of those, three belong to other files; the rail and
   all the section furniture are here, so that is where the work went.
   ═════════════════════════════════════════════════════════════════════════ */
@media (max-width: 760px) {
  .lnd { padding-bottom: 44px; }

  /* --- the hero, and the rail cards (merged in from the second 760 block) - */
  .lnd-hero-body { flex-direction: column; gap: 16px; }
  .lnd-hero-art { width: 132px; }
  .lnd-card { flex-basis: 112px; }
  .lnd-card .lnd-art { width: 112px; height: 168px; }

  /* --- section furniture ------------------------------------------------ */
  .lnd-sec { margin-bottom: 28px; }
  .lnd-sec-hd h3 { font-size: 12.5px; }
  .lnd-sec-meta { font-size: 11.5px; }
  .lnd-note { font-size: 12.5px; line-height: 1.55; }
  /* one column at the house mobile tier (tokens.css, the caption grid) */
  .lnd-sec-body > .lnd-note { columns: 1; }
  .lnd-empty { font-size: 12.5px; }
  .lnd-slate h2 { font-size: 24px; }
  .lnd-slate-sub { font-size: 11px; }

  /* --- the film figures -------------------------------------------------
     Dormant: the block is `mobile: false`.  Stated for the same reason as
     the 430 rule below — it must be right the day the flag flips. */
  .lnd-led { gap: 16px; }
  .lnd-led-say, .lnd-led-lede { font-size: 12.5px; }

  /* --- the route into the Screener, as an object you can hit ------------- */
  .lnd-jump {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 13px;
    border: var(--hair) solid var(--rule);
    font-size: 11px;
    color: var(--ink-2);
  }
  .lnd-jump:active { background: var(--panel-2); }

  /* --- "needs attention": the row unfolds ------------------------------- */
  .lnd-tbl:has(.lnd-jump) { display: block; }
  .lnd-tbl:has(.lnd-jump) > colgroup,
  .lnd-tbl:has(.lnd-jump) > thead { display: none; }
  .lnd-tbl:has(.lnd-jump) > tbody { display: block; }
  .lnd-tbl:has(.lnd-jump) > tbody > tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    align-items: baseline;
    column-gap: 12px;
    padding: 9px 0 10px;
    border-top: var(--hair) solid var(--rule);
  }
  .lnd-tbl:has(.lnd-jump) > tbody > tr:first-child { border-top: 0; }
  .lnd-tbl:has(.lnd-jump) td {
    display: block;
    border: 0;
    padding: 0;
    width: auto;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }
  /* flag · count · share, then the sentence, then the bar and the route */
  .lnd-tbl:has(.lnd-jump) td:nth-child(1) { grid-column: 1; grid-row: 1; font-size: 13px; }
  .lnd-tbl:has(.lnd-jump) td:nth-child(3) { grid-column: 2; grid-row: 1; font-size: 13px; text-align: right; }
  .lnd-tbl:has(.lnd-jump) td:nth-child(4) { grid-column: 3; grid-row: 1; font-size: 12px; text-align: right; }
  .lnd-tbl:has(.lnd-jump) td:nth-child(2) {
    grid-column: 1 / -1; grid-row: 2;
    margin: 2px 0 6px;
    font-size: 12.5px; line-height: 1.5;
  }
  .lnd-tbl:has(.lnd-jump) td:nth-child(5) {
    grid-column: 1; grid-row: 3;
    align-self: center;
    padding-right: 4px;
  }
  .lnd-tbl:has(.lnd-jump) td:nth-child(6) {
    grid-column: 2 / -1; grid-row: 3;
    justify-self: end;
  }
  .lnd-tbl:has(.lnd-jump) .lnd-bar { height: 6px; }

  /* --- the tables that stay tables -------------------------------------- */
  .lnd-tbl th { font-size: 11px; padding-bottom: 6px; }
  .lnd-panel h4 { font-size: 11px; letter-spacing: .12em; }
  .lnd-tbl td { padding-top: 7px; padding-bottom: 7px; }
  .lnd-tbl td.mono { font-size: 11px; }
  .lnd-tbl .t-name { font-size: 12.5px; }
  .lnd-kind { font-size: 11px; }
  /* a 456px box inside a scrolling page is a thumb trap: the list is short
     enough to simply print, and then its head has nothing to stick to */
  .lnd-scroll { max-height: none; overflow-y: visible; }
  .lnd-scroll .lnd-tbl thead th { position: static; }

  /* --- the named titles under a flag ------------------------------------ */
  .lnd-todo { margin-top: 10px; }
  .lnd-todo-hd { font-size: 11px; padding-bottom: 6px; }
  .lnd-names { gap: 0 16px; margin-bottom: 8px; }
  /* 40px with 16px of clear air beside it: one per line would be a page of
     its own, and thirty-five of them is a sentence, not a list.
     🔴 The height comes from PADDING, never from inline-flex.  A flex item is
     blockified, an inline-flex one becomes a flex CONTAINER, and a flex
     container does not ellipse — "Dragon Ball Z Side Story: Plan to Eradicate
     the Saiyans (1993)" was being cut off mid-word with no mark to say so. */
  .lnd-name {
    padding: 11px 0;
    line-height: 18px;
    font-size: 12.5px;
  }
  .lnd-name::after { padding-left: 12px; }
  .lnd-more {
    padding: 11px 0;
    line-height: 18px;
    font-size: 12.5px;
  }

  /* --- a rail's caption sits ON the rail --------------------------------
     section() returns a <section class="lnd-sec"> with an EMPTY body, and the
     rail is its sibling — so the 28px that separates two sections was being
     spent between a heading and the thing it names.  On a desk that is a
     margin; at 390px it is a third of a poster.  (0,2,0) beats .lnd-sec.  */
  .lnd-railwrap .lnd-sec { margin-bottom: 10px; }
  .lnd-railwrap { margin-bottom: 18px; }

  /* --- the contact strip bleeds to the glass ----------------------------
     A rail that stops at the gutter looks like it ends there.  Cut off at
     the edge, it says "there is more this way" without a word.

     🔴 scroll-padding-left IS NOT OPTIONAL HERE (MOBILE_SPEC §4.7).  These
     rails snap (scroll-snap-type on the rail, scroll-snap-align:start on the
     card) and snapping aligns to the SCROLLPORT edge, not to the padding box:
     without it the first card parks under the left edge of the screen the
     moment the reader flicks and lets go.  The value must equal the rail's own
     left padding, which is why mobile.css cannot supply it — it does not know
     this number.  Scoped to ≤760 with the bleed that created it, so desktop,
     which pads 18px and is finished, is not touched.

     overscroll-behavior-x keeps a flick that runs off the end of the rail from
     being read as the browser's back-swipe — on a phone that is the difference
     between "no more posters" and "you have left the page".              */
  .lnd-rail {
    margin: 0 calc(var(--pad) * -1);
    padding: 4px var(--pad) 16px;
    --rail-gap: 10px;              /* was `gap: 10px` — see the token's note */
    scroll-padding-left: var(--pad);
    overscroll-behavior-x: contain;
  }
  .lnd-strip {
    margin: 0 calc(var(--pad) * -1);
    padding: 0 var(--pad) 10px;
    scroll-padding-left: var(--pad);
    overscroll-behavior-x: contain;
  }
  .lnd-rail-empty { margin: 0 0 16px; font-size: 12.5px; }
  /* 🔴 width: auto IS THE FIX, NOT THE FONT SIZE.  .lnd-card-t and .lnd-card-m
     still carry `width: 128px` from the contact-strip era, when every card was
     128px wide.  The card is 112px here — so the caption was 16px wider than
     the poster it belongs to and ran UNDER its neighbour: "Minions & Monsters"
     printed straight through "OK! Madam", measured at 390px.  It never showed
     on desktop because a 132px card is wider than a 128px caption, which is
     exactly why it survived this long.  The card is a flex COLUMN, so auto
     makes the caption take the card's width and keep its 2-line clamp. */
  .lnd-card-t, .lnd-card-m { width: auto; }
  .lnd-card-t { font-size: 12.5px; }
  .lnd-card-s, .lnd-card-m { font-size: 11px; }
  .lnd-card-when { font-size: 11px; }

  /* --- the calendar rows ------------------------------------------------ */
  .lnd-up { min-height: 44px; padding: 7px 0; }
  .lnd-day-hd { font-size: 11.5px; }
  .lnd-day-rel { font-size: 10.5px; }
  .lnd-up-code, .lnd-up-net { font-size: 11px; }
  .lnd-up-mark, .lnd-win { font-size: 10px; }

  /* folded from the old 620 query — the date gutter stops being a gutter and
     becomes a line above its rows, and the row loses two more columns */
  .lnd-day { display: block; }
  .lnd-day-hd { padding-bottom: 2px; }
  .lnd-up { grid-template-columns: 30px 66px minmax(0, 1fr) 74px; }
}

/* ═════════════════════════════════════════════════════════════════════════
   NARROW — 430px.  The second and last tier (MOBILE_SPEC §1).
   Folded up from the old 340 query: 430 is an iPhone 16 Pro Max, so this is
   "phone", not "small phone", and a rule that only fired at 340 fired on
   almost nothing.
   ⚠️ Dormant while the film figures are off the phone (`mobile: false` in
   the registry) — stated so the block is correct the day that flag flips,
   for the reason the registry header gives about absent defaults.
   ═════════════════════════════════════════════════════════════════════════ */
@media (max-width: 430px) {
  .lnd-led-reg { grid-template-columns: minmax(0, 1fr); }
}

/* ═════════════════════════════════════════════════════════════════════════
   THE WAY IN — the five sagas, and the door to #/sagas.  2026-08-12.

   ⛔ THIS IS NOT THE RACK MADE SMALLER.  The rack — 443 lines of .sgr-* — was
   removed whole.  It packed thirty-four sets into an index, which is the right
   object when the binding constraint is "every set one click away without a
   carousel", and the wrong one now that sagas.py draws five.  The drawing
   moved to its own page (sagas.css); this is the door to it.

   ── THE MATERIAL ──────────────────────────────────────────────────────────
   Each door carries the instrument that page is built on: the saga's own
   films' MEASURED poster colours in order, at hard stops.  So the door shows
   what is behind it, and the five are told apart before a word is read.
   ⛔ Colour: tokens.css plus `--tint` / `poster_tint`.  Nothing typed in.
   Safety orange keeps its single site-wide meaning — hover intent and focus.
   ═════════════════════════════════════════════════════════════════════════ */
.sgw-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(172px, 1fr));
  gap: 10px;
}
.sgw-door {
  appearance: none; -webkit-appearance: none;
  display: block; width: 100%; text-align: left;
  background: var(--panel); cursor: pointer;
  border: var(--hair) solid var(--rule);
  border-left: 3px solid var(--tint, var(--rule));
  padding: 11px 12px 10px;
  color: var(--ink-2);
}
.sgw-name {
  display: block;
  font-family: var(--font-marquee); font-weight: 700;
  font-size: 23px; line-height: 1.0; letter-spacing: .01em;
  text-transform: uppercase; color: var(--ink-2);
}
.sgw-meta {
  display: flex; gap: 8px; margin-top: 4px;
  font-family: var(--font-mono); font-size: 10.5px;
  font-variant-numeric: tabular-nums; color: var(--muted);
}
.sgw-yr { margin-left: auto; }
.sgw-rule {
  display: block; height: 6px; margin-top: 9px;
  background-color: var(--panel-2); background-repeat: no-repeat;
}
.sgw-door:hover { border-color: var(--muted); border-left-color: var(--tint, var(--accent)); }
.sgw-door:hover .sgw-name { color: var(--ink); }
.sgw-door:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.sgw-note {
  margin: 12px 0 0; max-width: min(78ch, 100%);
  font-size: var(--size-dense); line-height: 1.45; color: var(--muted);
}
.sgw-go {
  appearance: none; -webkit-appearance: none;
  display: flex; align-items: baseline; gap: 10px;
  margin-top: 12px; padding: 8px 12px;
  background: none; border: var(--hair) solid var(--rule);
  color: var(--ink-2); cursor: pointer;
}
.sgw-go-t {
  font-family: var(--font-marquee); font-weight: 700; font-size: 19px;
  text-transform: uppercase; letter-spacing: .02em;
}
.sgw-go-n {
  font-family: var(--font-mono); font-size: 10.5px;
  font-variant-numeric: tabular-nums; color: var(--muted);
}
.sgw-go:hover { border-color: var(--muted); color: var(--ink); }
.sgw-go:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ═════ MOBILE — 760px.  MOBILE_SPEC §1: two tiers, no third. ═════════════
   🔴 ONE SWIPEABLE ROW, NOT A GRID — changed when the deck went from five
   boards to fifteen.  Two-up was the right answer at five (three short rows);
   at fifteen it is EIGHT rows and ~590px of doors on a 390px screen, which is
   the same height complaint the rack earned, arriving by a new road.

   ⭐ So the doors become the strip this site already uses for a rail in a
   hand — snap scrolling, one thumb-height row — and the button underneath is
   the way in for anyone who does not want to swipe.  The strip is a PREVIEW
   and the button is the door; that is why nothing is hidden by this.
   ═════════════════════════════════════════════════════════════════════════ */
@media (max-width: 760px) {
  .sgw-grid {
    display: flex; gap: 8px;
    overflow-x: auto; -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity; scroll-padding-left: 0;
    padding-bottom: 4px;
  }
  .sgw-door {
    flex: 0 0 auto; width: 156px;
    scroll-snap-align: start;
    padding: 9px 10px 9px; min-height: 44px;
  }
  .sgw-name { font-size: 18px; white-space: nowrap; overflow: hidden;
              text-overflow: ellipsis; }
  /* THE MONO FLOOR — wanted.css §MOBILE: a desk reads 10.5px figures, a phone
     does not, and two figures on one door must not disagree about their size. */
  .sgw-meta, .sgw-go-n { font-size: 11px; }
  .sgw-yr { margin-left: auto; }
}

@media (max-width: 430px) {
  .sgw-door { width: 148px; }
  .sgw-name { font-size: 17px; }
}

/* ⭐ TOUCH, not the 760 tier: a phone in landscape is 844px wide and above the
   mobile tier entirely (MOBILE_SPEC §10.3), and the finger is still a finger. */
@media (hover: none) {
  .sgw-go { min-height: 44px; align-items: center; }
}

/* ══════════════════════════════════════════════ SAGA DOORS: THE FILM BEHIND ═══
   John, 2026-08-13: "custom each of the deck box so that it has background of
   the movies". The image is the saga's own cached plate (--art, set in
   landing.js :: sagaDoor from plate_id) — the same one the open board draws.

   ⛔ THE PICTURE IS ATMOSPHERE, THE BAR IS DATA. `.sgw-rule` is one segment per
   film in its measured poster tint, and it is the thing John singled out. So the
   art sits UNDER a heavy scrim and the rule keeps a solid backing: a photograph
   behind a 4px colour strip destroys exactly the reading it exists for.
   ⚠️ Layered with a pseudo-element rather than a background-image on the button
   itself, so the existing --tint left border, hover and focus ring are untouched. */
.sgw-door.has-art { position: relative; isolation: isolate; overflow: hidden; }
/* ⚠️ LIGHT IS THE BASE. tokens.css defines light on bare :root and applies dark
   through prefers-color-scheme + [data-theme]; writing this dark-first produced a
   milky wash on the light theme with dark text-shadows fighting it. So the
   restrained values live here and dark gets the override below. */
.sgw-door.has-art::before {
  content: ""; position: absolute; inset: 0; z-index: -2;
  background-image: var(--art);
  background-size: cover; background-position: center 28%;
  opacity: .16;
  filter: saturate(.55);
}
/* the scrim — darkest at the bottom, where the name, meta and rule live */
.sgw-door.has-art::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg,
              color-mix(in srgb, var(--panel) 55%, transparent) 0%,
              color-mix(in srgb, var(--panel) 82%, transparent) 55%,
              color-mix(in srgb, var(--panel) 95%, transparent) 100%);
}
/* ⭐ The two things that must stay legible over a photograph. */
.sgw-door.has-art .sgw-name { color: var(--ink); }
.sgw-door.has-art .sgw-rule { box-shadow: 0 0 0 1px rgba(0,0,0,.20); }
.sgw-door.has-art:hover::before { opacity: .26; }

/* ⭐ DARK CARRIES THE PICTURE. A plate reads at more than twice the strength
   against a dark panel, and a dark drop-shadow only helps there — on light it
   muddies the very text it is meant to lift. Both dark selectors, per the
   tokens.css contract: the media query for "system dark", the attribute for an
   explicit toggle. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .sgw-door.has-art::before {
    opacity: .30; filter: saturate(.75);
  }
  :root:not([data-theme="light"]) .sgw-door.has-art:hover::before { opacity: .42; }
  :root:not([data-theme="light"]) .sgw-door.has-art .sgw-name { text-shadow: 0 1px 3px rgba(0,0,0,.55); }
  :root:not([data-theme="light"]) .sgw-door.has-art .sgw-meta { text-shadow: 0 1px 2px rgba(0,0,0,.5); }
  :root:not([data-theme="light"]) .sgw-door.has-art .sgw-rule { box-shadow: 0 0 0 1px rgba(0,0,0,.35); }
}
:root[data-theme="dark"] .sgw-door.has-art::before { opacity: .30; filter: saturate(.75); }
:root[data-theme="dark"] .sgw-door.has-art:hover::before { opacity: .42; }
:root[data-theme="dark"] .sgw-door.has-art .sgw-name { text-shadow: 0 1px 3px rgba(0,0,0,.55); }
:root[data-theme="dark"] .sgw-door.has-art .sgw-meta { text-shadow: 0 1px 2px rgba(0,0,0,.5); }
:root[data-theme="dark"] .sgw-door.has-art .sgw-rule { box-shadow: 0 0 0 1px rgba(0,0,0,.35); }

/* ⚠️ prefers-reduced-motion is not the right query here, but a viewer who has
   asked for less visual noise gets the flat panel back. */
@media (prefers-contrast: more) {
  .sgw-door.has-art::before { opacity: .12; }
}

/* ═════════════════════════════════════════ THE FRANCHISE'S OWN MARK ═══
   John: "i want the font of each saga following the movie franchise too" ->
   "they are not similar at all" -> "if you can use logoart is even better
   because it will be exactly the same."
   ⭐ He was right on both counts. The 16 open-licensed lookalike faces that
   used to live here were chosen for REGISTER and did not resemble the marks;
   they are gone, and so are their 348 KB of webfonts. What renders now is the
   studio's OWN transparent wordmark, cached by sagalogos.py from Plex's
   clearLogo art — exact, and with nothing licensed smuggled in.
   ⛔ .sgw-name is NOT removed, only visually hidden once the image loads: a
   logo is a picture of a word, and the text is what a screen reader and
   in-page search actually use. */
.sgw-logo {
  display: none;
  width: 100%; max-width: 138px; height: auto;
  max-height: 46px; object-fit: contain; object-position: left center;
  margin: 1px 0 3px;
}
.sgw-door.has-logo .sgw-logo { display: block; }
/* ⚠️ clip, not display:none — the name must stay reachable to assistive tech */
.sgw-door.has-logo .sgw-name {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}
/* ⭐ Most clearLogos are white-on-transparent, which vanishes on a light panel.
   A soft dark drop keeps them readable there without touching the dark theme. */
.sgw-door.has-logo .sgw-logo { filter: drop-shadow(0 1px 2px rgba(0,0,0,.45)); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .sgw-door.has-logo .sgw-logo { filter: none; }
}
:root[data-theme="dark"] .sgw-door.has-logo .sgw-logo { filter: none; }
