/**
 * StreamVerse — Movie Carousel
 * Sits directly below the Hero, synchronized with .hero__bg via
 * movie-showcase.js.
 *
 * Architecture (per request):
 *   .movie-carousel__viewport   FIXED — overflow:hidden, never moves,
 *                               never scrolls itself
 *     .movie-carousel__track    MOVES — a flex row positioned entirely
 *                               via CSS transform: translateX(), driven
 *                               by movie-showcase.js (click, autoplay,
 *                               keyboard, and pointer/touch drag all
 *                               update the same transform)
 *
 * There is no native browser scrolling here at all — no overflow-x,
 * no scrollbar to hide (there never was one to begin with), no
 * scroll-snap. The viewport clips; only the track's transform changes.
 */

.movie-carousel {
  position: relative;
  /* No background-color here on purpose — this section sits directly
     on the single global page background (var(--color-bg-base) on
     body, in base.css). Previously this rule redeclared that same
     value locally; removing the redeclaration doesn't change how it
     renders (the value was identical), but it does make body the one
     true source of the page background rather than something every
     section has to separately opt into. See ambient-glow.css for the
     section's own decorative layer, which sits on top of this same
     shared background, not as a separate background block.
     No overflow:hidden here either, on purpose — see ambient-glow.css's
     file header for why: clipping each section's glow to its own
     bounds is exactly what was producing a visible seam at the
     Movies/Sports boundary, even with matching background colors.
     Letting the glow bleed naturally past this section's own edges
     (contained instead at the page level, in base.css) is what makes
     the two sections' backgrounds actually continuous rather than two
     independently-clipped blocks that happen to use the same color. */
  padding-top: var(--space-5); /* tightened — see hero.css's matching note on .hero's
                                   padding-bottom; these two edges together are what
                                   separated Hero from Popular Movies */
  padding-bottom: var(--space-5); /* reduced from --space-7 (48px) — combined with
                                      Live Sports' own padding-top, the previous
                                      48+64=112px trailing gap read as excessive
                                      empty space rather than a comfortable section
                                      break. --space-5 here (matching this section's
                                      own padding-top above) brings the total gap to
                                      48px — inside the ~40-60px target range, using
                                      an existing design-system token rather than an
                                      arbitrary value. */
}

.movie-carousel__inner {
  max-width: var(--grid-max-width);
  margin-inline: auto;
  padding-inline: var(--space-5);
}

@media (min-width: 768px) {
  .movie-carousel__inner {
    padding-inline: var(--space-6);
  }
}

@media (min-width: 1024px) {
  .movie-carousel__inner {
    padding-inline: var(--space-7);
  }
}

.movie-carousel__header {
  /* Was display:flex + justify-content:space-between — a horizontal
     row layout, currently a no-op with only the title as a child, but
     it would have placed a new subtitle beside the title instead of
     stacking it below. Sports' own header (.sports-carousel__header)
     is a plain block for exactly this reason — matching that here is
     what actually makes title+subtitle stack vertically, not a
     spacing patch on top of the wrong layout mode. */
  margin-bottom: var(--space-4); /* tightened from --space-5, per request */
}

.movie-carousel__title {
  font-family: var(--font-heading);
  /* --text-h2 (36px) — matches Live Sports' and Live Channels' own
     section-title styling exactly (same token, same line-height, same
     weight), per request to bring Popular Movies back in line with
     the other two main section headings rather than standing out at
     the larger --text-h1 size it briefly used. */
  font-size: var(--text-h2);
  line-height: var(--text-h2-line-height);
  font-weight: 700;
  color: var(--color-text-primary);
}

.movie-carousel__subtitle {
  /* Same margin-top as Sports' own subtitle (--space-1) for identical
     title-to-subtitle rhythm between the two sections, even though the
     subtitle's own font-size differs (see below) — keeps the "compact,
     elegant" spacing request without inventing a new spacing value. */
  margin-top: var(--space-1);
  font-family: var(--font-body);
  /* --text-body (16px) — sits at the lower edge of the requested
     16-18px range: clearly readable but unambiguously secondary next
     to the 44px heading right above it. */
  font-size: var(--text-body);
  line-height: var(--text-body-line-height);
  font-weight: 400; /* "normal" weight, per request */
  color: #A3AED0; /* per request: all section subtitles/descriptions
                      use this exact color (local override, not the
                      --color-text-secondary token — that token is
                      also used by unrelated UI, e.g. nav links). */
}

/* ------------------------------------------------------------------
 * Fixed viewport — this element's box never moves and never scrolls.
 * It only clips whatever the track's transform brings into view.
 * ------------------------------------------------------------------ */

.movie-carousel__track-wrap {
  position: relative;
}

