/* Watch Unlocked.
 *
 * No build step, no dependency, no framework. Plain CSS, one request, cached across every
 * page on the site.
 *
 * This file NEVER names a colour. Every colour is a token from src/theme.ts, inlined into
 * each page's <head> as :root custom properties, so the open palette decision is one line
 * and cannot half-apply.
 *
 * Two principles it is worth being explicit about, because both are easy to undo:
 *
 * 1. THE ACCENT MARKS ONE THING: the exit click. Not the wordmark, not a heading, not a
 *    chip, not a score. If you find yourself adding `color: var(--accent)` to a fifth
 *    selector, the accent has stopped meaning anything and the page has stopped telling a
 *    reader what matters.
 * 2. HIERARCHY COMES FROM WEIGHT AND SPACE, not from boxes. There is no card-with-shadow
 *    in here, no gradient, no glow, and no border drawn for decoration. A border in this
 *    file separates two things that would otherwise run together, or it is a mistake.
 */

/* ------------------------------------------------------------ hidden means hidden */

/* THE `hidden` ATTRIBUTE HAS TO WIN, and without this rule it loses to every component in
 * this file that sets `display`.
 *
 * The browser's own stylesheet says `[hidden] { display: none }`, which is a bare attribute
 * selector - specificity 0,1,0. Any class rule that sets `display` outranks it. So
 * `.consent { display: flex }` meant a bar the server shipped `hidden` rendered anyway, and
 * `bar.hidden = true` in consent.js did nothing: the reader pressed Accept, the answer was
 * stored, the bar stayed on screen, and pressing it again did nothing visible. Reported as
 * "I can't click to accept or decline cookies", 2026-08-17.
 *
 * SIX components had it - `.consent`, `#services`, `#site-search`, `.offer-tabs`,
 * `.video-tabs`, `.modal-next` - and two of them were the failure their `hidden` exists to
 * prevent: the services picker and the search field are controls that DO nothing until
 * their script runs, so a reader with JavaScript off was being shown dead controls.
 *
 * `.modal[hidden]` and `.geo[hidden]` already carried their own copy of this fix, which is
 * the tell: the same bug had been found twice and patched per-component both times. One
 * rule, at the top, so the seventh component cannot repeat it. `!important` is what makes
 * it survive a later `display` on any class, which is the entire point. */
[hidden] { display: none !important; }

/* ---------------------------------------------------------------- the face */

/* Lato, SELF-HOSTED. The prototype specifies Lato at 400, 700 and 900, and the 900 is most
 * of what makes it look like itself.
 *
 * The objection to Lato was never the typeface, it was the CDN: hotlinking Google Fonts is a
 * render-blocking third-party request on every page and a German court has already ruled it
 * a GDPR violation, which matters with two EU markets and an AdSense review ahead. Serving
 * the bytes ourselves answers all of that and keeps the design. The previous lane threw the
 * typeface out with the CDN and the site went back to looking like a browser default.
 *
 * SIX faces, not three. Every weight ships latin AND latin-ext, because latin alone has no
 * ł, ż, ę or ą - one live market is Polish, and a missing subset does not fail, it silently
 * swaps the system face in mid-word. Same class of bug as the slug that ate the ł in
 * "Kryminał": invisible to anyone reading English output.
 *
 * 51KB for all six, subset by Google's own unicode-range split so a reader only downloads
 * the ranges the page actually uses. Italian pages never fetch latin-ext at all. */

@font-face {
  font-family: Lato; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/assets/site/fonts/lato-400-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: Lato; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/assets/site/fonts/lato-400-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: Lato; font-style: normal; font-weight: 700; font-display: swap;
  src: url(/assets/site/fonts/lato-700-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: Lato; font-style: normal; font-weight: 700; font-display: swap;
  src: url(/assets/site/fonts/lato-700-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: Lato; font-style: normal; font-weight: 900; font-display: swap;
  src: url(/assets/site/fonts/lato-900-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: Lato; font-style: normal; font-weight: 900; font-display: swap;
  src: url(/assets/site/fonts/lato-900-latin-ext.woff2) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------------------------------------------------------------- base */

*, *::before, *::after { box-sizing: border-box; }

html {
  /* The fallback stack still matters: `font-display: swap` means the first paint is set in
   * whatever is listed after Lato, and a reader on a slow connection may never leave it. */
  font-family: Lato, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  /* Polish stacks diacritics ABOVE and cedillas BELOW - Ż, ź, ą, ę - and a tight
   * line-height clips them. 1.6 is not a default here, it is the fix. */
  line-height: 1.6;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-size: clamp(1rem, 0.97rem + 0.15vw, 1.0625rem);
}

:where(a) { color: inherit; }
:where(img, video) { max-width: 100%; height: auto; }
/* Lato Black on every heading, which is how the prototype sets all of them. Loading the
 * face and then setting headings at 700 pays the bytes and keeps the document look. The
 * negative tracking is Lato's own: at 900 the counters close up and the default spacing
 * reads loose. */
:where(h1, h2, h3) {
  line-height: 1.2;
  text-wrap: balance;
  margin: 0;
  font-weight: 900;
  letter-spacing: -0.02em;
}
:where(p, ul, ol, dl, table) { margin: 0; }

:where(:focus-visible) {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 2px;
}

/* ---------------------------------------------------------------- shell */

/* The page gutter, lifted from the prototype, which uses one value everywhere: the bar, the
 * hero, every rail and every section all start on the same vertical line. That single
 * shared edge is most of why the prototype reads as one product and a stack of centred
 * cards does not. */
:root {
  --px: clamp(1rem, 4.4vw, 2.5rem);
  /* The globe on the geo band, as a mask rather than an <img>: it inherits currentColor and
   * costs no request. Inline data: rather than a file because it is 300 bytes and a
   * separate round trip for one glyph above the header would be on the critical path.
   * `data:` is already permitted by the CSP's img-src, which is what governs CSS masks. */
  --geo-glyph: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3a14 14 0 0 1 0 18a14 14 0 0 1 0-18"/></svg>');
}

/* FULL BLEED, LEFT ALIGNED. The site shipped `max-width: 46rem; margin-inline: auto`, so on
 * an 1100px screen a 736px column sat in the middle with roughly a third of the viewport
 * empty on either side. The prototype has no centred column anywhere.
 *
 * The measure is still capped - it is `.well` below, on the text that needs it - because a
 * 1000px line of prose is unreadable. The difference is that the cap now applies to the
 * PARAGRAPH rather than to the page, which is what leaves the right-hand side free for the
 * about rail. */
main > article {
  padding: clamp(1.25rem, 3vw, 2rem) var(--px) 5rem;
}

/* The measure, applied to the TEXT rather than to the page. Prose stops at ~46rem; a table,
 * a poster rail or a picker is free to use the width it now has. Without this the same
 * change that removed the dead margins would have produced 1000px lines of Italian. */
main > article > :where(h1, p, ul, ol, dl),
/* `ul.offers` is excluded BY NAME. It is the one list on this page type that is not prose:
   it is the offer cards, and capping it at the prose measure is what kept the block - and
   the exit click inside it - at two thirds of the width the layout already had. */
/* THE GRIDS ARE EXCLUDED BY NAME, all of them. The measure is for PROSE, and it was also
   catching every `ul` and `dl` that happens to sit in a section - so the video shelf, the
   gallery and the crew grid were each capped at 736px and left a third of the column blank
   beside them. `ul.offers` was excluded when the offer block became cards; the others are
   the same kind of object and needed the same exclusion. */
main > article > section > :where(h2, h3, p, ol),
main > article > section > ul:not(.offers):not(.video-cards):not(.video-list):not(.shots):not(.cast-rail):not(.leave-grid):not(.leave-later):not(.cat-strip),
/* The link fabric is a `nav`, not a `section`, and its rail needs the same exemption the
   other card rows got - otherwise the cross-sell is capped at the prose measure too. */
main > article > nav > :where(h2, p),
main > article > section > dl:not(.crew-grid),
main > article > footer > :where(p, small) {
  max-width: 46rem;
}

/* THE OFFER BLOCK TAKES THE WIDTH. The cap that used to be here said "for now" and
 * "it becomes cards in a later phase and the cap comes off with the rail". This is that
 * phase. The block is cards, not a five-column table, so width goes into the size of the
 * mark, the price and the button instead of into 300px of air between them. */
#services { max-width: 46rem; }

/* ---------------------------------------------------------------- the bar */

/* Sticky, translucent, hairline under it. 72px in the prototype; ours is shorter because it
 * carries three controls rather than seven, and a bar with room left over looks like a bar
 * missing something. */
.site-head {
  position: sticky;
  top: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem 1.25rem;
  min-height: 3.75rem;
  padding: 0.6rem var(--px);
  /* The alpha is deliberate: content scrolling under the bar should be visible and unread,
   * which is what tells a reader the page moved rather than changed. */
  background: color-mix(in srgb, var(--ground) 88%, transparent);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid var(--border);
}

/* No backdrop-filter, no translucency. A bar you can read the page through, with nothing
 * blurring it, is worse than an opaque one. */
@supports not (backdrop-filter: blur(1px)) {
  .site-head { background: var(--ground); }
}

.wordmark {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex: none;
  font-weight: 900;
  font-size: 1.1875rem;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-decoration: none;
}
/* The only place on the site where the accent is not the exit click.
 *
 * That rule was written against the prototype spending yellow on the CTA, the score, the
 * nav, the wordmark and the chips at once, which is what made it mean nothing. One mark, in
 * the corner, that never appears again on the page is not that: it is the logo, and a
 * wordmark in body grey is not a wordmark. Nothing else here gets it. */
.wordmark .mark {
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
  font-size: 0.875rem;
  line-height: 1.2;
  padding: 0.3rem 0.5rem;
  border-radius: 4px;
}

.site-nav, .site-geo { display: flex; align-items: center; gap: 0.5rem; flex: none; }
.site-nav a {
  font-weight: 700;
  font-size: 0.875rem;
  color: var(--ink-2);
  text-decoration: none;
  padding: 0.35rem 0;
}
.site-nav a:hover { color: var(--ink); }

.site-geo { margin-left: auto; gap: 0.375rem; }
.site-geo a {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.75rem 0.35rem 0.4rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  font-weight: 700;
  font-size: 0.8125rem;
  color: var(--ink-2);
  text-decoration: none;
}
.site-geo a:hover { border-color: var(--ink-3); color: var(--ink); }
/* The market you are in, marked with weight and a surface rather than the accent. */
.site-geo a[aria-current] { color: var(--ink); border-color: var(--ink-3); }
.geo-code {
  background: var(--surface-2);
  color: var(--ink-3);
  font-weight: 900;
  font-size: 0.6875rem;
  letter-spacing: 0.04em;
  padding: 0.25rem 0.375rem;
  border-radius: 4px;
}
.site-geo a[aria-current] .geo-code { color: var(--accent-ink); background: var(--accent); }

/* ---- the country selector -----------------------------------------------------------
 *
 * `Design.md` section 5: a pill showing code + name, opening a panel of all 54 countries
 * grouped under region headings, with the border turning yellow while open. Two of those
 * countries have pages; the other 52 render as text with a SOON marker, which is the same
 * treatment the front door's roadmap already gives them.
 *
 * `<details>` rather than a script: it opens, closes, takes focus and answers Enter and
 * Space with nothing loaded, so the control is never present-but-dead. */
.geo-picker { position: relative; }
.geo-picker > summary {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.7rem 0.35rem 0.4rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  font-weight: 700;
  font-size: 0.8125rem;
  color: var(--ink-2);
  cursor: pointer;
  list-style: none;
}
.geo-picker > summary::-webkit-details-marker { display: none; }
/* Hover is a border change and nothing else - Design.md section 4, which is also why there
   is no shadow anywhere in this file. */
.geo-picker > summary:hover { border-color: var(--border-hover); color: var(--ink); }
/* "Border turns yellow while open." The accent means act or you-are-here, and an open
   selector is exactly you-are-here. */
.geo-picker[open] > summary { border-color: var(--accent); color: var(--ink); }
.geo-picker > summary .geo-code { color: var(--accent-ink); background: var(--accent); }
.geo-caret { flex: none; transition: transform 0.18s ease-out; }
.geo-picker[open] .geo-caret { transform: rotate(180deg); }

.geo-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 0.5rem);
  z-index: 70;
  width: 340px;
  max-width: calc(100vw - 2rem);
  /* 54 countries under six headings. Taller than most viewports, so the panel scrolls
     rather than the page growing a second scrollbar behind an overlay. */
  max-height: min(70vh, 34rem);
  overflow-y: auto;
  padding: 0.9rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
}
.geo-note {
  margin: 0 0 0.75rem;
  font-size: 0.75rem;
  color: var(--ink-3);
}
.geo-region + .geo-region { margin-top: 0.85rem; }
.geo-region h3 {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 0.35rem;
}
.geo-region ul { list-style: none; padding: 0; display: grid; gap: 0.1rem; }
.geo-region a,
.geo-region .geo-soon {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.4rem;
  border-radius: 6px;
  font-size: 0.875rem;
  text-decoration: none;
  color: var(--ink-body);
}
.geo-region a:hover { background: var(--surface-2); color: var(--ink); }
.geo-region a[aria-current] { color: var(--ink); font-weight: 700; }
.geo-region a[aria-current]::after { content: '✓'; margin-left: auto; color: var(--accent); }
/* The 52 with no page. Not a link, and it must not look like one - the same rule the
   roadmap on the front door follows. */
.geo-region .geo-soon { color: var(--ink-dim, #6B7280); cursor: default; }
.geo-region .geo-soon .geo-code { opacity: 0.55; }

/* At 375 the bar was wrapping to three rows and taking 165px before the reader saw the
 * title - a fifth of the viewport spent on chrome. The country name goes; the code stays,
 * which is what the prototype's own pill leads with anyway. Measured, not guessed. */
@media (max-width: 40rem) {
  .site-geo a { padding: 0.3rem 0.4rem; font-size: 0; gap: 0; }
  .site-geo a .geo-code { font-size: 0.6875rem; }
  .geo-picker > summary .geo-name { display: none; }
  .site-head { gap: 0.5rem 0.75rem; }
}

/* ---------------------------------------------------------------- search */

#site-search {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex: 1 1 14rem;
  min-width: 11rem;
  max-width: 26rem;
  padding: 0.6rem 0.875rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  color: var(--ink-3);
}
#site-search:focus-within { border-color: var(--ink-3); }
.search-icon { flex: none; }
#site-search-q {
  flex: 1;
  min-width: 0;
  background: transparent;
  border: 0;
  outline: 0;
  color: var(--ink);
  font: inherit;
  font-size: 1rem;
}
#site-search-q::placeholder { color: var(--ink-3); }

#site-search-results {
  position: absolute;
  top: calc(100% + 0.5rem);
  left: 0;
  right: 0;
  z-index: 80;
  margin: 0;
  padding: 0.25rem;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 24px 60px rgb(0 0 0 / 0.55);
  max-height: 60vh;
  overflow-y: auto;
}
#site-search-results a {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.4rem 0.5rem;
  border-radius: 6px;
  color: var(--ink);
  text-decoration: none;
}
#site-search-results li[aria-selected="true"] a,
#site-search-results a:hover { background: var(--surface-2); }
/* The box is reserved whether or not a thumbnail exists, so a slow poster - and the four
 * Polish titles with no w185 derivative on disk - cannot reflow a list mid-keystroke. */
#site-search-results img {
  flex: none;
  width: 1.75rem;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: 3px;
  background: var(--surface-2);
}
#site-search-results strong { display: block; font-weight: 700; font-size: 0.9375rem; }
#site-search-results small { color: var(--ink-3); font-size: 0.8125rem; }
#site-search-results .no-hit { padding: 0.75rem 0.625rem; color: var(--ink-3); font-size: 0.875rem; }

