/* ===========================================================
 * FlickSpin v0.5.22 — defensive cinema-stage clip + crossfade cleanup
 * Mobile bug: after a winning spin the window appeared to stretch.
 * Cause: "ghost" cinemas from previous crossfades whose removal
 * timeout was interrupted could accumulate. Fix:
 *  (1) Clear any .is-fading-out cinemas at start of swap
 *  (2) Use explicit width:100% (not left+right:0) on ghost old
 *  (3) overflow: clip on cinema-stage hard-contains any leak
 * ============================================================ */

/* ─────────── Design tokens ─────────── */
:root {
    /* Paper / surface palette */
    --bg: #f3e8c8;          /* cream — matches paper-warm so cream extends to end of page */
    --surface: #ffffff;      /* clean white cards */
    --surface-2: #fffdf6;    /* slightly warmer white */
    --surface-tint: #f3eee2; /* subtle separator tint */

    /* Soft pastels (for ambient accents, card variants) */
    --lavender: #e7e1f8;
    --sage:     #d9e3c4;
    --butter:   #f7e9a8;
    --peach:    #fad7b9;
    --rose:     #fbd1d8;
    --sky:      #d6e4fa;

    /* Deep navy-blue UI accent — used for italic emphasis, genre underline,
       pool dot, save button, links. Deeper than the old electric blue so it
       harmonises with the warm gold + cream palette instead of fighting it. */
    --blue: #1f2c75;
    --blue-deep: #142060;
    --blue-soft: #b4c0e8;
    --blue-pale: #e6ebf6;

    /* Gold accent — used for CTA, brand "Spin" wordmark, watchlist badge.
       Pairs with the dark-navy header for a premium cinema feel. */
    --gold:        #c9a544;
    --gold-light:  #e6c97a;
    --gold-deep:   #8f7325;
    --gold-soft:   #efdfa9;
    --gold-pale:   #faf1d2;
    --shadow-gold: rgba(201, 165, 68, 0.32);
    --shadow-gold-lg: rgba(201, 165, 68, 0.42);

    /* Dark navy — header band (the dramatic top strip in the mockup) */
    --navy:        #0d1538;
    --navy-deep:   #060a22;
    --navy-text:   #ece3c8;   /* cream text/icons sitting on navy */

    /* Accent yellow — aliased to gold-light so the rating-star matches
       the rest of the gold palette. */
    --accent-yellow: #e6c97a;

    /* Text */
    --text: #161930;
    --text-secondary: #5a5d75;
    --text-tertiary: #9a9caa;

    /* Borders / dividers — VERY subtle, almost invisible */
    --hairline: rgba(22, 25, 48, 0.08);
    --hairline-strong: rgba(22, 25, 48, 0.14);

    /* Shadows — soft, modern, never harsh */
    --shadow-xs: 0 1px 2px rgba(22, 25, 48, 0.05);
    --shadow-sm: 0 2px 6px rgba(22, 25, 48, 0.06);
    --shadow-md: 0 6px 20px rgba(22, 25, 48, 0.07);
    --shadow-lg: 0 12px 36px rgba(22, 25, 48, 0.09);
    --shadow-blue: 0 6px 18px rgba(31, 44, 117, 0.28);
    --shadow-blue-lg: 0 10px 30px rgba(31, 44, 117, 0.35);

    /* Radii */
    --r-sm: 10px;
    --r-md: 16px;
    --r-lg: 24px;
    --r-xl: 32px;
    --r-pill: 999px;

    /* Spacing */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --space-7: 48px;
    --space-8: 64px;

    /* Easing */
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --ease-snap: cubic-bezier(0.34, 1.56, 0.64, 1);
    --ease-decel: cubic-bezier(0.08, 0.82, 0.2, 1);

    /* Safe areas */
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);

    /* Unified cinema height — all states (idle / reel / pick / empty)
       share this min-height so the page layout doesn't jump between them. */
    --cinema-min-h: 480px;
}

/* ─────────── Reset + base ─────────── */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

/* Make `hidden` attribute beat any flex/grid display rule we set elsewhere.
   Without this, .icon-btn-badge[hidden] still shows because the
   `display: inline-flex` set on .icon-btn-badge takes precedence over the
   user-agent `[hidden] { display: none }` default. */
[hidden] { display: none !important; }

html, body {
    height: 100%;
    overscroll-behavior: none;
    /* Prevent any horizontal scroll caused by the 100vw cinema-stage
       breakout — clip is the modern non-scroll-disabling overflow. */
    overflow-x: clip;
}

/* Body bg = cream paper-warm + subtle baked-in grain so the boundary
   where paper-sheet's alpha fades to body-bg is invisible. The grain
   matches the grain inside paper-sheet.png itself. */
body {
    background-color: var(--bg);
    background-image:
        repeating-linear-gradient(92deg, rgba(160, 130, 75, 0.025) 0 2px, transparent 2px 4px),
        repeating-linear-gradient(0deg,  rgba(160, 130, 75, 0.018) 0 1px, transparent 1px 3px);
}

body {
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
    color: var(--text);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    font-size: 15px;
    line-height: 1.5;
    min-height: 100dvh;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    position: relative;
}

/* body::before is unused now — the foxing + grain texture is baked
   directly into paper-sheet.png so there's no separate texture layer
   to mismatch with the torn fringe (which previously caused a visible
   "no-texture" band just above the rip). */

/* ── Torn paper sheet ──
   Real <img class="paper-sheet"> living in the DOM (NOT a CSS pseudo-element
   mask) so it always renders regardless of browser mask support or cache.
   paper-sheet.png is already tinted to --paper-warm; alpha IS the torn shape.
   JS sets `--paper-bottom` to match the actual document-Y of .genre-paper
   bottom, and this image is sized so its rip lands right there. */
.paper-sheet {
    position: absolute;
    left: 0;
    width: 100%;
    /* COVER preserves the natural 3.26:1 aspect of the source image so the
       torn fibers keep their designed shape (fill stretches them into
       vertical glitch lines on tall/narrow mobile containers).
       Per-variant `object-position` below anchors the image to whichever
       edge holds the torn fringe, so the rip lands at the expected Y even
       when the container's aspect ratio doesn't match the image's. */
    object-fit: cover;
    z-index: 1;
    pointer-events: none;
    user-select: none;
    -webkit-user-drag: none;
    /* Drop-shadow follows the alpha silhouette → fibers cast a visible dark
       line on the body bg below them. */
    filter:
        drop-shadow(0 4px 4px rgba(60, 45, 20, 0.42))
        drop-shadow(0 10px 16px rgba(60, 45, 20, 0.22))
        drop-shadow(0 22px 36px rgba(60, 45, 20, 0.10));
}

/* TOP paper — dynamically-sized container, positioned so the fringe always
   lands ~30 px past --paper-bottom (genre filter's lower edge), overlapping
   cinema's top edge.

   The container height uses `max(700px, 33vw)` so it always exceeds the
   image's natural rendered height at the current viewport width (image aspect
   = 3.26 → natural rendered height = vw / 3.26 ≈ 30.7vw). 33vw gives a safety
   margin, keeping `object-fit: cover` scaling HEIGHT-DRIVEN on any width
   (including 4K / 5K monitors). Height-driven scaling = no vertical overflow,
   no aspect-dependent cropping, so the torn fringe pattern keeps its exact
   shape across every viewport.

   The `top:` calc derives from the same height formula so the fringe Y stays
   constant: top = paper_bottom + 30 - 0.885 × height. Algebra cancels height
   in the absolute fringe Y, leaving it always at paper_bottom + 30.

   Earlier iterations:
   – original calc(paper-bottom × 1.13 + 50): height varied with paper-bottom
     instead of vw → width-driven scaling on wide screens, fringe drifted up
   – fixed height 700: stable up to ~2280 px wide, then width-driven kicks in
     on 4K and the fringe drifted ~55 px above its design Y. */
.paper-sheet--top {
    height: max(700px, 33vw);
    top: calc(var(--paper-bottom, 720px) + 30px - 0.885 * max(700px, 33vw));
    /* Safety net for any edge case where width-driven scaling still occurs:
       anchor image bottom to container bottom so fringe stays predictable. */
    object-position: bottom center;
}

/* BOTTOM paper — rotated 180° so it's mirrored on BOTH axes.
   Vertical flip puts the torn fringe at the top; horizontal flip
   inverts the asymmetric tear pattern so it looks like a different
   rip than the top paper. */