.movie-carousel__viewport {
  position: relative;
  overflow: hidden;
  width: 100%;
  /* Breathing room so the focused card's scale-up and glow don't get
     clipped by this element's own overflow:hidden edge. The focused
     poster's transform-origin is anchored to its own bottom (see
     .movie-carousel__poster-wrap below), so ALL of its scale growth
     happens upward, toward this padding — none happens downward
     toward the title. --space-6 comfortably covers the largest
     upward growth (focused + hovered, scale 1.08) with room to
     spare, so the poster image itself is never clipped. */
  padding-block: var(--space-6);
  margin-block: calc(-1 * var(--space-6)); /* cancels the padding's effect on outer layout/spacing */
  /* Let vertical page scroll pass through untouched on touch devices;
     movie-showcase.js owns horizontal drag/swipe itself. */
  touch-action: pan-y;
  cursor: grab;
  /* Soft fade at both edges — hints that more movies sit just past the
     visible frame without literally cropping a card. Purely cosmetic;
     the viewport's actual width/fixed position are unchanged. */
  -webkit-mask-image: linear-gradient(
    to right,
    transparent 0,
    black 24px,
    black calc(100% - 24px),
    transparent 100%
  );
  mask-image: linear-gradient(
    to right,
    transparent 0,
    black 24px,
    black calc(100% - 24px),
    transparent 100%
  );
}

.movie-carousel__viewport:active {
  cursor: grabbing;
}

/* ------------------------------------------------------------------
 * NOTE: there is deliberately NO separate "focus frame" overlay
 * element here. An earlier version had one (.movie-carousel__focus-frame,
 * a fixed-position div sitting permanently at the viewport's exact
 * center with its own always-on glow) — but because it was a fixed
 * position/size box independent of any actual card, it only lined up
 * with a card at the single instant that card's own (scaled) edges
 * happened to match the frame's fixed edges exactly. At every other
 * moment — mid-drift, or once .is-active scaled the real card up to
 * 1.12x — the frame's straight edge poked out from behind the poster
 * as a separate glowing blue sliver in the gap between two cards.
 *
 * The fix is architectural, not another CSS patch: the active glow
 * lives ONLY on the .is-active card's own .movie-carousel__poster-wrap
 * (see below), which moves and scales together with that exact poster.
 * There is no independent element that can ever drift out of alignment
 * with it, so there is nothing left to appear in the gap between cards.
 * ------------------------------------------------------------------ */



/* ------------------------------------------------------------------
 * Moving track — the ONLY element that ever moves, and it moves
 * exclusively via `transform`, never via scrollLeft/scrollTo.
 * ------------------------------------------------------------------ */

.movie-carousel__track {
  display: flex;
  gap: var(--space-4);
  width: max-content; /* sizes to its full content (two full sets) so transform has room to travel */
  will-change: transform;
  transition: opacity var(--duration-micro) var(--ease-standard);
  /* No default transition on transform: the continuous auto-scroll
     (movie-showcase.js) sets `transform` on every animation frame
     itself — a CSS transition here would lag behind and fight that
     per-frame update. A transition is added only momentarily, via
     .is-jumping, for the prev/next buttons' discrete step. */

  /* No leading/trailing padding here on purpose (a previous version
     added calc(50% - halfItemWidth) padding so the first/last real
     card could reach center) — that dedicated empty space is exactly
     what showed up as a large gap on the left at initial paint, since
     scrollOffset starts at 0 before any drift has happened. Since the
     track is an infinite loop (two identical sets back-to-back), every
     card already has real neighboring posters on both sides via the
     wrap — no card is ever a true "first" or "last" that needs special
     edge space. The actual fix is computing a correct, non-zero
     initial scrollOffset in movie-showcase.js's init(), not padding. */
}

/* Loading state — while tmdb-loader.js is fetching. Deliberately
   subtle (opacity only, existing tokens only) so this reads as a
   brief moment, not a redesign of the carousel. Cards already in the
   DOM (from a previous successful load) stay visible and dimmed
   rather than disappearing, avoiding layout shift. */
.movie-carousel.is-loading .movie-carousel__track {
  opacity: 0.4;
}

.movie-carousel.is-loading .movie-carousel__track-wrap {
  position: relative;
}

.movie-carousel.is-loading .movie-carousel__track-wrap::after {
  /* German default, English override below — :lang() tracks
     <html lang="..">, which i18n.js keeps in sync with the DE/EN
     switcher in real time, so this needs no JS of its own. */
  content: "Filme werden geladen…";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-text-secondary);
  font-family: var(--font-body);
  font-size: var(--text-body-sm);
  pointer-events: none;
}

html:lang(en) .movie-carousel.is-loading .movie-carousel__track-wrap::after {
  content: "Loading movies…";
}