/* ---------------------------------------------------------------- skip link */

/* Three controls sit between the top of the document and the content on every page now, so
 * a keyboard reader needs a way past them. Visible only when focused. */
.skip {
  position: absolute;
  left: 0.5rem;
  top: -4rem;
  z-index: 100;
  padding: 0.6rem 1rem;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
  border-radius: 0 0 8px 8px;
  text-decoration: none;
}
.skip:focus { top: 0; }

/* Used by the search label, which a sighted reader gets from the placeholder and a screen
 * reader needs as a real label - a placeholder is not one. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------------------------------------------------------------- the hero */

/* Breaks out of the article's padding to run edge to edge, then puts its own back. The
 * prototype has no inset on this band and an inset hero reads as a card, which is the
 * opposite of what a hero is for. */
.hero {
  position: relative;
  isolation: isolate;
  margin: calc(-1 * clamp(1.25rem, 3vw, 2rem)) calc(-1 * var(--px)) 0;
  padding: clamp(1.75rem, 4vw, 2.75rem) var(--px);
  border-bottom: 1px solid var(--border);
  display: flex;
  /* Top-aligned: the title starts on the same line as the poster, the way TMDB
   * draws this band. Centering it dropped the heading into the middle of a 450px
   * sheet and left a dead strip above the one sentence that has to stay on screen. */
  align-items: flex-start;
  gap: clamp(1rem, 3vw, 2.5rem);
}
.hero.has-art { min-height: 19rem; }
/* Poster on the LEFT, same gutter as the rest of the page. Width is also the flex
 * basis, and min-width is zero, because a 780px img inside a flex item with
 * `min-width: auto` inflates the sheet to the row width the moment the band wraps. */
.hero-poster {
  flex: 0 0 clamp(6.5rem, 22vw, 18.75rem);
  width: clamp(6.5rem, 22vw, 18.75rem);
  min-width: 0;
  z-index: 1;
}
.hero-poster picture { display: block; }
.hero-poster-img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: 6px;
  background: var(--surface-2);
}

.hero-art {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Anchored high. A 16:9 backdrop cropped to a 300px band from the centre cuts faces in
   * half; the top third is where the subject almost always is. */
  object-position: 50% 25%;
}

/* TWO gradients, both from the prototype and each doing a different job. The horizontal one
 * makes the text side readable; the vertical one lands the band on the page below it
 * instead of ending in a hard edge. Without the second, the join reads as a seam. */
.hero.has-art::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(0deg, var(--ground) 2%, transparent 70%),
    linear-gradient(90deg, var(--ground) 22%,
      color-mix(in srgb, var(--ground) 62%, transparent) 60%,
      color-mix(in srgb, var(--ground) 18%, transparent) 100%);
}

.hero-body,
.hero-lead {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  min-width: 0;
}
.hero-body {
  flex: 1 1 auto;
  max-width: 44rem;
}
/* Uppercase, as the prototype sets it. The year is inside the h1 and stays there: it is
 * part of the heading a search result shows, and splitting it into a sibling to grey it
 * would take it out of the title the crawler reads. */
.hero-body h1 {
  font-size: clamp(1.75rem, 1.1rem + 3vw, 2.5rem);
  text-transform: uppercase;
  letter-spacing: -0.01em;
}
.hero-body .answer { margin: 0; }

.hero-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  color: var(--ink-2);
  font-size: 0.9375rem;
  font-weight: 700;
}
.hero-meta i { color: var(--ink-3); font-style: normal; }
/* Sourced, and it says so. The prototype's "FR 93%" is a house score from a review
 * operation we do not run; this one carries the name of whoever measured it. */
.hero-meta .score {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--ink);
  padding: 0.2rem 0.5rem;
  border-radius: 4px;
  font-weight: 900;
  font-variant-numeric: tabular-nums;
}

.jumps { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.25rem; }
.jumps a {
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  font-weight: 700;
  font-size: 0.875rem;
  text-decoration: none;
}
.jumps a:hover { border-color: var(--ink-3); }

.hero-play {
  flex: none;
  align-self: center;
  margin-inline-start: auto;
  width: 4.75rem;
  height: 4.75rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  /* Optically centred: a triangle's mass sits left of its bounding box. */
  padding-inline-start: 0.35rem;
}
.hero-play:hover { background: color-mix(in srgb, var(--accent) 86%, black); }

/* The backdrop <picture> is taken out of flow so it cannot occupy a flex or
 * grid slot of its own - only the img is painted, absolutely. */
.hero > picture:has(.hero-art) {
  position: absolute;
  inset: 0;
  z-index: -2;
  pointer-events: none;
}
@media (max-width: 48rem) {
  .hero-play {
    width: 3.25rem;
    height: 3.25rem;
  }
  .hero-play svg { width: 15px; height: 18px; }
}

/* Phone: poster + title on one row, answer on a full-width row beneath.
 * Flex left the sentence in a 134px column beside the play circle. */
@media (max-width: 36rem) {
  .hero.has-poster {
    display: grid;
    grid-template-columns: 6.75rem minmax(0, 1fr);
    align-items: start;
    column-gap: 0.85rem;
    row-gap: 0.75rem;
  }
  .hero-poster {
    grid-column: 1;
    grid-row: 1;
    width: 6.75rem;
    flex: none;
  }
  .hero.has-poster .hero-body { display: contents; }
  .hero-lead { grid-column: 2; grid-row: 1; }
  .hero.has-poster .answer,
  .hero.has-poster .jumps { grid-column: 1 / -1; }
  .hero-body h1 { font-size: 1.35rem; }
  .hero-play {
    grid-column: 1 / -1;
    margin-inline-start: 0;
    justify-self: start;
  }
}

/* THE SPACE TO THE RIGHT OF THE PROSE IS INVENTORY, NOT A BUG. Owner, 2026-08-16.
 *
 * It looked like the verdict and the plot were "cut half way": a 736px paragraph under a
 * hairline running the full 1040px column. They are not cut - the 46rem measure is doing its
 * job, and it stays, because the design guide's own prototype caps its blurb at 760px and
 * 46rem of Italian is already ~90 characters, past the comfortable range rather than short
 * of it.
 *
 * MEASURED: the prose ends at x=776 and the sidebar starts at x=1112, so the gap inside the
 * main column is 304px. That is a standard 300x250 or 300x600 unit with room to spare, which
 * is exactly what the owner said it should be. So the measure keeps the text readable and
 * the leftover keeps the ad - the two are not in conflict, and neither one has to move. */
.in-content-slot {
  float: inline-end;
  width: 300px;
  margin: 0 0 1rem 2rem;
}
@media (max-width: 64rem) {
  /* No second column below the sidebar breakpoint: the slot goes full width in the flow
     rather than floating a 300px box beside a 375px screen. */
  .in-content-slot { float: none; width: 100%; margin: 1.25rem 0; }
}

/* Sections are separated by space and a single hairline, never by a box. The rule sits
 * above the heading so the heading reads as belonging to what follows it. */
article > section,
article > nav,
/* The aside is one block in the flow, so IT takes the hairline and the spacing; its own
 * sections are separated inside it by the sidebar rules and must not each draw a rule of
 * their own. */
article > aside.side {
  margin-top: clamp(2rem, 5vw, 3rem);
  padding-top: clamp(1.25rem, 3vw, 1.75rem);
  border-top: 1px solid var(--border);
}

/* Section labels. Small, quiet, and structural - the CONTENT is what should be loud.
 *
 * NOT ON THE FRONT DOOR, for the same reason as the link rule below: `/` is a component
 * page, its section headings ARE the content, and this rule turned the closing call - the
 * largest sentence on the page - into 12px grey capitals. Excluded here rather than reset
 * in the front-door block, because a reset written as `font-size: inherit` at (0,1,3) then
 * beat every component rule that set a real size, which is the same specificity trap one
 * layer down. */
/* The aside's own sections are listed here, at the definition, rather than restyled next
 * to the sidebar rules. They are the same kind of thing - a quiet structural label over a
 * block - and they are only grandchildren because the sidebar needed one wrapper to be
 * placed as a unit. Left out, the three reference blocks rendered their headings as full
 * white h2s and the ratings spread shouted louder than the verdict, which is precisely the
 * mistake the comment above this rule describes. */
article:not(.home) > section > h2,
article:not(.home) > nav > h2 {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: 0.85rem;
}
/* THE SIDEBAR'S OWN HEADINGS ARE LOUDER THAN THE MAIN COLUMN'S. Owner's reference: "ABOUT
   THE SERIES" is white and heavy over quiet blue field labels, so the panel reads as a card
   with a title rather than as four grey labels of equal weight. The main column keeps the
   quiet structural label, because there the CONTENT is what should be loud. */
article:not(.home) > aside.side > section > h2 {
  font-size: 0.9375rem;
  font-weight: 900;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 0.7rem;
}

/* 900, not 800. Lato ships 400/700/900 and there is no 800 face, so `font-weight: 800`
 * asked the browser to SYNTHESISE one - it picks 900 and may fake-bold it. Caught by
 * reading `getComputedStyle(h1).fontWeight` on the served page, which said 800 while this
 * file's `:where(h1, h2, h3)` rule said 900 and lost on specificity. */
h1 {
  font-size: clamp(1.75rem, 1.2rem + 2.6vw, 2.75rem);
  font-weight: 900;
  letter-spacing: -0.02em;
}

/* Where the prototype put "FR 76%". A sourced fact instead of a house opinion: this is the
 * one number on the page nobody can argue with, and no competitor page carries it.
 *
 * It is NOT accented. The accent means the exit click and nothing else, and a badge that
 * shouts as loudly as the CTA is the prototype's problem restated. It earns its place with
 * weight and a surface. */
.rank-badge {
  display: inline-block;
  margin-top: 0.6rem;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 0.8125rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-decoration: none;
}
.rank-badge:hover { color: var(--ink); border-color: var(--ink-3); }

.tagline {
  margin-top: 0.5rem;
  color: var(--ink-2);
  font-style: italic;
  font-size: 1.05rem;
}

/* ------------------------------------------------------- the answer */

/* The single most important element on the site. It is the sentence a featured snippet or
 * an AI Overview lifts whole, and the sentence a reader who bounces will have read. It is
 * the largest non-heading text on the page for exactly that reason, and nothing above it
 * may grow to the point where it pushes this below the fold. */
.answer {
  margin-top: 1.25rem;
  font-size: clamp(1.125rem, 1.02rem + 0.5vw, 1.375rem);
  line-height: 1.45;
  font-weight: 500;
  text-wrap: pretty;
}

/* ------------------------------------------------------- the buybox */

/* The buybox comes before the plot and it is the reason the page exists, so it is the one
 * block that gets a surface of its own. */
#where-to-watch { border-top: none; padding-top: 0; }

#where-to-watch > h2 {
  /* Carries the title's name, so it is a real heading and not a label. */
  font-size: 0.8125rem;
}

/* The season table still uses this container - it IS a table, it IS compared down, and it
   is capped for exactly the reason the offer table used to be. */
.offers-scroll {
  /* A 5-column table fits 360px only just. When it does not, this scrolls rather than
   * squeezing the price column to two characters. tabindex makes it reachable by keyboard,
   * which a plain overflow container is not. */
  overflow-x: auto;
  overscroll-behavior-x: contain;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  max-width: 46rem;
}

/* ------------------------------------------------------- the offer cards */

/* THE BLOCK THE SITE EARNS FROM, and until now the quietest thing on the page: a 20px mark,
   a 15px name, and a 40px chip reading "Vai" at the end of the fourth column of a table
   capped at the prose measure. Everything below is the correction. The rule it must keep is
   the one the accent has always had here - the exit click is the ONLY thing wearing it. */

/* TOKENS LIFTED VERBATIM from the prototype's detail view (the standalone-src copy of it,
   the offer row), rather than re-derived:

     row      flex · align-items center · gap 16px · padding 14px 16px · radius 8px
              background #101923 · 1px solid #1A2430 · hover border #374151
     mark     42x42 · radius 8px · flex none
     middle   flex 1 1 200px · min-width 0 · column gap 4px
     service  700 16px/1.2 #fff        kind 700 11px/1.2 .6px uppercase
     note     400 13px/1.2 #6B7280
     right    margin-left auto · gap 14px
     quality  padding 5px 9px · radius 4px · bg #1A2430 · 700 11px/1.2 #999C9F
     price    700 17px/1.2 #fff · min-width 78px · right
     cta      height 40px · padding 0 20px · radius 8px · 700 14px/1.2 */
ul.offers {
  list-style: none;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

li.offer {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 14px 16px;
  border-radius: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
}
li.offer:hover { border-color: var(--border-hover); }

li.offer .offer-mark {
  flex: none;
  width: 42px;
  height: 42px;
  border-radius: 8px;
  object-fit: contain;
  /* Many of these marks are pure black on transparent, invisible on a dark surface, so they
     sit on their own light chip - the treatment every service uses for its own mark. */
  background: #fff;
}
li.offer .offer-mark.is-blank {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
  color: var(--ink-3);
  font: 900 10px/1.2 inherit;
}

li.offer .offer-what {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1 1 200px;
  min-width: 0;
}
li.offer .offer-service { font: 700 16px/1.2 inherit; color: var(--ink); }
li.offer .route {
  display: block;
  font: 400 13px/1.2 inherit;
  color: var(--ink-dim, #6B7280);
}
li.offer .offer-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  font: 400 13px/1.2 inherit;
  color: var(--ink-dim, #6B7280);
}
/* Quality is a chip, at one size, the way the prototype draws it. */
li.offer .q, li.offer .q-top {
  padding: 5px 9px;
  border-radius: 4px;
  background: var(--border);
  font: 700 11px/1.2 inherit;
  color: var(--ink-2);
}
li.offer .q-top { color: var(--ink); }

li.offer .offer-price {
  margin-left: auto;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
li.offer .offer-price b { font: 700 17px/1.2 inherit; color: var(--ink); min-width: 78px; }
li.offer .offer-price small {
  display: block;
  margin-top: 3px;
  font: 700 11px/1.2 inherit;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--ink-3);
  white-space: nowrap;
}

/* THE EXIT CLICK. Scoped at the class, not under `li.offer`: the sidebar money seat is the
   same control and the first version of this rule left it an underlined text link. */
.offer-go {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  height: 40px;
  padding: 0 20px;
  border-radius: 8px;
  background: var(--accent);
  color: var(--accent-ink);
  font: 700 14px/1.2 inherit;
  text-decoration: none;
  white-space: nowrap;
}
.offer-go:hover { background: var(--accent-pressed); }
.go-play { flex-shrink: 0; }

/* The departure, on the card it belongs to. */
li.offer .offer-leaving {
  flex: 1 1 100%;
  margin-top: 4px;
  padding-top: 10px;
  border-top: 1px solid color-mix(in srgb, var(--alert) 35%, transparent);
  color: var(--alert);
  font: 600 13px/1.2 inherit;
}

@media (max-width: 34rem) {
  li.offer .offer-price { margin-left: 0; }
  .offer-go { flex: 1 1 100%; }
}

/* ------------------------------------------------------- the offer tabs */

/* A SEGMENTED CONTROL IN A BOX, which is what the prototype draws - not free-floating pills.
   Group: flex · gap 4px · bg #101923 · 1px solid #1A2430 · radius 8px · padding 4px
   Tab:   padding 8px 14px · radius 6px · 700 13px/1.2 */
.offer-tabs {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 12px;
  padding: 4px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.offer-tabs button {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--ink-2);
  font: 700 13px/1.2 inherit;
  cursor: pointer;
}
.offer-tabs button:hover { color: var(--ink); }
/* The selected tab takes the raised surface, never the accent: the accent is the exit click
   and a tab wearing it would compete with the button it filters. */
.offer-tabs button[aria-pressed="true"] {
  background: var(--surface-2);
  color: var(--ink);
}
.offer-tabs .tab-n { font: 700 12px/1.2 inherit; color: var(--ink-3); }
.offer-tabs button[aria-pressed="true"] .tab-n { color: var(--ink-2); }

ul.offers li[data-off] { display: none; }

/* --------------------------------------------- the sidebar money seat */

/* THE EXIT CLICK, IN THE COLUMN THAT FOLLOWS THE READER. The offer block is at the top of a
   page that runs to 6,972px; below the first screen there was no way to act without
   scrolling back. The sidebar is already sticky, so this card is on screen for the whole
   page - and it is the same accent on the same class, so there is still exactly one thing
   on this site wearing the loudest colour available. */
#side-cta {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 1rem;
}
#side-cta .side-cta-service {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin-bottom: 0.85rem;
  font-weight: 700;
  line-height: 1.25;
}
#side-cta .side-cta-service small {
  display: block;
  font-weight: 400;
  font-size: 0.8125rem;
  color: var(--ink-2);
}
/* Full width here, because in an 18rem column a button that is not full width is a button
   with a gap beside it and nothing to put in the gap. */
