/* Kinora web: after the signed-in Apple TV app (tv.apple.com). Design spec: Web/DESIGN.md.
 *
 * Layers, low to high: reset, tokens, base, layout, components, pages, utilities.
 * This file holds everything but `pages`; each page's own rules are in public/css/<page>.css
 * inside `@layer pages { … }` (home: Home + Title; browse: Movies, TV, Search, Library;
 * playback: picker + player; account: profiles, add-ons, connect).
 *
 * Components (class API; the Swift helper in Components.swift renders them):
 *   .button [.button-secondary | .button-text | .button-destructive | .button-small]   pill buttons
 *   .icon-button [.mat-thin]           40 px circle, 44 px hit area; toggles use aria-pressed
 *   .pill (a / button) [aria-current | aria-pressed]   genre / segment chips, in .pill-row
 *   .shelf > h2.shelf-title (+ a with chevron) + .shelf-list.shelf-{poster|wide|featured|cast|episode}
 *       shelf.js adds .shelf-arrow buttons (≥ 740 px, mouse). .is-deferred: content-visibility.
 *   .poster-grid                         3/5/6/8/8 poster columns
 *   .lockup.lockup-{poster|wide|featured|cast} [.lockup-rank | .lockup-continue]
 *       > a.lockup-link > .art (> img, .art-fallback, .art-logo, .art-caption, .art-overlay, .rank)
 *       + .lockup-caption (> .lockup-title, .lockup-subtitle, .lockup-synopsis)
 *       + .more-button (data-menu …)  "…" button (MoreMenu); shelf.js fills the page's one #more-menu
 *   .art                                 placeholder fill + 1 px stroke; img fades in (html.js)
 *   .progress (style="--progress: 40%")  thin bar; .logo-box sized logo slot (no layout shift)
 *   .menu [popover] > .menu-title, .menu-item [.is-destructive], .menu-note
 *   .empty-state > svg, h1|h2, p, .button;  .error-page wraps it on 404/500 pages
 *   .toast (role=status)                 bottom capsule, fades after 4 s; .spinner; .field
 *   .mat-bar | .mat-thin | .mat-thick    glass materials with solid fallbacks
 *   .large-title, .lede, .note, .badge, .meta, .visually-hidden, .skip-link
 */
@layer reset, tokens, base, layout, components, pages, utilities;

@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  body, h1, h2, h3, h4, p, figure, blockquote, dl, dd, ol, ul { margin: 0; }
  ol, ul { padding: 0; }
  img, svg, video { display: block; max-inline-size: 100%; }
  input, button, select, textarea { font: inherit; color: inherit; }
  button { cursor: pointer; }
  [hidden] { display: none !important; }
}