.paper-sheet--bottom {
    /* The torn fringe lives at ~11.5% from the TOP of the rendered box
       after rotate(180deg). With height: 900 px that's 103 px below the
       box top — so to land the fringe ~47 px ABOVE --cinema-bottom
       (visible overlap into the cinema), the box top has to start at
       --cinema-bottom − 150 px:    -150 + 103 = -47   ✓ */
    /* Container height uses `max(900px, 33vw)` — same strategy as the top
       paper. On 4K / 5K monitors the fixed 900 px floor would let cover
       scaling switch to width-driven (since vw / 3.26 > 900 once vw > 2934)
       and the rotated fringe would drift away from cinema-bottom. The 33vw
       lower bound (> image aspect's 30.7vw) keeps scaling height-driven on
       every width. The `top:` calc derives from the same height to keep the
       fringe Y constant at cinema-bottom − 47 px on all viewports. */
    height: max(900px, 33vw);
    /* Fringe (after rotation) sits at 11.5 % of container height from rotated
       top = 0.115 × height from container top. To land it at cinema-bottom
       − 47 (visible overlap into cinema), top = (cinema-bottom − 47) − fringe
       offset = cinema-bottom − 47 − 0.115 × height. */
    top: calc(var(--cinema-bottom, 1100px) - 47px - 0.115 * max(900px, 33vw));
    transform: rotate(180deg);
    /* Default `object-position: center center` is correct here: container is
       900 px tall, image scales height-driven on every viewport (no vertical
       overflow / crop), so the fringe always lands at the same 11.5 % from
       the rotated top — i.e. 103 px below cinema-bottom, design-intended. */
    object-position: center center;
    /* drop-shadow gets rotated 180° with the image → shadow points UPWARD
       onto the cinema. Boosted alpha + darker color compared to the top
       paper because this shadow casts onto the cinema's varied backdrop
       (blurred film poster) instead of uniform cream, so it needs more
       contrast to read at the same visual strength. */
    filter:
        drop-shadow(0 5px 5px rgba(30, 20, 5, 0.62))
        drop-shadow(0 14px 22px rgba(30, 20, 5, 0.34))
        drop-shadow(0 28px 46px rgba(30, 20, 5, 0.18));
}

/* Hero + genre filter + CTA + recent + footer sit ABOVE the paper layer so
   their text and interactive bits stay crisp even though the paper sheets
   extend over the cinema and into the CTA area. Footer was previously
   omitted, which caused paper-sheet--bottom (height 900px) to cover the
   entire footer block. */
.app-main > .hero,
.app-main > .genre-paper,
.app-main > .cta-wrap,
.app-main > .recent-section,
.app-main > .app-footer {
    position: relative;
    z-index: 5;
}

/* NOTE: previously had `body > *:not(.paper-sheet) { position: relative }`
   here, but its specificity (0,1,1) was overriding the explicit
   `.modal { position: fixed }` and `.sheet { position: fixed }` rules
   (0,1,0), making modals/sheets anchor to their natural document
   position instead of the viewport. The z-index hierarchy now lives
   on the individual elements (hero/genre/cta/recent z-index 5,
   paper-sheet 1, cinema-stage 0) without needing position:relative
   here, so this rule was deleted. */

button {
    font: inherit;
    color: inherit;
    background: none;
    border: none;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}

a { color: inherit; text-decoration: none; }

img { display: block; max-width: 100%; height: auto; }

.safe-top { height: var(--safe-top); }
.safe-bottom { height: var(--safe-bottom); }

/* ─────────── Header ─────────── */
.app-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-4) var(--space-5);
    gap: var(--space-3);
    position: sticky;
    top: var(--safe-top);
    /* Dramatic dark-navy strip at the top of the page — sits ABOVE the
       torn paper sheet, giving the brand a premium cinema-marquee feel. */
    background: linear-gradient(180deg, var(--navy) 0%, var(--navy-deep) 100%);
    color: var(--navy-text);
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
    box-shadow: 0 2px 12px rgba(6, 10, 34, 0.18);
    z-index: 50;
}

.icon-btn {
    position: relative;
    width: 40px;
    height: 40px;
    border-radius: var(--r-md);
    background: transparent;
    /* Cream icons against the dark navy — high contrast yet warm */
    color: var(--navy-text);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.18s var(--ease-out), color 0.18s;
}

.icon-btn:hover {
    background: rgba(255, 255, 255, 0.08);
    color: #fff;
}

.icon-btn:active {
    background: rgba(255, 255, 255, 0.12);
    transform: scale(0.96);
}

.icon-btn svg { width: 22px; height: 22px; }

.icon-btn-badge {
    position: absolute;
    top: 2px;
    right: 0;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: var(--r-pill);
    /* Gold badge with deep-navy numerals for contrast against the dark header */
    background: linear-gradient(135deg, var(--gold-light) 0%, var(--gold) 100%);
    color: var(--navy-deep);
    font-size: 10px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 2px solid var(--navy);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    line-height: 1;
}

/* Brand */
.app-brand {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: 'Fraunces', 'Inter', sans-serif;
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -0.02em;
    /* Cream "Flick" against the dark navy header */
    color: var(--navy-text);
}

/* "Spin" half of the wordmark — static gold gradient that pops against the
   dark navy header band. Background-clip: text paints the gradient onto the
   glyphs themselves. Earlier iterations tried an animated shimmer; even a
   periodic repeating-gradient produced a visible seam where the highlight
   wrapped, so the static version reads cleanest. */
.app-brand-text-spin {
    background: linear-gradient(135deg, var(--gold-light) 0%, var(--gold) 55%, var(--gold-deep) 100%);
    -webkit-background-clip: text;
            background-clip: text;
    -webkit-text-fill-color: transparent;
            color: transparent;
    /* Slightly heavier weight so the gradient reads punchier against Flick */
    font-weight: 700;
}

/* Brand mark — a 28×28 stage holding the static dashed ring AND the play
   arrow. Sized larger than the arrow itself (14 px) so the ring has visible
   breathing room around the triangle. */
.app-brand-mark {
    position: relative;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    will-change: transform, filter;
}

/* Static dashed ring under the arrow — decorative cinema-reel feel.
   No ambient rotation; movement only happens on hover (driven by the
   arrow's spin animation below). */
.app-brand-ring {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    border: 1px dashed var(--gold);
    opacity: 0.55;
}

.app-brand-arrow {
    position: relative;
    width: 14px;
    height: 14px;
    transform-origin: 50% 50%;
    filter: drop-shadow(0 1px 0 rgba(89, 65, 14, 0.45));
    z-index: 1;
}

/* Hover / focus / tap → 3-rotation playful flourish on the arrow, with
   motion blur peaking mid-spin. JS adds `is-spinning` on the events and
   removes it on animationend. */
.app-brand-mark.is-spinning .app-brand-arrow {
    animation: brand-arrow-spin 1100ms cubic-bezier(0.45, 0.05, 0.55, 0.95);
}

@keyframes brand-arrow-spin {
    0%   { transform: rotate(0deg);    filter: blur(0); }
    15%  { filter: blur(0.5px); }
    35%  { filter: blur(1.6px); }
    50%  { transform: rotate(540deg);  filter: blur(2.4px); }
    65%  { filter: blur(1.6px); }
    85%  { filter: blur(0.5px); }
    100% { transform: rotate(1080deg); filter: blur(0); }
}

/* Respect users who prefer reduced motion — kill the hover-triggered spin.
   The ring and "Spin" wordmark are already static. */
@media (prefers-reduced-motion: reduce) {
    .app-brand-mark.is-spinning .app-brand-arrow {
        animation: none !important;
    }
}

/* ─────────── Main content ─────────── */
.app-main {
    flex: 1 1 auto;
    width: 100%;
    max-width: 720px;
    margin: 0 auto;
    padding: var(--space-6) var(--space-5);
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
}

/* ─────────── Hero ─────────── */
.hero {
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-3);
}

.hero-title {
    font-family: 'Fraunces', serif;
    font-size: clamp(40px, 9vw, 60px);
    font-weight: 500;
    letter-spacing: -0.025em;
    line-height: 1.02;
    color: var(--text);
}

.hero-title-italic {
    font-style: italic;
    font-weight: 500;
    color: var(--blue);
    /* slight font variation: optical size, more elegant italic */
    font-variation-settings: "opsz" 80;
}

.hero-sub {
    font-size: 14.5px;
    color: var(--text-secondary);
    max-width: 480px;
    line-height: 1.6;
}

.pool-badge {
    margin-top: var(--space-2);
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 7px 16px;
    border-radius: var(--r-pill);
    background: rgba(255, 255, 255, 0.6);
    border: 1px solid rgba(31, 44, 117, 0.12);
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-secondary);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

.pool-badge-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--blue);
    box-shadow: 0 0 0 4px rgba(31, 44, 117, 0.12);
    animation: dot-pulse 2.4s ease-in-out infinite;
}