#side-cta .offer-go { display: flex; justify-content: center; width: 100%; }

/* --------------------------------------------- the sidebar cross-sell */

/* The next thing to watch, drawn from the SAME set as the link fabric at the foot of the
   page - never a second set, because two views of one list is how this site once ended up
   picturing a title it no longer linked. */
#side-similar ul { list-style: none; padding: 0; display: grid; gap: 0.6rem; }
#side-similar a {
  display: grid;
  grid-template-columns: 3rem minmax(0, 1fr);
  align-items: center;
  gap: 0.65rem;
  font-size: 0.875rem;
  line-height: 1.3;
  color: var(--ink-2);
}
#side-similar a:hover { color: var(--ink); }
#side-similar .side-art {
  width: 3rem;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: 6px;
  background: var(--surface-2);
}
/* Inline here, unlike the rail's block year - a sidebar row is one line. The space is drawn
   by the margin rather than by a text node, because the markup runs them together. */
#side-similar i { margin-left: 0.35rem; color: var(--ink-3); font-style: normal; }

/* The no-poster fallback. A name is a real answer; a grey rectangle standing in for artwork
   we do not have is not, so the whole poster column goes rather than shipping an empty one. */
#side-similar.is-text a { display: block; grid-template-columns: none; }

/* --------------------------------------------- the sellable slot */

/* Reserved size so a creative arriving later does not push the column around. It renders
   only with SITE_ADS=on: an empty grey box on 538 live pages is an advert for the fact that
   we could not fill it. */
.ad-slot {
  min-height: 250px;
  margin-top: clamp(1.25rem, 3vw, 1.75rem);
  border: 1px dashed var(--border);
  border-radius: 10px;
}

/* ------------------------------------------------------- the offer tabs */

/* Ships `hidden`; tabs.js un-hides it. With JavaScript off it never appears, rather than
   appearing and doing nothing. */
.offer-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 0.75rem;
}
.offer-tabs button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: 0.875rem;
  cursor: pointer;
}
.offer-tabs button:hover { color: var(--ink); }
/* The selected tab is stated with weight and the surface, never with the accent: the accent
   is the exit click, and a tab that wears it competes with the button it filters. */
.offer-tabs button[aria-pressed="true"] {
  background: var(--surface-2);
  border-color: var(--ink-3);
  color: var(--ink);
  font-weight: 700;
}
.offer-tabs .tab-n { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.offer-tabs button[aria-pressed="true"] .tab-n { color: var(--ink-2); }

/* HIDES, where the services picker DIMS the same cards. A tab is a momentary "show me the
   rentals"; the picker is a standing preference about what you already pay for, which is
   still worth seeing greyed. If both dimmed, a card excluded by each would be dimmed twice
   and unreadable. */
ul.offers li[data-off] { display: none; }

/* ------------------------------------------------------- services picker */

/* Ships `hidden`; picker.js un-hides it. With JavaScript off it never appears, rather than
 * appearing and doing nothing. */
#services {
  border: 0;
  margin: 0 0 0.9rem;
  padding: 0;
}
#services fieldset {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 0.85rem 1rem 0.95rem;
  margin: 0;
  background: var(--surface);
}
#services legend {
  padding: 0 0.4rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
}
#services .hint {
  margin: 0 0 0.65rem;
  color: var(--ink-3);
  font-size: 0.8125rem;
}
#services label {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0 0.75rem 0.35rem 0;
  font-size: 0.9375rem;
  cursor: pointer;
}
#services input { accent-color: var(--accent); margin: 0; }
#services button {
  display: block;
  margin-top: 0.55rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-3);
  font: inherit;
  font-size: 0.8125rem;
  text-decoration: underline;
  text-underline-offset: 0.18em;
  cursor: pointer;
}
#services button:hover { color: var(--ink); }

/* THE ROWS ARE NEVER HIDDEN. They are dimmed and sorted after the ones you have, so the
 * reader can still see the whole market and the crawler is looking at an untouched DOM.
 * Hiding them would make the picker a content-cloaking device on the page that ranks. */
:root[data-services-on] li.offer:not([data-mine]) { opacity: 0.42; }
:root[data-services-on] li.offer:not([data-mine]) .offer-go {
  background: var(--surface-2);
  color: var(--ink-2);
}
/* A card for a service you have is marked with an edge rather than another colour - the
 * accent still means the exit click and nothing else. */
:root[data-services-on] li.offer[data-mine] {
  box-shadow: inset 3px 0 0 var(--accent);
}

/* The explicit negatives. A reader deciding tonight needs to be told it cannot be bought,
 * not left to infer it from a row that is not there - so this is quiet, but present. */
.no-offers, .watch-note {
  margin-top: 0.9rem;
  color: var(--ink-2);
  font-size: 0.9375rem;
}

/* The honest page. Nothing streams it here, and this is the block no competitor ships. */
.unavailable {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1.1rem 1.15rem;
}
.unavailable p + p { margin-top: 0.6rem; color: var(--ink-2); }

/* The freshness stamp. Small, but this is the claim the entire site rests on: an undated
 * availability claim is untrustworthy within weeks, and this page type goes stale by
 * design. It sits directly under the answer it dates. */
.verified {
  margin-top: 0.75rem;
  color: var(--ink-3);
}
.verified small, small { font-size: 0.8125rem; }

/* ------------------------------------------------------- per-season */

/* Reuses .offers, so it inherits the hairlines, the scroll container and the tabular
 * figures. The overrides are only where the columns mean different things: the first cell
 * is a season NUMBER rather than a service name, and every remaining cell is comparable
 * DOWN the column, which is the whole reason this is a table. */
/* Selectors are written at table.offers' own specificity on purpose. The base table styles
 * column 3 as QUALITY (small, muted) and column 5 as the CTA button; here column 3 is a
 * rental price and there is no column 5, so a lower-specificity override would silently
 * lose and the price column would render as muted small print. */
table.season-offers td:first-child {
  min-width: 0;
  width: 1%;
  font-weight: 400;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
table.season-offers td:nth-child(2) {
  white-space: normal;
  font-size: 0.9375rem;
  color: var(--ink);
}
table.season-offers td:nth-child(3),
table.season-offers td:nth-child(4) {
  font-size: 0.9375rem;
  color: var(--ink);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
table.season-offers td:last-child { text-align: left; width: auto; }

/* These cells are links, not buttons. The buybox above is the action; four accent pills a
 * row would drown the comparison this table exists to make - and the accent means the exit
 * click, which the buybox already owns. */
table.offers.season-offers td a,
table.offers.season-offers td:last-child a {
  display: inline;
  padding: 0;
  border-radius: 0;
  background: none;
  color: inherit;
  font-weight: inherit;
  font-size: inherit;
  text-decoration: underline;
  text-decoration-color: var(--ink-3);
  text-underline-offset: 0.18em;
}
table.offers.season-offers td a:hover,
table.offers.season-offers td:last-child a:hover {
  text-decoration-color: var(--accent);
  filter: none;
}

/* ------------------------------------------------------- departures */

/* The only alarm on the site. `available_to` is the scarcest data in this vertical and the
 * single reason a reader comes back, so red is spent here and nowhere else. */
#leaving {
  border-top: none;
  padding: 0.9rem 1.1rem;
  margin-top: 1.5rem;
  background: color-mix(in srgb, var(--alert) 9%, transparent);
  border-inline-start: 3px solid var(--alert);
  border-radius: 0 8px 8px 0;
}
#leaving > h2 { color: var(--alert); margin-bottom: 0.35rem; }
#leaving ul { list-style: none; padding: 0; font-size: 0.9375rem; }
#leaving li + li { margin-top: 0.35rem; }
/* What STAYS. Quieter than the departure it qualifies, but present - it is the half that
 * makes the claim true, and 44% of this site's series departure claims were wrong without
 * it. Its own line, because the two clauses ran together as one sentence. */
#leaving .stays { display: block; color: var(--ink-2); font-size: 0.875rem; }

/* ------------------------------------------------------- the chart */

/* The uncopyable fact. "1,670 days in Italy's top 100, peaked at number 1" is a per-title
 * number no competitor page carries and no reader can argue with. In the prototype this
 * slot held a Watch Unlocked score - a percentage we would have had to defend. A sourced fact
 * is worth more than a house opinion here, so it gets the emphasis the score was drawn
 * with, and none of the colour. */
#chart p:first-of-type {
  font-size: clamp(1.0625rem, 1rem + 0.35vw, 1.25rem);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
#chart p + p { margin-top: 0.5rem; color: var(--ink-3); }

/* ------------------------------------------------------- facts, ratings */

#ratings ul, #aka p { list-style: none; padding: 0; }
#ratings li { font-variant-numeric: tabular-nums; }
#ratings li + li { margin-top: 0.3rem; }
#ratings small { color: var(--ink-3); }

#facts { display: flow-root; }

/* THE SIDEBAR FACTS ARE STACKED, LABEL ABOVE VALUE. Owner's reference, 2026-08-16.
 *
 * They were a two-column grid - label left in grey, value right - in an 18rem column. At
 * that width the value column is ~9rem, so "20th Century Studios, Wendy Finerman
 * Productions" wrapped to four ragged lines against a one-line label and the block read as
 * broken rather than as a table.
 *
 * Stacked, every value gets the full column and nothing wraps against a label. The label
 * takes the link blue, uppercase, 12px/700 - the same treatment the crew grid uses, because
 * it is the same object: a small field name over a value. */
#facts dl { display: block; }
#facts dt {
  font-weight: 700;
  font-size: 0.75rem;
  line-height: 1.2;
  letter-spacing: 0.033em;
  text-transform: uppercase;
  color: var(--link);
}
#facts dd {
  margin: 0.2rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: var(--ink);
}
#facts dd + dt { margin-top: 0.85rem; }

/* ------------------------------------------------------- prose */

/* 760px, WHICH IS THE PROTOTYPE'S OWN MEASURE for `detail.blurb`, not a number of mine.
 *
 * This was 38rem - 608px - with a note reading "~72 characters". That is a defensible
 * typographic rule and it was still wrong here, because it is narrower than the design it is
 * implementing: the prose stopped at 608px under a hairline running the full column, which is
 * what "cut half way" was pointing at. The prototype puts the same paragraph at 760px. */
#verdict p, #plot p, #context p {
  max-width: 760px;
  text-wrap: pretty;
}
#verdict p { font-size: 1.0625rem; }
.lang-note { color: var(--ink-3); margin-bottom: 0.5rem; }

/* ------------------------------------------------------- cast, crew */

#collection p {
  list-style: none;
  padding: 0;
}


/* THE CAST IS A RAIL OF PORTRAIT CARDS. Owner's reference, 2026-08-16: the TMDB "Top Billed
 * Cast" strip - a headshot, the name in 700 under it, the character under that, scrolled
 * sideways.
 *
 * 3,495 headshots were on disk while this rendered as a 44px avatar beside a line of text.
 * The face is the fastest way a reader confirms they have the right person, and at 44px it
 * was an icon rather than a photograph.
 *
 * NATIVE SCROLL, NO ARROWS - `Design.md` section 1.3: "the fade IS the affordance". The rail
 * scrolls with a trackpad, a touch swipe and the keyboard, and nothing has to load first.
 *
 * The card keeps its shape when the photo is missing - 74 people have no headshot - because
 * the portrait box is drawn by the card, not by the image. #crew is untouched: it has no
 * faces and reads as a list of jobs. */
#cast ul {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 10.5rem;
  gap: 0.85rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  /* Room for the shadowless card edge and the scrollbar some platforms draw. */
  padding-bottom: 0.5rem;
  /* The edge fade. It disappears at the end of the scroll because the mask is painted on
     the container, not on a card. */
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 3rem), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 3rem), transparent);
}
#cast li {
  scroll-snap-align: start;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  overflow: hidden;
}
/* Hover is a border change and nothing else - Design.md section 4, and section 8's first
   Don't is shadows. */
#cast li:hover { border-color: var(--accent); }
#cast .face {
  display: block;
  width: 100%;
  aspect-ratio: 2 / 3;
  height: auto;
  border-radius: 0;
  object-fit: cover;
  /* The archive is a portrait: centring the crop keeps the face in frame rather than the
   * chin. */
  object-position: 50% 22%;
  background: var(--surface-2);
}
#cast .who {
  display: block;
  min-width: 0;
  padding: 0.6rem 0.65rem 0.7rem;
  font-weight: 700;
  font-size: 0.9375rem;
  line-height: 1.25;
}
/* The character, quieter than the person and on its own line. It is the second fact, not a
   second name - so no em dash in front of it now that it is not sharing a row. */
#cast .who i {
  display: block;
  margin-top: 0.2rem;
  font-style: normal;
  font-weight: 400;
  font-size: 0.8125rem;
  color: var(--ink-2);
}
#cast .who i::before { content: none; }
/* The cross-links into OUR catalogue. This is the uncopyable part - a fact about our corpus,
   not about TMDB's - so it stays on the card rather than being dropped to make it tidier. */
#cast .also {
  display: block;
  margin-top: 0.35rem;
  color: var(--ink-3);
  font-size: 0.75rem;
  line-height: 1.35;
}

/* ---- the crew grid ------------------------------------------------------------------
 *
 * The owner's prototype: the ROLE is the label, in the link blue, uppercase and small; the
 * people are the value under it in white. Cells divided by hairlines and nothing else -
 * Design.md section 4, "every surface: 1px solid #1A2430... this single move replaces
 * shadows entirely".
 *
 * EXACT TOKENS from the prototype's own markup: label `700 12px/1.2`, `letter-spacing .4px`,
 * uppercase, `#78A6B8` (which is `--link` here, named for the job it does); value
 * `400 15px/22px` in `--ink`.
 *
 * `auto-fit` with a 12rem floor rather than a fixed four columns: a film with two roles
 * should not draw two empty cells, and the same grid has to hold a series with nine. */
.crew-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  background: var(--surface);
}
.crew-grid > div {
  /* The hairlines ARE the grid. Drawn as insets so the outer edges are the container's own
     border and no cell doubles it. */
  box-shadow: inset -1px -1px 0 var(--border);
  padding: 0.8rem 0.95rem;
  min-width: 0;
}
.crew-grid dt {
  font-weight: 700;
  font-size: 0.75rem;
  line-height: 1.2;
  letter-spacing: 0.033em;
  text-transform: uppercase;
  color: var(--link);
}
.crew-grid dd {
  margin: 0.25rem 0 0;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: var(--ink);
}

/* ------------------------------------------------------- tables (seasons) */

