/* ================================================================== */
/* Jambo Header — YouTube-style                                       */
/* ================================================================== */

.jambo-header {
    position: sticky;
    top: 0;
    z-index: 1000;
    background: rgba(10, 10, 10, 0.75);
    backdrop-filter: blur(20px) saturate(1.5);
    -webkit-backdrop-filter: blur(20px) saturate(1.5);
    border-bottom: 1px solid rgba(255,255,255,0.06);
}

/* Override old template padding that was for the fixed header. */
.custom-header-relative .main-content {
    padding-top: 0 !important;
}

/* ---- Row 1: Main bar ---- */
.jambo-header__bar {
    padding: 0.5rem 0;
}

.jambo-header__logo img {
    height: 36px;
    width: auto;
}

.jambo-header__menu-btn {
    background: none;
    border: 0;
    color: rgba(255,255,255,0.85);
    font-size: 1.5rem;
    padding: 0.375rem;
    line-height: 1;
    cursor: pointer;
    border-radius: 50%;
    transition: background 0.15s;
    display: flex;
    align-items: center;
    justify-content: center;
}
.jambo-header__menu-btn:hover {
    background: rgba(255,255,255,0.1);
}

/* Subscribe badge after logo */
.jambo-subscribe-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.25rem 0.625rem;
    border-radius: 1rem;
    font-size: 0.75rem;
    font-weight: 600;
    color: #f59e0b;
    background: rgba(245,158,11,0.12);
    border: 1px solid rgba(245,158,11,0.25);
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s, border-color 0.15s;
}
.jambo-subscribe-badge:hover {
    background: rgba(245,158,11,0.2);
    border-color: rgba(245,158,11,0.4);
    color: #f59e0b;
}
.jambo-subscribe-badge i {
    font-size: 0.8rem;
}