@layer tokens {
  :root {
    color-scheme: dark;

    /* Color (dark only) */
    --bg-nav: #000;
    --bg-0: #1f1f1f;
    --bg-1: rgb(255 255 255 / 0.10);
    --bg-2: #2d2d2d;
    --bg-placeholder: #323232;
    --lockup-stroke: rgb(255 255 255 / 0.16);
    --fill-1: rgb(255 255 255 / 0.10);
    --fill-2: rgb(255 255 255 / 0.16);
    --fill-3: rgb(255 255 255 / 0.24);
    --separator: rgb(255 255 255 / 0.08);
    --text-1: rgb(255 255 255 / 0.92);
    --text-2: rgb(255 255 255 / 0.72);
    --text-3: rgb(255 255 255 / 0.55);
    --text-4: rgb(255 255 255 / 0.40);
    --text-nav: rgb(255 255 255 / 0.64);
    --primary-fill: #fff;
    --primary-hover: rgb(255 255 255 / 0.86);
    --on-primary: rgb(0 0 0 / 0.88);
    --accent: #409cff;
    --destructive: #ff6961;
    --success: #31de4b;
    --warning: #ffb340;
    --progress-track: rgb(255 255 255 / 0.30);
    --progress-fill: #fff;
    --scrim: rgb(0 0 0 / 0.55);
    --mat-bar: rgb(22 22 24 / 0.72);
    --mat-thin: rgb(40 40 40 / 0.50);
    --mat-thick: rgb(44 44 46 / 0.82);

    /* Type */
    --font: -apple-system, BlinkMacSystemFont, "SF Pro", "SF Pro Icons", "Helvetica Neue", Helvetica, Arial, system-ui, sans-serif;
    --font-mono: ui-monospace, "SF Mono", Menlo, monospace;
    --type-display: 700 clamp(32px, 2.2vw + 24px, 56px) / 1.05 var(--font);
    --type-large-title: 700 clamp(28px, 0.6vw + 26px, 34px) / 1.2 var(--font);
    --type-title-1: 700 clamp(24px, 0.4vw + 22px, 28px) / 1.2 var(--font);
    --type-title-2: 700 22px / 28px var(--font);
    --type-title-3: 700 20px / 25px var(--font);
    --type-shelf: 700 17px / 22px var(--font);
    --type-headline: 600 17px / 22px var(--font);
    --type-body: 400 16px / 22px var(--font);
    --type-callout: 400 15px / 20px var(--font);
    --type-subhead: 500 14px / 18px var(--font);
    --type-footnote: 400 13px / 18px var(--font);
    --type-caption-1: 600 12px / 16px var(--font);
    --type-caption-2: 600 11px / 13px var(--font);

    /* Spacing (4 px base) */
    --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px;
    --sp-8: 32px; --sp-10: 40px; --sp-14: 56px; --sp-18: 72px; --sp-24: 96px;
    --shelf-space: 44px;           /* art bottom to the next header, hero bottom to the first */

    /* Layout: breakpoints 740 / 1000 / 1320 / 1680 (media queries can't read these) */
    --gutter: calc(24px + max(env(safe-area-inset-left), env(safe-area-inset-right)));
    --gap: 10px;
    --nav-h: 52px;
    --tabbar-h: 60px;
    --tabbar-space: 0px;           /* room kept under main for the phone tab bar */
    --poster-cols: 5;
    --wide-cols: 3;
    --featured-cols: 2;
    --reading: 60ch;

    /* Radii */
    --r-xs: 4px; --r-s: 8px; --r-art: 14px; --r-art-l: 20px; --r-arrow: 6px; --r-menu: 14px; --r-pill: 999px;

    /* Shadows */
    --shadow-rest: 0 1px 1px rgb(0 0 0 / .04), 0 4px 8px rgb(0 0 0 / .12);
    --shadow-lift: 0 18px 36px -8px rgb(0 0 0 / .55), 0 6px 12px rgb(0 0 0 / .35);
    --shadow-float: 0 12px 32px rgb(0 0 0 / .45);

    /* Motion. Springs only on transform/scale/translate; the cubic-bezier line is the fallback. */
    --dur-press: 100ms; --dur-fast: 200ms; --dur-base: 300ms; --dur-slow: 500ms;
    --ease-standard: cubic-bezier(0.25, 0.1, 0.25, 1);
    --ease-out: cubic-bezier(0.2, 0.8, 0.2, 1);
    --ease-in: cubic-bezier(0.4, 0, 1, 1);
    --ease-spring: cubic-bezier(0.2, 0.9, 0.3, 1.05);
    --ease-spring: linear(0, 0.068, 0.221, 0.4, 0.573, 0.72, 0.835, 0.918, 0.973, 1.007, 1.025, 1.031, 1.031, 1.027, 1.021, 1.016, 1.011, 1.007, 1.004, 1.001, 1, 0.999, 0.999, 0.999, 1);
    --ease-spring-soft: cubic-bezier(0.25, 0.9, 0.3, 1);
    --ease-spring-soft: linear(0, 0.053, 0.172, 0.315, 0.457, 0.586, 0.695, 0.783, 0.851, 0.902, 0.938, 0.964, 0.981, 0.992, 0.999, 1.003, 1.005, 1.005, 1.005, 1.004, 1.004, 1.003, 1.002, 1.002, 1);

    /* Icons (Icon/IconSize in Components.swift): xs in footnote text and small pills, sm inline with
       body text, md in circle buttons, menus, toasts and notices, lg in the top and tab bars, xl for
       big arrows and the large play circle, xxl for empty and error states. */
    --icon-xs: 12px; --icon-sm: 16px; --icon-md: 20px; --icon-lg: 24px; --icon-xl: 28px; --icon-xxl: 48px;

    /* Z-layers (menus, toasts and dialogs use the top layer instead) */
    --z-base: 0; --z-lockup-hover: 1; --z-shelf-arrows: 2; --z-hero-content: 3; --z-nav: 100; --z-tabbar: 100; --z-skip-link: 1000;
  }

  @media (width >= 740px) {
    :root { --gutter: 40px; --gap: 20px; --poster-cols: 5; --wide-cols: 3; --featured-cols: 2; }
  }
  @media (width >= 1000px) {
    :root { --poster-cols: 6; --wide-cols: 4; }
  }
  @media (width >= 1320px) {
    :root { --poster-cols: 8; --wide-cols: 5; --featured-cols: 3; }
  }
  @media (width >= 1680px) {
    :root { --gutter: max(40px, (100vw - 1680px) / 2); }
  }
  @media (width < 740px) {
    :root { --tabbar-space: calc(var(--tabbar-h) + 36px + env(safe-area-inset-bottom)); }
  }

  @media (prefers-contrast: more) {
    :root { --text-2: rgb(255 255 255 / 0.85); --text-3: rgb(255 255 255 / 0.72); --lockup-stroke: rgb(255 255 255 / 0.4); }
  }
}

@layer base {
  html {
    background: var(--bg-0);
    /* Rows scroll inside themselves; the page never scrolls sideways. */
    overflow-x: clip;
    /* Focus and in-page links land clear of the sticky bar and the phone's tab bar (WCAG 2.4.11). */
    scroll-padding-block: calc(var(--nav-h) + 16px) calc(var(--tabbar-space) + 16px);
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
  }

  body {
    min-block-size: 100dvh;
    background: var(--bg-0);
    color: var(--text-1);
    font: var(--type-body);
    -webkit-font-smoothing: antialiased;
    overflow-x: clip;
  }

  h1, h2, h3 { text-wrap: balance; }
  a { color: inherit; }
  p { text-wrap: pretty; }
  code { font-family: var(--font-mono); font-size: 0.9em; overflow-wrap: anywhere; }

  :focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 3px;
  }

  ::selection { background: rgb(64 156 255 / 0.4); }

  ::placeholder { color: var(--text-3); opacity: 1; }

  @media (prefers-reduced-motion: no-preference) {
    @view-transition { navigation: auto; }
    ::view-transition-old(root) { animation: 150ms var(--ease-in) both fade-out; }
    ::view-transition-new(root) { animation: 250ms var(--ease-out) both fade-in-up; }
  }
  @keyframes fade-out { to { opacity: 0; } }
  @keyframes fade-in-up { from { opacity: 0; translate: 0 8px; } }
}