#seasons table { width: 100%; border-collapse: collapse; font-size: 0.9375rem; }
#seasons th {
  text-align: left; font-size: 0.6875rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-3); padding: 0.5rem 0.6rem;
}
#seasons td { padding: 0.5rem 0.6rem; border-top: 1px solid var(--border); }

/* --------------------------------------------- the ranking neighbourhood */

/* Scoped at the definition. `#seasons table` above is a sibling rule, not a parent: giving
 * this one its own selectors is what stops a later change to season rows reaching a block
 * that is not a season table. */
table.chart-around {
  width: 100%; border-collapse: collapse; font-size: 0.9375rem;
  font-variant-numeric: tabular-nums;
}
table.chart-around th {
  text-align: left; font-size: 0.6875rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--ink-3); padding: 0.5rem 0.6rem;
}
table.chart-around td { padding: 0.5rem 0.6rem; border-top: 1px solid var(--border); }
/* The position column is scanned down, not read across, so it is narrow and quiet. */
table.chart-around td:first-child { width: 1%; white-space: nowrap; color: var(--ink-3); }
/* This page's own row. A tint and a weight, no accent bar: the row is a "you are here"
 * marker, not an alert, and #rail-leaving already taught this stylesheet what a red box on
 * a neutral block reads as. */
table.chart-around tr.is-self td { background: var(--surface-2); }
table.chart-around tr.is-self td:first-child { color: var(--ink); }
#chart-around p:last-child { margin-top: 0.6rem; color: var(--ink-3); }

/* TMDB's required sentence. It stays on the page - their terms require the attribution to be
   displayed, and it is the provenance this entire corpus rests on - but it is the quietest
   line in the document rather than a paragraph competing with the roadmap. Not hidden: an
   `aria-hidden` or `display:none` here would be a terms breach dressed up as a design choice. */
.site-foot-tmdb {
  display: block;
  margin-top: 1.25rem;
  font-size: 0.6875rem;
  line-height: 1.4;
  color: var(--ink-dim, #6B7280);
}
/* The closing line, under everything. */
.site-foot-count { margin-top: 0.5rem; }

/* --------------------------------------------- the consent bar */

/* `Design.md` section 5: muted 13px copy, one yellow accept button. Fixed to the bottom, on
   its own surface, above everything except an overlay. Ships `hidden` - consent.js un-hides
   it - so with the script blocked there is no bar rather than one that cannot be dismissed. */
.consent {
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 80;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem 1.25rem;
  padding: 0.85rem clamp(1rem, 4vw, 2.5rem);
  background: var(--surface);
  border-top: 1px solid var(--border);
}
.consent p {
  flex: 1 1 22rem;
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--ink-2);
}
.consent a {
  flex: none;
  font-size: 0.8125rem;
  color: var(--link);
  text-decoration: none;
}
.consent a:hover { color: var(--accent); }
/* The one accented control here, and it is the only button on the bar. It is not an exit
   click, so it does not use `.offer-go` - the accent marks "act" as well as "you are here",
   which Design.md section 1.5 states and this is the other half of it. */
.consent button {
  flex: none;
  padding: 0.55rem 1.25rem;
  border: 0;
  border-radius: 8px;
  background: var(--accent);
  color: var(--accent-ink);
  font: inherit;
  font-weight: 700;
  font-size: 0.875rem;
  cursor: pointer;
}
.consent button:hover { background: var(--accent-pressed); }

/* ------------------------------------------------------- FAQ */

#faq h3 {
  font-size: 1rem;
  font-weight: 700;
  margin-top: 1.25rem;
}
#faq h3:first-of-type { margin-top: 0; }
#faq p { color: var(--ink-2); margin-top: 0.3rem; }

/* ------------------------------------------------------- links */

/* Links are ink with an underline, not a colour. A separate link colour would be a second
 * accent, and this site has one. The underline is offset so Polish descenders and the
 * cedilla on ą and ę are not struck through by it.
 *
 * NOT ON THE FRONT DOOR, and the exclusion is a scoping decision rather than a specificity
 * fight. Two `:not()`s put this selector at (0,3,4), which beat every `.home-*` rule that
 * named a colour - so the yellow country buttons rendered white-on-yellow at 1.7:1, the
 * roadmap's live and soon rows lost their two tones, and the rail's "See all" lost its blue.
 * All three looked like plausible design choices in a screenshot, which is why they survived
 * one. `/` is a component page and owns its own link colours; every one of them is set
 * explicitly in the front-door block below. */
/* `.saga-offers a` joins the exclusions rather than being fixed next to its own block: the
 * selector above sits at (0,3,4) and beats any `.saga-offers a` rule wherever it is written,
 * so a downstream override would have to out-specify it and that is how the front door ended
 * up with 1.7:1 buttons. These links ARE exit clicks - the same thing the offer table's last
 * cell carries - so they take the same colour for the same reason. */
/* `.offer-go` replaced `table.offers td:last-child a` when the offer block became cards. It
 * is the same element doing the same job - the exit click - and it has to stay excluded here
 * or the loudest control on the site inherits body ink and an underline. */
/* `.hero-play` and `.trailer-facade` join the exclusions for the same reason `.offer-go`
   did, and it is the same specificity trap this comment block already describes: they are
   ANCHORS, so this selector at (0,3,4) beat `.hero-play`'s own (0,1,0) `color` and handed the
   play triangle body ink - white on the accent, 1.34:1, a control you could not see. A
   downstream override would have had to out-specify it, which is how the front door ended up
   with 1.7:1 buttons; the fix belongs in the exclusion list. */
article:not(.home) a:not(.chip):not(.offer-go):not(.hero-play):not(.trailer-facade):not(.saga-offers a) {
  color: inherit;
  text-decoration-color: var(--ink-3);
  text-underline-offset: 0.18em;
}
article:not(.home) a:not(.chip):not(.offer-go):not(.hero-play):not(.trailer-facade):not(.saga-offers a):hover {
  text-decoration-color: var(--accent);
}

/* ------------------------------------------------------- discover more */

/* Read off the real Interstellar page: genres, themes and 12 providers rendered as one
 * unbroken paragraph of underlined links, which is unreadable and also the block carrying
 * the internal-link fabric the whole corpus depends on. Chips give each destination an
 * edge, so the eye can pick one - and the row labels stay visible as labels. */
#related p,
#siblings p,
/* Phase 5. `chips()` joins with NO separator on purpose - the gap below is the separator -
 * so a chip block missing from this list renders as one unbroken word. The person page's
 * colleague block did exactly that on its first build. */
#also-with p {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
  color: var(--ink-3);
  font-size: 0.8125rem;
}
#related p + p, #siblings p + p { margin-top: 0.75rem; }
/* SCOPED TO THE CHIP PARAGRAPHS, not to every link in the block. `#related a` gave the pill -
   999px radius, surface, hairline - to the poster CARD links too, so each card was drawn
   inside a giant rounded blob taller than the poster. The chips are in `<p>`; the cards are
   in `.related-cards`, so the paragraph is the scope. */
#related > p a,
#siblings a,
#also-with a {
  padding: 0.22rem 0.6rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 0.8125rem;
  text-decoration: none;
}
#related > p a:hover,
#siblings a:hover,
#also-with a:hover { color: var(--ink); border-color: var(--ink-3); }

/* The second cross-sell rail. Same component as `#related`'s, and its sub-label sits beside
   the heading the way the prototype's rails carry "Taste graph" and "On your services". */
#also-on h2 small {
  margin-left: 0.5rem;
  font-weight: 400;
  font-size: 0.8125rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-3);
}

/* ------------------------------------------------------- the index pages */

/* The top rail. The prototype's big rank numerals, kept - but ours are SOURCED. These are
 * real JustWatch chart positions, so they read 5, 12, 15 rather than 1, 2, 3, and the
 * heading says "among the titles we cover" because that is the claim we can actually make.
 * Renumbering them 1, 2, 3 would be inventing a ranking we did not compute. */
.rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(9.5rem, 1fr);
  gap: 1rem;
  list-style: none;
  margin: 0;
  padding: 0 0 0.75rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
}
.rail > li { position: relative; scroll-snap-align: start; min-width: 0; }
.rail a { display: block; text-decoration: none; color: inherit; }

/* The numeral overlaps the artwork rather than sitting above it, which is what stops a
 * rail of ten cards reading as ten equal things. */
.rank {
  position: absolute;
  top: -0.15em;
  left: -0.1em;
  z-index: 1;
  font-size: clamp(1.75rem, 1.2rem + 2vw, 2.5rem);
  font-weight: 900;
  line-height: 1;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  -webkit-text-stroke: 3px var(--ground);
  paint-order: stroke fill;
}

.card-art {
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: 8px;
  background: var(--surface-2);
  display: block;
}
.card-name { display: block; margin-top: 0.5rem; font-weight: 600; font-size: 0.9375rem; }
.card-year { color: var(--ink-3); font-weight: 400; }
.card-providers {
  display: block;
  margin-top: 0.15rem;
  color: var(--ink-3);
  font-size: 0.8125rem;
}
.source { margin-top: 0.5rem; color: var(--ink-3); }

#browse p {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.4rem;
  color: var(--ink-3);
  font-size: 0.8125rem;
}
#browse p + p { margin-top: 0.9rem; }
#browse .browse-col a {
  flex: none;
  padding: 0.32rem 0.72rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 0.8125rem;
  line-height: 1.25;
  text-decoration: none;
  white-space: nowrap;
}
#browse .browse-col a:hover { color: var(--ink); border-color: var(--border-hover); background: var(--surface-2); }
#browse .browse-svc {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}
.browse-mark {
  width: 18px;
  height: 18px;
  border-radius: 4px;
  object-fit: contain;
  background: #fff;
  flex: none;
}

/* The market list on the root, and the per-market trust links under each entry. */
.trust-links {
  display: block;
  margin-top: 0.2rem;
  color: var(--ink-3);
  font-size: 0.8125rem;
}

/* ------------------------------------------------------- hubs */

.hub-list { list-style: none; padding: 0; }
.hub-list li {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0 0.75rem;
  padding: 0.6rem 0;
  border-top: 1px solid var(--border);
  color: var(--ink-2);
  font-size: 0.9375rem;
}

/* Row artwork. Small - it identifies the title, it does not sell it, and a hub of 65 rows
 * is a list rather than a gallery. `aspect-ratio` reserves the box because HubMember
 * carries no stored dimensions, so a slow poster cannot shift a 65-row list as it loads. */
.row-art {
  flex: 0 0 auto;
  width: 34px;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: 3px;
  background: var(--surface-2);
}
.hub-list li a { font-weight: 600; color: var(--ink); font-size: 1rem; }
.hub-list li em { font-style: normal; color: var(--ink-3); }

/* ------------------------------------------------------- footer */

article > footer {
  margin-top: 3rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
  color: var(--ink-3);
}

/* The byline and the trust links. These render for the first time on the build where the
 * owner supplied the last identity values - until then `trustShips` suppressed them, so
 * they had never been seen on a page.
 *
 * The byline is the loudest thing in the footer because "no author attribution" is a
 * Google rater marker and the answer to it should be legible, not buried in small print
 * with the API credit. */
.byline {
  margin-bottom: 0.5rem;
  color: var(--ink-2);
  font-size: 0.9375rem;
}
.byline a { font-weight: 600; color: var(--ink); }

#trust-nav {
  /* Overrides the `article > nav` rule, which draws a rule and a top margin for a
   * top-level section. This one sits inside the footer and already has one above it. */
  margin: 0 0 0.9rem;
  padding: 0;
  border-top: 0;
}
#trust-nav p {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 0.5rem;
  font-size: 0.875rem;
}
#trust-nav a { color: var(--ink-2); }
#trust-nav a:hover { color: var(--ink); }

/* ------------------------------------------------------- the front door */

/* `/` is the one page built section by section rather than as a document, because the
 * prototype's home is a stack of full-bleed bands - key art, then cards, then rails, then a
 * closing call - and every one of them runs edge to edge with its own gutter inside.
 *
 * So the article's padding and the 46rem measure cap both come off here and each band puts
 * its own back. Doing it the other way round - a padded article with bands breaking out of
 * it - is what produced the negative-margin arithmetic on the title hero, and one band that
 * cannot bleed is worse than a rule with an exception. */
main > article.home { padding: 0; }
main > article.home > :where(section, footer) > :where(h1, h2, h3, p, ul, ol, dl) {
  max-width: none;
}
article.home > footer { margin-top: 0; padding-top: 0; }

/* Three document-page rules turned off, each for the same reason: these bands carry their
 * own spacing and their own hairline, and inheriting a second set drew a stray divider in
 * the gap between the key art and the cards.
 *
 * The heading rule is handled at its own definition instead, by excluding `.home` there:
 * `article > section > h2` is the quiet structural label a title page needs - 12px,
 * uppercase, grey - and it silently turned the closing call, which is the largest sentence
 * on the page, into small grey capitals. It looked deliberate, which is why it survived a
 * screenshot. */
article.home > section,
article.home > nav {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}

/* ON SPENDING THE ACCENT HERE, because the rest of this file reserves it for the exit click
 * and this page has no exit click at all - nothing on the front door leaves for a provider.
 *
 * The accent means ONE thing on this page too, and it is the same kind of thing: GO. The
 * country buttons carry it, in the band and again in the closing call, because choosing a
 * country is the only action this page is asking for. The featured-title badge and the
 * "live" pill carry it as a small chip rather than as a filled block, so they read as
 * labels on the same idea rather than as four competing calls to action. Nothing else on
 * the page is yellow. */

/* ---- the band */

.home-hero {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: flex-end;
  min-height: min(34rem, 76vh);
  padding: clamp(3rem, 8vw, 6rem) var(--px) clamp(2rem, 4vw, 2.75rem);
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}

/* EAGER and full bleed. This is the LCP element on the most-linked page on the site. */
.home-hero-art {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 22%;
}

/* TWO gradients, each doing a different job, which is the same pair the title hero uses.
 * The vertical one lands the band on the page instead of ending in a hard seam. The
 * horizontal one buys contrast for the text on the left WITHOUT flattening the artwork on
 * the right, which a single flat scrim does.
 *
 * `color-mix` rather than a hardcoded rgba: this file never names a colour, and a scrim
 * written as `rgba(6,13,23,.6)` is the palette switch silently half-applying. */
.home-hero.has-art::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(0deg,
      var(--ground) 3%,
      color-mix(in srgb, var(--ground) 72%, transparent) 46%,
      color-mix(in srgb, var(--ground) 30%, transparent) 100%),
    linear-gradient(90deg,
      color-mix(in srgb, var(--ground) 88%, transparent) 4%,
      color-mix(in srgb, var(--ground) 20%, transparent) 66%);
}

/* On a phone the art fills the full width, so the HORIZONTAL half of the scrim has nothing
 * to hide behind and the kicker sat on the bright part of the frame at about 2.5:1. Narrow
 * viewports get a heavier vertical wash instead. Measured on the Prada backdrop, which is a
 * near-white marble interior and the worst case in the corpus. */
@media (max-width: 40rem) {
  .home-hero.has-art::after {
    background: linear-gradient(0deg,
      var(--ground) 8%,
      color-mix(in srgb, var(--ground) 88%, transparent) 52%,
      color-mix(in srgb, var(--ground) 45%, transparent) 100%);
  }
}

.home-hero-body {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-width: min(44rem, 100%);
}

.home-hero h1 {
  margin: 0;
  font-size: clamp(2rem, 5.2vw, 3.4rem);
  line-height: 1.04;
  letter-spacing: -0.03em;
  text-wrap: balance;
}

.home-hero-lede {
  margin: 0;
  max-width: 34rem;
  color: var(--ink-2);
  font-size: clamp(1rem, 0.95rem + 0.35vw, 1.1875rem);
  line-height: 1.45;
  text-wrap: pretty;
}

