/* ==========================================================================
   vxe — Netflix-style editors-pick billboard for styles/default
   Restyles the editors-pick hero (all 3 view types: default swiper, hero
   image, hero video) into a Netflix billboard, and drives the trailer
   "shrink" animation (logo scales down + description fades ~8s into playback,
   toggled by the .vxe-shrunk class the Vue instance adds).
   Scoped under .featureSlider so it only touches the billboard. Consumes only
   --vod-* customizer vars (incl. --vod-ep-* button colours) with fallbacks;
   beats vodlix.css's vw-based !important overlay rules with scoped !important.
   vodlix.css loads first and is untouched.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Billboard overlay — bottom-left anchored content column
   -------------------------------------------------------------------------- */
/* Poster shown over the (chrome-less) trailer player when it ends or fails —
   sits above the video/gradients (z 1–2) but below the logo/buttons (z 10) and
   the mute/replay controls (z 11), so the thumbnail replaces the video while the
   billboard stays legible. */
.featureSlider .vxe-ended-poster {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 3;
}
.featureSlider .swiperInfo.vxe-billboard {
  position: absolute;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: flex-end;
  /* bottom padding must clear the -13vw rail overlap (.featureSlider +
     .overLapEditor / #items-list .featureSlider + div) so the buttons never
     collide with the first rail */
  /* The billboard MUST share the page gutter, or the hero's title and buttons
     sit on a different left edge than every rail beneath them (3% vs the
     layout's own gutter — a visible ~20px step). The 3% fallback keeps the
     classic layout, which sets no gutter token, pixel-identical. */
  padding: 0 var(--vxl-gutter, 3%) 7vw !important;
  pointer-events: none;
}
/* Gradients live on `.relative` (the artwork wrapper), NOT on `.swiperInfo`
   (z-index 10). The artwork's own wrapper (`.ratio > div`) is `position:absolute;
   z-index:1`, so the gradients MUST carry a z-index above that (2) or they paint
   BEHIND the image and never show. They still stay below `.cateHolder` (the rail
   wrapper) and the overlapping first rail because the whole `.featureSlider` is
   non-positioned while `.cateHolder` is positioned (z-index 1) — a local z-index
   inside `.featureSlider` can't lift its subtree past a positioned ancestor's
   sibling. So the fade covers the image bottom yet the rails still paint on top.
   `.relative::before` = left scrim (legibility) + top vignette (blends the
   artwork under the fixed header instead of a hard cut). */
.featureSlider .relative::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    linear-gradient(90deg, rgba(0, 0, 0, 0.72) 0%, rgba(0, 0, 0, 0.4) 26%, rgba(0, 0, 0, 0) 58%),
    linear-gradient(180deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 16%);
}
/* `.relative::after` = bottom fade to the page background, solid for the full
   ~13vw rail-overlap depth then fades up, so the rails sit on a merged surface
   (restores the old .sliderInnerShadow feel). z-index 2 = above the artwork,
   below the rails (see note above). */
.featureSlider .relative::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 26vh;
  z-index: 2;
  pointer-events: none;
  /* gentle Netflix-style fade: the artwork stays visible and just darkens
     toward the bottom (solid only in the last sliver where the page bg starts),
     so the first rail sits on a darkened image instead of a hard black band */
  background: linear-gradient(0deg,
    var(--vod-body-bg, #141414) 0%,
    var(--vod-body-bg, #141414) 8%,
    rgba(20, 20, 20, 0) 100%);
}
/* --------------------------------------------------------------------------
   Billboard geometry — Netflix-style full-bleed hero (default + hero-image)
   A natural 16:9 leaves black at the bottom on wide-but-tall viewports and
   isn't full-bleed. Instead the hero fills the viewport (`calc(100vh - 64px)`)
   with `object-fit: cover` pinned to the top, so the artwork covers the whole
   screen, the top is never sliced, and the first rail peeks over the bottom.
   This single !important rule is the canonical hero height for ALL view types
   — default (vt1), hero-image (vt2) and hero-VIDEO (vt3) — on BOTH the homepage
   and the group/list page. The old per-template inline `.heroVideoDiv` <style>
   blocks were redundant (this rule already won) and have been removed; the
   `heroVideoDiv` class is now just markup parity between the two pages.
   -------------------------------------------------------------------------- */
.featureSlider .ratio.ratio-16x9 {
  padding-top: 0 !important;
  height: var(--vxl-hero-h, calc(100vh - 64px)) !important;
}
.featureSlider .ratio.ratio-16x9 > div,
.featureSlider .ratio.ratio-16x9 img.imgFull,
.featureSlider .ratio.ratio-16x9 > video {
  height: 100% !important;
  object-fit: cover !important;
  /* pin the crop to the TOP so the header-side of the artwork is never sliced;
     any cover overflow is taken off the bottom (which the fade covers anyway) */
  object-position: center top !important;
}
/* The trailer element carries `autoplay muted` and its <source>s in the
   markup, so it starts playing BEFORE the player library wraps it — and a
   bare <video> with only a height sizes its width from the footage's own
   aspect. A 4:3 trailer then played in the left two thirds of the hero with
   page background beside it until the wrap landed (owner report, 26.473.0).
   The width is pinned on the bare element and on both wrappers, so the
   frame is the hero's from the first painted frame. */
.featureSlider .ratio.ratio-16x9 > video,
.featureSlider .ratio.ratio-16x9 > .video-js,
.featureSlider .ratio.ratio-16x9 > .vdx-player {
  width: 100% !important;
  max-width: none !important;
}
/* Top pull is HOME-only (`#items-list`). The home content is pulled up ~64px
   under the fixed header by the global layout, which slices the top of the
   artwork; a +64px margin lands the hero flush at the viewport top (behind the
   floating header) so the top is never cut. The group/list page isn't pulled
   up, so it keeps the vodlix.css -6rem to sit flush (overriding it there
   re-opens a gap under the header). */
#items-list .featureSlider {
  margin-top: 64px !important;
}
/* First-rail overlap — pull the rail up so it peeks over the hero bottom
   (Netflix). Home and standalone (group/list) share the SAME pull so the gap
   between the hero buttons and the first rail is identical on both: the hero is
   the same height and the billboard is bottom-anchored, so the gap depends only
   on this value (-8vw made the group rail sit too close under the buttons). */