/* Error state — deliberately visible and honest (per requirement: no
   fake/placeholder movies substituted silently). No cards render at
   all in this state, so the wrap needs an explicit min-height to
   avoid collapsing to nothing; nav buttons are hidden since there is
   nothing to navigate. Existing tokens only — same visual language as
   the loading state above, not a new design. */
.movie-carousel.has-error .movie-carousel__track {
  display: none;
}

.movie-carousel.has-error .movie-carousel__track-wrap {
  position: relative;
  min-height: 200px;
}

.movie-carousel.has-error .movie-carousel__nav {
  display: none;
}

.movie-carousel.has-error .movie-carousel__track-wrap::after {
  content: attr(data-error-message);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding-inline: var(--space-5);
  color: var(--color-text-secondary);
  font-family: var(--font-body);
  font-size: var(--text-body-sm);
}

/* Applied only for the brief duration of a prev/next button's nudge,
   a card click that re-centers it, or a tap-release re-centering. */
.movie-carousel__track.is-jumping {
  transition: transform 300ms var(--ease-standard); /* within the requested 250-350ms range */
}

@media (prefers-reduced-motion: reduce) {
  .movie-carousel__track.is-jumping {
    transition: none;
  }
}

.movie-carousel__item {
  flex: 0 0 auto;
  width: 140px; /* reduced from 168px — more compact, per request */
}

@media (min-width: 480px) {
  .movie-carousel__item {
    width: 160px; /* reduced from 196px */
  }
}

@media (min-width: 1024px) {
  .movie-carousel__item {
    width: 200px; /* reduced from 248px */
  }
}

/* Raises whichever <li> currently contains the focused card above its
   neighbors in paint order. Flex/DOM order alone would otherwise let
   the card to its right (later in the DOM, painted on top by default)
   visually paint over the focused card's slight rightward overhang —
   this keeps the focused poster reading cleanly on top regardless of
   which side it overhangs toward. */
.movie-carousel__item:has(.js-movie-card.is-active) {
  position: relative;
  z-index: 3;
}

/* ------------------------------------------------------------------
 * Card — no visible container: no background, no border, no card-level
 * box-shadow. It exists only as a clickable/focusable wrapper (a real
 * <button>, keyboard-focusable) around a poster + title. All visual
 * treatment (shadow, hover, active) lives on .movie-carousel__poster-wrap
 * below, so the poster itself reads as floating artwork, not a card.
 * ------------------------------------------------------------------ */

.movie-carousel__card {
  display: flex;
  flex-direction: column;
  width: 100%;
  background: none;
  border: none;
  padding: 0;
  text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .movie-carousel__poster-wrap {
    transition: box-shadow var(--duration-transition) var(--ease-standard);
  }

  .movie-carousel__card:hover .movie-carousel__poster-wrap,
  .movie-carousel__card.is-active .movie-carousel__poster-wrap,
  .movie-carousel__card.is-active:hover .movie-carousel__poster-wrap {
    transform: none; /* keep the glow cue, drop the scale motion */
  }
}

.movie-carousel__poster-wrap {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius-sm); /* subtle radius — floating artwork, not a card */
  box-shadow: var(--shadow-card); /* very subtle shadow under the poster itself */
  transform: scale(1);
  transform-origin: 50% 100%; /* anchor scaling to the poster's own BOTTOM edge —
                                  this is what actually keeps the title clear: all
                                  scale growth happens upward and sideways, so the
                                  poster's bottom edge (closest to the title) never
                                  moves, regardless of how much the focused card
                                  scales up. See .movie-carousel__viewport's
                                  padding-block for the matching upward headroom. */
  filter: brightness(1);
  transition:
    transform var(--duration-transition) var(--ease-standard),
    box-shadow var(--duration-transition) var(--ease-standard),
    filter var(--duration-transition) var(--ease-standard);
}

/* Hover: scale + soft accent glow — matches the site's blue/cyan
   identity via the existing --color-accent-glow token. No card
   border, no large glowing box — the glow sits close to the poster. */
.movie-carousel__card:hover .movie-carousel__poster-wrap {
  transform: scale(1.045);
  box-shadow: var(--shadow-card), 0 0 24px var(--color-accent-glow);
}

/* Focused/active card: no border, no separate rectangle/panel/overlay —
   the emphasis lives entirely on the poster's own box. Scale is capped
   at 1.05 at rest / 1.08 on hover (the "approximately 1.05–1.08
   maximum" requested) — small enough that, combined with the existing
   --space-4 gap between cards, the focused poster's sideways overhang
   (at most ~8px per side at the 1.08 ceiling) never reaches its
   neighbor. The glow itself is intentionally small and fully
   symmetric (no offset, modest blur, the site's existing accent-glow
   token) rather than layering in the heavier --shadow-card-hover token
   used elsewhere on the site — that combination was what previously
   read as too large/bright for a compact carousel card and bled too
   far down toward the title. */