@layer layout {
  /* Top bar: solid black, sticky, 52 px; brand | tabs | search + avatar. */
  .top-bar {
    position: sticky;
    inset-block-start: 0;
    z-index: var(--z-nav);
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: var(--sp-4);
    block-size: var(--nav-h);
    padding-inline: var(--gutter);
    background: var(--bg-nav);
    view-transition-name: nav;
  }

  .brand {
    justify-self: start;
    display: inline-flex;
    align-items: center;
    min-block-size: 44px;
    font: var(--type-title-3);
    letter-spacing: -0.01em;
    color: var(--text-1);
    text-decoration: none;
    border-radius: var(--r-s);
  }

  .top-tabs {
    display: flex;
    gap: var(--sp-1);

    & a {
      display: inline-flex;
      align-items: center;
      min-block-size: 44px;
      padding-inline: 10px;
      border-radius: var(--r-s);
      color: var(--text-nav);
      font: 600 16px / 20px var(--font);
      text-decoration: none;
      white-space: nowrap;
      transition: color var(--dur-fast) linear;
    }

    & a:hover, & a[aria-current="page"] { color: var(--text-1); }
  }

  .top-actions {
    justify-self: end;
    display: flex;
    align-items: center;
    gap: var(--sp-3);
  }

  /* Desktop search field (≥ 1000): 28 px, outlined, 172–200 px. */
  .nav-search {
    position: relative;
    display: none;
    align-items: center;

    & .icon { position: absolute; inset-inline-start: 8px; color: var(--text-2); pointer-events: none; }

    & input {
      inline-size: clamp(172px, 14vw, 200px);
      block-size: 28px;
      padding: 0 8px 0 28px;
      border: 1px solid var(--text-1);
      border-radius: var(--r-xs);
      background: transparent;
      font: 400 15px / 20px var(--font);
    }

    & input:focus-visible { outline-offset: 1px; }
    & input::-webkit-search-cancel-button { filter: invert(1); }
  }

  .avatar-button {
    display: grid;
    place-items: center;
    inline-size: 44px;
    block-size: 44px;
    margin-inline-end: -10px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: none;

  }

  /* Phone tab bar: floating glass capsule. */
  .tab-bar {
    position: fixed;
    inset-inline: max(16px, env(safe-area-inset-left)) max(16px, env(safe-area-inset-right));
    inset-block-end: calc(12px + env(safe-area-inset-bottom));
    z-index: var(--z-tabbar);
    display: none;
    grid-template-columns: repeat(5, 1fr);
    min-block-size: var(--tabbar-h);
    padding: 4px;
    border-radius: var(--r-pill);
    view-transition-name: tabbar;

    & a {
      display: grid;
      place-content: center;
      justify-items: center;
      gap: 2px;
      min-block-size: 52px;
      min-inline-size: 44px;
      border-radius: var(--r-pill);
      color: var(--text-2);
      font: 500 11px / 13px var(--font);
      text-decoration: none;
      overflow-wrap: anywhere;
      text-align: center;
    }

    & a[aria-current="page"] { background: var(--fill-2); color: var(--text-1); }
    & a:focus-visible { outline-offset: -3px; }
  }

  main { padding-block-end: calc(var(--sp-18) + var(--tabbar-space)); }

  @media (width < 740px) {
    /* Phone: a slim bar that scrolls away (brand + avatar); sections live in the tab bar. */
    .top-bar {
      position: static;
      grid-template-columns: 1fr auto;
      block-size: 48px;
      padding-block-start: env(safe-area-inset-top);
      box-sizing: content-box;
    }
    .top-tabs, .nav-search-link { display: none; }
    .tab-bar { display: grid; }
    html { scroll-padding-block-start: 16px; }
  }

  @media (width >= 1000px) {
    .nav-search { display: flex; }
    .nav-search-link { display: none; }
  }

  /* A bar too narrow for tabs + field at big text sizes: the magnifier replaces the field. */
  @media (740px <= width < 1000px) {
    .top-tabs a { padding-inline: 8px; }
  }

  /* Full-width content, capped at 1680 px by the gutter formula. */
  .page-content { padding-inline: var(--gutter); }
}