/* Refer & earn badge — same shape as the subscribe badge, brand blue */
.jambo-refer-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.25rem 0.625rem;
    border-radius: 1rem;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--bs-primary, #FF6C02);
    background: rgba(var(--bs-primary-rgb, 255, 108, 2), 0.12);
    border: 1px solid rgba(var(--bs-primary-rgb, 255, 108, 2), 0.25);
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s, border-color 0.15s;
}
.jambo-refer-badge:hover {
    background: rgba(var(--bs-primary-rgb, 255, 108, 2), 0.2);
    border-color: rgba(var(--bs-primary-rgb, 255, 108, 2), 0.4);
    color: var(--bs-primary, #FF6C02);
}
.jambo-refer-badge i {
    font-size: 0.8rem;
}

/* ---- Search bar ----
 * The header search, one set of rules (2026-09-26). The first styles
 * (04-17) lived here; 1.4.4 (e4fab19) restyled the pill, the button and
 * the dropdown in an inline <style> in header-default.blade.php without
 * removing them, so their leftovers leaked into the new design: on a phone
 * `bottom: 0` collapsed the row to its padding and hung the pill over the
 * genre bar, and from 992 to 1199 the bar floated under the header. These
 * are 1.4.4's values, moved here per ADR-0001 and the inline block deleted.
 * Jambo's own classes; no vendor rule is overridden.
 */
.jambo-header__search {
    position: relative;
    max-width: 560px;
    margin: 0 auto;
}

.jambo-search-form {
    display: flex;
    align-items: center;
    gap: 6px;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 999px;
    padding: 4px 4px 4px 18px;
    transition: border-color 0.18s ease, background 0.18s ease;
}
.jambo-search-form:focus-within {
    border-color: var(--bs-primary);
    background: rgba(255, 255, 255, 0.09);
}
.jambo-search-input {
    flex: 1 1 auto;
    min-width: 0;
    background: transparent;
    border: 0;
    outline: 0;
    color: var(--bs-body-color, #fff);
    font-size: 14px;
    line-height: 1.4;
    padding: 8px 0;
}
.jambo-search-input::placeholder {
    color: rgba(255, 255, 255, 0.45);
}
.jambo-search-btn {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 0;
    background: var(--bs-primary);
    color: #fff;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background 0.18s ease, transform 0.12s ease;
}
.jambo-search-btn:hover { background: var(--bs-primary); filter: brightness(1.1); }
.jambo-search-btn:active { transform: scale(0.94); }
.jambo-search-btn i { font-size: 16px; line-height: 1; }

/* Mobile: search bar hidden, toggle icon visible */
.jambo-header__search-toggle {
    background: none;
    border: 0;
    color: rgba(255,255,255,0.85);
    font-size: 1.25rem;
    width: 2.25rem;
    height: 2.25rem;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    border-radius: 50%;
    transition: background 0.15s;
    flex-shrink: 0;
}
.jambo-header__search-toggle:hover {
    background: rgba(255,255,255,0.1);
}

@media (min-width: 992px) {
    .jambo-header__search-toggle { display: none !important; }
    .jambo-header__search { display: block !important; }
}
@media (max-width: 991.98px) {
    .jambo-header__bar .container-fluid {
        gap: 0.5rem !important;
    }
    .jambo-header__logo img {
        height: 28px;
    }
    /* The magnifier opens the search as a full-width row below the header,
       and the dropdown hangs from the row. Below 992 only, because that is
       where the magnifier exists (`d-lg-none`). `z-index` keeps the row over
       the page it opens on. */
    .jambo-header__search {
        display: none;
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        max-width: none;
        z-index: 10;
        padding: 10px 14px 14px;
        background: var(--bs-body-bg, #0f0f15);
        border-top: 1px solid rgba(255, 255, 255, 0.06);
    }
    .jambo-header__search.jambo-search--expanded {
        display: block;
    }
    .jambo-header__right {
        gap: 0 !important;
    }
    .jambo-header__icon,
    .jambo-header__search-toggle {
        width: 2rem;
        height: 2rem;
        font-size: 1.125rem;
    }
    .jambo-header__avatar img {
        width: 28px;
        height: 28px;
    }
}

/* ---- Search results dropdown (1.4.4; see "Search bar" above) ---- */
.jambo-search-results {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    right: 0;
    z-index: 1050;
    background: var(--bs-body-bg, #0f0f15);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: 12px;
    box-shadow: 0 18px 48px rgba(0, 0, 0, 0.55);
    overflow: hidden;
    max-height: 70vh;
    overflow-y: auto;
}
.jambo-search-results[hidden] { display: none; }

.jambo-search-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    color: var(--bs-body-color, #fff);
    text-decoration: none;
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
    transition: background 0.12s ease;
}
.jambo-search-item:last-of-type { border-bottom: 0; }
.jambo-search-item:hover,
.jambo-search-item.is-active {
    background: rgba(var(--bs-primary-rgb, 229, 9, 20), 0.12);
    color: #fff;
}
.jambo-search-thumb {
    width: 44px;
    height: 62px;
    flex: 0 0 auto;
    object-fit: cover;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.04);
}
.jambo-search-info {
    min-width: 0;
    flex: 1 1 auto;
}
.jambo-search-title {
    font-size: 14px;
    font-weight: 500;
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.jambo-search-meta {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.55);
    margin-top: 2px;
}
.jambo-search-empty {
    padding: 22px 16px;
    text-align: center;
    color: rgba(255, 255, 255, 0.55);
    font-size: 13px;
}
.jambo-search-all {
    display: block;
    padding: 10px 14px;
    text-align: center;
    font-size: 13px;
    font-weight: 500;
    color: var(--bs-primary);
    text-decoration: none;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    background: rgba(255, 255, 255, 0.02);
    transition: background 0.12s ease;
}
.jambo-search-all:hover,
.jambo-search-all.is-active {
    background: rgba(var(--bs-primary-rgb, 229, 9, 20), 0.14);
    color: #fff;
}

/* ---- Right side icons ---- */
.jambo-header__right {
    gap: 0.25rem !important;
}
.jambo-header__icon {
    color: rgba(255,255,255,0.85);
    font-size: 1.25rem;
    width: 2.25rem;
    height: 2.25rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    transition: background 0.15s, color 0.15s;
    flex-shrink: 0;
}
.jambo-header__icon:hover {
    background: rgba(255,255,255,0.1);
    color: #fff;
}

/* Unread-notification count badge on the bell icon. Absolute-positioned
   relative to .jambo-header__icon so it sits on the top-right corner
   without affecting the icon's hit target. */
.jambo-notif-badge {
    position: absolute;
    top: 2px;
    right: 2px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    background: var(--bs-primary, #FF6C02);
    color: #fff;
    border-radius: 999px;
    font-size: 10px;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
    pointer-events: none;
    box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.8);
}

.jambo-header__avatar {
    display: flex;
    align-items: center;
    flex-shrink: 0;
}
.jambo-header__avatar img {
    cursor: pointer;
    border: 2px solid transparent;
    transition: border-color 0.15s;
}
.jambo-header__avatar img:hover {
    border-color: rgba(255,255,255,0.3);
}

/* User dropdown */
.jambo-user-dropdown {
    background: #1a1a1a;
    border: 1px solid rgba(255,255,255,0.1) !important;
    border-radius: 0.75rem !important;
    min-width: 240px;
    overflow: hidden;
    box-shadow: 0 8px 24px rgba(0,0,0,0.6);
}
.jambo-user-dropdown .dropdown-item {
    color: rgba(255,255,255,0.85);
    font-size: 0.875rem;
}
.jambo-user-dropdown .dropdown-item:hover {
    background: rgba(255,255,255,0.08);
    color: #fff;
}
.jambo-user-dropdown .dropdown-item i {
    font-size: 1.1rem;
    opacity: 0.7;
}

/* ---- Row 2: Genre chips bar ---- */
.jambo-genres-bar {
    padding: 0.5rem 0;
}

.jambo-genres-scroll {
    display: flex;
    gap: 0.5rem;
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 2px;
    /* Fade edges */
    mask-image: linear-gradient(to right, transparent 0, #000 1rem, #000 calc(100% - 1rem), transparent 100%);
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 1rem, #000 calc(100% - 1rem), transparent 100%);
}
.jambo-genres-scroll::-webkit-scrollbar {
    display: none;
}

.jambo-genre-chip {
    flex-shrink: 0;
    padding: 0.375rem 0.875rem;
    border-radius: 0.5rem;
    font-size: 0.8125rem;
    font-weight: 500;
    color: rgba(255,255,255,0.85);
    background: rgba(255,255,255,0.1);
    text-decoration: none;
    white-space: nowrap;
    transition: background 0.15s, color 0.15s;
}
.jambo-genre-chip:hover {
    background: rgba(255,255,255,0.2);
    color: #fff;
}
.jambo-genre-chip.active {
    background: #fff;
    color: #000;
}

/* ================================================================== */
/* Desktop sidebar (YouTube-style, expands on hamburger click)        */
/* ================================================================== */

.jambo-sidebar {
    position: fixed;
    top: 0;
    left: 0;
    width: 240px;
    height: 100vh;
    background: #111;
    z-index: 1100;
    transform: translateX(-100%);
    transition: transform 0.25s ease;
    overflow-y: auto;
    padding-top: 3.5rem;
    scrollbar-width: thin;
    scrollbar-color: rgba(255,255,255,0.1) transparent;
    display: none;
}
@media (min-width: 992px) {
    .jambo-sidebar { display: block; }
}
.jambo-sidebar--open {
    transform: translateX(0);
}

.jambo-sidebar__inner {
    padding: 0.5rem 0;
}

.jambo-sidebar__link {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.625rem 1.25rem;
    color: rgba(255,255,255,0.8);
    text-decoration: none;
    font-size: 0.875rem;
    font-weight: 400;
    transition: background 0.12s;
    border-radius: 0.5rem;
    margin: 0.125rem 0.5rem;
}
.jambo-sidebar__link:hover {
    background: rgba(255,255,255,0.08);
    color: #fff;
}
.jambo-sidebar__link.active {
    background: rgba(255,255,255,0.12);
    color: #fff;
    font-weight: 500;
}
.jambo-sidebar__link i {
    font-size: 1.25rem;
    flex-shrink: 0;
    opacity: 0.8;
}
.jambo-sidebar__link.active i {
    opacity: 1;
}

.jambo-sidebar__divider {
    height: 1px;
    background: rgba(255,255,255,0.08);
    margin: 0.5rem 1rem;
}

/* ================================================================== */
/* Mobile bottom navigation                                            */
/* ================================================================== */

.jambo-mobile-nav {
    display: none;
    position: fixed;
    bottom: 0;
    /* Bind to the VISUAL viewport, not the containing block. With
       `left: 0; right: 0` the nav fills its containing block (the
       initial containing block / layout viewport). On mobile, ANY
       element on the page that escapes 100% width — a swiper wrapper
       with a transform, an oversized image, a vendor stylesheet that
       sets `width: 1920px` — extends the layout viewport past the
       screen. The nav then renders that wider, with the rightmost
       tabs sliding offscreen.

       `width: 100vw` + `left: 0` is bound to the visual viewport
       directly; `max-width: 100%` falls back to 100% when 100vw
       includes a phantom scrollbar (rare on mobile, defensive). The
       inner flex layout still distributes the four items evenly. */
    left: 0;
    right: auto;
    width: 100vw;
    max-width: 100%;
    box-sizing: border-box;
    z-index: 1000;
    background: rgba(10, 10, 10, 0.85);
    backdrop-filter: blur(20px) saturate(1.5);
    -webkit-backdrop-filter: blur(20px) saturate(1.5);
    border-top: 1px solid rgba(255,255,255,0.08);
    padding: 0.375rem 0.5rem calc(0.375rem + env(safe-area-inset-bottom, 0));
    justify-content: space-around;
    align-items: center;
}

@media (max-width: 991.98px) {
    .jambo-mobile-nav { display: flex; }
    /* Push content above the bar so the last section isn't hidden behind it. */
    body { padding-bottom: calc(3.75rem + env(safe-area-inset-bottom, 0)); }
}

.jambo-mobile-nav__item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.125rem;
    padding: 0.375rem 0.25rem;
    color: rgba(255,255,255,0.65);
    text-decoration: none;
    font-size: 0.6875rem;
    font-weight: 500;
    border-radius: 0.75rem;
    transition: color 0.15s, background 0.15s;
    min-width: 0;
}
.jambo-mobile-nav__item:hover {
    color: rgba(255,255,255,0.9);
}
.jambo-mobile-nav__item.is-active {
    color: #fff;
}

.jambo-mobile-nav__icon {
    font-size: 1.5rem;
    line-height: 1;
    display: block;
}
.jambo-mobile-nav__icon--active {
    display: none;
}
.jambo-mobile-nav__item.is-active .jambo-mobile-nav__icon {
    display: none;
}
.jambo-mobile-nav__item.is-active .jambo-mobile-nav__icon--active {
    display: block;
}

.jambo-mobile-nav__label {
    display: block;
    line-height: 1.2;
    letter-spacing: 0.01em;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}

/* Overlay behind sidebar */
.jambo-sidebar-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.5);
    z-index: 1099;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.25s;
}
.jambo-sidebar-overlay--visible {
    opacity: 1;
    pointer-events: auto;
}

/* ================================================================== */
/* /movie banner — responsive fix                                      */
/* ================================================================== */
/*
 * The movie-slider partial sets background-image inline but the
 * Streamit SCSS for .movie-banner-image is missing background-size /
 * background-position. On mobile that means the 1920x1080 backdrop
 * renders at its native pixel width, blowing the page horizontally
 * out of the viewport — which then misaligns the fixed bottom nav
 * and makes the whole page feel "not responsive". This block fixes
 * that without touching the Vite SCSS pipeline. Same rule on every
 * screen, so add it outside any media query.
 */
.movie-banner-image {
    background-size: cover;
    background-position: center center;
    background-repeat: no-repeat;
    /* Defensive: hard-cap horizontal width to the viewport so even
       if a future inline style or child element tries to push wider,
       the parent never blows out. */
    max-width: 100%;
}
.banner-container,
.movie-banner,
.movie-banner .swiper-banner-container {
    max-width: 100%;
    overflow-x: hidden;
}

/* ================================================================== */
/* Mobile horizontal-overflow guard                                    */
/* ================================================================== */
/*
 * Cap body width to the viewport on phones / portrait tablets so any
 * accidental overflow (too-wide swiper wrapper, oversized image,
 * stray `width: 1920px` from a vendor SCSS) doesn't push the layout
 * viewport wider than the screen — when that happens
 * `.jambo-mobile-nav` (position:fixed; right:0) anchors to the
 * document's right edge and slides Series / Watchlist offscreen.
 *
 * Scoped to <body> (not <html>) and to <992px only because:
 *   1. `overflow-x: clip` on <html> interferes with the fullscreen
 *      API in some browsers — the fullscreen target gets clipped
 *      against the html overflow setting on mobile WebKit.
 *   2. Desktop has a horizontal scrollbar to fall back on if some
 *      weird overflow ever happens, and the bottom nav doesn't
 *      exist there. No need to clip.
 *
 * `clip` is preferred over `hidden`: it doesn't create a scroll
 * container, so position:sticky inside still works. Falls back to
 * `hidden` on older browsers via the cascade.
 */
@media (max-width: 991.98px) {
    body {
        overflow-x: hidden;
        overflow-x: clip;
    }

    /* ========================================================== */
    /* THE actual /movie + /series + /vj overflow source           */
    /* ========================================================== */
    /*
     * Streamit's SCSS sets `.card-style-slider .swiper { overflow:
     * visible }` so the card-hover :hover effect can extend ~12%
     * past the swiper boundary on desktop. Mobile has no hover
     * state, but the visible overflow still leaks every VJ row's
     * swiper-wrapper (7+ slides * card width = far wider than the
     * phone viewport) past the right edge of the screen.
     *
     * That horizontal overflow is what extends the document width
     * on /movie, which then anchored the bottom nav offscreen.
     * Kill the visible overflow on mobile only — hover effects
     * weren't usable on touch anyway, so nothing visual is lost.
     */
    .card-style-slider .swiper,
    .card-style-slider .swiper-card,
    .swiper.swiper-card {
        overflow: hidden !important;
    }
}

/* ================================================================== */
/* .btn-ghost — back / cancel / subtle secondary action               */
/* ================================================================== */
/*
 * Used in 30+ places across the app per docs/ui-guidelines.md and
 * docs/final-polish.md ("Ghost = back/cancel only"), but the class
 * itself was never defined anywhere — Bootstrap doesn't ship it.
 * Result: every "Mark all read", "Back to list", "Clear filter"
 * button rendered as plain unstyled text on dark cards, invisible
 * to most users.
 *
 * Defined here on jambo-header.css because it's loaded site-wide
 * by Modules/Frontend/.../layouts/master.blade.php — covers the
 * frontend (user inbox + profile-hub) without a Vite rebuild.
 * Admin panel uses dashboard/* CSS — admin "Back to list" buttons
 * are still invisible until we either add this rule there too or
 * migrate the admin button class.
 *
 * Neutral grey hover so the rule works equally well on the dark
 * theme the streaming pages use AND any light surface.
 */
.btn-ghost {
    background-color: transparent;
    border: 1px solid transparent;
    color: inherit;
}

.btn-ghost:hover,
.btn-ghost:focus-visible {
    background-color: rgba(127, 127, 127, 0.14);
    color: inherit;
}

.btn-ghost:active {
    background-color: rgba(127, 127, 127, 0.22);
}

.btn-ghost:focus-visible {
    outline: 2px solid var(--bs-primary, #FF6C02);
    outline-offset: 2px;
}

.btn-ghost:disabled,
.btn-ghost.disabled {
    opacity: 0.5;
    pointer-events: none;
}



/* ================================================================== */
/* Archive-page poster grid — one universal card size matching the    */
/* homepage rails (8 across desktop, 4 tablet, 3 mobile). Bootstrap   */
/* only ships row-cols-*-1..6, so the 7/8-column steps live here.     */
/* ================================================================== */
@media (min-width: 1200px) {
    .row-cols-xl-7 > * {
        flex: 0 0 auto;
        width: 14.2857143%;
    }

    .row-cols-xl-8 > * {
        flex: 0 0 auto;
        width: 12.5%;
    }
}


/* ================================================================== */
/* Hero + banner height — cap the vh-based vendor rules on tall       */
/* viewports                                                          */
/* ================================================================== */
/*
 * Streamit sizes every desktop hero from the viewport HEIGHT alone:
 *   OTT home hero   (.iq-banner-thumb-slider, hero-banner.blade)   92vh
 *   guest home hero (.banner-home-swiper, index-page.blade)        92vh
 *   listing banner  (.movie-banner, movie-slider.blade: /movie,
 *                    /series, /upcoming, /genres/*, VJ pages)      72vh
 * On a 16:9 monitor 92vh is roughly a widescreen frame of the width,
 * so it reads as intended. On a portrait or 5:4 screen the same rule
 * made a 1069px-wide hero 1560px tall: title and CTA in the middle,
 * empty backdrop above and below, and a full screen to scroll past
 * before the first rail (report: "huge uncontrolled spacing for
 * vertical screens").
 *
 * Fix: the vendor value stays as the ceiling, but a hero can never be
 * taller than a widescreen frame of the viewport WIDTH. The floor
 * keeps title, meta, synopsis, tags, CTA and (OTT) the poster rail
 * from being squeezed on short landscape windows. On 16:9 landscape
 * clamp() resolves to the vendor value, so desktop monitors do not
 * change; only tall viewports get shorter heroes.
 *
 * Desktop-only on purpose: below Streamit's own mobile breakpoints
 * (lg for the home heroes, 999px for .movie-banner) the vendor SCSS
 * already replaces these vh rules with content-driven height
 * (`min-height: inherit` + padding), and the caps must not fire there.
 * Selectors mirror the vendor chains exactly so equal specificity plus
 * load order (this file loads after the Vite bundle) wins without
 * !important.
 */
:root {
    --jambo-hero-max-h: 56.25vw;   /* a 16:9 frame of the viewport width */
    --jambo-hero-min-h: 34em;      /* OTT hero: content + poster rail */
    --jambo-banner-max-h: 50vw;    /* listing banners sit a little lower */
    --jambo-banner-min-h: 26em;
}

@media (min-width: 992px) {
    /* OTT home hero — the post-login landing at "/" */
    .iq-banner-thumb-slider .slider .slider-bg .slider-images .slider--image,
    .iq-banner-thumb-slider .slider .slider-bg .slider-images .swiper-wrapper .banner-bg .slider-content-full-height {
        min-height: clamp(var(--jambo-hero-min-h), var(--jambo-hero-max-h), 92vh);
    }

    /* Guest home hero — "/home" */
    .banner-home-swiper,
    .banner-home-swiper .banner-home-swiper-image,
    .banner-home-swiper .slider-content-full-height {
        min-height: clamp(var(--jambo-hero-min-h), var(--jambo-hero-max-h), 92vh);
    }
}

@media (min-width: 1000px) {
    /* Listing banner — /movie, /series, /upcoming, /genres/*, VJ pages */
    .movie-banner .swiper-banner-container,
    .movie-banner .movie-banner-image,
    .movie-banner .slider-content-full-height {
        min-height: clamp(var(--jambo-banner-min-h), var(--jambo-banner-max-h), 72vh);
    }
}

/* ================================================================== */
/* Movie / series detail hero — drop the phantom header allowance     */
/* ================================================================== */
/*
 * Streamit sizes the detail hero as a padded box:
 *   .iq-main-slider.site-video { padding-bottom: calc(42% + var(--header-height, 5em)) }
 * The `+ header` compensated for the template's fixed, transparent
 * header overlapping the top of the hero. Jambo's header is sticky and
 * in flow (see "Override old template padding" at the top of this
 * file) and --header-height is never defined, so the 5em fallback put
 * ~80px of black below the backdrop on every movie and series detail
 * page. The box is now 21:9 — the same ratio as the inline
 * aspect-ratio backdrop the detail pages render when there is no
 * trailer — so image and box coincide and the band is gone. Trailers
 * are absolutely positioned to fill the box, so they follow it. One
 * rule covers every breakpoint: both vendor rules (base and <lg) have
 * the same specificity and load earlier.
 */
.iq-main-slider.site-video {
    padding-bottom: 42.8571%; /* 21:9 */
}

/* ================================================================== */
/* Detail-page description: in flow on xl (1200–1399px), overlay     */
/* only from xxl up                                                   */
/* ================================================================== */
/*
 * _page-content.scss overlays .movie-detail-part on the trailer from
 * xl up (position: absolute; top: 28%). On 1200–1399px the description
 * column is 50% of a narrow page, so an ordinary VJ title wraps to
 * three lines and the block runs ~200px past the 21:9 hero box,
 * straight through the "Starring" heading (seen at 1280×1024; it was
 * already colliding before 1.8.9). No banner height at these widths
 * can hold that block, so the details go back into flow below the
 * banner — the layout the page already uses below xl — and the
 * overlay stays for xxl+, where the box is 600px+ and the column is
 * wide enough for two-line titles. Same specificity as the vendor
 * rules, later in the cascade.
 */
@media (min-width: 1200px) and (max-width: 1399.98px) {
    .movie-detail-part {
        position: relative;
        top: auto;
        bottom: auto;
        left: auto;
        right: auto;
    }

    .movie-detail-part .trending-info .details-parts {
        width: 80%;
        padding: 0 2em;
    }
}

/* ================================================================== */
/* Detail / watch / episode pages — tighter rail rhythm               */
/* ================================================================== */
/*
 * 1.8.9 put these pages on the home rhythm (vendor .swiper margin,
 * 3.75em between rails). Rio wanted them tighter still on the detail,
 * watch and episode pages, where the rails are secondary to the title
 * block above them. `.jambo-detail-rails` is the rails wrapper on those
 * four pages only — the home page does not carry it, so home rails
 * keep the vendor 3.75em. The episode number grid reads the same token
 * from its inline CSS (episode-layout-assets.blade.php), so scroller
 * and grid stay in step. The wrapper's own top gap uses the token too,
 * so title block → first rail and rail → rail move together.
 */
:root {
    --jambo-rail-gap: 2.5em;
}

@media (max-width: 991.98px) {
    :root {
        --jambo-rail-gap: 1.5em;
    }
}

.jambo-detail-rails.section-padding-top {
    padding-top: var(--jambo-rail-gap);
}

.jambo-detail-rails .swiper {
    margin-bottom: var(--jambo-rail-gap);
}

/* ================================================================== */
/* Top 10 rails — smaller rank numeral                                 */
/* ================================================================== */
/*
 * Streamit sets .top-ten-numbers to 7.5em on desktop and 4.5em below
 * 992px (_top-ten-card.scss). At 8 posters across (1.8.x standard) the
 * numeral covered most of the poster and read as the card's subject.
 * Rio asked for "slightly smaller": one sixth off at both breakpoints,
 * same anchor and hover lift. Two rules because the vendor's mobile
 * rule has the same specificity and loads earlier — a single base
 * override here would win on phones too and drop 4.5em to 6.25em.
 */
.iq-top-ten-block .block-image .top-ten-numbers {
    font-size: 6.25em;
}

@media (max-width: 991px) {
    .iq-top-ten-block .block-image .top-ten-numbers {
        font-size: 3.75em;
    }
}

/* ================================================================== */
/* The two daily Top 10 banners — a scrim that is actually painted     */
/* ================================================================== */
/*
 * Rio, 2026-09-10, over a screenshot of the Top 10 Movies of the Day
 * slide on a phone: "the texts here are not visible enough work around
 * the opacity to have it clear".
 *
 * He is right, and the cause is not a missing gradient — it is a
 * gradient nothing can see. Streamit declares
 *
 *     .slider--image { background-image: linear-gradient(90deg, …) }
 *
 * on the element that CONTAINS the slide's <img>. A child image paints
 * over its own parent's background, and this one is `object-fit: cover`
 * at the full size of the box, so the declared scrim has never reached a
 * pixel on any slide since the section was built. Every word on that
 * banner has been sitting on raw artwork, and how legible it was
 * depended entirely on which film happened to be on screen.
 *
 * WHY 0.6, AND NOT A NUMBER THAT LOOKED RIGHT
 *
 * Each of the ten slides' backdrops was composited the way the slide
 * composites it (cover into 390x530), the luminance of the band the text
 * occupies was read, and the veil was solved for: the smallest alpha
 * that still clears WCAG AA, 4.5:1, for the 16px synopsis in #d1d0cf.
 * The brightest slide in the catalogue needed 0.586 and the series
 * banner's brightest needed 0.607. 0.6 covers the shelf as it stands and
 * the arithmetic is in the worklog, so the next person can re-solve it
 * rather than re-guess it.
 *
 * WHY FLAT, AND NOT A GRADIENT
 *
 * Both of this project's other banners scrim their edges, because their
 * text is anchored to one. This banner's is not: below 992px every line
 * of it is centred and the block spans 326 of the 390, so there is no
 * edge for a gradient to hide in. A flat veil is what a centred block
 * over a full-bleed image actually needs.
 *
 * The series slider keeps its own three gradients — those are real, they
 * are on a `::before`, and they are part of its look. This only adds the
 * floor underneath them, because at mid-width they contribute almost
 * nothing and that is exactly where its synopsis is.
 *
 * The app draws the same 0.6 from the same reasoning; see
 * `mobile/src/ui/theme.ts`, `rankedBanner.scrimAlpha`.
 */
/*
 * The movies slider has no overlay of its own, so it gets one. z-index 2
 * puts it above the <img>, which is a static child and paints below every
 * positioned one, and below `.description`, which is z-index 99.
 */
.verticle-slider .slider-images .swiper-slide .slider--image::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 2;
    background-color: rgba(0, 0, 0, 0.6);
    pointer-events: none;
}

/*
 * The series slider already has the right element — its three gradients
 * live on a `::before` that is correctly stacked under the copy — so this
 * adds the floor to that layer instead of a second one.
 *
 * `background-color`, deliberately, and not a fourth entry in
 * `background-image`. A colour paints beneath the image layers on the same
 * box, which composites to exactly the same result, and it means this file
 * does not hold a second copy of three gradient definitions that would
 * silently stop matching the template the day one of them changes.
 */
.otthome-tab-slider .tab-slider-banner .tab-slider-banner-images::before {
    background-color: rgba(0, 0, 0, 0.6);
}


/* ================================================================== */
/* Your Favourite Personality — round avatars, four across on a phone */
/* ================================================================== */
/*
 * Rio, 2026-09-10, over a shot of four circular avatars: *"make the people's
 * cards like this and smaller on home for both webapp and mobile"*. The app
 * carries the same change.
 *
 * **Scoped to `--home`, a class added for this, and the first attempt got that
 * wrong.** `components/cards/personality-card.blade.php` is included five
 * times — this rail plus the cast and crew rows on the movie and TV detail
 * pages — and those are not "home". Editing the partial would have rounded all
 * five. So would scoping to `.favourite-person-block`, which was the first
 * attempt: the detail pages wrap their rows in that same class, and a probe of
 * a movie page caught it reading `border-radius: 50%` where nothing should
 * have changed.
 *
 * **The detail pages keeping the rectangle is Rio's decision, not a leftover.**
 * He was asked directly on 2026-09-11, shown that a circle on the home rail
 * against a rounded rectangle on a film's cast row reads as an oversight, and
 * told it was one selector either way. He chose to keep them as they are. Do
 * not "fix" this into consistency without asking him again.
 *
 * The template draws this image as a 1/1.3 portrait with an 8px corner. A
 * circle needs a square box, so the aspect goes to 1 and the radius to 50%;
 * `object-position: 50% 0%` stays, because these are faces and a square crop
 * of a portrait should keep the top of the head rather than the middle.
 *
 * The count per view is the blade's `data-mobile`, not CSS — Swiper reads it
 * from the attribute.
 */
.favourite-person-block--home .personality-img {
    aspect-ratio: 1;
    /*
     * `!important`, and only on this one line. The card carries Bootstrap's
     * `rounded-3` utility, and every Bootstrap utility ships `!important`, so
     * a plain declaration here loses however specific the selector is. The
     * alternative was removing the class from the shared partial, which the
     * four detail-page cast rows also render.
     */
    border-radius: 50% !important;
}

/*
 * The name under a smaller avatar. The template's `.cast-title` is 14px,
 * which at a quarter of the row's width wraps most full names to three lines
 * and pushes the rail's height past the artwork it is labelling.
 */
.favourite-person-block--home .cast-title {
    font-size: 12px;
    line-height: 1.25;
}

/* ------------------------------------------------------------------ */
/* Outline-secondary buttons, readable on the black page               */
/* ------------------------------------------------------------------ */
/*
 * Overrides Bootstrap's `.btn-outline-secondary` from the Vite bundle
 * (`app.scss` → Bootstrap's `_buttons.scss`), which paints the words and
 * the border with this theme's `--bs-secondary`, #222020: the grey the
 * theme fills buttons WITH. On the site's black page that is about 1.2:1,
 * and the idle "Movies" / "Series" tabs on every taxonomy archive
 * (`MainPages/taxonomy-archive.blade.php`) and the back button on
 * `geners-vjs-page.blade.php` could barely be read. Rio, 2026-09-25: "the
 * other words like movies or series are not clear and for both the app
 * and webapp".
 *
 * The idle colours are the site's own for a segmented button — the
 * Episodes card/grid switch in `partials/episode-layout-assets.blade.php`:
 * words at 55% white (about 6:1 on black), border at 15%. Hover, active and
 * disabled keep the vendor's values. Same selector as the vendor rule, so
 * this wins on load order alone (ADR-0001). The app's archive heading
 * (`mobile/src/features/archive/ArchiveHeading.tsx`) draws the same two.
 */
.btn-outline-secondary {
    --bs-btn-color: var(--jambo-idle-button-fg);
    --bs-btn-border-color: var(--jambo-idle-button-border);
}

:root {
    --jambo-idle-button-fg: rgba(255, 255, 255, 0.55);
    --jambo-idle-button-border: rgba(255, 255, 255, 0.15);
}

/* --------------------------------------------------------------------------
   Watchlist albums (ADR-0017; Rio, 2026-09-28: "stacked, like your picture",
   a YouTube Mix card). The cover is the first title's wide art at the hub's
   12px radius; two edges sit above it, each inset further and fainter, so the
   card reads as a stack. Only transform and opacity animate.
   -------------------------------------------------------------------------- */
.jambo-album {
    display: block;
    padding-top: 8px; /* room for the two edges above the cover */
    color: inherit;
    text-decoration: none;
}
.jambo-album:hover,
.jambo-album:focus-visible { color: inherit; }
.jambo-album:focus-visible { outline: 2px solid var(--bs-primary); outline-offset: 4px; border-radius: 12px; }

.jambo-album__stack { position: relative; display: block; height: 0; }
.jambo-album__stack span {
    position: absolute;
    left: 16px;
    right: 16px;
    top: -8px;
    height: 4px;
    border-radius: 6px 6px 0 0;
    background: rgba(255, 255, 255, 0.22);
}
.jambo-album__stack span + span {
    left: 8px;
    right: 8px;
    top: -4px;
    background: rgba(255, 255, 255, 0.40);
}

.jambo-album__cover {
    position: relative;
    display: block;
    aspect-ratio: 16 / 9;
    border-radius: 12px;
    overflow: hidden;
    background: var(--panel-3);
    transition: transform 120ms ease-out;
}
.jambo-album:active .jambo-album__cover { transform: scale(0.98); }
.jambo-album__cover img { display: block; width: 100%; height: 100%; object-fit: cover; }
.jambo-album__cover > .ph {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 2.25rem;
    color: var(--brand-muted);
}

.jambo-album__count {
    position: absolute;
    right: 8px;
    bottom: 8px;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.72);
    color: #fff;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.5;
}

.jambo-album__name,
.jambo-album__meta {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.jambo-album__name { margin-top: 0.6rem; font-weight: 600; color: #fff; }
.jambo-album__meta { font-size: 0.8125rem; color: var(--brand-muted); }

@media (prefers-reduced-motion: reduce) {
    .jambo-album__cover { transition: none; }
}

/* The "Save to..." arrow beside a title's Watchlist button (ADR-0017): the
   same height as its neighbour, square, not the neighbour's padding. */
.watchlist-button-wrapper .jambo-save-to-btn {
    min-width: 0;
    padding-left: 0.85rem;
    padding-right: 0.85rem;
}