/* The line above the headline: what is number one where, right now. It is the hook, and it
 * is a SOURCED one - a chart position in a named country, not "editor's pick". */
.home-hero-kick {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.45rem 0.75rem;
  margin: 0;
  font-size: 0.8125rem;
  color: var(--ink-2);
}
.home-hero-badge {
  padding: 0.3rem 0.5rem;
  border-radius: 4px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-decoration: none;
}

/* The featured title itself, under the buttons rather than over them: the country choice is
 * what this page is for, and a title link that outranked it would send a first-time reader
 * into Italy by accident. */
.home-hero-feat {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.6rem;
  margin: 0.25rem 0 0;
  font-size: 0.9375rem;
  color: var(--ink-2);
}
/* THE HERO HAD NO ACTION. On a site whose entire job is answering "where can I watch
   this", the featured title was a text link inside a paragraph, indistinguishable from
   the sentence around it. The owner's prototype puts a real button here, and it is the
   one place a reader arriving cold has somewhere obvious to go.

   The label stays the title itself rather than a generic "Where to watch" - it names the
   destination instead of describing the click, which is the stronger version of the same
   affordance. Height is 44px so it is a real touch target.

   DELIBERATELY NOT THE ACCENT, though the owner's prototype puts a yellow button here.
   Principle 1 at the top of this file reserves the accent for the exit click alone, and
   this is internal navigation. A bordered control is the affordance without spending the
   one colour that tells a reader which link earns. The border is doing the job principle 2
   allows: separating a control from the prose it sits in. */
.home-hero-feat a {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 44px;
  padding: 0.5rem 1rem;
  border-radius: 6px;
  border: 1px solid var(--ink);
  color: var(--ink);
  text-decoration: none;
  font-weight: 700;
  transition: background-color 140ms ease-out, color 140ms ease-out;
}
.home-hero-feat strong { color: inherit; }
.home-hero-feat a:hover { background: var(--ink); color: var(--ground); }
.home-hero-feat a:active { background: var(--ink); color: var(--ground); }
.home-hero-feat a:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
@media (prefers-reduced-motion: reduce) {
  .home-hero-feat a { transition: none; }
  .home-hero-feat a:hover { transform: none; }
}
.home-hero-meta {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  color: var(--ink-3);
  font-size: 0.8125rem;
}
.home-hero-meta i { font-style: normal; color: var(--border); }
.home-hero-meta .score {
  color: var(--accent);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ---- the country buttons, which are the geo picker */

.home-hero-go,
.home-cta-go {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem;
  margin: 0.25rem 0 0;
}
.home-hero-go a,
.home-cta-go a {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.8rem 1.15rem;
  border: 1px solid var(--accent);
  border-radius: 8px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
  font-size: 1rem;
  text-decoration: none;
  transition: background-color 0.14s, color 0.14s;
}
/* The title count rides inside the button. It is the proof the country is real, and it is
 * the difference between a flag and an answer. */
.home-hero-go a span,
.home-cta-go a span {
  font-weight: 400;
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  opacity: 0.75;
}
.home-hero-go a:hover,
.home-cta-go a:hover {
  background: transparent;
  color: var(--accent);
}
.home-hero-go a:focus-visible,
.home-cta-go a:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }

/* ---- the three cards */

.home-props {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: 1.125rem;
  padding: clamp(2rem, 4vw, 3.25rem) var(--px);
}
.home-props > div {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  padding: 1.5rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
}
.home-prop-kick {
  color: var(--accent);
  font-weight: 700;
  font-size: 0.75rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.home-props h2 {
  margin: 0;
  font-weight: 700;
  font-size: clamp(1.25rem, 2.6vw, 1.5rem);
  line-height: 1.22;
}
.home-props p {
  margin: 0;
  color: var(--ink-2);
  font-size: 1rem;
  line-height: 1.5;
  text-wrap: pretty;
}

/* ---- one ranked rail per country */

.home-rails {
  display: flex;
  flex-direction: column;
  gap: clamp(2rem, 4vw, 3rem);
  padding: clamp(1rem, 2vw, 1.75rem) 0 clamp(2rem, 4vw, 3rem);
}

/* Label column beside the track, not above it, which is how the prototype draws a ranked
 * rail and is why five of them stack without reading as five identical headings. */
/* HEAD ON TOP, TRACK UNDERNEATH, FULL WIDTH. Owner's reference (pilotwp.pl, 2026-08-16).
   The head used to sit in an 11rem column BESIDE the posters, which spent a sixth of every
   rail on two lines of label and squeezed the cards it was describing. Stacked, the title and
   its line of description read as the rail's own heading and the posters get the whole row. */
.home-rail {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.7rem;
  padding-left: var(--px);
}
.home-rail-head {
  flex: none;
  padding-right: var(--px);
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
}
.home-rail-head h2 {
  margin: 0;
  font-size: clamp(1.125rem, 1rem + 0.6vw, 1.4rem);
  line-height: 1.2;
  text-wrap: balance;
}
.home-rail-head p {
  margin: 0;
  color: var(--ink-3);
  font-size: 0.875rem;
  line-height: 1.35;
}
.home-rail-head a {
  color: var(--focus);
  font-weight: 700;
  font-size: 0.8125rem;
  text-decoration: none;
}
.home-rail-head a:hover { text-decoration: underline; }
.home-rail-head small { color: var(--ink-3); font-size: 0.75rem; }

/* The track BLEEDS off the right edge on purpose. A rail that stops flush with the gutter
 * looks finished; one whose last card is cut says there is more and invites the scroll. The
 * built /it page had the cut without the affordance, which is the version that just looks
 * broken - so the padding goes on the track's end rather than on the rail. */
.home-track {
  flex: none;
  min-width: 0;
  display: flex;
  gap: 0.375rem;
  margin: 0;
  padding: 0 var(--px) 0.5rem 0;
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}
.home-track::-webkit-scrollbar { height: 0; display: none; }
/* `--card` is the one number the numeral, the poster and the tuck-under all derive from, so
 * they cannot drift apart. Poster height is `--card * 1.5` and nothing else needs saying. */
.home-track > li {
  /* 15rem, up from 9.375rem. The reference draws roughly five posters across a 2000px
     viewport - about 18% each - and at 9.375rem ours were half that, which is why the rail
     read as a strip of thumbnails rather than as artwork you choose from. */
  --card: 15rem;
  position: relative;
  flex: none;
  /* How much of the numeral is left showing. Two digits at the 6rem cap are about 6.2rem
   * wide, so 4.4rem shows both and the card covers the last ~1.8rem - the same proportion
   * the prototype uses (96px numeral, 26px tucked). At 2.1rem the second digit was entirely
   * behind the poster and every rank above 9 read as its first digit alone: 12 as 1, 21 as
   * 2. A ranking a reader misreads is worse than no ranking.
   *
   * Only the ranked rails pay for it. On "leaving soon" or "cheapest to rent" the order is
   * a date or a price, a numeral there would imply a ranking that does not exist, and 4.4rem
   * of gutter per card with nothing in it is five fewer cards on screen. */
  padding-left: 0;
  scroll-snap-align: start;
}
.home-rail.is-ranked .home-track > li { padding-left: 4.4rem; }

/* The ghost numeral, in the BORDER colour and behind the artwork. This is the single
 * component the prototype is most recognisable by. It is real text rather than a CSS
 * counter so the source order and the number a reader sees cannot disagree - these are
 * JustWatch chart positions, so they read 5, 12, 16 and renumbering them 1, 2, 3 would be
 * inventing a ranking we did not compute. */
/* IT TUCKS UNDER ITS OWN CARD, and that is the whole difficulty.
 *
 * Laid out in flow with a negative margin - the prototype's own approach - it ended up
 * floating in the gap BETWEEN two cards, closer to the previous card's right edge than to
 * its own card's left edge, so every number read as belonging to the title before it. The
 * prototype gets away with it because its cards are flat dark gradients and the numeral
 * reads as background; ours are real posters, and a bright poster beside a number makes the
 * pairing look deliberate and wrong.
 *
 * So it is positioned instead: bottom edge on the POSTER's bottom edge - not the card's,
 * which includes the name and the year - and pulled left far enough that the poster covers
 * most of it. What sticks out is the leading digit, under the card it belongs to. */
/* Anchored to a box exactly the POSTER's height and bottom-aligned inside it, rather than
 * offset by the numeral's own line box. `translateY(-100%)` moves an element by its line
 * height, and a line height of 0.78 is smaller than the glyphs it contains, so the digits
 * overhung the bottom by the difference and landed on the title text. A box with a known
 * height cannot be wrong about that. */
.home-rank {
  position: absolute;
  left: 0;
  top: 0;
  height: calc(var(--card) * 1.5);
  display: flex;
  align-items: flex-end;
  z-index: 0;
  color: var(--border);
  font-size: clamp(3.5rem, 8.4vw, 6rem);
  font-weight: 900;
  line-height: 1;
  letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
.home-track a {
  position: relative;
  z-index: 1;
  display: block;
  width: var(--card);
  color: inherit;
  text-decoration: none;
}
/* HOVER IS THE BORDER, NOT A SCALE. Design.md section 6: "Hover is always a border or color
   change - never scale, never shadow", and section 8's first Don't is shadows and glows. This
   was `transform: scale(1.035)`, which also nudged its neighbours' apparent spacing on a rail
   that is meant to read as an even row.
   The border takes the ACCENT rather than the neutral raise, on the owner's reference
   (pilotwp.pl, 2026-08-16): a picture card is a thing you are about to open, and the accent
   means act or you-are-here. Controls - tabs, the geo pill, the close button - keep the quiet
   #374151 raise, so the two kinds of hover stay distinguishable. */
.home-track a:hover .home-card-art { border-color: var(--accent); }
/* The artwork and its corner chip share a positioned box, so the chip cannot drift when the
 * title below it wraps to two lines. */
.home-card-shot { position: relative; display: block; }
.home-card-art {
  display: block;
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border: 1px solid var(--border);
  border-radius: 4px;
  background: var(--surface);
}

/* The one fact the rail exists for, on the artwork: a departure date, a price, 4K, +7.
 * The prototype puts a score here in the accent and a departure badge in the alarm colour,
 * and that split is the rule - `alert` means departures and nothing else, because
 * `available_to` is the scarcest data in this vertical and the only urgent thing on the
 * page. Everything else is a quiet chip on a scrim so it stays readable over any poster. */
.home-card-badge {
  position: absolute;
  top: 0.4rem;
  left: 0.4rem;
  padding: 0.2rem 0.4rem;
  border-radius: 3px;
  background: color-mix(in srgb, var(--ground) 82%, transparent);
  color: var(--ink);
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
  backdrop-filter: blur(4px);
}
.home-card-badge.is-urgent { background: var(--alert); color: #fff; }

/* ONE LINE, THEN AN ELLIPSIS. Owner's call, 2026-08-16: a card is a thing you scan, and a
   two-line title next to a one-line title makes a rail of cards that no longer line up -
   "Una di famiglia - The Housemaid" was taking 35px against 18px for its neighbour, so every
   card below it sat at a different height. One line each, truncated, and the row is a grid
   again.

   `display: block`, not flex. The flex row existed to baseline-align a year element beside
   the name; no home card renders one (grep says 0), and a flex container cannot ellipsis a
   bare text node - the child has to be an element for `text-overflow` to reach it. If a year
   ever comes back here it goes INSIDE the span and truncates with the rest. */
.home-card-name {
  display: block;
  margin-top: 0.5rem;
  font-weight: 700;
  font-size: 0.875rem;
  line-height: 1.25;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.home-card-meta {
  display: block;
  margin-top: 0.1rem;
  color: var(--ink-3);
  font-size: 0.75rem;
  line-height: 1.3;
  font-variant-numeric: tabular-nums;
  /* "HBO Max, Netflix, Now TV, Sky Go, Timvision" is a real value and it wrapped to two
     lines. The list is a hint, not the answer - the answer is on the title page. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Where the JustWatch number went. It is still on the page - it is the sourced fact and the
 * reason the rail is ordered the way it is - but it is no longer pretending to be the
 * headline, because as a headline it read as a top ten with holes in it. */
.home-card-src {
  display: block;
  color: var(--border);
  font-size: 0.6875rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ---- the closing call */

.home-cta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.125rem;
  padding: clamp(3rem, 7vw, 4.75rem) var(--px) clamp(3.5rem, 8vw, 5.25rem);
  border-top: 1px solid var(--border);
  text-align: center;
}
.home-cta .mark {
  padding: 0.5rem 0.7rem;
  border-radius: 4px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 900;
  font-size: 1rem;
  line-height: 1.2;
}
.home-cta h2 {
  margin: 0;
  max-width: 24ch;
  font-size: clamp(1.625rem, 4.4vw, 2.3rem);
  line-height: 1.18;
  text-wrap: balance;
}
.home-cta-go { justify-content: center; }
.home-cta .verified { margin: 0.5rem 0 0; color: var(--ink-3); }

/* ---- the roadmap */

/* All 54 countries, live and not. The badge is the whole point of showing the unbuilt ones:
 * a bare list of 54 names under "available in" is a claim we cannot make, and the same list
 * with 52 of them marked is a roadmap, which is true and is also the more interesting page.
 *
 * An unbuilt country is a `<span>`, never an `<a>` - the renderer enforces it and a test
 * pins it. 52 crawlable dead ends on the most-linked page on the site is the front-door 404
 * the trust gate exists to catch, at scale. */
.home-regions {
  padding: clamp(2rem, 4vw, 2.75rem) var(--px) clamp(2.5rem, 5vw, 3.5rem);
  border-top: 1px solid var(--border);
}
.home-regions h2 {
  margin: 0 0 1.5rem;
  font-weight: 700;
  font-size: 0.9375rem;
  text-align: center;
  color: var(--ink);
}
.home-regions-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10.5rem), 1fr));
  gap: 1.5rem 2rem;
}
.home-regions-grid > div { display: flex; flex-direction: column; gap: 0.4rem; }
.home-region-name {
  color: var(--focus);
  font-weight: 700;
  font-size: 0.8125rem;
}
.home-live,
.home-soon {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.8125rem;
  line-height: 1.3;
}
.home-live { color: var(--ink-2); text-decoration: none; }
.home-live:hover { color: var(--ink); }
.home-soon { color: var(--ink-3); }

.home-live i,
.home-soon i {
  font-style: normal;
  font-size: 0.5625rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.1rem 0.32rem;
  border-radius: 3px;
}
.home-live i { background: var(--accent); color: var(--accent-ink); }
.home-soon i { border: 1px solid var(--border); color: var(--ink-3); }

/* The flag. Computed from the country code as a pair of regional indicator symbols, so
 * there is no sprite to keep in sync with the roadmap.
 *
 * `font-style: normal` because it is an `<i>` - the element is right (an unlabelled visual
 * aside) and the default italic is not. The font stack names the two colour flag fonts
 * before falling through: on Windows, which ships neither, the browser draws the two
 * letters instead, and `IT` beside `Italia` is a fallback that is still correct.
 *
 * A country that is not live is dimmed rather than desaturated: `filter: grayscale()` on an
 * emoji is inconsistent across platforms and does nothing at all where the glyph is text. */
.flag {
  font-style: normal;
  font-size: 1.05em;
  line-height: 1;
  font-family: "Apple Color Emoji", "Noto Color Emoji", "Segoe UI Emoji", sans-serif;
}
.home-soon .flag { opacity: 0.45; }
.home-hero-badge .flag,
.home-hero-go a .flag,
.home-cta-go a .flag { margin-right: 0.4rem; }
.home-live .flag,
.home-soon .flag { width: 1.35em; flex: none; }

/* The overflow link, once there are more markets than buttons. Deliberately not a seventh
 * yellow block: it goes to the roadmap grid, which is the list. */
.home-hero-go a.more,
.home-cta-go a.more {
  background: transparent;
  border-color: var(--border);
  color: var(--ink-2);
}
.home-hero-go a.more:hover,
.home-cta-go a.more:hover { color: var(--ink); border-color: var(--ink-3); }

/* ------------------------------------------------- the footer, on every page */

/* Owner requirement, 2026-08-15: the footer was complete on the root and thin on the other
 * 326 pages. This is the same block under every page, so it is styled once here and the
 * root's own `home-foot-cols` rules are gone with the markup they styled.
 *
 * `margin-top: auto` is NOT set and the shell is not a flex column: these pages are long
 * enough that a footer pinned to the viewport bottom would only matter on a page with no
 * content, and this build refuses to write one of those. */
.site-foot {
  border-top: 1px solid var(--border);
  padding: clamp(2rem, 4vw, 2.75rem) var(--px) clamp(2.5rem, 5vw, 3.5rem);
  display: flex;
  flex-direction: column;
  gap: 1.75rem;
  color: var(--ink-3);
}
.site-foot-brand {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
}
.site-foot-brand p {
  margin: 0;
  font-size: 0.9375rem;
  color: var(--ink-3);
}
.site-foot-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11.875rem), 1fr));
  gap: 1.75rem 2rem;
}
.site-foot-col { display: flex; flex-direction: column; gap: 0.45rem; }
.site-foot-col > span {
  color: var(--ink);
  font-weight: 700;
  font-size: 0.875rem;
}
.site-foot-col a {
  color: var(--ink-2);
  font-size: 0.875rem;
  line-height: 1.3;
  text-decoration: none;
}
.site-foot-col a:hover { color: var(--ink); text-decoration: underline; }