@keyframes dot-pulse {
    0%, 100% { box-shadow: 0 0 0 4px rgba(31, 44, 117, 0.12); }
    50%      { box-shadow: 0 0 0 7px rgba(31, 44, 117, 0.06); }
}

.pool-badge-num {
    font-family: 'JetBrains Mono', monospace;
    color: var(--blue);
    font-weight: 700;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.01em;
}

.pool-badge-label {
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 10.5px;
    opacity: 0.78;
}

/* ─────────── Genre filter ─────────── */
/* ─────────── Genre filter — torn paper + ink ─────────── */

/* Ink color for handwritten genres — deep navy/indigo, slightly warmer than brand blue */
:root {
    --ink-blue: #1f2c75;
    --paper-warm: #f3e8c8;
    --paper-shadow: rgba(120, 95, 50, 0.18);
}

/* Genre paper is now a layout wrapper only — the actual paper texture and
   torn edge come from body::before which covers everything from top to here. */
.genre-paper {
    position: relative;
    padding: 8px 0 40px;
}

.genre-ink-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 8px 28px;
}

.genre-ink-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 6px 28px;
}

.genre-ink {
    position: relative;
    background: none;
    border: none;
    padding: 4px 4px 8px;
    color: var(--ink-blue);
    /* Special Elite — inky typewriter — only ships at weight 400, so the
       "bold" active state is achieved via text-shadow stamp doubling. */
    font-family: 'Special Elite', 'Courier New', monospace;
    font-size: 17px;
    font-weight: 400;
    letter-spacing: 0.01em;
    line-height: 1.1;
    cursor: pointer;
    transition: color 0.22s var(--ease-out), transform 0.18s var(--ease-snap);
    display: inline-flex;
    align-items: center;
    gap: 6px;
    /* Slight per-button rotation — small offsets only; a typewriter is more
       orderly than handwriting. */
}

.genre-ink:nth-child(1) { transform: rotate(-0.5deg) translateY(0.5px); }
.genre-ink:nth-child(2) { transform: rotate(0.4deg) translateY(-0.5px); }
.genre-ink:nth-child(3) { transform: rotate(-0.2deg); }
.genre-ink:nth-child(4) { transform: rotate(0.5deg) translateY(0.5px); }
.genre-ink:nth-child(5) { transform: rotate(-0.3deg) translateY(-0.5px); }

.genre-ink-text {
    position: relative;
    /* "Wet ink" stamp — subtle bleed in two directions, simulating typewriter
       ribbon ink soaking slightly into paper fibers. */
    text-shadow:
        0 0.5px 0 rgba(31, 44, 117, 0.18),
        0.3px 0 0 rgba(31, 44, 117, 0.10);
}

/* Hand-drawn underline that draws on hover (and stays for active) */
.genre-ink-text::after {
    content: "";
    position: absolute;
    left: -3%;
    right: -3%;
    bottom: -3px;
    height: 2px;
    background: currentColor;
    border-radius: 1px;
    transform-origin: left center;
    transform: scaleX(0) rotate(-0.4deg);
    transition: transform 0.32s cubic-bezier(0.65, 0, 0.35, 1);
    opacity: 0.55;
}

.genre-ink:hover .genre-ink-text::after {
    transform: scaleX(1) rotate(-0.4deg);
}

/* Active state — same size (Special Elite has only weight 400), but heavier
   ink stamp + permanent underline + check */
.genre-ink.is-active {
    color: var(--blue);
}

.genre-ink.is-active .genre-ink-text {
    /* Double-stamp the ink to simulate a hard typewriter strike */
    text-shadow:
        0 0 0.6px currentColor,
        0.6px 0 0 currentColor,
        0 0.6px 0 rgba(31, 44, 117, 0.32),
        0.4px 0 0 rgba(31, 44, 117, 0.24);
}

.genre-ink.is-active .genre-ink-text::after {
    transform: scaleX(1) rotate(-0.4deg);
    opacity: 0.85;
    height: 2.5px;
}

/* The animated check that draws on activation */
.genre-ink-check {
    width: 0;
    height: 22px;
    color: var(--blue);
    opacity: 0;
    transform: scale(0.6) rotate(-3deg);
    transition:
        opacity 0.2s var(--ease-out),
        transform 0.32s var(--ease-spring),
        width 0.28s var(--ease-out);
    flex-shrink: 0;
}

.genre-ink-check polyline {
    stroke-dasharray: 30;
    stroke-dashoffset: 30;
    transition: stroke-dashoffset 0.45s 0.1s cubic-bezier(0.65, 0, 0.35, 1);
}

.genre-ink.is-active .genre-ink-check {
    width: 22px;
    opacity: 1;
    transform: scale(1) rotate(-3deg);
}

.genre-ink.is-active .genre-ink-check polyline {
    stroke-dashoffset: 0;
}

/* Press feedback */
.genre-ink:active {
    transition-duration: 0.05s;
}
.genre-ink:nth-child(1):active { transform: rotate(-0.5deg) translateY(0.5px) scale(0.96); }
.genre-ink:nth-child(2):active { transform: rotate(0.4deg) translateY(-0.5px) scale(0.96); }
.genre-ink:nth-child(3):active { transform: rotate(-0.2deg) scale(0.96); }
.genre-ink:nth-child(4):active { transform: rotate(0.5deg) translateY(0.5px) scale(0.96); }
.genre-ink:nth-child(5):active { transform: rotate(-0.3deg) translateY(-0.5px) scale(0.96); }

@media (prefers-reduced-motion: reduce) {
    .genre-ink,
    .genre-ink-text::after,
    .genre-ink-check,
    .genre-ink-check polyline {
        transition: none !important;
    }
}

/* ─────────── Cinema stage ─────────── */
.cinema-stage {
    position: relative;
    /* z-index 0 + paper-sheets z-index 1 = both papers paint OVER cinema's
       top AND bottom edges. Negative margin slides cinema-stage up so
       its top edge tucks under the top paper fringe. */
    z-index: 0;
    margin-top: -24px;
    /* Break out of .app-main's max-width — cinema becomes a full-viewport
       cinemascope band cutting across the page. */
    width: 100vw;
    margin-left: calc(50% - 50vw);
    margin-right: calc(50% - 50vw);
    /* Hard-contain any internal overflow (e.g. the absolute-positioned
       "ghost" cinema during a crossfade) so the page never gets a
       horizontal scroll or visible "stretch". */
    overflow: clip;
}