@layer components {
  /* Buttons: white pill, gray secondary, 40 px circles. No hover scale; press scales down. */
  .button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-2);
    min-block-size: 44px;
    padding: 0 22px;
    border: 0;
    border-radius: var(--r-pill);
    background: var(--primary-fill);
    color: var(--on-primary);
    font: 600 15px / 20px var(--font);
    text-decoration: none;
    white-space: nowrap;
    transition: background-color var(--dur-fast) linear, scale var(--dur-press) var(--ease-out);

    &:hover { background: var(--primary-hover); }
    &:active { scale: 0.97; }
    &:disabled, &[aria-disabled="true"] { opacity: 0.4; cursor: not-allowed; scale: none; }
  }

  .button-secondary, .button-destructive {
    background: var(--fill-1);
    color: var(--text-1);
    &:hover { background: var(--fill-2); }
    &:active { background: var(--fill-3); }
  }
  .button-destructive { color: var(--destructive); }

  .button-text {
    min-inline-size: 44px;
    padding-inline: var(--sp-2);
    background: none;
    color: var(--accent);
    &:hover { background: none; text-decoration: underline; }
    &:active { opacity: 0.7; scale: none; }
  }

  .button-small { min-block-size: 32px; padding: 0 14px; font-size: 13px; }

  @media (width < 740px) {
    .button:not(.button-small, .button-text) { min-block-size: 50px; }
  }

  /* Circle icon button: 40 px, 44 px hit area (the border is transparent padding). */
  .icon-button {
    display: inline-grid;
    place-items: center;
    inline-size: 44px;
    block-size: 44px;
    padding: 0;
    border: 2px solid transparent;
    border-radius: 50%;
    background: var(--fill-1) padding-box;
    color: var(--text-1);
    text-decoration: none;
    transition: background-color var(--dur-fast) linear, scale var(--dur-press) var(--ease-out);

    &:hover { background-color: var(--fill-2); }
    &:active { scale: 0.94; }
    &[aria-pressed="true"] { background-color: var(--fill-3); }
    &.mat-thin { background-color: var(--mat-thin); }
  }
  .top-bar .icon-button { background: none; color: var(--text-2); &:hover { color: var(--text-1); } }
  /* The magnifier shows only where the field doesn't (740–999). */
  @media (width < 740px), (width >= 1000px) {
    .nav-search-link { display: none; }
  }

  /* Chips: gray text, gray capsule when selected (tvOS ChipButtonStyle). */
  .pill-row {
    display: flex;
    gap: var(--sp-2);
    padding: 4px var(--gutter);
    margin-inline: calc(-1 * var(--gutter));
    list-style: none;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scroll-padding-inline: var(--gutter);
    scrollbar-width: none;
    /* Pills scrolled past the gutter fade out instead of being cut at the screen's edge. */
    --fade: linear-gradient(90deg, transparent 0, #000 var(--gutter), #000 calc(100% - var(--gutter)), transparent);
    -webkit-mask: var(--fade);
    mask: var(--fade);
    & > li { scroll-snap-align: start; flex: none; }
  }

  .pill {
    display: inline-flex;
    align-items: center;
    min-block-size: 36px;
    padding: 0 16px;
    border: 0;
    border-radius: var(--r-pill);
    background: none;
    color: var(--text-2);
    font: var(--type-subhead);
    text-decoration: none;
    white-space: nowrap;
    transition: background-color var(--dur-fast) linear, color var(--dur-fast) linear;

    &:hover { background: var(--fill-1); color: var(--text-1); }
    &[aria-current="page"], &[aria-current="true"], &[aria-pressed="true"] { background: var(--fill-3); color: var(--text-1); }
  }
  @media (pointer: coarse) {
    .pill { min-block-size: 44px; }
  }

  /* Text styles */
  .large-title { font: var(--type-large-title); letter-spacing: -0.005em; }
  .lede { color: var(--text-2); max-inline-size: var(--reading); }
  .note { color: var(--text-2); font: var(--type-footnote); }
  .meta { color: var(--text-2); font: var(--type-callout); }

  .badge {
    display: inline-flex;
    align-items: center;
    block-size: 16px;
    padding: 0 4px;
    border: 1px solid currentColor;
    border-radius: var(--r-xs);
    color: var(--text-2);
    font: 700 10px / 1 var(--font);
    text-transform: uppercase;
    vertical-align: middle;
  }

  /* Materials */
  .mat-bar, .mat-thin, .mat-thick { -webkit-backdrop-filter: saturate(180%) blur(20px); backdrop-filter: saturate(180%) blur(20px); }
  .mat-bar { background: var(--mat-bar); }
  .mat-thin { background: var(--mat-thin); -webkit-backdrop-filter: saturate(180%) blur(30px); backdrop-filter: saturate(180%) blur(30px); }
  .mat-thick { background: var(--mat-thick); -webkit-backdrop-filter: saturate(180%) blur(40px); backdrop-filter: saturate(180%) blur(40px); box-shadow: var(--shadow-float); }
  /* No blur (old WebKit, reduced transparency, more contrast): solid fills. */
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .mat-bar, .mat-thin, .mat-thick { background: var(--bg-2); }
  }
  @media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
    .mat-bar, .mat-thin, .mat-thick { -webkit-backdrop-filter: none; backdrop-filter: none; background: var(--bg-2); }
  }

  /* Avatar: the TV's picture over the initial on the profile's color. Size with --size. */
  .avatar {
    --size: 36px;
    position: relative;
    display: grid;
    place-items: center;
    flex: none;
    inline-size: var(--size);
    block-size: var(--size);
    border-radius: 50%;
    background: var(--avatar, #5e8cd9);
    color: #fff;
    font-weight: 600;
    line-height: 1;
    overflow: hidden;
  }

  .avatar img { position: absolute; inset: 0; inline-size: 100%; block-size: 100%; object-fit: cover; }
  .avatar-button .avatar { --size: 24px; font-size: 11px; }
  @media (width < 740px) {
    .avatar-button .avatar { --size: 32px; font-size: 14px; }
  }

  /* Menus (avatar, "…", confirm): a popover under its button. */
  .menu {
    min-inline-size: 220px;
    max-inline-size: min(320px, 100vw - 32px);
    margin: 0;
    padding: 6px;
    border: 0;
    border-radius: var(--r-menu);
    /* Denser than --mat-thick: WebKit blurs the top layer lightly, and text behind showed through. */
    background: rgb(44 44 46 / 0.94);
    color: var(--text-1);
    box-shadow: var(--shadow-float);
    -webkit-backdrop-filter: saturate(180%) blur(40px);
    backdrop-filter: saturate(180%) blur(40px);

    &:popover-open { display: grid; }
    & form { display: contents; }
  }

  /* Anchored below its button where anchor positioning works; else a sheet at the bottom. */
  [popover].menu {
    inset: auto;
    position-area: block-end span-inline-start;
    position-try-fallbacks: flip-block, flip-inline;
    margin-block: 6px;
  }
  @supports not (position-area: block-end) {
    [popover].menu {
      position: fixed;
      inset: auto 16px calc(16px + var(--tabbar-space)) 16px;
      max-inline-size: none;
      margin: 0;
    }
    [popover].account-menu { inset: calc(var(--nav-h) + 8px) var(--gutter) auto auto; }
  }

  .menu-title {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    padding: 8px 12px 10px;
    border-block-end: 1px solid var(--separator);
    margin-block-end: 4px;
    color: var(--text-2);
    font: var(--type-footnote);
    & .avatar { --size: 28px; font-size: 13px; }
    & span { color: var(--text-1); font-weight: 600; }
  }

  .menu-note { padding: 0 12px 8px; color: var(--text-2); font: var(--type-footnote); }

  .menu-item {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    inline-size: 100%;
    min-block-size: 44px;
    padding: 0 12px;
    border: 0;
    border-radius: var(--r-s);
    background: none;
    color: var(--text-1);
    font: var(--type-body);
    text-align: start;
    text-decoration: none;

    &:hover { background: var(--fill-1); }
    &:focus-visible { outline-offset: -3px; }
    /* checkmark (Framework7, as Icon.check) */
    &[aria-current="page"]::after {
      content: "";
      flex: none;
      inline-size: var(--icon-md);
      block-size: var(--icon-md);
      margin-inline-start: auto;
      background: var(--text-2);
      mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 56 56'%3E%3Cpath d='M23.08 48.03C24.09 48.03 24.88 47.58 25.45 46.71L47.59 11.84C48.02 11.16 48.2 10.64 48.2 10.11C48.2 8.82 47.34 7.97 46.05 7.97C45.13 7.97 44.59 8.28 44.03 9.17L22.98 42.71L12.06 28.41C11.48 27.59 10.91 27.26 10.05 27.26C8.73 27.26 7.8 28.18 7.8 29.46C7.8 30 8.03 30.61 8.48 31.18L20.64 46.67C21.37 47.58 22.07 48.03 23.08 48.03Z'/%3E%3C/svg%3E") center / contain no-repeat;
    }
    &.is-destructive { color: var(--destructive); }
  }

  @media (prefers-reduced-motion: no-preference) {
    .menu:popover-open {
      transition: opacity var(--dur-fast) linear, translate 550ms var(--ease-spring-soft);
      @starting-style { opacity: 0; translate: 0 -6px; }
    }
  }

  /* Shelves: a title, then a row that scrolls sideways, full-bleed and snapped to the gutter. */
  .shelf {
    position: relative;
    margin-block-start: var(--shelf-space);
  }

  .shelf.is-deferred {
    content-visibility: auto;
    contain-intrinsic-block-size: auto 320px;
  }

  .shelf-title {
    padding-inline: var(--gutter);
    margin-block-end: var(--sp-3);
    font: var(--type-shelf);
    color: var(--text-1);

    & a {
      display: inline-flex;
      align-items: center;
      gap: 4px;
      position: relative;
      /* A 24 px box (the line is 22) and a 44 px hit area around it; the look doesn't change. */
      padding-block: 1px;
      margin-block: -1px;
      color: inherit;
      text-decoration: none;
      border-radius: var(--r-xs);
      &::before { content: ""; position: absolute; inset: -10px -4px; }
    }
    & .icon { color: var(--text-2); transition: color var(--dur-fast) linear; }
    & a:hover .icon { color: var(--text-1); }
  }

  .shelf-list {
    --cols: var(--poster-cols);
    --xs-width: 40vw;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: calc((100% - (var(--cols) - 1) * var(--gap)) / var(--cols));
    gap: var(--gap);
    /* 16 px above and below so focus rings aren't clipped; the mask softens the edges. */
    padding: 16px var(--gutter);
    margin-block: -16px;
    list-style: none;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: var(--gutter);
    scrollbar-width: none;
    -webkit-mask: linear-gradient(90deg, transparent 0, #000 16px, #000 calc(100% - 16px), transparent);
    mask: linear-gradient(90deg, transparent 0, #000 16px, #000 calc(100% - 16px), transparent);

    &::-webkit-scrollbar { display: none; }
    & > li { scroll-snap-align: start; min-inline-size: 0; }
  }

  .shelf-wide, .shelf-episode { --cols: var(--wide-cols); --xs-width: 57vw; }
  .shelf-featured { --cols: var(--featured-cols); --xs-width: 86vw; }
  .shelf-cast { --xs-width: 96px; }

  @media (width < 740px) {
    .shelf-list { grid-auto-columns: var(--xs-width); }
  }

  /* Shelf arrows (shelf.js): 28×64, chevron only, on hover. Mouse and ≥ 740 px only. */
  .shelf-arrow {
    position: absolute;
    inset-block-start: var(--arrow-top, 50%);
    z-index: var(--z-shelf-arrows);
    display: grid;
    place-items: center;
    inline-size: 28px;
    block-size: 64px;
    margin-block-start: -32px;
    padding: 0;
    border: 0;
    border-radius: var(--r-arrow);
    background: transparent;
    color: var(--text-2);
    opacity: 0;
    transition: opacity 250ms linear, background-color 250ms linear;

    &:hover { background: var(--fill-2); color: var(--text-1); }
    &:active { background: var(--fill-3); }
    &:disabled { opacity: 0 !important; pointer-events: none; }
  }
  .shelf-arrow-prev { inset-inline-start: max(6px, var(--gutter) - 34px); }
  .shelf-arrow-next { inset-inline-end: max(6px, var(--gutter) - 34px); }
  .shelf:hover .shelf-arrow, .shelf-arrow:focus-visible { opacity: 1; }
  @media (width < 740px), (hover: none) {
    .shelf-arrow { display: none; }
  }

  /* Poster grid (Movies, TV Shows, Library, results) */
  .poster-grid {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols, var(--poster-cols)), minmax(0, 1fr));
    gap: var(--sp-6) var(--gap);
    padding: var(--sp-4) var(--gutter);
    list-style: none;
  }
  @media (width < 740px) {
    .poster-grid { --grid-cols: 3; }
  }

  /* Artwork box: placeholder color + 1 px inner stroke; the picture fades in over it. */
  .art {
    position: relative;
    /* Its layers (scrims, text) stack inside it, under the lockup's "…" button. */
    isolation: isolate;
    display: block;
    overflow: clip;
    aspect-ratio: var(--aspect, 2 / 3);
    border-radius: var(--r-art);
    background: var(--art-bg, var(--bg-placeholder));

    &::after {
      content: "";
      position: absolute;
      inset: 0;
      border-radius: inherit;
      box-shadow: inset 0 0 0 1px var(--lockup-stroke);
      pointer-events: none;
    }

    & > img {
      position: absolute;
      inset: 0;
      inline-size: 100%;
      block-size: 100%;
      object-fit: cover;
    }
  }

  html.js .art img:not(.is-loaded) { opacity: 0; }
  html.js .art img { transition: opacity var(--dur-base) var(--ease-out); }
  .art.is-failed img { visibility: hidden; }

  /* The title on the placeholder, when the picture is missing or fails. */
  .art-fallback, .art-initials {
    position: absolute;
    inset: 0;
    display: none;
    place-items: center;
    padding: var(--sp-3);
    color: var(--text-2);
    font: 600 14px / 18px var(--font);
    text-align: center;
    overflow-wrap: anywhere;
  }
  .art:not(:has(img)) .art-fallback, .art.is-failed .art-fallback { display: grid; }

  /* A sized logo slot: the space is kept while the logo loads (no layout shift). */
  .logo-box {
    display: block;
    inline-size: var(--logo-w, 240px);
    block-size: var(--logo-h, 64px);
    & img { inline-size: 100%; block-size: 100%; object-fit: contain; object-position: left bottom; }
  }

  /* Lockups: the link is the art (+ caption). Hover shows only the "…" button; press 0.98. */
  .lockup {
    --ratio: 1.5;             /* art height / width, for placing the "…" button */
    position: relative;
    container-type: inline-size;
    min-inline-size: 0;
  }

  .lockup-link {
    display: grid;
    gap: var(--sp-2);
    border-radius: var(--r-art);
    color: inherit;
    text-decoration: none;
    -webkit-tap-highlight-color: transparent;

    &:focus-visible { outline: none; }
    &:focus-visible .art { outline: 3px solid var(--accent); outline-offset: 3px; }
    &:active .art { scale: 0.98; }
  }
  .lockup-link .art { transition: scale var(--dur-press) var(--ease-out); }

  .lockup-poster { --aspect: 2 / 3; --ratio: 1.5; }
  .lockup-wide { --aspect: 20 / 13; --ratio: 0.65; }
  .lockup-featured { --aspect: 16 / 9; --ratio: 0.5625; & .art { border-radius: var(--r-art-l); } }
  .lockup-cast { --aspect: 1; --ratio: 1; & .art { border-radius: 50%; } }
  @container (width < 120px) {
    .lockup-poster .art { border-radius: 10px; }
  }

  .lockup-caption { display: grid; gap: 2px; min-inline-size: 0; }
  .lockup-title, .lockup-subtitle {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .lockup-title { font: 600 14px / 18px var(--font); color: var(--text-1); }
  .lockup-subtitle { font: var(--type-footnote); color: var(--text-2); }
  .lockup-synopsis {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font: var(--type-footnote);
    color: var(--text-2);
  }

  /* Logo on wide art: bottom-left, max 50% × 30%. */
  .art-logo {
    position: absolute;
    inset: auto auto 5% 5%;
    z-index: 1;
    display: flex;
    align-items: flex-end;
    inline-size: 50%;
    block-size: 30%;
    & img { max-inline-size: 100%; max-block-size: 100%; object-fit: contain; object-position: left bottom; }
  }
  .lockup-wide .art:has(.art-logo)::before,
  .lockup-featured .art:has(.art-logo)::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    background: linear-gradient(transparent 50%, rgb(0 0 0 / 0.55));
  }
  .lockup-featured .art-logo { inline-size: 40%; }

  /* Poster caption inside the art ("New Episodes", a Top 10 genre), over the poster gradient. */
  .art-caption {
    position: absolute;
    inset: auto 8px 10px;
    z-index: 1;
    color: var(--text-2);
    font: 400 13px / 16px var(--font);
    text-align: center;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .art:has(.art-caption, .rank)::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    background: linear-gradient(transparent 54%, rgb(0 0 0 / .4) 70%, rgb(0 0 0 / .65) 85%, rgb(0 0 0 / .75));
  }

  /* Top 10: the rank inside the art, top-left. */
  .rank {
    position: absolute;
    inset: 12px auto auto 12px;
    z-index: 2;
    color: #fff;
    font: 700 40px / 1 var(--font);
    font-variant-numeric: tabular-nums;
    text-shadow: 0 1px 12px rgb(0 0 0 / 0.5);
  }

  /* Continue Watching: logo centered, ▶ + progress + "S2, E1 · 40m" inside the art. */
  .lockup-continue {
    & .art-logo {
      inset: 0 20% 16%;
      inline-size: auto;
      block-size: auto;
      margin: auto;
      max-block-size: 35%;
      align-items: center;
      justify-content: center;
      & img { object-position: center; }
    }
    & .art:has(.art-logo)::before { content: none; }
    & .art::before {
      content: "";
      position: absolute;
      inset: auto 0 0;
      z-index: 1;
      block-size: 66px;
      background: linear-gradient(transparent, rgb(0 0 0 / .13) 16px, rgb(0 0 0 / .3) 40px, rgb(0 0 0 / .55));
    }
  }

  .art-overlay {
    position: absolute;
    inset: auto 48px 12px 12px;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--text-2);
    font: 600 12px / 15px var(--font);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    & span { overflow: hidden; text-overflow: ellipsis; }
    & .icon { flex: none; color: var(--text-1); }
    & .progress { --track: 26px; }
  }

  .progress {
    flex: none;
    display: block;
    inline-size: var(--track, 50px);
    block-size: 4px;
    border-radius: 2px;
    background: linear-gradient(var(--progress-fill), var(--progress-fill)) no-repeat 0 0 / var(--progress, 0%) 100%, var(--progress-track);
  }

  /* Cast circle */
  .lockup-cast {
    text-align: center;
    & .art { background: linear-gradient(#6e6e73, #3a3a3c); }
    & .art-initials { display: grid; color: #fff; font-size: 36cqi; font-weight: 600; }
    & .art:has(img:not(.is-loaded)) .art-initials { display: grid; }
    & .art:has(img.is-loaded) .art-initials { display: none; }
    & .lockup-caption { margin-block-start: 2px; }
    & .lockup-title { font: 400 13px / 18px var(--font); }
    & .lockup-subtitle { color: rgb(255 255 255 / 0.5); }
  }

  /* "…" button: 28 px circle at the art's bottom-right; shows on hover/focus, always on touch. */
  .more-button {
    position: absolute;
    inset-block-start: calc(100cqi * var(--ratio) - 36px);
    inset-inline-end: 8px;
    z-index: var(--z-lockup-hover);
    display: grid;
    place-items: center;
    inline-size: 28px;
    block-size: 28px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: var(--mat-thin);
    color: var(--text-1);
    -webkit-backdrop-filter: saturate(180%) blur(30px);
    backdrop-filter: saturate(180%) blur(30px);
    transition: opacity var(--dur-fast) var(--ease-out), background-color var(--dur-fast) linear;

    /* 44 px target around the 28 px circle. */
    &::before { content: ""; position: absolute; inset: -8px; }
    /* The three dots (ellipsis, Framework7, as Icon.more), drawn here rather than an SVG in every lockup. */
    &::after {
      content: "";
      inline-size: var(--icon-md);
      block-size: var(--icon-md);
      background: currentColor;
      mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 56 56'%3E%3Cpath d='M15.32 28C15.32 25.4 13.23 23.31 10.59 23.31C7.98 23.31 5.9 25.4 5.9 28C5.9 30.6 7.98 32.69 10.59 32.69C13.23 32.69 15.32 30.6 15.32 28ZM32.66 28C32.66 25.4 30.6 23.31 28 23.31C25.4 23.31 23.34 25.4 23.34 28C23.34 30.6 25.4 32.69 28 32.69C30.6 32.69 32.66 30.6 32.66 28ZM50.1 28C50.1 25.4 47.99 23.31 45.41 23.31C42.77 23.31 40.68 25.4 40.68 28C40.68 30.6 42.77 32.69 45.41 32.69C47.99 32.69 50.1 30.6 50.1 28Z'/%3E%3C/svg%3E") center / contain no-repeat;
    }
    &:hover, &.is-open { background: var(--accent); color: #fff; }
  }
  @media (hover: hover) {
    .lockup .more-button { opacity: 0; }
    .lockup:hover .more-button, .lockup:focus-within .more-button, .lockup .more-button.is-open { opacity: 1; }
  }
  /* The menu needs JS (shelf.js fills it) and popover support; without them the card's link leads
     to the title page, which has the same actions. */
  html:not(.js) .more-button { display: none; }
  @supports not selector(:popover-open) {
    .more-button { display: none; }
  }
  /* Anchored to the button that opened it (shelf.js names it; also the popover's invoker). */
  #more-menu { position-anchor: --more-menu; }

  /* Empty and error states */
  .empty-state {
    display: grid;
    justify-items: center;
    align-content: center;
    gap: var(--sp-2);
    min-block-size: 50svh;
    max-inline-size: 36ch;
    margin-inline: auto;
    padding: var(--sp-10) var(--gutter);
    text-align: center;

    & > svg { color: var(--text-3); margin-block-end: var(--sp-2); }
    & h1, & h2 { font: var(--type-title-2); color: var(--text-1); }
    & p { color: var(--text-2); }
    & .button { margin-block-start: var(--sp-3); }
  }

  .error-page {
    display: grid;
    grid-template-rows: auto 1fr;
    min-block-size: 100dvh;
    padding: calc(14px + env(safe-area-inset-top)) var(--gutter) 0;
    & .brand { align-self: start; }
    & .empty-state { padding-block-end: var(--sp-24); }
  }

  /* Toast: bottom-center capsule; in, then out after 4 s (paused while hovered/focused). */
  .toast {
    position: fixed;
    inset-inline: 0;
    inset-block-end: calc(32px + var(--tabbar-space));
    z-index: var(--z-tabbar);
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    inline-size: max-content;
    max-inline-size: min(560px, 100vw - 40px);
    min-block-size: 44px;
    margin-inline: auto;
    padding: 12px 20px;
    border-radius: var(--r-pill);
    color: var(--text-1);
    font: var(--type-subhead);
    pointer-events: auto;
    animation: toast-in 550ms var(--ease-spring-soft) both, toast-out var(--dur-fast) linear 4s forwards;

    &:hover, &:focus-within { animation-play-state: paused; }
    & .icon { flex: none; color: var(--success); }
    &[role="alert"] .icon { color: var(--warning); }
  }
  @keyframes toast-in { from { opacity: 0; translate: 0 16px; } }
  @keyframes toast-out { to { opacity: 0; visibility: hidden; } }

  /* Spinner: a white arc; pulses instead under reduced motion. */
  .spinner {
    display: inline-block;
    flex: none;
    inline-size: var(--spinner, 20px);
    block-size: var(--spinner, 20px);
    border: 2px solid rgb(255 255 255 / 0.25);
    border-block-start-color: currentColor;
    border-radius: 50%;
    animation: spin 1s linear infinite;
  }
  @keyframes spin { to { rotate: 1turn; } }
  @keyframes pulse { 50% { opacity: 0.4; } }

  /* A row that says more is loading (infinite scroll), and one that says it's all there. */
  .loading-row, .end-row {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: var(--sp-3);
    padding: var(--sp-8) var(--gutter);
    color: var(--text-2);
    font: var(--type-footnote);
  }

  /* Error over artwork or video: centered on a scrim. */
  .error-overlay {
    position: absolute;
    inset: 0;
    z-index: var(--z-hero-content);
    display: grid;
    place-content: center;
    justify-items: center;
    gap: var(--sp-3);
    padding: var(--sp-6);
    background: rgb(0 0 0 / 0.8);
    text-align: center;
    & > svg { color: var(--text-3); }
    & h2 { font: var(--type-title-2); }
    & p { max-inline-size: 44ch; color: var(--text-2); }
  }

  /* Form fields */
  .field {
    display: grid;
    gap: 6px;
    min-inline-size: 0;

    & input {
      inline-size: 100%;
      min-block-size: 44px;
      padding: 0 14px;
      border: 1px solid var(--fill-2);
      border-radius: 10px;
      background: rgb(0 0 0 / 0.3);
      color: var(--text-1);
    }
    & input[aria-invalid="true"] { border-color: var(--destructive); }
  }
  .field-label { font: 600 14px / 18px var(--font); color: var(--text-1); }

  .form-error, .form-notice {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-basis: 100%;
    font: 600 13px / 18px var(--font);
  }
  .form-error { color: var(--destructive); }
  .form-notice { color: var(--text-2); }

  /* One-button forms sit in their row like any other button. */
  .inline-form { display: contents; }

  /* Artwork with nothing to show (Artwork component): the title on a plain tile. */
  .art-missing {
    display: grid;
    place-items: center;
    padding: 12px;
    background: var(--bg-placeholder);
    color: var(--text-2);
    text-align: center;
    font-weight: 600;
  }
}

@layer utilities {
  .visually-hidden {
    position: absolute !important;
    inline-size: 1px;
    block-size: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .skip-link {
    position: absolute;
    inset-inline-start: 8px;
    inset-block-start: -100px;
    z-index: var(--z-skip-link);
    padding: 10px 16px;
    border-radius: var(--r-s);
    background: var(--primary-fill);
    color: var(--on-primary);
    font-weight: 600;
    &:focus-visible { inset-block-start: 8px; }
  }

  /* Icons: Framework7 glyphs in currentColor (Components.swift), one size per context. Inline in
     text they sit on the text's center; in flex rows `align-items: center` does it. */
  .icon { flex: none; vertical-align: -0.125em; }
  .icon-xs { inline-size: var(--icon-xs); block-size: var(--icon-xs); }
  .icon-sm { inline-size: var(--icon-sm); block-size: var(--icon-sm); }
  .icon-md { inline-size: var(--icon-md); block-size: var(--icon-md); }
  .icon-lg { inline-size: var(--icon-lg); block-size: var(--icon-lg); }
  .icon-xl { inline-size: var(--icon-xl); block-size: var(--icon-xl); }
  .icon-xxl { inline-size: var(--icon-xxl); block-size: var(--icon-xxl); }

  /* One place for reduced motion: no transforms or springs; fades stay. */
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { scroll-behavior: auto !important; }
    .button:active, .icon-button:active, .lockup-link:active .art { scale: none; }
    .toast { animation: toast-out var(--dur-fast) linear 4s forwards; }
    .spinner { animation: pulse 1.2s ease-in-out infinite; border-color: currentColor; }
  }

  /* Windows High Contrast and friends: keep states visible without color. */
  @media (forced-colors: active) {
    :focus-visible, .lockup-link:focus-visible .art { outline-color: Highlight; }
    .top-tabs a[aria-current="page"], .tab-bar a[aria-current="page"], .pill[aria-current], .pill[aria-pressed="true"],
    .menu-item[aria-current="page"] { outline: 2px solid CanvasText; outline-offset: -2px; }
    .top-tabs a[aria-current="page"] { text-decoration: underline; }
    .progress { background: Highlight; forced-color-adjust: none; border: 1px solid CanvasText; }
    .badge, .pill, .button, .icon-button, .more-button, .avatar, .shelf-arrow, .tab-bar, .menu, .toast { border: 1px solid CanvasText; }
    .art::after { box-shadow: none; border: 1px solid CanvasText; }
    .more-button::after { forced-color-adjust: none; background: ButtonText; }
    /* Browsers don't force an SVG's `color`, so an icon would keep its (often white) color on the
       forced Canvas; take the forced color of the text around it instead. */
    .icon { color: inherit !important; }
    .menu-item[aria-current="page"]::after { forced-color-adjust: none; background: CanvasText; }
  }
}