/* The geo picker, drawn like the header's: the same pill and the same code badge, because
 * it is the same control and two shapes for one control is how a site starts looking
 * assembled rather than designed. */
.site-foot-geo {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem 0.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--border);
}
.site-foot-geo > span {
  color: var(--ink);
  font-weight: 700;
  font-size: 0.875rem;
}
.site-foot-geo a {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.35rem 0.75rem 0.35rem 0.4rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  font-weight: 700;
  font-size: 0.8125rem;
  color: var(--ink-2);
  text-decoration: none;
}
.site-foot-geo a:hover { border-color: var(--ink-3); color: var(--ink); }
.site-foot-count { margin: 0; font-size: 0.8125rem; }
.site-foot-count a { color: var(--ink-2); }
.site-foot > small { color: var(--ink-3); }

/* ------------------------------------------------------- motion */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}

/* ------------------------------------------- document bands inside a bleed layout
 *
 * `/it` and `/pl` are `.home` articles now: they lead with the key-art band and carry the
 * same rails as the root, so they take the same deal - the article drops its padding and
 * its 46rem measure, and every band puts its own back.
 *
 * Three of their bands are not rails. The departures list, the browse index and the
 * unavailable link are document sections, and the moment the article stopped padding them
 * they ran flush to the left edge of the viewport with their headings touching the gutter.
 *
 * This is the class that says "a document band inside a bleed layout" - defined once here
 * rather than as a `.home #leaving, .home #browse, ...` reset next to each block, because
 * the next band added to these pages needs the same thing and a list of ids is a list that
 * gets out of date. */
.band {
  padding-inline: var(--px);
  padding-block: clamp(1.25rem, 2.5vw, 2rem);
}
.band > :where(h2, h3, p, ul, ol, dl) { max-width: 46rem; }

/* The departures block keeps the alarm and loses the alert box.
 *
 * Red is still spent here and nowhere else - `available_to` is the scarcest fact in this
 * vertical - but a filled red panel is the shape of an error, and this is the most useful
 * block on the page rather than something that went wrong. The colour moves onto the
 * heading and a hairline rule, which is how the prototype marks its own departures row.
 *
 * Scoped to `.home` so the market pages change and nothing else does: `#leaving` is also
 * the id of the title page's own departure notice, which is a genuine warning on a single
 * title and keeps its panel. */
.home #leaving {
  background: none;
  border-inline-start: 0;
  border-top: 1px solid var(--border);
  border-radius: 0;
  margin-top: 0;
  padding-block: clamp(1.75rem, 3vw, 2.75rem);
  scroll-margin-top: 5.5rem;
}
@media (max-width: 50rem) {
  .home #leaving { scroll-margin-top: 10.5rem; }
}
.home #leaving > h2,
.home #leaving .leave-head > h2 {
  color: var(--ink);
  font-size: clamp(1.5rem, 1.15rem + 1.4vw, 2.15rem);
  letter-spacing: -0.03em;
  margin-bottom: 0;
}
.home #leaving .leave-head {
  max-width: none;
  margin-bottom: 1.15rem;
}
.home #leaving .leave-sub {
  margin: 0.35rem 0 0;
  color: var(--ink-3);
  font-size: 0.9375rem;
}
.home #leaving li { padding-block: 0; }
.home #leaving .leave-grid {
  list-style: none;
  padding: 0;
  margin: 0;
  max-width: none;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.75rem;
}
@media (min-width: 48rem) {
  .home #leaving .leave-grid { grid-template-columns: 1fr 1fr; }
  .home #leaving .leave-grid:has(> :only-child) {
    grid-template-columns: minmax(16rem, 36rem);
  }
}
.leave-card {
  display: grid;
  grid-template-columns: 4.25rem minmax(0, 1fr);
  gap: 0.9rem;
  align-items: start;
  min-height: 6.4rem;
  padding: 0.85rem 1rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  text-decoration: none;
  color: inherit;
}
.leave-card:hover { border-color: var(--border-hover); }
.leave-card.is-hot { border-color: color-mix(in srgb, var(--alert) 45%, var(--border)); }
.leave-card:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
.leave-shot {
  display: block;
  width: 4.25rem;
  aspect-ratio: 2 / 3;
  border-radius: 7px;
  overflow: hidden;
  background:
    linear-gradient(165deg,
      color-mix(in srgb, var(--ink) 16%, var(--surface-2)) 0%,
      var(--surface-2) 100%);
}
.leave-art {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.leave-copy { min-width: 0; }
.leave-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.65rem;
}
.leave-name {
  font-weight: 700;
  font-size: 1.0125rem;
  line-height: 1.25;
  letter-spacing: -0.015em;
}
.leave-days {
  flex: none;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  line-height: 1;
  padding: 0.32rem 0.48rem;
  border-radius: 6px;
  font-variant-numeric: tabular-nums;
}
.leave-card.is-hot .leave-days {
  background: var(--alert);
  color: #fff;
}
.leave-card.is-warn .leave-days {
  background: var(--accent);
  color: var(--accent-ink);
}
.leave-meta {
  display: block;
  margin-top: 0.22rem;
  color: var(--ink-2);
  font-size: 0.8125rem;
  line-height: 1.35;
}
.leave-track {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0.7rem;
  margin-top: 0.7rem;
}
.leave-bar {
  display: block;
  height: 4px;
  background: var(--border);
  border-radius: 99px;
  overflow: hidden;
}
.leave-bar > i {
  display: block;
  height: 100%;
  width: var(--leave-pct, 0%);
  border-radius: inherit;
  background: var(--alert);
}
.leave-card.is-warn .leave-bar > i { background: var(--accent); }
.leave-date {
  font-size: 0.75rem;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.home #leaving .leave-card .stays,
.home #leaving .leave-row .stays {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.75rem;
}
.leave-later-head {
  margin: 1.6rem 0 0.35rem;
  color: var(--ink-3);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.home #leaving .leave-later {
  list-style: none;
  padding: 0;
  margin: 0;
  max-width: none;
}
.leave-row {
  display: grid;
  grid-template-columns: 2.15rem minmax(0, 1fr) auto;
  gap: 0.75rem;
  align-items: center;
  padding: 0.65rem 0.15rem;
  border-bottom: 1px solid var(--border);
  text-decoration: none;
  color: inherit;
}
.leave-row:hover .leave-name { color: var(--link); }
.leave-row .leave-shot {
  width: 2.15rem;
  border-radius: 4px;
}
.leave-row .leave-name {
  font-size: 0.9375rem;
  font-weight: 700;
}
.leave-row .leave-meta {
  margin-top: 0.05rem;
  font-size: 0.75rem;
}
.leave-row time {
  color: var(--ink-3);
  font-size: 0.8125rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
@media (prefers-reduced-motion: no-preference) {
  .leave-bar > i { transition: width 0.4s ease; }
}

/* Browse: a directory, not a tag cloud and not a leftover SEO dump.
 * Three columns take the width the old pill-rows left empty. */
.home #browse {
  border-top: 1px solid var(--border);
  padding-block: clamp(1.75rem, 3vw, 2.75rem);
}
.home #browse > h2 {
  color: var(--ink);
  font-size: clamp(1.5rem, 1.15rem + 1.4vw, 2.15rem);
  letter-spacing: -0.03em;
  margin-bottom: 1.25rem;
}
.cat-block {
  margin-bottom: 1.6rem;
  max-width: none;
}
.cat-block > h3 {
  margin: 0 0 0.7rem;
  color: var(--ink-3);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.cat-strip {
  display: flex;
  gap: 0.65rem;
  margin: 0;
  padding: 0 0 0.35rem;
  list-style: none;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
}
.cat-strip::-webkit-scrollbar { height: 0; display: none; }
.cat-strip > li {
  flex: none;
  scroll-snap-align: start;
}
.cat-card {
  position: relative;
  display: block;
  width: clamp(10.5rem, 22vw, 13.75rem);
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: 12px;
  text-decoration: none;
  color: #fff;
  background: var(--surface-2);
}
.cat-shot,
.cat-art {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.cat-shot {
  background:
    linear-gradient(160deg,
      color-mix(in srgb, var(--ink) 22%, var(--surface-2)),
      var(--surface-2));
}
.cat-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.78) 0%, rgba(0, 0, 0, 0.08) 55%, transparent 78%);
  pointer-events: none;
}
.cat-name {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 0.65rem 0.75rem;
  font-size: 0.95rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.2;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.45);
}
.cat-card:hover { box-shadow: inset 0 0 0 1.5px var(--accent); }
.cat-card:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
.home #browse .browse-cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.5rem 2.25rem;
  max-width: none;
}
@media (min-width: 40rem) {
  .home #browse .browse-cols {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (min-width: 56rem) {
  .home #browse .browse-cols {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
.home #browse .browse-col h3 {
  margin: 0 0 0.7rem;
  color: var(--ink-3);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.home #browse .browse-col p {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  max-width: none;
  margin: 0;
}
.home #unavailable {
  border-top: none;
  padding-top: 0;
  padding-bottom: clamp(1.75rem, 3vw, 2.5rem);
}
.home #unavailable > h2 { display: none; }
.home a.gone-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 0.9rem 1.15rem;
  align-items: center;
  max-width: none;
  padding: 1.05rem 1.25rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  text-decoration: none;
  color: inherit;
}
.home a.gone-card::after {
  content: "";
  width: 0.42rem;
  height: 0.42rem;
  border-right: 1.5px solid var(--ink-3);
  border-top: 1.5px solid var(--ink-3);
  transform: rotate(45deg);
}
.home a.gone-card:hover { border-color: var(--border-hover); }
.gone-n {
  font-size: clamp(1.75rem, 1.4rem + 1vw, 2.25rem);
  font-weight: 900;
  letter-spacing: -0.04em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.gone-copy {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}
.gone-h {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.3;
  color: var(--ink);
}
.gone-copy > span {
  color: var(--ink-3);
  font-size: 0.875rem;
  line-height: 1.4;
}
.home > footer.band {
  padding-top: 0.75rem;
  padding-bottom: 1.25rem;
  border-top: 1px solid var(--border);
  color: var(--ink-3);
  font-size: 0.8125rem;
}
.home > footer.band { border-top: 1px solid var(--border); }

/* ------------------------------------------------- the title page's reference column
 *
 * The measure caps TEXT at 46rem, deliberately - 1000px lines of Italian are unreadable.
 * What it does not do is decide the page is one column, and for a while the page acted as
 * though it did: on a 1100px viewport the right third was empty from the offer table all
 * the way to the footer.
 *
 * The chart position, the ratings spread and the facts table are reference. They go beside
 * the prose, which is where a reader checking a runtime looks anyway, and the prose keeps
 * its measure untouched.
 *
 * ONLY the aside is placed. Everything else auto-places into column 1, so a page that grows
 * a new section needs nothing here - and no `article > section` selector is broken, because
 * the main column's sections are still direct children of the article.
 *
 * `grid-row: 2 / 200` rather than a span: the aside must start below the hero and run as far
 * as the content does, and the row count varies per page - a title with no season table and
 * no collection has six fewer. 200 is past any real page. The implicit rows it opens are
 * zero-height and `row-gap` is 0, so they cost nothing. */
@media (min-width: 64rem) {
  main > article:has(> aside.side) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 18rem;
    column-gap: clamp(1.5rem, 3vw, 3rem);
    row-gap: 0;
    align-items: start;
  }
  main > article:has(> aside.side) > * { grid-column: 1; }
  /* The band and the link fabric span both columns: one is full-bleed art, the other is the
   * widest row of chips on the page and reads as a floor under everything above it. */
  /* The band and the footer span both columns: one is full-bleed art, the other closes the
     page under everything above it. */
  main > article:has(> aside.side) > :where(.hero, footer, nav#trust-nav) {
    grid-column: 1 / -1;
  }
  /* `nav#related` USED TO SPAN BOTH COLUMNS AND IT CANNOT. The aside is `position: sticky`
     over a `grid-row: 2 / 200` area, so it stays pinned in the viewport for the whole scroll
     of that area - and a full-width row inside it is drawn straight underneath the pinned
     panel. The cross-sell rail was painted over by the facts list.
     It stays in column 1, which is also where every other card row on this page lives, so
     the rail is 1029px like the offer cards, the video shelf and the gallery. */
  main > article:has(> aside.side) > aside.side {
    grid-column: 2;
    grid-row: 2 / 200;
    position: sticky;
    top: calc(var(--header-h, 4.25rem) + 1rem);
  }
  aside.side > section { margin-top: 0; }
  /* The reference column sets its own measure. Inheriting 46rem here would let a ratings
   * line try for 736px inside an 18rem box. */
  aside.side :where(h2, p, ul, ol, dl) { max-width: none; }

  /* The poster fills the head of its own column instead of floating against prose it was
   * never related to. INSIDE the breakpoint on purpose: below it there is no column, and a
   * full-width poster on a 375px screen is a 513px-tall block sitting between the offer
   * table and the plot. It keeps its small float there. */
  aside.side #facts picture,
  aside.side #facts img.poster {
    float: none;
    width: 100%;
    height: auto;
    margin: 0 0 0.85rem;
    max-width: none;
  }
}



/* Inside the aside the sections are a stack, not a sequence of document bands: no hairline,
 * no top padding, one gap between them. Outside the two-column breakpoint the aside is just
 * three blocks in the flow and the same rules hold, which is why this is not inside the
 * media query. */
aside.side > section {
  margin-top: 0;
  padding-top: 0;
  border-top: 0;
}
aside.side > section + section { margin-top: 1.4rem; }

/* ------------------------------------------------------- the franchise page
 *
 * One row per film: art, then the name, then every way to watch it with the price. The page
 * exists because three Polish keywords worth 7,800/mo ask "where can I watch this series",
 * so the answer is the whole set on one screen rather than eight pages to visit.
 *
 * The film names are h3 and NOT links. None of these films has a keyword of its own, so none
 * ships a title page; underlining them would promise a page that was never written. */