.cinema {
    position: relative;
    width: 100%;
    /* Locked min-height across all states (idle/reel/pick/empty) so the
       CTA and recent section below don't jump when crossfading states. */
    min-height: var(--cinema-min-h);
    /* Horizontal cinemascope vignette — bright cream center, darker at
       left + right ends. Paper covers top + bottom so no need for radial
       darkening there. */
    background:
        radial-gradient(ellipse 65% 100% at 50% 50%,
            #fffbf0 0%,
            #f8f0d8 55%,
            #d4c290 100%);
    /* No border, no radius — cinema is a full-width band, paper handles
       top + bottom edges. */
    border: none;
    border-radius: 0;
    overflow: hidden;
    /* Subtle inner edge fade to deepen the side vignette */
    box-shadow:
        inset 60px 0 80px -40px rgba(80, 60, 20, 0.20),
        inset -60px 0 80px -40px rgba(80, 60, 20, 0.20);
    contain: layout style paint;
    transform: translateZ(0);
    isolation: isolate;
    /* Smooth crossfade on state swaps (reel → pick → marquee). */
    transition: opacity 320ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* Inner cinema states with READABLE text content stay bounded so titles
   don't stretch across 1400+ px of viewport. The reel/spin window is
   deliberately EXCLUDED — posters scrolling across the whole viewport
   is the point of that state. */
.cinema > .marquee,
.cinema > .pick,
.cinema > .empty-state {
    max-width: 880px;
    margin-left: auto;
    margin-right: auto;
}

/* ── Pick state: full-viewport blurred poster backdrop ──
   Pick state replaces the cinemascope vignette with the chosen film's
   own poster, heavily blurred. The URL is injected as --pick-poster-bg
   from JS onto .cinema.cinema--pick. The backdrop ::before and overlay
   ::after span the entire 100vw cinema band — the pick content (.pick,
   max-width 880px) sits centered on top. */
.cinema.cinema--pick {
    background: transparent;   /* override cinema's cinemascope gradient */
    box-shadow: none;          /* override cinema's side vignette shadow */
}

.cinema.cinema--pick::before {
    content: "";
    position: absolute;
    inset: -50px;              /* oversize so the blur doesn't leak hard edges */
    background-image: var(--pick-poster-bg, none);
    background-size: cover;
    background-position: center;
    filter: blur(32px) saturate(1.4) brightness(0.95);
    opacity: 0.70;
    transform: scale(1.10);
    z-index: -2;
    pointer-events: none;
}

.cinema.cinema--pick::after {
    content: "";
    position: absolute;
    inset: 0;
    background:
        /* Spotlight focused on the center where the .pick content lives */
        radial-gradient(ellipse 45% 65% at 50% 50%,
            rgba(253, 248, 230, 0.72) 0%,
            rgba(253, 248, 230, 0.30) 60%,
            rgba(253, 248, 230, 0.0) 100%),
        /* Soft vertical edge fade — readable top/bottom */
        linear-gradient(180deg,
            rgba(253, 248, 230, 0.35) 0%,
            rgba(253, 248, 230, 0.05) 28%,
            rgba(253, 248, 230, 0.05) 72%,
            rgba(253, 248, 230, 0.40) 100%);
    z-index: -1;
    pointer-events: none;
}

.cinema.is-fading-out {
    opacity: 0;
    transition-duration: 240ms;
    transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}

.cinema.is-fading-in {
    opacity: 0;  /* initial — JS removes class on next frame to trigger transition */
}

/* ─────────── Idle marquee state ─────────── */

/* Animated poster collage that lives BEHIND the marquee text.
   Two parallaxing rows of TMDb thumbnails drift right→left at slightly
   different speeds. Heavy blur + desaturation + radial fade-mask keep
   them ambient so the headline reads cleanly on top. */
.cinema-collage {
    position: absolute;
    inset: 0;
    overflow: hidden;
    z-index: 0;
    pointer-events: none;
    display: flex;
    flex-direction: column;
    /* Render the posters as ambient texture, not focal content */
    filter: blur(1.5px) saturate(0.62) brightness(1.06);
    opacity: 0.62;
    /* Soft vignette fade at edges so posters don't hit the card border hard.
       Wider ellipse + later fade start so MORE of the card is filled with
       posters (less perceived empty space at the corners). */
    -webkit-mask-image: radial-gradient(ellipse 115% 105% at center, #000 60%, transparent 100%);
            mask-image: radial-gradient(ellipse 115% 105% at center, #000 60%, transparent 100%);
}

.cinema-collage-row {
    display: flex;
    flex: 1 1 50%;
    overflow: hidden;
    align-items: stretch;
}

.cinema-collage-track {
    display: flex;
    flex-shrink: 0;
    /* Tighter horizontal gap — posters almost touch for a wall-of-films look */
    gap: 4px;
    padding: 0;
    height: 100%;
    align-items: stretch;
    will-change: transform;
    /* translate3d hint for GPU layer */
    transform: translate3d(0, 0, 0);
    animation: collage-drift 88s linear infinite;
}

.cinema-collage-row--top .cinema-collage-track {
    animation-duration: 96s;
}

.cinema-collage-row--bot .cinema-collage-track {
    animation-duration: 68s;
    /* Negative delay desyncs the second row so columns never line up */
    animation-delay: -23s;
}

.cinema-collage-poster {
    /* Posters fill the FULL row height — rows touch each other vertically,
       removing the white band that used to sit between top and bottom rows. */
    height: 100%;
    width: auto;
    aspect-ratio: 2 / 3;
    object-fit: cover;
    border-radius: 3px;
    flex-shrink: 0;
    background: rgba(22, 25, 48, 0.05);
    /* Tiny shadow so adjacent posters separate visually under the blur */
    box-shadow: 0 2px 4px rgba(22, 25, 48, 0.06);
}

@keyframes collage-drift {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(-50%, 0, 0); }
}

/* Light overlay above the collage so the headline + sub-text read clearly.
   Narrower spotlight (60% × 42%) keeps a clear bright band where the text
   sits without washing out the posters above and below. Vertical edge fades
   blend the collage into the card boundary. */
.cinema-collage-overlay {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background:
        radial-gradient(ellipse 62% 45% at 50% 50%,
            rgba(255, 255, 255, 0.78) 0%,
            rgba(255, 255, 255, 0.45) 55%,
            rgba(255, 255, 255, 0.0) 100%
        ),
        linear-gradient(180deg,
            rgba(255, 255, 255, 0.22) 0%,
            rgba(255, 255, 255, 0.0) 30%,
            rgba(255, 255, 255, 0.0) 70%,
            rgba(255, 255, 255, 0.26) 100%
        );
}

.marquee {
    position: relative;
    z-index: 2;
    padding: 56px 32px 48px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 18px;
    text-align: center;
    /* Match the cinema's locked min-height so content centers in the same
       box across all states (idle/reel/pick share the same vertical area). */
    min-height: var(--cinema-min-h);
    /* Soft pastel ambient — kept very subtle since the collage adds richness */
    background:
        radial-gradient(circle at 50% 0%, rgba(31, 44, 117, 0.05) 0%, transparent 60%),
        radial-gradient(circle at 30% 100%, rgba(230, 201, 122, 0.06) 0%, transparent 50%);
}

@media (prefers-reduced-motion: reduce) {
    .cinema-collage-track {
        animation: none !important;
    }
}

.marquee-eyebrow {
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--text-tertiary);
    /* Faint glow so it stays readable over the denser poster wall */
    text-shadow: 0 0 8px rgba(255, 255, 255, 0.9);
}

.marquee-headline {
    font-family: 'Fraunces', serif;
    font-size: clamp(36px, 8vw, 52px);
    font-weight: 500;
    letter-spacing: -0.03em;
    line-height: 1.02;
    color: var(--text);
    /* Soft white halo behind the serif type — anchors it against the posters */
    text-shadow:
        0 0 14px rgba(255, 255, 255, 0.85),
        0 0 28px rgba(255, 255, 255, 0.55);
}

.marquee-headline-blue {
    color: var(--blue);
    font-style: italic;
    font-variation-settings: "opsz" 80;
}

.marquee-sub {
    font-size: 14px;
    color: var(--text-secondary);
    max-width: 280px;
    line-height: 1.55;
    text-shadow: 0 0 10px rgba(255, 255, 255, 0.9);
}

.marquee-dots {
    display: inline-flex;
    gap: 6px;
    align-items: center;
    margin-top: 4px;
}

.marquee-dots span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--blue);
    opacity: 0.3;
    animation: dot-wave 1.4s ease-in-out infinite;
}
.marquee-dots span:nth-child(2) { animation-delay: 0.15s; }
.marquee-dots span:nth-child(3) { animation-delay: 0.3s; }

@keyframes dot-wave {
    0%, 100% { transform: translateY(0); opacity: 0.3; }
    50%      { transform: translateY(-4px); opacity: 0.9; }
}