.movie-carousel__card.is-active .movie-carousel__poster-wrap {
  transform: scale(1.05);
  box-shadow: var(--shadow-card), 0 0 14px var(--color-accent-glow);
  filter: brightness(1.03);
}

.movie-carousel__card.is-active:hover .movie-carousel__poster-wrap {
  transform: scale(1.08);
  box-shadow: var(--shadow-card), 0 0 18px var(--color-accent-glow);
  filter: brightness(1.04);
}

.movie-carousel__poster {
  display: block;
  width: 100%;
  height: auto; /* required: without this, the poster's HTML height
                   attribute (set in JS for layout-shift prevention)
                   wins the cascade over aspect-ratio, since aspect-ratio
                   only computes a dimension that is otherwise auto */
  aspect-ratio: 2 / 3;
  object-fit: cover; /* preserves correct poster proportions, no stretching */
  background-color: var(--color-bg-elevated);
}

/* ------------------------------------------------------------------
 * 4K quality badge — small, top-right, dark/transparent with a subtle
 * accent border. Purely decorative (aria-hidden) — the accessible
 * name for the movie comes from the button's own aria-label.
 * ------------------------------------------------------------------ */

/* Uses the site's secondary accent — Electric Cyan (--color-highlight) —
   rather than the primary Violet used for the active-card glow, so the
   "quality" cue reads as a distinct, deliberate second light source
   instead of just a smaller version of the focus glow. */
.movie-carousel__badge-4k {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  padding: 1px var(--space-2);
  background-color: rgba(8, 10, 15, 0.72); /* dark, semi-transparent fill — stays legible over bright poster
                                              art without blocking it entirely, unlike a fully opaque fill */
  border: 1px solid rgba(34, 211, 238, 0.55); /* Electric Cyan border */
  border-radius: var(--radius-xs); /* slight rounding, matches the site's small-badge radius */
  color: var(--color-highlight); /* Electric Cyan lettering */
  font-family: var(--font-body);
  font-size: var(--text-micro);
  font-weight: 700;
  letter-spacing: 0.03em;
  line-height: 1.6;
  /* Faint depth on the lettering itself */
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.55);
  /* Subtle cyan top highlight (shine) + a very small grounding shadow so
     the badge reads as a distinct object even over light poster art —
     neither is a glow, both stay close to the badge's own edges. */
  box-shadow:
    inset 0 1px 0 rgba(165, 243, 252, 0.22),
    0 1px 3px rgba(0, 0, 0, 0.45);
  transition:
    border-color var(--duration-micro) var(--ease-standard),
    box-shadow var(--duration-micro) var(--ease-standard);
}

.movie-carousel__card:hover .movie-carousel__badge-4k {
  border-color: var(--color-highlight);
  /* Slightly brighter shine plus the faintest cyan edge — stays subtle,
     no neon/large glow. */
  box-shadow:
    inset 0 1px 0 rgba(165, 243, 252, 0.36),
    0 1px 3px rgba(0, 0, 0, 0.45),
    0 0 4px rgba(34, 211, 238, 0.3);
}

/* ------------------------------------------------------------------
 * Title — the only text under the poster. No genre, no metadata.
 * ------------------------------------------------------------------ */

.movie-carousel__card-title {
  display: block;
  margin-top: var(--space-4); /* increased from --space-3 (12px) — gives the
                                  focused card's glow room to fade out before it
                                  reaches the title, now that the poster's own
                                  bottom edge no longer moves when it scales up
                                  (see poster-wrap's transform-origin) */
  font-family: var(--font-body);
  font-size: var(--text-body-sm);
  font-weight: 600;
  color: var(--color-text-primary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* ------------------------------------------------------------------
 * Prev/Next controls — hidden on touch-first mobile (swipe covers it),
 * shown from tablet up where a mouse/trackpad is more likely
 * ------------------------------------------------------------------ */

.movie-carousel__nav {
  display: none;
}

@media (min-width: 768px) {
  .movie-carousel__nav {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 40px;
    height: 40px;
    border-radius: var(--radius-full);
    background-color: var(--color-bg-elevated);
    border: 1px solid var(--color-border-strong);
    color: var(--color-text-primary);
    z-index: 2;
    transition: background-color var(--duration-micro) var(--ease-standard);
  }

  .movie-carousel__nav:hover {
    background-color: var(--color-bg-elevated-hover);
  }

  .movie-carousel__nav--prev {
    left: calc(-1 * var(--space-5));
  }

  .movie-carousel__nav--next {
    right: calc(-1 * var(--space-5));
  }
}

@media (min-width: 1024px) {
  .movie-carousel__nav--prev {
    left: calc(-1 * var(--space-6));
  }

  .movie-carousel__nav--next {
    right: calc(-1 * var(--space-6));
  }
}

.movie-carousel__nav-icon {
  width: 18px;
  height: 18px;
}