.saga {
  list-style: none;
  padding: 0;
  margin: clamp(1.5rem, 3vw, 2.25rem) 0 0;
  display: flex;
  flex-direction: column;
  gap: clamp(1rem, 2.5vw, 1.75rem);
}
.saga > li {
  display: flex;
  gap: clamp(0.875rem, 2vw, 1.25rem);
  padding-top: clamp(1rem, 2.5vw, 1.75rem);
  border-top: 1px solid var(--border);
}
.saga > li:first-child { border-top: 0; padding-top: 0; }

.saga-art {
  flex: 0 0 auto;
  width: clamp(72px, 12vw, 104px);
  height: auto;
  border-radius: 6px;
  background: var(--surface-2);
}
.saga-body { min-width: 0; flex: 1 1 auto; }
.saga-body h3 {
  margin: 0 0 0.6rem;
  font-size: clamp(1rem, 0.95rem + 0.3vw, 1.15rem);
  line-height: 1.25;
}
.saga-year { color: var(--ink-2); font-weight: 400; }

/* The offers. A grid rather than a table: three fields, and a table would put a header row
 * on each of eight blocks saying the same three words. */
.saga-offers { list-style: none; padding: 0; margin: 0; font-size: 0.9375rem; }
.saga-offers > li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.3rem 0;
}
.saga-offers > li + li { border-top: 1px solid color-mix(in srgb, var(--border) 60%, transparent); }
/* The exit click, and the only accent on this page - the same rule the rest of the site
 * follows: yellow means GO and nothing else wears it. */
.saga-offers a {
  color: var(--accent);
  font-weight: 700;
  text-decoration: none;
}
.saga-offers a:hover { text-decoration: underline; }
.saga-kind { color: var(--ink-3); font-size: 0.875rem; }
/* The number that decides it, so it is not the quietest thing on the row. */
.saga-price { margin-inline-start: auto; font-weight: 700; }
.saga-none { margin: 0; color: var(--ink-2); }

@media (max-width: 30rem) {
  /* The price stops being right-aligned when the row wraps: pushed to the end of a wrapped
   * line it lands under the service name it does not belong to. */
  .saga-price { margin-inline-start: 0; }
}

/* ---- the trailer player -------------------------------------------------------------
 *
 * The facade is an <a> to youtube.com/watch carrying our own artwork; trailer.js swaps it
 * for a nocookie iframe on click. Nothing about YouTube is requested until then, which is
 * the owner's requirement and the EU cookie position in one mechanism.
 *
 * Sized by aspect-ratio rather than a fixed height so the box the iframe lands in is the box
 * the artwork already occupied - swapping a 16:9 frame into a differently-shaped hole is a
 * layout shift on the element the reader just pressed. */
.trailer-facade,
.trailer-frame {
  display: block;
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius, 0.5rem);
  overflow: hidden;
  background: var(--surface-2, #1a1a1a);
}
.trailer-facade img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* A poster standing in for a missing backdrop is 2:3, so `cover` would crop it to a band of
 * torso. `contain` keeps the whole poster and lets the ground show through. */
.trailer-facade img[src*="poster"] { object-fit: contain; }

.trailer-btn {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 4.75rem;
  height: 4.75rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  /* Optically centred, same as .hero-play: a triangle's mass sits left of its box. */
  padding-inline-start: 0.35rem;
}
.trailer-facade:hover .trailer-btn {
  background: color-mix(in srgb, var(--accent) 86%, black);
}
.trailer-facade:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }

.trailer-frame iframe { width: 100%; height: 100%; border: 0; display: block; }

@media (max-width: 48rem) {
  .trailer-btn { width: 3.25rem; height: 3.25rem; }
}

/* ---- the video shelf ----------------------------------------------------------------
 *
 * A list, not a grid of thumbnails: every video would draw the same title backdrop, so a
 * dozen cards is one image a dozen times. The NAME is what tells them apart, so the name
 * leads. Each row is a data-yt control, so trailer.js swaps it for an inline nocookie
 * iframe in place - the same mechanism as the hero facade, a different shape. */
#videos h3 {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  margin: 1.25rem 0 0.4rem;
}
#videos h3 small { font-weight: 400; color: var(--muted); font-variant-numeric: tabular-nums; }

.video-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.video-list li + li { border-top: 1px solid var(--rule, rgba(128,128,128,.25)); }

.video-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0;
  text-decoration: none;
  color: inherit;
}
.video-item:hover .video-name { text-decoration: underline; }
.video-item:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The triangle is drawn with a border rather than an SVG per row: 24 inline SVGs is 24
 * copies of the same path in the HTML of every title page. */
.video-play {
  flex: none;
  width: 0;
  height: 0;
  margin-inline: 0.35rem 0.15rem;
  border-style: solid;
  border-width: 0.42rem 0 0.42rem 0.7rem;
  border-color: transparent transparent transparent var(--accent);
}
.video-name { flex: 1 1 auto; min-width: 0; }
.video-flag {
  flex: none;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}

/* ---- the video shelf, ported from the prototype -------------------------------------
 *
 * TOKENS LIFTED VERBATIM from the design comp's detail view rather than re-derived:
 *
 *   grid   repeat(auto-fill, minmax(min(100%,280px),1fr)) · gap 14px · max-width 760px
 *   card   aspect-ratio 16/9 · radius 8px · 1px solid #1A2430 · padding 14px
 *          align-items flex-end · hover border-color #374151
 *   play   52px circle, #FBC500 on #060D17, centred
 *   label  700 14px/1.2 #fff, INSIDE the card at the bottom
 *
 * The first version of this was a wall of 25 small cards under seven kind headings, which
 * the owner called horrible and was. The kinds are pills on the section head now and the
 * cards have the size the prototype gives them. */
.video-cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
  gap: 14px;
}
.video-card {
  position: relative;
  display: flex;
  align-items: flex-end;
  aspect-ratio: 16 / 9;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  background: var(--surface);
  text-decoration: none;
  color: inherit;
}
/* Hover is the border and nothing else - Design.md section 4, section 8's first Don't. */
.video-card:hover { border-color: var(--accent); }
.video-card:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.video-card .video-art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.video-card picture { position: absolute; inset: 0; }
/* The label sits ON the still, so it needs its own ground rather than a text shadow. */
.video-card::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  height: 60%;
  background: linear-gradient(transparent, rgba(3, 7, 12, 0.88));
}
.video-card .video-name {
  position: relative;
  z-index: 1;
  font-weight: 700;
  font-size: 14px;
  line-height: 1.2;
  color: #fff;
  /* One line then an ellipsis, the same rule the home cards now follow: a two-line caption
     makes one tile taller than its neighbour and the grid stops being a grid. */
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.video-card .video-flag {
  position: absolute;
  z-index: 1;
  top: 10px;
  left: 12px;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #fff;
}
/* The play mark: 52px, the accent, centred. Straight from the prototype. */
.video-card .video-play {
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 52px;
  height: 52px;
  border-radius: 9999px;
  background: var(--accent);
  color: var(--accent-ink);
  display: flex;
  align-items: center;
  justify-content: center;
  /* The triangle is an inline SVG here, so the border-triangle rule the text rows use must
     not also apply. */
  border: 0;
  padding-left: 3px;
}

/* The section head: title left, kind pills right. */
.video-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem 1.25rem;
  flex-wrap: wrap;
  margin-bottom: 0.9rem;
}
.video-head h2 { margin: 0; }
.video-tabs { display: flex; flex-wrap: wrap; gap: 0.4rem; }
.video-tabs button {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: 0.875rem;
  cursor: pointer;
}
.video-tabs button:hover { border-color: var(--border-hover); color: var(--ink); }
.video-tabs button[aria-pressed="true"] {
  background: var(--surface-2);
  border-color: var(--ink-3);
  color: var(--ink);
  font-weight: 700;
}
.video-tabs .tab-n { color: var(--ink-3); font-variant-numeric: tabular-nums; }
.video-cards li[data-off], .video-list li[data-off] { display: none; }

/* ---- the artwork gallery ------------------------------------------------------------
 *
 * UNIFORM TILES, one grid per ratio. It used to draw every image at its natural size in a
 * row, so a 2:3 poster, a 16:9 still and a wordmark logo sat side by side at three different
 * heights with a 900px logo underneath. Same card shape as the video shelf - 8px radius, the
 * hairline, the same hover - because they are the same object: a piece of artwork we hold.
 *
 * `object-fit: cover` with a fixed `aspect-ratio` is what makes the row a row. The box is
 * reserved from the ratio, so nothing jumps as the lazy images land. */
.shots {
  list-style: none;
  margin: 0 0 14px;
  padding: 0;
  display: grid;
  gap: 14px;
}
.shots-backdrop { grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr)); }
.shots-poster { grid-template-columns: repeat(auto-fill, minmax(min(100%, 150px), 1fr)); }
/* Logos are wordmarks on transparent: small, and never blown up to fill a tile. */
.shots-logo { grid-template-columns: repeat(auto-fill, minmax(min(100%, 190px), 1fr)); }

.shot {
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow: hidden;
  background: var(--surface);
}
.shot:hover { border-color: var(--accent); }
.shot picture { display: block; }
.shot img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.shots-backdrop .shot img { aspect-ratio: 16 / 9; }
.shots-poster .shot img { aspect-ratio: 2 / 3; }
.shots-logo .shot img { aspect-ratio: 16 / 9; object-fit: contain; padding: 0.75rem; }
/* ---- the artwork mosaic -------------------------------------------------------------
 *
 * One row per kind, because posters are 2:3 and backdrops 16:9 and a single grid of mixed
 * ratios jumps as it loads. Every tile carries the ORIGINAL width/height so the browser
 * reserves the box from the ratio - a poster grid without reserved boxes is the easiest
 * Core Web Vitals failure there is. */
#gallery .shots {
  list-style: none;
  margin: 0 0 0.75rem;
  padding: 0 0 0.35rem;
  display: grid;
  grid-auto-flow: column;
  gap: 0.6rem;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  overscroll-behavior-x: contain;
}
#gallery .shots-poster { grid-auto-columns: minmax(9rem, 1fr); }
#gallery .shots-backdrop { grid-auto-columns: minmax(18rem, 1fr); }
#gallery .shots-logo { grid-auto-columns: minmax(7rem, max-content); }

#gallery .shot { scroll-snap-align: start; }
#gallery .shot img,
#gallery .shot picture {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius, 0.5rem);
}
/* A logo is usually a transparent PNG drawn for a dark plate; on a light one it disappears.
 * The tile carries its own ground rather than the section assuming a theme. */
#gallery .shots-logo .shot {
  background: var(--surface-2, rgba(128, 128, 128, 0.15));
  border-radius: var(--radius, 0.5rem);
  padding: 0.5rem;
}

/* ------------------------------------------------- the person page (Phase 5) */

/* The photo sits BESIDE the heading rather than above it: this page type answers "what else
 * can I watch with them", so the answer sentence and the count have to be the first thing
 * read, the same rule the title page follows with its poster. */
.person-head {
  display: flex;
  align-items: flex-start;
  gap: 1.25rem;
  margin-bottom: 1.5rem;
}
.person-head > div { min-width: 0; }
.person-head h1 { margin-top: 0; }

/* Reserved by RATIO, not by stored dimensions: `people` carries no width or height, and a
 * 2:3 box is right for every profile TMDB serves. CLS on a headshot is the same failure as
 * CLS on a poster and it is prevented the same way. */
.person-photo {
  flex: none;
  width: clamp(5.5rem, 14vw, 8.5rem);
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: 8px;
  background: var(--surface-2);
}
.person-roles {
  margin: 0 0 0.5rem;
  color: var(--ink-3);
  font-size: 0.875rem;
  font-weight: 700;
}

/* A cast name is a link now that person pages exist. It stays ink-coloured with an
 * underline on hover rather than taking the accent: twelve accented names in a row reads as
 * a warning band, and the row's subject is the person, not the link. */
#cast a[rel="person"] { color: var(--ink); text-decoration: none; }
#cast a[rel="person"]:hover { text-decoration: underline; }

@media (max-width: 30rem) {
  .person-head { gap: 0.875rem; }
}

/* The person index (Phase 3). Same row component as the cast rail - one way of drawing a
 * person on this site, not two. */
.person-index { list-style: none; margin: 0; padding: 0; }
.person-index li {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding: 0.5rem 0;
  border-top: 1px solid var(--border);
}
.person-index li:first-child { border-top: 0; }
.person-index .face {
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
  background: var(--surface-2);
}
.person-index .who a { color: var(--ink); text-decoration: none; font-weight: 600; }
.person-index .who a:hover { text-decoration: underline; }
.person-index .who i { color: var(--ink-3); font-style: normal; font-size: 0.8125rem; }
.person-index .also { color: var(--ink-3); font-size: 0.8125rem; }

/* Related titles as cards (Phase 4). The prototype draws a related work as artwork with the
 * name under it, and a reader picks one by looking - a row of underlined text chips is the
 * shape for a genre, which has no picture, and the wrong one for a film that does. */
/* THE CROSS-SELL RAIL, on the prototype's bottom rails ("People who liked X also liked",
 * "Similar titles you already pay for"). It was a 7rem grid of thumbnails, which reads as a
 * footnote; the prototype gives these cards real size because this is the block that sends a
 * reader to the next page rather than off the site.
 *
 * A RAIL, not a wrapping grid - Design.md section 1.3: native horizontal scroll with an edge
 * fade, no arrows, no scrollbar, and the fade disappears at the end. Same component as the
 * cast rail, because they are the same object: a row of cards you scan sideways. */
.related-cards {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0 0 0.5rem;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 15rem;
  gap: 14px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 3rem), transparent);
  mask-image: linear-gradient(90deg, #000 calc(100% - 3rem), transparent);
}
.related-cards::-webkit-scrollbar { display: none; }
.related-cards li { scroll-snap-align: start; }
.related-cards a {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  color: var(--ink-2);
  text-decoration: none;
  font: 700 15px/1.25 inherit;
}
.related-cards a > span { color: var(--ink); }
.related-cards a:hover { color: var(--ink); }
.related-cards a:hover .card-art { border-color: var(--accent); }
/* Reserved by ratio: these rows carry no stored dimensions, and a poster of unknown height
 * is still 2:3. CLS on a grid of twelve is the easiest Core Web Vitals failure there is. */
.card-art {
  width: 100%;
  aspect-ratio: 2 / 3;
  object-fit: cover;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  display: block;
}
/* The year, under the name and quieter - the prototype's second line. */
.related-cards i {
  display: block;
  margin-top: 0.15rem;
  color: var(--ink-3);
  font: 400 13px/1.3 inherit;
  font-style: normal;
}

/* The languages an offer carries, under the service name in the buybox. Small and quiet:
 * it is a qualifier on the row, not a second subject. */
.langs {
  display: block;
  margin-top: 0.15rem;
  color: var(--ink-3);
  font-size: 0.75rem;
  line-height: 1.35;
}

/* The provider's own mark in the offer table. 20px so it reads as identification beside the
   name rather than as a logo wall, and the name stays the thing being read. `flex-shrink: 0`
   because a long service name must not squeeze the mark into a smear. */
.buy td .provider-icon,
.provider-icon {
  width: 20px;
  height: 20px;
  border-radius: 4px;
  flex-shrink: 0;
  vertical-align: -4px;
  margin-right: 0.45rem;
  object-fit: contain;
  /* Many of these marks are pure black on transparent. On a dark surface that is invisible,
     so they sit on their own light chip - the same treatment every service uses for its own
     mark on dark UI. */
  background: #fff;
}

/* ============================================================ overlays
 *
 * The player modal (z 90) and the gallery lightbox (z 92), ported from the prototype's own
 * markup. Design.md section 6: overlays fade in over .18s ease-out and NOTHING else animates
 * on entry; every overlay closes on backdrop click and inner panels stop propagation.
 * Section 8: no modal stacking beyond these two layers. */