/* ─────────── Reel state ─────────── */
.cinema-window {
    position: relative;
    /* Matches the unified cinema height so the reel state takes up the same
       vertical area as idle/pick. The strip inside stays centered. */
    height: var(--cinema-min-h);
    overflow: hidden;
    /* ── 35mm film-cell aesthetic on dark navy ──
       Four background layers turn the empty space around the poster strip
       into a proper vintage film cell — but now in dark navy, like the
       lights dimming in a real cinema before the show. */
    background:
        /* Top perforation row — cream/gold dashes 14×8 px (light on dark) */
        repeating-linear-gradient(90deg,
            rgba(247, 236, 200, 0.55) 0 14px,
            transparent 14px 30px
        ) center 22px / 100% 8px no-repeat,
        /* Bottom perforation row */
        repeating-linear-gradient(90deg,
            rgba(247, 236, 200, 0.55) 0 14px,
            transparent 14px 30px
        ) center calc(100% - 30px) / 100% 8px no-repeat,
        /* Warm spotlight behind the moving strip — projector beam feel */
        radial-gradient(ellipse 80% 45% at 50% 50%,
            rgba(247, 220, 140, 0.18) 0%,
            rgba(247, 220, 140, 0.08) 55%,
            transparent 100%),
        /* Dark navy vignette base — darker in corners */
        radial-gradient(ellipse 115% 95% at 50% 50%,
            #1c2a5c 0%,
            #0d1538 70%,
            #060a22 100%);
}

/* Side fade gradients — dark navy fading to transparent so posters
   ease in/out of the reel window without a hard edge. */
.cinema-window::before,
.cinema-window::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    width: 60px;
    z-index: 2;
    pointer-events: none;
}
.cinema-window::before {
    left: 0;
    background: linear-gradient(to right, #0a1230 0%, rgba(10, 18, 48, 0.55) 50%, transparent 100%);
}
.cinema-window::after {
    right: 0;
    background: linear-gradient(to left, #0a1230 0%, rgba(10, 18, 48, 0.55) 50%, transparent 100%);
}

.cinema-marker {
    position: absolute;
    top: 12px;
    bottom: 12px;
    left: 50%;
    width: 2px;
    transform: translateX(-50%);
    /* Gold marker — reads on the dark navy reel window where blue would
       compete with the bg. Subtle glow halo around it. */
    background: var(--gold-light);
    border-radius: 1px;
    z-index: 3;
    pointer-events: none;
    box-shadow:
        0 0 0 4px rgba(201, 165, 68, 0.15),
        0 0 12px rgba(247, 220, 140, 0.40);
}
.cinema-marker::before,
.cinema-marker::after {
    content: "";
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    width: 0;
    height: 0;
    border-left: 6px solid transparent;
    border-right: 6px solid transparent;
}
.cinema-marker::before {
    top: -1px;
    border-top: 8px solid var(--gold-light);
}
.cinema-marker::after {
    bottom: -1px;
    border-bottom: 8px solid var(--gold-light);
}

.reel-strip {
    display: flex;
    align-items: center;
    height: 100%;
    will-change: transform;
}

.reel-item {
    width: 170px;
    flex: 0 0 170px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 8px;
    text-align: center;
}

.reel-poster {
    width: 130px;
    height: 195px;
    border-radius: var(--r-sm);
    object-fit: cover;
    background: rgba(255, 255, 255, 0.08);  /* placeholder bg for missing posters on dark */
    /* Posters now sit on dark navy — gold-tinted rim + deeper shadow for separation */
    box-shadow:
        0 0 0 1px rgba(201, 165, 68, 0.20),
        0 6px 18px rgba(0, 0, 0, 0.45);
}

.reel-title {
    font-size: 13px;
    font-weight: 600;
    /* Cream text reads cleanly on navy */
    color: #f7ecc8;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    letter-spacing: -0.01em;
}

.reel-year {
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    /* Gold-soft for the year tag — quieter than the title, still readable on navy */
    color: var(--gold-soft);
    opacity: 0.75;
    font-weight: 500;
}

/* ─────────── Pick reveal card ─────────── */
.pick {
    position: relative;
    overflow: hidden;
    /* Mobile padding:
         top    48 → poster clears the top torn paper edge with breathing room
         horiz  20 → tighter sides so the 168 px poster has more chrome ratio
         bottom 72 → pick-actions clear the bottom torn fringe
       Cinema-stage uses `isolation: isolate`, so we can't z-index above the
       paper — the content has to physically sit higher. Desktop overrides
       this padding (44 44) below. */
    padding: 48px 20px 72px;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Vertically center content within the unified cinema area when the
       pick is shorter than the locked min-height. On desktop the layout
       is row + align-items: center so this still centers correctly. */
    justify-content: center;
    /* 20 px gap (was 16) gives every block — title, meta pills, genre pills,
       providers, action buttons — proper breathing room. Desktop overrides
       to 32. */
    gap: 20px;
    text-align: center;
    min-height: var(--cinema-min-h);
    animation: pick-fade-up 700ms var(--ease-out) both;
    isolation: isolate;  /* contain ::before/::after stacking */
}

/* NOTE: pick blurred-poster backdrop was moved from .pick to .cinema--pick
   (see ::before/::after on .cinema.cinema--pick below) so the film art
   spans the FULL VIEWPORT instead of just the 880 px centered content. */

/* Original (non-translated) film title — small italic subtitle paired with
   the main title. On mobile the parent (.pick-info-col) is plain block
   layout, so a small positive margin gives 6 px clean breathing room
   between title descenders and italic ascenders. On desktop the parent
   becomes flex column with `gap: 14px`, so we cancel most of that gap with
   a negative margin override to keep the tight title↔alt-title pair. */
.pick-original-title {
    font-family: 'Fraunces', serif;
    font-style: italic;
    font-size: 14.5px;
    font-weight: 500;
    /* Warm gold-deep for the alt-language subtitle so it reads as a
       deliberate secondary label, not muted afterthought. Sits well on
       both the blurred-poster backdrop (pick state) and the white modal
       (detail view). */
    color: var(--gold-deep);
    margin-top: 6px;
    font-variation-settings: "opsz" 60;
    letter-spacing: 0;
    line-height: 1.4;
}

@keyframes pick-fade-up {
    from { opacity: 0; transform: translateY(14px); }
    to   { opacity: 1; transform: translateY(0); }
}

/* Premium staged reveal (desktop only — needs horizontal flex layout).
   Poster appears centered, briefly steps forward (scale 1.08), then glides
   to its final left position. Info column emerges from behind the poster,
   sliding right with fade-in. Slower, more cinematic timing. */
@keyframes pick-poster-staged {
    0% {
        transform: translateX(var(--poster-center-x, 0)) scale(0.92);
        opacity: 0;
    }
    14% {
        transform: translateX(var(--poster-center-x, 0)) scale(0.96);
        opacity: 1;
    }
    24% {
        transform: translateX(var(--poster-center-x, 0)) scale(1.08);
    }
    36% {
        transform: translateX(var(--poster-center-x, 0)) scale(1.06);
    }
    100% {
        transform: translateX(0) scale(1);
        opacity: 1;
    }
}

@keyframes pick-info-staged {
    0% {
        opacity: 0;
        transform: translateX(-90px);
    }
    100% {
        opacity: 1;
        transform: translateX(0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .pick,
    .pick-poster,
    .pick-info-col {
        animation: none !important;
    }
}

.pick-eyebrow {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--blue);
}

.pick-poster {
    width: 168px;
    height: 252px;
    border-radius: var(--r-md);
    object-fit: cover;
    background: var(--surface-tint);
    box-shadow: var(--shadow-lg);
}

.pick-title {
    font-family: 'Fraunces', serif;
    font-size: clamp(24px, 5.5vw, 34px);
    font-weight: 600;
    letter-spacing: -0.025em;
    line-height: 1.1;
    color: var(--text);
    max-width: 100%;
    margin-top: 4px;
}

/* Dynamic title sizing for long film names — applied in JS via class on
   `.pick-title` based on character count. Each tier drops the clamp range so
   even "Borat: Cultural Learnings of America…" fits without 4-line wrap on
   mobile. Desktop overrides all variants back to 40 px (see media query),
   since the desktop card has horizontal room for any title length. */
.pick-title.is-long   { font-size: clamp(20px, 4.6vw, 30px); }
.pick-title.is-xlong  { font-size: clamp(17px, 3.8vw, 26px); }
.pick-title.is-xxlong { font-size: clamp(15px, 3.2vw, 22px); line-height: 1.18; }

.pick-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 6px;
}

.pick-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 11px;
    border-radius: var(--r-pill);
    background: var(--surface-2);
    color: var(--text-secondary);
    border: 1px solid var(--hairline);
    font-size: 12px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
}

.pick-chip svg {
    width: 12px;
    height: 12px;
    color: var(--text-tertiary);
}

.pick-chip-rating {
    color: var(--text);
    font-weight: 600;
}
.pick-chip-rating svg {
    color: var(--accent-yellow);
}

.pick-genres {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    justify-content: center;
}

.pick-genre {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.02em;
    color: var(--blue);
    padding: 4px 10px;
    border-radius: var(--r-pill);
    background: var(--blue-pale);
    border: 1px solid var(--blue-soft);
}

.pick-providers {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    flex-wrap: wrap;
    margin-top: 6px;
}

.pick-providers-label {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    /* Gold accent matches the alt-title and ties the row to the brand
       palette — sits next to colorful provider logos without competing. */
    color: var(--gold-deep);
}

.pick-provider-logo {
    width: 28px;
    height: 28px;
    border-radius: 8px;
    background: #fff;
    border: 1px solid var(--hairline);
    object-fit: cover;
    box-shadow: var(--shadow-xs);
}

.pick-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: center;
    margin-top: 8px;
    width: 100%;
    max-width: 360px;
}

.pick-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 11px 18px;
    border-radius: var(--r-pill);
    font-size: 13.5px;
    font-weight: 500;
    text-decoration: none;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--hairline);
    transition: background 0.18s var(--ease-out), color 0.18s, border-color 0.18s, transform 0.12s;
}

.pick-action:hover {
    background: var(--surface-2);
    border-color: var(--hairline-strong);
}

.pick-action:active {
    transform: scale(0.97);
}

.pick-action--trailer {
    background: var(--blue);
    color: white;
    border-color: var(--blue);
    box-shadow: var(--shadow-blue);
}
.pick-action--trailer:hover {
    background: var(--blue-deep);
    border-color: var(--blue-deep);
}