#items-list .featureSlider + div,
.featureSlider.vxe-ep-standalone + .overLapEditor,
.featureSlider.vxe-ep-standalone + [id] {
  margin-top: -5vw !important;
}
/* info column above the scrim (z-index 10 already set below) */
.featureSlider .swiperInfo.vxe-billboard .row {
  position: relative;
  z-index: 1;
  width: 100%;
  margin: 0;
  align-items: flex-end !important;
}
.featureSlider .swiperInfo.vxe-billboard .row > [class*="col-"] {
  padding-left: 0;
}
.featureSlider .swiperInfo.vxe-billboard .row > [class*="col-"],
.vxe-billboard__col {
  max-width: 42% !important;
  flex: 0 0 42% !important;
  pointer-events: auto;
}

/* --------------------------------------------------------------------------
   Logo / title — big by default, shrinks on .vxe-shrunk
   -------------------------------------------------------------------------- */
.featureSlider .vxe-billboard .slideLogo {
  transform-origin: bottom left;
  transition: transform var(--vxl-dur-4) var(--vxl-ease-io);
  margin-bottom: 18px !important;
}
.featureSlider .vxe-billboard .slideLogo img.innerSlideLogo {
  width: auto !important;
  max-width: clamp(200px, 30vw, 420px) !important;
  max-height: clamp(90px, 13vw, 200px) !important;
  object-fit: contain;
  object-position: bottom left;
}
.featureSlider .vxe-billboard .slideTitle {
  font-size: clamp(1.9rem, 4vw, 3.6rem) !important;
  line-height: 1.05;
  color: var(--vod-white-color, #fff);
  transform-origin: bottom left;
  transition: transform var(--vxl-dur-4) var(--vxl-ease-io);
  margin-bottom: 14px !important;
}
/* 26.499.0 — the admin's logo text standing in for a logo image. A mark, not
   a heading: display weight, tight tracking, the admin's own casing, and a
   balanced two-line wrap so "EMILY in PARIS" breaks like a lockup would. */
.featureSlider .vxe-billboard .slideTitle.vxe-wordmark {
  font-weight: 800;
  letter-spacing: var(--vxl-tracking-tight, -0.03em);
  text-transform: none;
  text-wrap: balance;
  max-width: 14ch;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.45);
}
/* shrink state — logo/title stay clearly visible, just smaller (Netflix keeps
   the logo prominent while the trailer plays). scale(0.55) read as "gone"; 0.72
   is a comfortable shrink that keeps it legible. The description fades out below
   (that collapse is intentional — matches Netflix), and the billboard row is
   bottom-anchored (align-items:flex-end above), so the logo + buttons stay
   pinned to the bottom-left and don't jump when the description collapses. */
.featureSlider .vxe-billboard.vxe-shrunk .slideLogo,
.featureSlider .vxe-billboard.vxe-shrunk .slideTitle {
  transform: scale(0.85);
}

/* --------------------------------------------------------------------------
   Description — visible by default, fades + collapses on shrink
   -------------------------------------------------------------------------- */