@keyframes wgIn { from { opacity: 0 } to { opacity: 1 } }

.modal {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(14px, 3vw, 44px);
  background: rgba(3, 7, 12, 0.9);
  backdrop-filter: blur(10px);
  animation: wgIn 0.18s ease-out;
}
.modal[hidden] { display: none; }
.modal.is-light {
  z-index: 92;
  flex-direction: column;
  align-items: stretch;
  padding: 0;
  background: rgba(3, 7, 12, 0.94);
}

.modal-panel {
  width: min(1080px, 100%, 118vh);
  max-height: 100%;
  overflow-y: auto;
  scrollbar-width: none;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.modal-head { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; flex: none; }
.modal-heading { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.modal-eyebrow {
  font: 700 12px/1.2 inherit;
  letter-spacing: 0.7px;
  text-transform: uppercase;
  color: var(--accent);
}
.modal-eyebrow.is-quiet { color: var(--ink-dim, #6B7280); letter-spacing: 0.6px; }
.modal-label { font: 900 clamp(20px, 2.6vw, 26px)/1.2 inherit; color: var(--ink); }
.modal-sub { font: 400 14px/1.2 inherit; color: var(--ink-dim, #6B7280); }

/* The close control: a 44px circle, the minimum tap target Design.md section 4 sets. */
.modal-x {
  margin-left: auto;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 9999px;
  background: var(--surface);
  border: 1px solid var(--border);
  font: 700 16px/1 inherit;
  color: var(--ink-2);
  cursor: pointer;
}
.modal-x:hover { color: var(--ink); border-color: var(--border-hover); }

/* The stage holds a real youtube-nocookie iframe, which owns its own transport. The
   prototype's progress bar, time counter and HD/CC labels are driven by a fake timer and are
   deliberately not reproduced: a second progress bar over a real player is decoration that
   lies, and we hold no duration to count against. */
.modal-stage {
  position: relative;
  flex: none;
  aspect-ratio: 16 / 9;
  width: 100%;
  border-radius: 12px;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
}
.modal-stage iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

.modal-next { display: flex; flex: none; flex-direction: column; gap: 10px; }
.modal-next ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
  gap: 10px;
}
.modal-next button {
  display: flex;
  flex-direction: column;
  gap: 7px;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
  color: inherit;
}
.modal-next img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 6px;
  border: 1px solid var(--border);
}
.modal-next button:hover img { border-color: var(--accent); }
.modal-next span { font: 700 13px/1.25 inherit; color: var(--ink); }
.modal-hint { flex: none; font: 400 12px/1.2 inherit; color: var(--ink-faint, #4B5563); }

/* ---- the gallery lightbox */

.light-head {
  flex: none;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 18px clamp(14px, 3vw, 32px);
}
.light-count { font: 700 13px/1.2 inherit; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.light-stage {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  align-items: center;
  gap: clamp(8px, 2vw, 20px);
  padding: 0 clamp(10px, 3vw, 32px);
}
.light-arrow {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 9999px;
  background: rgba(16, 25, 35, 0.85);
  border: 1px solid var(--border);
  font: 700 18px/1 inherit;
  color: var(--ink);
  cursor: pointer;
}
.light-arrow:hover { background: var(--accent); color: var(--accent-ink); border-color: var(--accent); }
.light-frame {
  flex: 1 1 auto;
  height: 100%;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
/* CONTAIN, not a fixed 16:10 stage. The prototype's frame holds a gradient so it can pin a
   ratio; ours holds real artwork at two ratios - a 2:3 poster in a 16:10 box is either
   letterboxed or cropped, and cropping a poster cuts the title off it. */
.light-frame img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 10px;
  border: 1px solid var(--border);
}
.light-foot {
  flex: none;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px clamp(14px, 3vw, 32px) 22px;
}
.light-thumbs { list-style: none; margin: 0; padding: 0; display: flex; gap: 8px; overflow-x: auto; scrollbar-width: none; }
.light-thumbs button {
  display: block;
  flex: none;
  width: 104px;
  aspect-ratio: 16 / 10;
  padding: 0;
  border-radius: 5px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  opacity: 0.55;
  cursor: pointer;
  overflow: hidden;
}
.light-thumbs button:hover { opacity: 1; }
/* The active frame is outlined in the accent - Design.md section 5 names this one. */
.light-thumbs button[aria-current] { opacity: 1; border-color: var(--accent); }
.light-thumbs img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Design.md section 6: nothing animates on entry except the overlay fade. */
@media (prefers-reduced-motion: reduce) {
  .modal { animation: none; }
}

/* ---- the poster ring -----------------------------------------------------------------
 *
 * Owner's reference (pilotwp.pl, 2026-08-16): at rest the poster carries a faint arc of
 * border at about 11 o'clock; on hover the ring completes around the whole card.
 *
 * A MASKED CONIC GRADIENT, not `border-image`. `border-image` ignores `border-radius` and
 * squares the corners off, which on an 8px-radius poster is worse than no ring at all. This
 * paints a 1px frame into a pseudo-element and punches the middle out with a mask, so the
 * ring follows the radius exactly.
 *
 * The pseudo is sized by ratio rather than by height: every poster on this site is 2:3 and
 * full-width in its card, so `aspect-ratio` puts the ring exactly over the artwork without
 * anything having to know how tall the card's text is.
 *
 * `from 290deg` is the 11 o'clock start. The rest angle fades out by 60deg; the hover state
 * carries the accent the whole way round. Only the gradient transitions - Design.md section 6
 * allows a colour change on hover and forbids scale and shadow. */
.related-cards a,
.home-card-shot { position: relative; }

.related-cards a::before,
.home-card-shot::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  aspect-ratio: 2 / 3;
  border-radius: 8px;
  /* The ring's thickness. `padding` IS the stroke here - the mask punches out the content
     box, so whatever the padding is becomes the visible frame. 2px, owner's call. */
  padding: 2px;
  pointer-events: none;
  z-index: 1;
  /* THE FALLOFF IS THE DETAIL. The reference is brightest ON the top-left corner and fades
     gradually down the left edge and along the top - not a hard stop. `from 265deg` puts 0deg
     of the sweep on the left edge, so the corner sits mid-arc; three stops carry it from full
     accent through a half tint to nothing by 135deg, which is roughly a third of the
     perimeter. A two-stop version read as a clipped segment rather than a fade. */
  background: conic-gradient(from 270deg,
    /* 9 o'clock. It used to START here at full strength, which left a hard cut at the bottom
       of the arc; now it fades UP from nothing over the first 45deg, so both ends of the ring
       dissolve instead of one of them being sliced off. */
    transparent 0deg,
    var(--accent) 45deg,
    color-mix(in srgb, var(--accent) 45%, transparent) 85deg,
    transparent 125deg);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  transition: background 0.18s ease-out;
}
/* The home rail's art is 4px, not 8px - the ring has to match the box it traces. */
.home-card-shot::before { border-radius: 4px; }

.related-cards a:hover::before,
.home-track a:hover .home-card-shot::before {
  background: conic-gradient(from 290deg, var(--accent) 0deg, var(--accent) 360deg);
}

@media (prefers-reduced-motion: reduce) {
  .related-cards a::before,
  .home-card-shot::before { transition: none; }
}

/* ---- the card CTA -------------------------------------------------------------------
 *
 * Owner's reference (pilotwp.pl): a button sits on the poster and appears on hover. It tells
 * the reader what the card leads to before they commit the click, which on a rail of twelve
 * posters is the difference between browsing and guessing.
 *
 * NOT THE ACCENT, and this is the one place the reference is not copied. `theme.ts` reserves
 * the accent for the EXIT CLICK - the link that leaves this site and earns - and this button
 * goes to our own title page. Painting it the same colour would make the loudest signal on
 * the page mean two things, which is the rule that file exists to hold. It takes the raised
 * surface and the accent border instead, so it still reads as the action on the card.
 *
 * `aria-hidden`, because it is not a second control: the whole card is already one link, and
 * announcing "Dove vedere" after the title would give a screen reader two names for it. */
.card-cta {
  position: absolute;
  left: 0.6rem;
  right: 0.6rem;
  bottom: 0.6rem;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0.5rem 0.7rem;
  border-radius: 8px;
  border: 1px solid var(--accent);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: blur(6px);
  color: var(--ink);
  font-weight: 700;
  font-size: 0.8125rem;
  line-height: 1.2;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* Hidden until hover, and it must not be reachable or announced while hidden. */
  opacity: 0;
  transform: translateY(0.35rem);
  transition: opacity 0.18s ease-out, transform 0.18s ease-out;
}
.home-track a:hover .card-cta,
.home-track a:focus-visible .card-cta,
.related-cards a:hover .card-cta,
.related-cards a:focus-visible .card-cta {
  opacity: 1;
  transform: none;
}
/* The related card's art box is the positioning context for its CTA - the link is a flex
   column, so without this the button would pin to the bottom of the TEXT instead. */
.related-cards a > picture, .related-cards a > img { position: relative; }
.related-cards a { position: relative; }

/* Touch has no hover. Showing it always on a coarse pointer would cover a third of every
   poster, so it stays off - the whole card is the link there anyway. */
@media (hover: none) {
  .card-cta { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .card-cta { transition: none; }
}

/* ---- rail overflow: fades and arrows --------------------------------------------------
 *
 * Owner's call, 2026-08-16, overriding Design.md section 1.3 ("no arrows... the fade IS the
 * affordance"). Recorded in `rails.js`.
 *
 * `rails.js` builds the wrapper and the buttons, so with the script blocked there are no
 * controls and the rails scroll natively - the guide's own behaviour is the no-JS default.
 * `data-at` says which side still has more, so a rail scrolled to its end is not left sitting
 * behind a gradient that promises content it does not have. */
.rail-wrap { position: relative; }

/* The fade is a mask on the scroller itself, so it tracks the artwork rather than sitting
   over it as a coloured block - which would have to know the page background and would be
   wrong the moment a rail sits on a different surface. */
.rail-wrap > [data-at='start'] { -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 5rem), transparent); mask-image: linear-gradient(90deg, #000 calc(100% - 5rem), transparent); }
.rail-wrap > [data-at='end'] { -webkit-mask-image: linear-gradient(90deg, transparent, #000 5rem); mask-image: linear-gradient(90deg, transparent, #000 5rem); }
.rail-wrap > [data-at='both'] {
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5rem, #000 calc(100% - 5rem), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 5rem, #000 calc(100% - 5rem), transparent);
}

.rail-arrow {
  position: absolute;
  top: 0;
  /* Centred on the ARTWORK, not on the card: the title and its meta line sit under the
     poster, so centring on the whole card would drop the arrow below the image. */
  bottom: 4.5rem;
  margin: auto 0;
  z-index: 3;
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 9999px;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  border: 1px solid var(--border);
  backdrop-filter: blur(6px);
  color: var(--ink);
  cursor: pointer;
}
.rail-arrow.is-prev { left: 0.35rem; }
.rail-arrow.is-next { right: 0.35rem; }
.rail-arrow:hover { border-color: var(--accent); }

/* Shown only on the side that has more to scroll to. A control that cannot do anything is
   the dead control this codebase refuses everywhere else. */
.rail-wrap:has([data-at='end']) .is-prev,
.rail-wrap:has([data-at='both']) .is-prev,
.rail-wrap:has([data-at='start']) .is-next,
.rail-wrap:has([data-at='both']) .is-next { display: flex; }

/* No hover means no discoverable arrow, and a finger already swipes. */
@media (hover: none) {
  .rail-arrow { display: none !important; }
}

/* ---- the geo band ------------------------------------------------------------------
 *
 * A full-bleed strip ABOVE the header saying which country the prices below belong to.
 * Ships `hidden`; geo.js un-hides it after asking /geo. Not dismissible - it states the
 * scope of the page, and that does not stop being true once a reader has read it once.
 *
 * COLOUR. The accent is `--accent` lime and `--alert` is the departures red, and this is
 * neither: a countdown is urgent, and this is not. It gets its own muted crimson, dark
 * enough that white sits at 8.9:1 on it, so the band reads as a statement of scope rather
 * than as an alarm competing with the "leaving soon" flags further down the page.
 *
 * IT IS NOT STICKY, and the header above it is. The band belongs to the top of the
 * document, not to the furniture that follows the reader - pinning both would spend two
 * rows of a phone screen on chrome forever. It scrolls away; the header stays. */
.geo {
  background: #5B1220;
  color: #FFFFFF;
  padding: 0.7rem var(--px);
  /* Under the header's z-index so that when the sticky header scrolls up over the band,
   * the header is what stays on top. */
  position: relative;
  z-index: 50;
}
.geo[hidden] { display: none; }
.geo-in {
  max-width: 46rem;
  display: grid;
  /* The icon column the reference uses is a glyph rather than an asset: one more image in
   * the critical path for a decorative globe is not a trade worth making. */
  grid-template-columns: auto 1fr;
  gap: 0.15rem 0.75rem;
}
.geo-in::before {
  content: "";
  grid-row: 1 / span 2;
  align-self: start;
  width: 1.25rem;
  height: 1.25rem;
  margin-top: 0.15rem;
  background: currentColor;
  /* A globe, as a mask so it inherits `currentColor` and costs no request. */
  -webkit-mask: var(--geo-glyph) center / contain no-repeat;
  mask: var(--geo-glyph) center / contain no-repeat;
  opacity: 0.9;
}
.geo-h {
  margin: 0;
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.35;
}
.geo-b {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.45;
  /* Not pure white: the second line is supporting text, and two identical whites read as
   * one undifferentiated block at this size. 6.6:1 on the band. */
  color: #E8D7DB;
}
.geo-cta {
  grid-column: 2;
  justify-self: start;
  margin-top: 0.4rem;
  padding: 0.35rem 0.75rem;
  border-radius: 6px;
  background: #FFFFFF;
  color: #5B1220;
  font-weight: 700;
  font-size: 0.8125rem;
  text-decoration: none;
}
.geo-cta:hover { background: #F3E7EA; }
.geo-cta[hidden] { display: none; }

@media (max-width: 36rem) {
  .geo-in { gap: 0.15rem 0.6rem; }
  .geo-h { font-size: 0.9rem; }
  .geo-b { font-size: 0.8125rem; }
}

/* ---- the live countries, first and marked ------------------------------------------
 *
 * The panel lists all 54 in region order, which is the right shape for "where is this
 * going" and the wrong one for "where can I go now". Two live countries were sitting inside
 * a list of 52 dead ones - one under Southern Europe, one under Eastern Europe - at the same
 * weight and in the same typeface as the rest, so the only two rows on the panel that led
 * anywhere were the two hardest to find on it.
 *
 * They stay in their regions below as well: the regional list is a map of the plan, and
 * removing two countries from it leaves a hole exactly where a reader looks for them. */
.geo-live {
  padding: 0.5rem;
  margin-bottom: 0.85rem;
  border-radius: 8px;
  /* A tint of the accent rather than a border. `no-ai-slop-borders`: the block needs to read
   * as raised, not as fenced off. */
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.geo-live h3 {
  /* The one heading on the panel that is not muted - it labels the only actionable rows. */
  color: var(--accent);
  margin-bottom: 0.4rem;
}
.geo-live-a {
  /* Full ink and a heavier weight, against the `--ink-3` the dead rows carry. The contrast
   * between this and a `.geo-soon` row is the whole point of the block. */
  color: var(--ink) !important;
  font-weight: 600;
}
.geo-live-a:hover { background: color-mix(in srgb, var(--accent) 18%, transparent); }
.geo-live .geo-code {
  /* The country code gets the accent as a chip, so the eye lands on the block before it
   * reads a word of it. */
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 700;
}