.pick-action--save {
    background: var(--blue-pale);
    border-color: var(--blue-soft);
    color: var(--blue);
    font-weight: 600;
}
.pick-action--save.is-saved {
    background: var(--surface);
    color: var(--text-secondary);
    border-color: var(--hairline);
    font-weight: 500;
}

/* "Viděno" — mark as watched. Off state is a quiet secondary button;
   On state turns sage-green to read clearly as "done / handled". */
.pick-action--watched {
    background: var(--surface);
    border-color: var(--hairline);
    color: var(--text-secondary);
    font-weight: 500;
}
.pick-action--watched:hover {
    background: var(--surface-2);
    border-color: var(--hairline-strong);
    color: var(--text);
}
.pick-action--watched.is-watched {
    background: var(--sage);
    border-color: var(--sage);
    color: #4a5b32;
    font-weight: 600;
}
.pick-action--watched.is-watched:hover {
    background: #cdd9b5;
    border-color: #cdd9b5;
}

.pick-action svg { width: 13px; height: 13px; }

/* Empty state */
.empty-state {
    padding: 60px 28px 56px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    min-height: var(--cinema-min-h);
    background:
        radial-gradient(circle at 50% 0%, rgba(31, 44, 117, 0.04) 0%, transparent 50%);
}

.empty-state-icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--blue-pale);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--blue);
}

.empty-state-icon svg { width: 26px; height: 26px; }

.empty-state-title {
    font-family: 'Fraunces', serif;
    font-size: 22px;
    font-weight: 500;
    letter-spacing: -0.02em;
    color: var(--text);
}

.empty-state-text {
    font-size: 14px;
    color: var(--text-secondary);
    max-width: 280px;
    line-height: 1.55;
}

/* ─────────── CTA bar ─────────── */
.cta-wrap {
    margin-top: 4px;
    display: flex;
    justify-content: center;
}

/* ── Simple blue pill spin button ──
   Modest, decent, doesn't shout — fits the calm cream paper aesthetic. */
.spin-cta {
    position: relative;
    width: 100%;
    max-width: 480px;
    min-height: 50px;
    padding: 12px 32px;
    border-radius: var(--r-pill);
    background: rgba(255, 253, 246, 0.85);    /* very light cream-white */
    border: 1px solid var(--blue-soft);
    color: var(--blue);
    text-transform: uppercase;
    letter-spacing: 0.16em;
    font-family: 'Inter', sans-serif;
    font-size: 12.5px;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    box-shadow:
        0 2px 6px rgba(31, 44, 117, 0.06),
        0 4px 14px rgba(31, 44, 117, 0.06);
    transition:
        background 0.2s var(--ease-out),
        border-color 0.2s var(--ease-out),
        transform 0.15s var(--ease-out),
        box-shadow 0.2s;
    will-change: transform;
    cursor: pointer;
}

.spin-cta:hover:not(:disabled) {
    background: #fff;
    border-color: var(--blue);
    box-shadow:
        0 4px 10px rgba(31, 44, 117, 0.14),
        0 8px 20px rgba(31, 44, 117, 0.10);
    transform: translateY(-1px);
}

.spin-cta:active:not(:disabled) {
    transform: translateY(0) scale(0.98);
    transition-duration: 0.06s;
}

.spin-cta:disabled {
    background: rgba(255, 253, 246, 0.4);
    color: var(--text-tertiary);
    border-color: var(--hairline);
    box-shadow: none;
    cursor: not-allowed;
}

.spin-cta-text {
    position: relative;
    z-index: 1;
}

.spin-cta-arrow {
    position: relative;
    z-index: 1;
    width: 18px;
    height: 18px;
    transition: transform 0.25s var(--ease-out);
    animation: cta-arrow-invite 4s ease-in-out infinite;
}

@keyframes cta-arrow-invite {
    0%, 78%, 100% { transform: translateX(0); }
    85%           { transform: translateX(5px); }
    92%           { transform: translateX(-1px); }
}

.spin-cta:hover:not(:disabled) .spin-cta-arrow {
    transform: translateX(5px);
    animation: none;  /* hover state takes over */
}

.spin-cta.is-spinning .spin-cta-arrow {
    animation: cta-rotate 1.1s linear infinite;
}


@keyframes cta-rotate {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
    .spin-cta-arrow {
        animation: none !important;
    }
}

/* ─────────── Recently picked ─────────── */
.recent-section {
    margin-top: 0;
}

.section-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: var(--space-4);
}

.section-title {
    font-family: 'Fraunces', serif;
    font-size: 22px;
    font-weight: 500;
    letter-spacing: -0.02em;
    color: var(--text);
}

.ghost-btn {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-tertiary);
    transition: color 0.18s;
    padding: 4px 8px;
    border-radius: 8px;
}

.ghost-btn:hover { color: var(--blue); background: var(--blue-pale); }

.recent-scroller {
    display: flex;
    gap: 12px;
    overflow-x: auto;
    padding: 0 4px 12px;
    margin: 0 calc(-1 * var(--space-5));
    padding-left: var(--space-5);
    padding-right: var(--space-5);
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x mandatory;
}
.recent-scroller::-webkit-scrollbar { display: none; }

/* Click-and-drag scrolling on devices with a real pointer (desktop / laptop).
   Touch devices keep the native momentum scroll — JS doesn't attach the drag
   handler there, so no cursor hint is needed. While dragging, snap is turned
   off so the strip tracks the cursor 1:1 instead of resisting. */
@media (hover: hover) and (pointer: fine) {
    .recent-scroller {
        cursor: grab;
    }
    .recent-scroller.is-dragging {
        cursor: grabbing;
        scroll-snap-type: none;
        scroll-behavior: auto;
        user-select: none;
    }
    /* Suppress the lift/shadow hover transform while a drag is in progress —
       otherwise every card the cursor passes over twitches. */
    .recent-scroller.is-dragging .recent-card:hover .recent-poster {
        transform: none;
        box-shadow: var(--shadow-sm);
    }
}

.recent-card {
    flex: 0 0 auto;
    scroll-snap-align: start;
    width: 110px;
    text-align: left;
    /* Button reset — the wrapper is a <button> so it's keyboard-focusable */
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    font: inherit;
    color: inherit;
    -webkit-tap-highlight-color: transparent;
}

.recent-card:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 4px;
    border-radius: var(--r-sm);
}

.recent-poster {
    width: 110px;
    height: 165px;
    border-radius: var(--r-sm);
    object-fit: cover;
    background: var(--surface-tint);
    box-shadow: var(--shadow-sm);
    margin-bottom: 8px;
    transition: transform 0.2s var(--ease-out), box-shadow 0.2s;
}

.recent-card:hover .recent-poster {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
}

.recent-title {
    font-size: 12px;
    font-weight: 500;
    line-height: 1.3;
    color: var(--text);
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    letter-spacing: -0.01em;
}

.recent-year {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10.5px;
    font-weight: 500;
    color: var(--text-tertiary);
    margin-top: 2px;
}

/* ─────────── App footer ─────────── */
.app-footer {
    margin-top: var(--space-7);
    padding: var(--space-6) var(--space-4) var(--space-5);
    border-top: 1px solid var(--hairline);
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    color: var(--text-tertiary);
}

.app-footer-brand {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: 'Fraunces', serif;
    font-size: 17px;
    font-weight: 500;
    color: var(--text);
    letter-spacing: -0.015em;
    margin-bottom: 2px;
}

.app-footer-mark {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
}

.app-footer-mark svg {
    width: 12px;
    height: 12px;
    filter: drop-shadow(0 0.5px 0 rgba(143, 115, 37, 0.40));
}

.app-footer-tagline {
    font-family: 'Fraunces', serif;
    font-style: italic;
    font-size: 13px;
    font-weight: 400;
    color: var(--text-secondary);
    margin-bottom: 6px;
    letter-spacing: -0.005em;
}

.app-footer-meta {
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    line-height: 1.5;
}

.app-footer-sep {
    color: var(--text-tertiary);
    opacity: 0.6;
}

.app-footer a {
    color: var(--blue);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    transition: border-color 0.18s;
}

.app-footer a:hover {
    border-bottom-color: var(--blue-soft);
}

.app-footer-data {
    font-size: 11.5px;
    color: var(--text-tertiary);
    line-height: 1.55;
    max-width: 420px;
    margin-top: 4px;
}

.app-footer-rights {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10px;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-tertiary);
    opacity: 0.7;
    margin-top: 8px;
}

/* ─────────── Win confetti ───────────
   Gold confetti burst spawned from the picked poster on roulette reveal.
   Container is fixed full-viewport, pieces are absolutely positioned with
   per-piece custom props for trajectory + duration. */