.featureSlider .vxe-billboard .text_description,
.featureSlider .vxe-billboard .text_description1 {
  font-size: clamp(0.9rem, 1.15vw, 1.35rem) !important;
  line-height: 1.5;
  color: color-mix(in srgb, var(--vod-white-color, #fff) 90%, transparent);
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.45);
  max-height: 8em;
  overflow: hidden;
  transition: opacity var(--vxl-dur-3) var(--vxl-ease), max-height var(--vxl-dur-4) var(--vxl-ease-io),
    margin var(--vxl-dur-4) var(--vxl-ease-io);
}
/* Owner call (critique round): the classic billboard description sat at a
   near-invisible step — one size up, slightly brighter ink. Cinematic keeps
   its own scale. */
@media (min-width: 992px) {
  body[data-lo-home-hero="band"] .featureSlider .vxe-billboard .text_description,
  body[data-lo-home-hero="band"] .featureSlider .vxe-billboard .text_description1 {
    font-size: clamp(1rem, 1.28vw, 1.45rem) !important;
    color: color-mix(in srgb, var(--vod-white-color, #fff) 96%, transparent);
  }
}

.featureSlider .vxe-billboard.vxe-shrunk .text_description,
.featureSlider .vxe-billboard.vxe-shrunk .text_description1 {
  opacity: 0;
  max-height: 0;
  margin-top: 0 !important;
  margin-bottom: 0 !important;
}

/* --------------------------------------------------------------------------
   Buttons — Play (solid) + More Info (translucent grey), stay put on shrink
   -------------------------------------------------------------------------- */
.featureSlider .vxe-billboard .sldieBtns {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 4px;
}
/* The row's markup carries Bootstrap's `d-none d-sm-block d-md-block
   d-lg-block`, and `.d-lg-block { display: block !important }` outranks the
   plain `display: flex` above. A block ignores `gap`, and the buttons'
   `margin: 0 !important` (26.141.0) had already retired the `mr-2` that used
   to space them, so on desktop the three pills sat 4px apart on inline
   whitespace (owner report, 2026-09-10). The centered and stacked CTA
   words below already force flex for the same reason; the default word
   needs it too. Desktop only: the phone hero lays this row out itself in
   mobile-app.css. */
@media (min-width: 992px) {
  .featureSlider .vxe-billboard .sldieBtns {
    display: flex !important;
  }
}
.featureSlider .vxe-billboard .sldieBtns .btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  /* Was em-padded (`0.55rem 1.9rem`) on a viewport-scaled label
     (`clamp(0.95rem, 1.15vw, 1.25rem)` — 16.6px at 1440, 20px at 1920).
     Two problems the owner saw as "swelled": the label outgrew the --lg
     tier's own 15.5px at every desktop width, and because the height was
     derived from content, a button WITH an icon measured 44px next to one
     without at 42 — the row never lined up. Fixed measure instead, the
     same 46/15.5/26 the --lg tier and the cinematic billboard use, so all
     layouts land on one control. Phones override this (mobile-app.css
     loads after this file and pins 44px). */
  height: 46px;
  padding: 0 26px !important;
  /* DS pill — this rule outweighs the paint rules below on specificity, so
     the radius must agree with them or the hero squares off while every
     other control in the storefront is a pill */
  border-radius: var(--vxl-btn-radius, 999px) !important;
  font-size: 15.5px !important;
  font-weight: 600 !important;
  margin: 0 !important;
}
.featureSlider .vxe-billboard .sldieBtns .btn .iconsize {
  /* width/height:auto works for an MDI font glyph but makes an inline SVG
     balloon to its intrinsic size. Pin to a fixed box that reads proportional
     to the ~15px button label (was ballooning to ~34px). */
  height: 20px !important;
  width: 20px !important;
  line-height: 1 !important;
  margin: 0 !important;
}
/* Play / Trailer — the tenant's PRIMARY button chain. The dedicated
   --vod-ep-playbutton-* knob is retired (#5350: derivation-owned) — post-
   curation saves derive it equal to the primary anyway, but LEGACY published
   themes still carry the old #fff default, and since a published var always
   wins its chain, leading with the ep name kept those billboards white
   forever (owner report: preview primary, storefront white). Primary leads;
   the ep vars remain as fallback for themes with no primary at all. */
.featureSlider .vxe-billboard .sldieBtns .btn.btn-editors-pick {
  background-color: var(--vod-btn-primary-bg, var(--vod-ep-playbutton-bg, var(--vod-ep-playbutton-color, #fff))) !important;
  border-color: var(--vod-btn-primary-bg, var(--vod-ep-playbutton-bg, var(--vod-ep-playbutton-color, #fff))) !important;
  color: var(--vod-btn-primary-text, var(--vod-ep-playbutton-text, #000)) !important;
  transition: background-color var(--vxl-dur-1) var(--vxl-ease),
              border-color var(--vxl-dur-1) var(--vxl-ease),
              filter var(--vxl-dur-1) var(--vxl-ease);
}
/* Hover. The billboard rule above is (0,5,0) !important, so the generic
   .btn.btn-editors-pick:hover further down — (0,3,0) — never got a look in:
   the default-state declaration kept winning WHILE the button was hovered,
   and Primary Button Hover was dead on the storefront's biggest CTA. Stating
   the hover chain at the billboard's own weight is what lets it through.
   brightness() stays on top: it is this hero's own touch, and it is the only
   feedback left on a theme whose hover is still equal to its background. */
.featureSlider .vxe-billboard .sldieBtns .btn.btn-editors-pick:hover,
.featureSlider .vxe-billboard .sldieBtns .btn.btn-editors-pick:focus {
  background-color: var(--vod-btn-primary-hover-bg, var(--vod-btn-primary-bg, var(--vod-ep-playbutton-bg, var(--vod-ep-playbutton-color, #fff)))) !important;
  border-color: var(--vod-btn-primary-hover-bg, var(--vod-btn-primary-bg, var(--vod-ep-playbutton-bg, var(--vod-ep-playbutton-color, #fff)))) !important;
  color: var(--vod-btn-primary-text, var(--vod-ep-playbutton-text, #000)) !important;
  filter: brightness(0.9);
}
/* More Info — the tenant's SECONDARY button chain, translucent grey by
   default. Same correction the play button above already carries: the
   dedicated --vod-ep-secondary-button-* knobs are retired (#5350:
   derivation-owned) and a curated save derives them equal to the secondary
   anyway — but they are still written into every published theme, and a
   published var always wins its chain, so leading with the ep name left the
   hero's More Info stuck on the stock grey no matter what the operator set
   under Advanced → Buttons (background, text, border AND hover, all four).
   Secondary leads; the ep vars remain the fallback for themes that carry no
   secondary at all. */
.featureSlider .vxe-billboard .sldieBtns .btn.btn-secondary {
  background-color: var(--vod-btn-secondary-bg, var(--vod-ep-secondary-button-bg, rgba(109, 109, 110, 0.7))) !important;
  border-color: var(--vod-btn-secondary-border, var(--vod-ep-secondary-button-border, transparent)) !important;
  color: var(--vod-btn-secondary-text, var(--vod-ep-secondary-button-text, var(--vod-white-color, #fff))) !important;
  /* An edge the tenant's palette cannot lose. Reported as "More Info is
     shorter than Play": both boxes measured 46px, but a tenant had the
     secondary at #1f1f1f with a #010101 border, and on dark artwork the
     slab's top and bottom rows dissolve into the photo — only the band
     around the label still reads as a button, so it LOOKS shorter beside
     the hard-edged primary. A 1px inner hairline of ink at low alpha keeps
     the full box legible on any backdrop without touching the tenant's
     fill or border colours. */
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--vod-white-color, #fff) 16%, transparent);
  transition: background-color var(--vxl-dur-1) var(--vxl-ease);
}
.featureSlider .vxe-billboard .sldieBtns .btn.btn-secondary:hover {
  background-color: var(--vod-btn-secondary-hover-bg, var(--vod-ep-secondary-button-hover-bg, rgba(109, 109, 110, 0.5))) !important;
}

/* --------------------------------------------------------------------------
   Controls — bottom-right mute / replay (trailer view types)
   -------------------------------------------------------------------------- */
/* controls sit just above the age tag on the right edge */
.featureSlider .vxe-controls {
  position: absolute;
  right: 0;
  bottom: calc(35% + 54px);
  z-index: 11;
  display: flex;
  align-items: center;
  gap: 12px;
  padding-right: 3%;
}
.featureSlider .vxe-ctrl {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  padding: 0;
  border-radius: 50%;
  background-color: rgba(0, 0, 0, 0.35);
  border: 1px solid color-mix(in srgb, var(--vod-white-color, #fff) 50%, transparent);
  border-color: color-mix(in srgb, var(--vod-white-color, #fff) 50%, transparent);
  color: var(--vod-white-color, #fff);
  cursor: pointer;
  transition: border-color var(--vxl-dur-1) var(--vxl-ease), background-color var(--vxl-dur-1) var(--vxl-ease);
}
.featureSlider .vxe-ctrl:hover {
  border-color: var(--vod-white-color, #fff);
  background-color: rgba(0, 0, 0, 0.55);
}
.featureSlider .vxe-ctrl .mdi,
.featureSlider .vxe-ctrl .vxm-ico {
  font-size: 20px;
  line-height: 1;
}

/* --------------------------------------------------------------------------
   Age-rating tag — Netflix vertical tab on the right edge
   -------------------------------------------------------------------------- */
.featureSlider .maturityLevel.vxe-agetag,
.featureSlider .maturityLevel {
  position: absolute;
  right: 0;
  bottom: 35%;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 6px 3% 6px 14px !important;
  border: 0 !important;
  border-left: 3px solid color-mix(in srgb, var(--vod-white-color, #fff) 85%, transparent) !important;
  background-color: var(--vxl-scrim, rgba(51, 51, 51, 0.6)) !important;
  color: var(--vod-white-color, #fff) !important;
  font-size: clamp(0.8rem, 1vw, 1.1rem) !important;
  letter-spacing: 0.02em;
}

/* --------------------------------------------------------------------------
   Legacy shadow layers — fold into the billboard gradient (avoid double-dark)
   -------------------------------------------------------------------------- */
.featureSlider .slideRightShadow,
.featureSlider .sliderInnerShadow {
  display: none;
}

/* The hero trailer is an AMBIENT muted preview — the native video.js control
   bar (seek/time/gear/volume) must never show over the billboard on any
   viewport; the custom .vxe-controls mute button is the only control. (Was
   bleeding through and breaking the mobile hero.) */
.featureSlider .video-js .vjs-control-bar,
.featureSlider .vjs-control-bar,
.featureSlider .video-js .vjs-big-play-button {
  display: none !important;
}

/* --------------------------------------------------------------------------
   Mobile — static billboard, no shrink; smaller logo, hide description,
   KEEP the Play / More Info buttons (Netflix mobile shows them), pin the age
   tag + mute control to the top-right.
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
  .featureSlider .swiperInfo.vxe-billboard {
    align-items: flex-end;
    padding: 0 16px 22px !important;
  }
  .featureSlider .swiperInfo.vxe-billboard .row > [class*="col-"],
  .vxe-billboard__col {
    max-width: 100% !important;
    flex: 0 0 100% !important;
  }
  .featureSlider .vxe-billboard .slideLogo img.innerSlideLogo {
    max-width: 160px !important;
    max-height: 74px !important;
  }
  .featureSlider .vxe-billboard .text_description,
  .featureSlider .vxe-billboard .text_description1 {
    display: none !important;
  }
  /* no shrink transform on mobile */
  .featureSlider .vxe-billboard.vxe-shrunk .slideLogo,
  .featureSlider .vxe-billboard.vxe-shrunk .slideTitle {
    transform: none;
  }
  /* The mobile hero action row (un-hiding it, its sizing, gap and padding) is
     owned by mobile-app.css, which matches it to the native app. It used to be
     duplicated here too — and since these selectors carry one more class, the
     copy here quietly won every property it shared, so the app-parity values
     never took effect. One owner only; the ellipsis rule below is the sole
     thing this file still contributes. */
  .featureSlider .vxe-billboard .sldieBtns .btn span {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .featureSlider .vxe-controls {
    bottom: auto;
    top: 118px; /* clear the mobile filter pills row (header 68px + pills) */
    gap: 8px;
  }
  .featureSlider .vxe-ctrl {
    width: 36px;
    height: 36px;
  }
  /* Kill any native video.js chrome (settings gear / big-play / spinner /
     error) that bleeds over the ambient mobile trailer — keep only the <video>
     tech + poster and the custom .vxe-controls mute button. */
  .featureSlider .video-js > *:not(.vjs-tech):not(video):not(.vjs-poster) {
    display: none !important;
  }
  /* Age tag: hidden on mobile — pinned top-right it collided with the header
     profile menu, and it isn't essential on the small hero. */
  .featureSlider .maturityLevel.vxe-agetag,
  .featureSlider .maturityLevel {
    display: none !important;
  }
}

/* --------------------------------------------------------------------------
   Reduced motion — no shrink/fade transitions
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .featureSlider .vxe-billboard .slideLogo,
  .featureSlider .vxe-billboard .slideTitle,
  .featureSlider .vxe-billboard .text_description,
  .featureSlider .vxe-billboard .text_description1 {
    transition: none;
  }
}

/* --------------------------------------------------------------------------
   RTL — anchor content right, flip gradient + controls/age tag to the left
   -------------------------------------------------------------------------- */
body.rtl .featureSlider .relative::before {
  background:
    linear-gradient(270deg, rgba(0, 0, 0, 0.72) 0%, rgba(0, 0, 0, 0.4) 26%, rgba(0, 0, 0, 0) 58%),
    linear-gradient(180deg, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 16%);
}
body.rtl .featureSlider .vxe-billboard .slideLogo,
body.rtl .featureSlider .vxe-billboard .slideTitle {
  transform-origin: bottom right;
}
body.rtl .featureSlider .vxe-billboard .slideLogo img.innerSlideLogo {
  object-position: bottom right;
}
body.rtl .featureSlider .vxe-controls {
  right: auto;
  left: 0;
  padding-right: 0;
  padding-left: 3%;
}
body.rtl .featureSlider .maturityLevel {
  right: auto;
  left: 0;
  border-left: 0 !important;
  border-right: 3px solid color-mix(in srgb, var(--vod-white-color, #fff) 85%, transparent) !important;
  padding: 6px 14px 6px 3% !important;
}

/* --------------------------------------------------------------------------
   Hero CTA paint — moved from the components.css adapter block when it was
   retired. The hero honours the tenant's editors-pick button chain, with the
   accent as the final fallback; pill per the 2026 DS. Hover prefers the
   tenant's own hover setting, then the derived accent hover.
   -------------------------------------------------------------------------- */
.btn.btn-editors-pick {
  border-radius: var(--vxl-btn-radius, 999px) !important;
  border: 0 !important;
  /* primary leads — the ep knob is retired (#5350); see the billboard rule
     above for why legacy #fff publishes must not own this chain */
  background: var(--vod-btn-primary-bg, var(--vod-ep-playbutton-bg, var(--vxl-accent, var(--vod-primary, #e50914)))) !important;
  color: var(--vod-btn-primary-text, var(--vod-ep-playbutton-text, #fff)) !important;
  font-weight: 600;
  transition: background-color var(--vxl-dur-1, 0.15s) ease, opacity var(--vxl-dur-1, 0.15s) ease;
}
.btn.btn-editors-pick:hover,
.btn.btn-editors-pick:focus {
  background: var(--vod-btn-primary-hover-bg, var(--vod-ep-playbutton-bg, var(--vxl-accent-hover))) !important;
  color: var(--vod-btn-primary-text, var(--vod-ep-playbutton-text, #fff)) !important;
  filter: brightness(1.08);
}

/* --------------------------------------------------------------------------
   Arrangement: hero_cta — the first layouts.json "options" entry
   (goals/layout-arrangement-spec.md). Stamped by body.html as
   data-lo-hero-cta from the tenant's saved choice; registry-validated, so
   only declared variants ever reach the DOM. Desktop only — the phone hero
   is the app-parity design and keeps its own arrangement. `left` is the
   default and needs no rules. ARRANGEMENT ONLY: no colours, no component
   restyling — that is components.css's job.
   -------------------------------------------------------------------------- */
@media (min-width: 992px) {
  /* centered — the whole info block sits centred in the frame */
  body[data-lo-hero-cta="centered"] .featureSlider .swiperInfo.vxe-billboard .row {
    justify-content: center;
  }
  body[data-lo-hero-cta="centered"] .featureSlider .swiperInfo.vxe-billboard .row > [class*="col-"],
  body[data-lo-hero-cta="centered"] .vxe-billboard__col {
    max-width: 56% !important;
    flex: 0 0 56% !important;
    text-align: center;
  }
  body[data-lo-hero-cta="centered"] .featureSlider .vxe-billboard .slideLogo img.innerSlideLogo {
    display: block;
    margin-inline: auto;
  }
  /* the shrink animation scales the logo from its origin — centred content
     must shrink toward its own middle, not drift to the left corner */
  body[data-lo-hero-cta="centered"] .featureSlider .vxe-billboard .slideLogo {
    transform-origin: bottom center;
  }
  /* width-capped text blocks are blocks, not lines: text-align centres their
     LINES, but the boxes themselves hug the column's left edge without
     auto margins — the one thing that made "centered" read broken.
     The text title is the same shape (cinematic caps it at 16ch) and also
     carries the logo's bottom-left shrink origin. */
  body[data-lo-hero-cta="centered"] .featureSlider .vxe-billboard .text_description,
  body[data-lo-hero-cta="centered"] .featureSlider .vxe-billboard .text_description1 {
    margin-inline: auto;
  }
  body[data-lo-hero-cta="centered"] .featureSlider .vxe-billboard .slideTitle {
    margin-inline: auto;
    text-align: center;
    transform-origin: bottom center;
  }
  body[data-lo-hero-cta="centered"] .featureSlider .vxe-billboard .sldieBtns {
    display: flex !important; /* cinematic flattens the box to block */
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
  }

  /* stacked — an app-style column of full-width buttons; text stays left.
     gap needs force: the cinematic hero restates the row's flex spacing at
     higher specificity, which zeroed the column's breathing room. */
  body[data-lo-hero-cta="stacked"] .featureSlider .vxe-billboard .sldieBtns {
    display: flex !important; /* cinematic flattens the box to block, which
                                 makes gap and flex-direction inert */
    flex-direction: column;
    align-items: stretch;
    max-width: 320px;
    gap: 10px !important;
  }
  /* hero_meta="clean" — the billboard speaks with title and buttons only */
  body[data-lo-hero-meta="clean"] .featureSlider .vxe-billboard .text_description,
  body[data-lo-hero-meta="clean"] .featureSlider .vxe-billboard .text_description1 {
    display: none !important;
  }

  body[data-lo-hero-cta="stacked"] .featureSlider .vxe-billboard .sldieBtns .btn {
    width: 100%;
    justify-content: center;
  }
}

/* --------------------------------------------------------------------------
   Arrangement: hero_button_gap — Snug / Standard / Roomy (26.502.0). The air
   between the billboard's action buttons, the tenant's call. Standard is the
   row's own 10px above; the other two restate the gap with !important so the
   Stacked CTA word (which pins its column gap the same way) follows the word
   too. Desktop only, like the row rule it arranges.
   -------------------------------------------------------------------------- */
@media (min-width: 992px) {
  body[data-lo-hero-button-gap="snug"] .featureSlider .vxe-billboard .sldieBtns {
    gap: 6px !important;
  }
  body[data-lo-hero-button-gap="roomy"] .featureSlider .vxe-billboard .sldieBtns {
    gap: 18px !important;
  }
}

/* --------------------------------------------------------------------------
   Arrangement: home_hero="fullbleed" — the billboard as a letterboxed
   dissolve (formerly the whole personality of the cinematic layout). The
   bottom gradient melts the artwork into the page background and the sides
   are vignetted, so the image has no hard edge anywhere; type is the single
   loudest thing on the page; the billboard finishes, THEN the page begins.
   Scrims come from the tenant's body colour, so a light palette dissolves to
   white just as correctly. `band` is the default and needs no rules.
   -------------------------------------------------------------------------- */
body[data-lo-home-hero="fullbleed"] {
  --vxl-hero-h: 86vh;
}
body[data-lo-home-hero="fullbleed"] .featureSlider {
  position: relative;
}
@media (min-width: 992px) {
  /* Scrims live on `.relative`, not on `.featureSlider` — the billboard sits
     inside a `z-index: 1` stacking context, so an overlay on `.featureSlider`
     paints over the hero text as well as the art.
     ::before = left scrim (the title's ground) + soft side/top vignettes. */
  body[data-lo-home-hero="fullbleed"] .featureSlider .relative::before {
    background:
      linear-gradient(90deg,
        var(--vxl-scrim) 0%,
        var(--vxl-scrim-weak) 30%,
        transparent 58%),
      linear-gradient(270deg, var(--vxl-scrim-weak) 0%, transparent 22%),
      linear-gradient(180deg, var(--vxl-scrim-weak) 0%, transparent 16%);
  }
  /* ::after = the deep bottom dissolve that melts the billboard into the page */
  body[data-lo-home-hero="fullbleed"] .featureSlider .relative::after {
    height: 40vh;
    background: linear-gradient(0deg,
      var(--vxl-scrim-solid) 0%,
      var(--vxl-scrim-solid) 6%,
      var(--vxl-scrim) 42%,
      transparent 100%);
  }

  /* Billboard → first rail: the element after the billboard carries
     `margin-top: -5vw !important` (the Netflix habit of riding the first
     rail up over the hero). Full-bleed wants the opposite: the billboard
     finishes, then the page begins. Mirrors the ID rule above exactly (an
     ID rule, so nothing shorter can win) and turns the pull into space. */
  body[data-lo-home-hero="fullbleed"].page-home #new-editorpick {
    margin-bottom: 64px !important;
  }
  body[data-lo-home-hero="fullbleed"] #items-list .featureSlider + div {
    margin-top: 32px !important;
  }
  /* The billboard's copy sits 34px above the dissolve's bottom edge, not
     7vw: this was a phone rule of the cinematic sheet that also applied on
     desktop (it lived in an @media all block), and it is the position every
     Cinematic tenant has been looking at — kept as the full-bleed measure
     rather than corrected on their behalf. */
  body[data-lo-home-hero="fullbleed"] .vxe-mob-portrait .swiperInfo.vxe-billboard,
  body[data-lo-home-hero="fullbleed"] .vxe-mob-landscape .swiperInfo.vxe-billboard {
    padding-top: 0 !important;
    padding-bottom: 34px !important;
  }
}

/* Type: the single loudest thing on the page */
body[data-lo-home-hero="fullbleed"] .featureSlider .vxe-billboard .slideTitle {
  font-size: clamp(2.4rem, 5vw, 4.5rem) !important;
  font-weight: 700;
  letter-spacing: var(--vxl-tracking-tight);
  line-height: 1.05;
  max-width: 16ch;
}
/* 26.499.0 — the wordmark keeps its mark weight under the full-bleed word
   (the rule above sets 700 with a body-attribute selector, which outranks
   the plain wordmark rule at the top of the sheet) */
body[data-lo-home-hero="fullbleed"] .featureSlider .vxe-billboard .slideTitle.vxe-wordmark {
  font-weight: 800;
  text-transform: none;
  letter-spacing: var(--vxl-tracking-tight, -0.03em);
  max-width: 14ch;
}
body[data-lo-home-hero="fullbleed"] .featureSlider .vxe-billboard .slideLogo img.innerSlideLogo {
  max-width: clamp(240px, 34vw, 500px) !important;
  max-height: clamp(100px, 15vw, 230px) !important;
}
body[data-lo-home-hero="fullbleed"] .featureSlider .vxe-billboard .text_description,
body[data-lo-home-hero="fullbleed"] .featureSlider .vxe-billboard .text_description1 {
  max-width: 46ch;
  color: var(--vxl-ink-muted);
}
/* Glyphs track the larger label so the pairing stays balanced. */
body[data-lo-home-hero="fullbleed"] .featureSlider .vxe-billboard .sldieBtns .btn .vxm-ico,
body[data-lo-home-hero="fullbleed"] .featureSlider .vxe-billboard .sldieBtns .btn svg,
body[data-lo-home-hero="fullbleed"] .featureSlider .vxe-billboard .sldieBtns .btn i {
  width: 22px !important;
  height: 22px !important;
  font-size: 22px !important;
}

/* Maturity rating — the stock style is a tab welded to the viewport edge at
   bottom:35%, which floats mid-artwork with no gutter and reads as a clipped
   fragment rather than a label. Bring it onto the page gutter and align its
   baseline with the billboard's button row (both measured in the same 7vw the
   billboard pads with), so it belongs to the content block. */
body[data-lo-home-hero="fullbleed"] .featureSlider .maturityLevel.vxe-agetag,
body[data-lo-home-hero="fullbleed"] .featureSlider .maturityLevel {
  right: var(--vxl-gutter) !important;
  bottom: 7vw !important;
  padding: 5px var(--vxl-space-3) !important;
  border-left-width: 3px !important;
  border-radius: var(--vxl-radius-sm) !important;
  font-size: var(--vxl-text-sm) !important;
  min-height: 0 !important;
  /* the chip vanished on light artwork — a scrim ground + soft blur keep it
     legible everywhere */
  background: color-mix(in srgb, var(--vod-body-back-color, #0e0e10) 52%, transparent) !important;
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
}

/* --------------------------------------------------------------------------
   Arrangement: home_hero="banner" — a shorter frame, inset from the page
   edges under the header, with the tiles' corner. The other two words fill
   the screen and differ only in how they meet the page (rails riding up
   over the foot vs a dissolve with the rails below), which on dark artwork
   reads as no difference at all (owner report, 26.485.0) — this one is the
   visibly different shape. Desktop only: the phone billboard is the app
   shell's own inset card already.
   -------------------------------------------------------------------------- */
@media (min-width: 992px) {
  body[data-lo-home-hero="banner"] {
    /* The frame keeps a wide-screen ASPECT rather than a viewport-height
       cap: 58vh at 1920 made a 3:1 letterbox strip that showed the top
       third of a 16:9 still (owner report). 21:9 of the inset width, and
       never taller than two thirds of the viewport, so a 16:9 still loses
       its edges, not its subject. */
    /* 40vw ≈ 21:9 of the inset width (94vw × 9/21). Stated in vw, not via
       the gutter token: a percentage inside a height calc resolves against
       the parent's height, which is auto here, and the frame collapsed. */
    --vxl-hero-h: min(66vh, 40vw);
  }
  /* crop from the middle: the shared hero rule pins the crop to the top for
     the full-screen frames (their bottom is under the dissolve anyway); in
     a banner that cut every subject off at the chin */
  body[data-lo-home-hero="banner"] .featureSlider .ratio.ratio-16x9 > div,
  body[data-lo-home-hero="banner"] .featureSlider .ratio.ratio-16x9 img.imgFull,
  body[data-lo-home-hero="banner"] .featureSlider .ratio.ratio-16x9 > video {
    object-position: center 35% !important;
  }
  /* the home shell pulls the hero up under the transparent header
     (`#new-editorpick { margin-top: -64px }` against the slider's +64); the
     banner sits BELOW the header instead, with a beat of page above it */
  body[data-lo-home-hero="banner"].page-home #new-editorpick,
  body[data-lo-home-hero="banner"].page-movies #new-editorpick,
  body[data-lo-home-hero="banner"].page-tv_shows #new-editorpick,
  body[data-lo-home-hero="banner"].page-content_list_group #new-editorpick {
    /* the offset lives on the slider below: a top margin here collapses
       through .featureSlider and the larger of the two (its 64px) wins */
    margin-top: 0 !important;
    margin-inline: var(--vxl-gutter) !important;
    width: auto !important;
    border-radius: var(--vxl-radius-lg);
    /* legacy-override: vodlix.css unsets the swiper container's overflow so
       the dwell panels can spill; inset like this, the neighbouring slides
       would show beside the frame — clip them */
    overflow: hidden !important;
  }
  /* The corner is clipped on the artwork box and on the scrim layers, not
     on the swiper container — the container keeps `overflow: visible` for
     the dwell panels, and a corner on it alone would clip nothing. */
  body[data-lo-home-hero="banner"] .featureSlider .ratio.ratio-16x9,
  body[data-lo-home-hero="banner"] .featureSlider .relative::before,
  body[data-lo-home-hero="banner"] .featureSlider .relative::after {
    border-radius: var(--vxl-radius-lg);
  }
  body[data-lo-home-hero="banner"] .featureSlider .relative::after {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
  }
  /* The home shell lands the frame's top on the header's own top edge
     (`#items-list .featureSlider { margin-top: 64px }` against the content
     pulled up under the fixed header). 84 leaves a 16px beat under the
     68px header. Mirrors the ID rule exactly (an ID rule, so nothing
     shorter can win). */
  body[data-lo-home-hero="banner"] #items-list .featureSlider {
    margin-top: 84px !important;
  }
  /* the first rail no longer rides up over the hero — mirrors the ID rule
     above (an ID rule, so nothing shorter can win) and turns the pull into
     one section beat */
  body[data-lo-home-hero="banner"] #items-list .featureSlider + div,
  body[data-lo-home-hero="banner"] .featureSlider.vxe-ep-standalone + .overLapEditor,
  body[data-lo-home-hero="banner"] .featureSlider.vxe-ep-standalone + [id] {
    margin-top: 28px !important;
  }
  /* copy sits on a fixed inset inside the frame rather than the page gutter
     (the frame already carries the gutter) */
  body[data-lo-home-hero="banner"] .featureSlider .swiperInfo.vxe-billboard {
    padding: 0 40px 40px !important;
  }
  /* the age tag sits in the frame's top-right corner — a tab welded
     mid-way down the frame's edge read as a fragment */
  body[data-lo-home-hero="banner"] .featureSlider .maturityLevel.vxe-agetag,
  body[data-lo-home-hero="banner"] .featureSlider .maturityLevel {
    top: 20px !important;
    bottom: auto !important;
    right: 20px !important;
    border-radius: var(--vxl-radius-sm) !important;
  }
}