.confetti-burst {
    position: fixed;
    inset: 0;
    pointer-events: none;
    z-index: 1500;
    overflow: hidden;
}

.confetti-piece {
    position: absolute;
    width: 10px;
    height: 14px;
    border-radius: 2px;
    transform-origin: center;
    will-change: transform, opacity;
    animation: confetti-fly var(--dur, 1500ms) cubic-bezier(0.12, 0.74, 0.30, 1.0) forwards;
    box-shadow: 0 1px 2px rgba(60, 40, 10, 0.20);
}

@keyframes confetti-fly {
    0% {
        transform: translate3d(0, 0, 0) rotate(0deg) scale(1);
        opacity: 1;
    }
    15% {
        opacity: 1;
    }
    100% {
        /* Particles fly outward + downward (gravity) and tumble */
        transform: translate3d(var(--tx, 0), var(--ty, 600px), 0) rotate(var(--rot, 540deg)) scale(0.55);
        opacity: 0;
    }
}

@media (prefers-reduced-motion: reduce) {
    .confetti-burst { display: none; }
}

/* ─────────── Sheets (watchlist, settings) ───────────
   Same animation pattern as .modal below: backdrop animates its own
   opacity + blur in lockstep, card has independent fade + scale-in.
   See the longer comment on .modal for the rationale. */
.sheet {
    position: fixed;
    inset: 0;
    z-index: 1000;
    pointer-events: none;
}

.sheet.is-open {
    pointer-events: auto;
}

.sheet-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(22, 25, 48, 0.45);
    opacity: 0;
    backdrop-filter: blur(0) saturate(100%);
    -webkit-backdrop-filter: blur(0) saturate(100%);
    transition:
        opacity 0.28s var(--ease-out),
        backdrop-filter 0.28s var(--ease-out),
        -webkit-backdrop-filter 0.28s var(--ease-out);
    will-change: opacity, backdrop-filter;
}

.sheet.is-open .sheet-backdrop {
    opacity: 1;
    backdrop-filter: blur(10px) saturate(140%);
    -webkit-backdrop-filter: blur(10px) saturate(140%);
}

/* Centered-modal style (was bottom-sheet originally) — watchlist +
   settings now use this same look as the trailer/detail modal. */
.sheet-content {
    position: absolute;
    top: 50%;
    left: 50%;
    width: min(560px, calc(100vw - 32px));
    max-height: calc(100vh - 64px);
    background: var(--surface);
    border-radius: var(--r-xl);
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.94);
    transition:
        opacity 0.28s var(--ease-out),
        transform 0.32s var(--ease-decel);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    box-shadow:
        0 30px 80px rgba(22, 25, 48, 0.40),
        0 12px 28px rgba(22, 25, 48, 0.18);
    will-change: opacity, transform;
}

.sheet.is-open .sheet-content {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
}

.sheet-header {
    padding: 24px var(--space-5) var(--space-4);
    display: flex;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid var(--hairline);
    position: relative;
}

/* Bottom-sheet grab bar removed — sheets now use centered-modal layout
   where a top grab bar doesn't belong. */

.sheet-title {
    font-family: 'Fraunces', serif;
    font-size: 22px;
    font-weight: 500;
    letter-spacing: -0.02em;
}

.sheet-close {
    width: 38px;
    height: 38px;
    border-radius: var(--r-md);
    background: var(--surface-tint);
    color: var(--text);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.18s var(--ease-out);
}

.sheet-close:hover { background: var(--hairline); }
.sheet-close svg { width: 16px; height: 16px; }

/* ─────────── Modal popup (trailer + movie detail) ───────────
   Generic centered popup. Two variants:
     .modal--trailer  → black card, 16:9 YouTube iframe
     .modal--detail   → surface card, full pick layout (no staged animation)

   Animation strategy: backdrop fade (opacity + blur) and card scale-in run
   on the SAME duration and start simultaneously. Previously the wrapper had
   its own opacity transition (240 ms) while the backdrop-filter ran 320 ms,
   so the modal visually "popped" against an un-blurred page and the blur
   crept in afterwards. Letting the backdrop animate its own opacity +
   backdrop-filter together, while the card fades + scales, keeps every
   layer perfectly in sync. */
.modal {
    position: fixed;
    inset: 0;
    z-index: 1100;
    pointer-events: none;
}

.modal.is-open {
    pointer-events: auto;
}

.modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(22, 25, 48, 0.55);
    opacity: 0;
    /* Start unblurred; ramp the blur AND the dim-overlay opacity together
       on .is-open. The matching 280 ms / same easing pair means the dim
       and the blur arrive at the same moment instead of one trailing. */
    backdrop-filter: blur(0) saturate(100%);
    -webkit-backdrop-filter: blur(0) saturate(100%);
    transition:
        opacity 0.28s var(--ease-out),
        backdrop-filter 0.28s var(--ease-out),
        -webkit-backdrop-filter 0.28s var(--ease-out);
    will-change: opacity, backdrop-filter;
}

.modal.is-open .modal-backdrop {
    opacity: 1;
    backdrop-filter: blur(10px) saturate(140%);
    -webkit-backdrop-filter: blur(10px) saturate(140%);
}

.modal-card {
    position: absolute;
    top: 50%;
    left: 50%;
    width: min(720px, calc(100vw - 24px));
    max-height: calc(100vh - 48px);
    background: var(--surface);
    border-radius: var(--r-xl);
    box-shadow:
        0 30px 80px rgba(22, 25, 48, 0.40),
        0 12px 28px rgba(22, 25, 48, 0.18);
    overflow: hidden;
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.94);
    transition:
        opacity 0.28s var(--ease-out),
        transform 0.32s cubic-bezier(0.22, 1, 0.36, 1);
    display: flex;
    flex-direction: column;
    will-change: opacity, transform;
}

.modal.is-open .modal-card {
    opacity: 1;
    transform: translate(-50%, -50%) scale(1);
}

.modal-close {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.92);
    color: var(--text);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    box-shadow: 0 2px 8px rgba(22, 25, 48, 0.16);
    transition: background 0.18s, transform 0.12s;
}

.modal-close:hover { background: white; transform: scale(1.05); }
.modal-close:active { transform: scale(0.94); }
.modal-close svg { width: 16px; height: 16px; }

.modal-body {
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

/* ── Trailer variant ── */
.modal--trailer .modal-card {
    background: #000;
    width: min(960px, calc(100vw - 24px));
}

.modal--trailer .modal-close {
    background: rgba(255, 255, 255, 0.15);
    color: white;
    box-shadow: none;
}
.modal--trailer .modal-close:hover {
    background: rgba(255, 255, 255, 0.28);
}

.modal-trailer {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    background: #000;
}

.modal-trailer iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
    display: block;
}

/* ── Detail variant ── reuses the .pick layout from the cinema card.
   Disable the staged poster animation so the modal pops in clean. */
.modal--detail .pick,
.modal--detail .pick-poster,
.modal--detail .pick-info-col {
    animation: none !important;
}

/* The pick inside a modal needs the same horizontal layout on desktop */
@media (min-width: 700px) {
    .modal--detail .modal-card {
        width: min(720px, calc(100vw - 32px));
    }
}

.watchlist-list, .settings-list {
    padding: var(--space-5);
    overflow-y: auto;
    flex: 1 1 auto;
}

/* "Vymazat vše" row inside watchlist sheet */
.wl-meta-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-bottom: 14px;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--hairline);
}

.wl-meta-count {
    font-size: 12.5px;
    font-weight: 500;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

.wl-clear-all {
    padding: 6px 12px;
    border-radius: var(--r-pill);
    background: var(--surface-tint);
    color: var(--text-secondary);
    font-size: 12px;
    font-weight: 500;
    transition: background 0.18s, color 0.18s;
}

.wl-clear-all:hover {
    background: var(--rose);
    color: var(--text);
}

/* Watchlist item */
.wl-item {
    display: flex;
    gap: 14px;
    padding: 12px;
    border-radius: var(--r-md);
    background: var(--surface-2);
    margin-bottom: 10px;
    align-items: center;
    border: 1px solid var(--hairline);
    cursor: pointer;
    transition: background 0.18s, transform 0.12s, border-color 0.18s;
}

.wl-item:hover {
    background: var(--bg);
    border-color: var(--hairline-strong);
}
.wl-item:active {
    transform: scale(0.99);
}

.wl-poster {
    width: 52px;
    height: 78px;
    border-radius: 6px;
    object-fit: cover;
    background: var(--surface-tint);
    box-shadow: var(--shadow-xs);
}

.wl-info { flex: 1; min-width: 0; }

.wl-title {
    font-family: 'Fraunces', serif;
    font-size: 16px;
    font-weight: 500;
    color: var(--text);
    margin-bottom: 3px;
    line-height: 1.25;
    letter-spacing: -0.015em;
}

.wl-meta {
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    color: var(--text-tertiary);
    font-weight: 500;
}

.wl-remove {
    width: 32px;
    height: 32px;
    border-radius: var(--r-sm);
    background: transparent;
    color: var(--text-tertiary);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.18s, color 0.18s;
}

.wl-remove:hover {
    background: var(--rose);
    color: var(--text);
}

.wl-remove svg { width: 14px; height: 14px; }

.wl-empty {
    text-align: center;
    padding: 48px 20px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    align-items: center;
}

.wl-empty-icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--blue-pale);
    color: var(--blue);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 4px;
}
.wl-empty-icon svg { width: 26px; height: 26px; }

.wl-empty-title {
    font-family: 'Fraunces', serif;
    font-size: 20px;
    font-weight: 500;
    color: var(--text);
}

.wl-empty-text {
    font-size: 13.5px;
    color: var(--text-secondary);
    max-width: 240px;
    line-height: 1.55;
}

/* Settings — sectioned card layout with icons + descriptions */
.settings-section {
    margin-bottom: var(--space-6);
}
.settings-section:last-of-type {
    margin-bottom: var(--space-5);
}

.settings-section-title {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--text-tertiary);
    margin-bottom: 10px;
    padding-left: 4px;
}

.settings-card {
    background: var(--surface-2);
    border: 1px solid var(--hairline);
    border-radius: var(--r-md);
    overflow: hidden;
}

.settings-row {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 14px 16px;
    border-bottom: 1px solid var(--hairline);
    transition: background 0.16s var(--ease-out);
}
.settings-row:last-child { border-bottom: none; }
.settings-row.is-clickable { cursor: pointer; }
.settings-row.is-clickable:hover { background: var(--bg); }
.settings-row.is-clickable:active { background: var(--surface-tint); }

.settings-row-icon {
    width: 36px;
    height: 36px;
    border-radius: 10px;
    background: var(--blue-pale);
    color: var(--blue);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    transition: background 0.2s;
}

.settings-row-icon svg {
    width: 18px;
    height: 18px;
}

.settings-row-icon--danger {
    background: var(--rose);
    color: #c93b5b;
}

.settings-row-icon--neutral {
    background: var(--surface-tint);
    color: var(--text-secondary);
}

.settings-row-body {
    flex: 1;
    min-width: 0;
}

.settings-row-title {
    font-size: 14px;
    font-weight: 500;
    color: var(--text);
    line-height: 1.3;
    letter-spacing: -0.005em;
}

.settings-row-desc {
    font-size: 12px;
    color: var(--text-tertiary);
    margin-top: 2px;
    line-height: 1.4;
}

.settings-row-action {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
}

/* iOS-style toggle */
.settings-toggle {
    width: 46px;
    height: 28px;
    border-radius: var(--r-pill);
    background: var(--surface-tint);
    border: 1px solid var(--hairline);
    position: relative;
    transition: background 0.22s var(--ease-out), border-color 0.22s;
    cursor: pointer;
    padding: 0;
}

.settings-toggle::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: white;
    box-shadow: 0 1px 3px rgba(22, 25, 48, 0.18), 0 1px 2px rgba(22, 25, 48, 0.08);
    transition: transform 0.24s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.settings-toggle.is-on {
    background: var(--blue);
    border-color: var(--blue);
}

.settings-toggle.is-on::after {
    transform: translateX(18px);
}

/* Compact segmented control for the language switcher inside settings.
   Two pill buttons share a track, the active one carries the blue accent.
   Sits in the same `settings-row-action` slot as the haptics toggle so the
   row layout stays consistent across rows. */
.lang-switch {
    display: inline-flex;
    background: var(--surface-tint);
    border: 1px solid var(--hairline);
    border-radius: var(--r-pill);
    padding: 2px;
    gap: 2px;
}

.lang-switch-opt {
    font-family: 'JetBrains Mono', monospace;
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.06em;
    padding: 5px 12px;
    border-radius: var(--r-pill);
    color: var(--text-secondary);
    background: transparent;
    transition: background 0.18s var(--ease-out), color 0.18s;
    -webkit-tap-highlight-color: transparent;
}

.lang-switch-opt:hover {
    color: var(--text);
}

.lang-switch-opt.is-active {
    background: var(--blue);
    color: white;
    box-shadow: 0 2px 6px rgba(31, 44, 117, 0.18);
}

/* Danger button (vymazat) */
.settings-btn-danger {
    color: #c93b5b;
    font-size: 12.5px;
    font-weight: 500;
    padding: 6px 12px;
    border-radius: var(--r-pill);
    background: transparent;
    transition: background 0.18s, color 0.18s;
}
.settings-btn-danger:hover {
    background: var(--rose);
}
.settings-btn-danger:disabled {
    color: var(--text-tertiary);
    cursor: not-allowed;
    background: transparent;
}

/* Footer / about block */
.settings-about {
    padding: 20px 16px 4px;
    text-align: center;
    display: flex;
    flex-direction: column;
    gap: 4px;
    color: var(--text-tertiary);
    font-size: 12px;
    line-height: 1.5;
}

.settings-about-brand {
    font-family: 'Fraunces', serif;
    font-size: 18px;
    font-weight: 500;
    color: var(--text);
    letter-spacing: -0.01em;
}

.settings-about-version {
    font-family: 'JetBrains Mono', monospace;
    font-weight: 600;
    color: var(--blue);
    font-size: 11.5px;
    letter-spacing: 0.04em;
}

/* ─────────── Reduced motion ─────────── */
@media (prefers-reduced-motion: reduce) {
    .pool-badge-dot, .marquee-dots span, .spin-cta-arrow {
        animation: none !important;
    }
}

/* ─────────── Desktop layout ─────────── */
@media (min-width: 900px) {
    :root {
        /* Larger unified cinema area on desktop — gives the pick card room
           to breathe horizontally while keeping marquee/reel matching. */
        --cinema-min-h: 560px;
    }

    .app-main {
        max-width: 880px;
        padding: var(--space-7) var(--space-6);
        gap: var(--space-7);
    }

    /* Larger desktop flex gap requires a deeper pull-up so the paper still
       overlaps the cinema top by a visible amount. */
    .cinema-stage {
        margin-top: -38px;
    }

    .hero-title { font-size: 68px; }
    .hero-sub { font-size: 16px; }

    .genre-pill {
        padding: 11px 18px;
        font-size: 14.5px;
    }
    .genre-icon { width: 18px; height: 18px; }

    .marquee { padding: 72px 36px; }
    .marquee-headline { font-size: 60px; }

    /* Pick horizontal on desktop */
    .pick {
        flex-direction: row;
        align-items: center;
        text-align: left;
        gap: 32px;
        padding: 44px 44px;
        /* Disable mobile fade-up — children animate individually below */
        animation: none;
    }
    .pick-poster {
        width: 220px;
        height: 330px;
        flex: 0 0 220px;
        position: relative;
        z-index: 2;
        transform-origin: center center;
        /* Premium 1500ms staged reveal: enter centered, scale up briefly,
           glide to final left position. Custom curve eases slowly into rest. */
        animation: pick-poster-staged 1500ms cubic-bezier(0.22, 1, 0.36, 1) both;
    }
    .pick-info-col {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: 14px;
        min-width: 0;
        position: relative;
        z-index: 1;
        /* Emerges from behind poster after it begins moving left. Delay 650ms
           lines up with the moment poster starts gliding (frame 36% of 1500ms). */
        animation: pick-info-staged 950ms cubic-bezier(0.16, 1, 0.3, 1) 650ms both;
    }
    /* Desktop pick card has room for any title length — override all the
       length-modifier classes set by JS so they don't carry over from mobile. */
    .pick-title,
    .pick-title.is-long,
    .pick-title.is-xlong,
    .pick-title.is-xxlong { text-align: left; font-size: 40px; line-height: 1.1; }

    /* Desktop pick-info-col is flex column with `gap: 14px`, so we cancel
       most of that gap on the alt-title to keep the tight title↔alt-title
       pair from the design. Mobile keeps the +6 px positive margin above. */
    .pick-original-title { margin-top: -8px; }
    .pick-meta, .pick-genres, .pick-providers {
        justify-content: flex-start;
    }
    .pick-actions {
        justify-content: flex-start;
        max-width: none;
        margin-top: 4px;
    }

    .spin-cta { font-size: 13px; min-height: 60px; }

    .section-title { font-size: 26px; }
}
