/* ===== from main.css lines 199-487 ===== */
    /* ---------- Hero ----------
       Top padding uses env(safe-area-inset-top) so the header controls
       (logo, search, buttons) stay clear of the iOS status bar / dynamic
       island while the featured HERO image behind (#featuredHero) can still
       reach pixel 0 of the viewport.
       Full-bleed: the header escapes the .shell's 1240px content cap (via
       negative margins canceling the shell's left/right inset) so at wide
       viewports the logo/actions no longer sit behind a 100+px fixed gutter.
       Horizontal padding uses clamp() so the inset scales fluidly with the
       viewport width instead of being pegged at a stepped per-breakpoint
       value. */
    :root {
      --floating-header-top-gap: 12px;
      --floating-header-pad-x: 28px;
      --floating-header-pad-y: 8px;
      --floating-header-row-h: 53px;
      --floating-header-flow-gap: 44px;
      --floating-header-page-gap: 28px;
      --floating-header-focus-row-gap: 10px;
      --floating-header-reserve-compact: calc(env(safe-area-inset-top, 0px) + var(--floating-header-top-gap) + var(--floating-header-pad-y) + var(--floating-header-pad-y) + var(--floating-header-row-h) + var(--floating-header-flow-gap) + var(--floating-header-page-gap));
      --floating-header-reserve-expanded: calc(env(safe-area-inset-top, 0px) + var(--floating-header-top-gap) + var(--floating-header-pad-y) + var(--floating-header-pad-y) + var(--floating-header-row-h) + var(--floating-header-focus-row-gap) + var(--floating-header-row-h) + var(--floating-header-page-gap));
    }

    .hero {
      /* --vw-px is set by JS (see syncViewportWidthVar) to
         document.documentElement.clientWidth, which EXCLUDES the vertical
         scrollbar. `100vw` includes it, so using 100vw here caused the hero
         to overflow the visible viewport by ~17px on desktop and clip the
         rightmost actions under overflow-x:clip. The fallback to 100vw
         covers the initial paint before JS boots. */
      width: var(--vw-px, 100vw);
      margin-left: calc((100% - var(--vw-px, 100vw)) / 2);
      margin-right: calc((100% - var(--vw-px, 100vw)) / 2);
      box-sizing: border-box;
      padding: calc(env(safe-area-inset-top, 0px) + 32px) clamp(24px, 4vw, 80px) 28px;
      background: transparent;
      border: 0;
      border-radius: 0;
      box-shadow: none;
      position: relative;
      z-index: 40;
      text-align: center;
    }

    .hero-top {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      gap: 12px;
      margin-bottom: 44px;
      /* min-width: 0 prevents the flex/grid container from propagating a
         min-content size upward — without this a single wide child (e.g. an
         SVG whose browser-computed max-content matches its viewBox) can
         blow the header out past the viewport edge. */
      min-width: 0;
    }
    /* Header packing strategy:
       – `justify-content: flex-start` makes every item flow from the left, so
         the logo hugs the left edge (right after .brand-back when shown).
       – `.search-form { margin: 0 auto }` makes the search bar self-center
         within the flex row's remaining space. Its `flex: 1 1 auto` lets it
         grow to `max-width: 520px`; the leftover space is split equally
         between `margin-left: auto` and `margin-right: auto`, so once
         clamped at 520, the bar is centered between the logo cluster and
         the actions cluster.
       – `.hero-actions` has no auto margin — it packs naturally to the
         right of the search bar's auto-absorbed right margin, so the
         actions land near the right edge without stealing centering space
         from the search. */
    .hero-top > .search-form { margin: 0 auto; }

    /* ============================================================
     * Header logo component
     * ============================================================
     * Structure:
     *   <button id="brandHome" class="brand-logo">
     *     <svg class="brand-logo-svg">
     *       <path /> <path />
     *     </svg>
     *   </button>
     *
     * Adaptive color is driven entirely by `body.is-logo-on-light`,
     * which is toggled by the JS block "Header logo component —
     * adaptive color system" (search for that banner in the <script>).
     * Default fill = white. When the body class is set, both paths
     * flip to solid black. No mix-blend-mode, no per-page overrides.
     *
     * The onboarding logo (span.onboarding-logo.brand-logo) is a
     * separate DOM with its own teal-glow filter and is intentionally
     * NOT included in the adaptive switch.
     * ============================================================ */
    .brand-logo {
      border: 0;
      padding: 0;
      background: none;
      color: #ffffff;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      -webkit-tap-highlight-color: transparent;
      transition: transform 0.2s ease;
    }
    .brand-logo:hover { transform: translateY(-1px); }
    .brand-logo:active,
    .brand-logo:focus,
    .brand-logo:focus-visible {
      outline: none;
    }
    /* Adaptive color: the inline <path> fills (white + mix-blend-mode:
       difference, see `.brand-logo-svg path` below) invert against whatever
       is directly behind the logo, so the letters turn BLACK when the pixels
       immediately behind are light, and WHITE when they're dark. No glass
       panel / mask / backdrop-filter — those would force their own opaque
       tint between the page background and the blended paths and break the
       adaptation. */
    .brand-logo-svg {
      display: block;
      width: auto;
      height: calc(var(--floating-header-row-h) * 0.6875);
      /* Verrouille le ratio aux dimensions du viewBox (2200/1050). Pas de
         `min-width: max-content` : sur Chromium `max-content` pour ce SVG
         peut resoudre à 2200 px (la largeur du viewBox), ce qui fait exploser
         la colonne et pousser le reste du header hors ecran. */
      aspect-ratio: 2200 / 1050;
      flex: 0 0 auto;
      overflow: visible;
    }
    /* Contour blanc 55 % + inversion couleur via blend. Stroke non-scaling
       pour garder 1.5 px peu importe la taille. mix-blend-mode: difference
       fait varier la couleur du trait en fonction du backdrop dynamique. */
    /* Mobile : on garde le ratio natif du viewBox (2200/1050) et on pilote
       uniquement la hauteur. Forcer aspect-ratio: 1 + mask-size custom
       désalignait le mask des paths et clippait des bouts des lettres TV. */
    @media (max-width: 900px) {
      .brand-logo-svg { height: calc(var(--floating-header-row-h) * 0.6875); }
    }
    @media (max-width: 380px) {
      .brand-logo-svg { height: calc(var(--floating-header-row-h) * 0.6875); }
    }
    /* Binary adaptive color: fills stay solid white by default, and flip to
       solid black when JS detects a bright backdrop behind the logo
       (see updateBrandLogoContrast + body.is-logo-on-light). No blend mode,
       so no color inversion on mid-tone backdrops — pure white OR pure black. */
    .brand-logo-svg path {
      fill: #ffffff;
      vector-effect: non-scaling-stroke;
      transition: fill 0.18s ease;
    }
    body.is-logo-on-light .brand-logo-svg path {
      fill: #000000;
    }

    .brand-back {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      border: 0;
      background: transparent;
      color: #ffffff;
      cursor: pointer;
      -webkit-tap-highlight-color: transparent;
      transition: color 0.2s ease, transform 0.2s ease;
    }
    .brand-back[hidden] { display: none; }
    .brand-back svg { width: 35px; height: 35px; }
    .brand-back:hover { transform: translateX(-2px); }
    .brand-back:active,
    .brand-back:focus,
    .brand-back:focus-visible { outline: none; }
    body.is-logo-on-light .brand-back { color: #000000; }

    .show-card-episode-still {
      position: absolute;
      inset: 0;
      width: 100%;
      height: 100%;
      object-fit: cover;
      object-position: center;
      opacity: 0;
      transition: opacity 160ms ease;
      pointer-events: none;
      border-radius: inherit;
      background: #000;
      z-index: 2;
    }
    .show-card:hover .show-card-episode-still[data-ready="1"],
    .show-card:focus-within .show-card-episode-still[data-ready="1"] {
      opacity: 1;
    }

    .hero-actions { display: inline-flex; gap: 8px; position: relative; }

    .icon-button {
      min-width: 53px;
      min-height: 53px;
      width: 53px;
      height: 53px;
      box-sizing: border-box;
      padding: 0;
      border: 1.5px solid var(--header-control-border);
      border-radius: 999px;
      background: rgba(255, 255, 255, 0.12);
      -webkit-backdrop-filter: blur(14px) saturate(1.6) brightness(0.78);
      backdrop-filter: blur(14px) saturate(1.6) brightness(0.78);
      color: #fff;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      font-size: 1rem;
      transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
    }
    .icon-button svg { width: 22px; height: 22px; }

    .icon-button:hover,
    .icon-button:focus-visible {
      background: rgba(255, 255, 255, 0.24);
      border-color: var(--header-control-border-hover);
      transform: translateY(-1px);
      outline: none;
    }

    #settingsToggle { line-height: 1; }
    #settingsToggle svg { display: block; }
    #settingsToggle.active { border-color: var(--header-control-border); }
    #settingsToggle.active:hover,
    #settingsToggle.active:focus-visible { border-color: var(--header-control-border-hover); }

    .watchlist-toggle[hidden] { display: none !important; }
    .watchlist-toggle {
      min-width: 53px;
      min-height: 53px;
      box-sizing: border-box;
      padding: 0 15px;
      border: 1.5px solid var(--header-control-border);
      border-radius: 999px;
      background: rgba(255, 255, 255, 0.12);
      -webkit-backdrop-filter: blur(14px) saturate(1.6) brightness(0.78);
      backdrop-filter: blur(14px) saturate(1.6) brightness(0.78);
      color: #fff;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      gap: 8px;
      font-size: var(--fs-sm);
      font-weight: var(--fw-semi);
      transition: background 0.2s ease, border-color 0.2s ease, transform 0.2s ease, color 0.2s ease;
      font-family: inherit;
    }
    .watchlist-toggle-icon { flex-shrink: 0; width: 20px; height: 20px; }
    .watchlist-toggle .icon-stars { display: none; }
    .watchlist-toggle:hover,
    .watchlist-toggle:focus-visible {
      background: rgba(255, 255, 255, 0.24);
      border-color: var(--header-control-border-hover);
      color: #fff;
      transform: translateY(-1px);
      outline: none;
    }
    body.watchlist-mode .watchlist-toggle .icon-bookmark { display: none; }
    body.watchlist-mode .watchlist-toggle .icon-stars {
      display: inline-block;
      color: #FCEC62;
    }

    body.watchlist-mode #homeTabs,
    body.watchlist-mode #homeBecause,
    body.watchlist-mode #homeCarousels,
    body.watchlist-mode #homeDiscover { display: none !important; }
    body.watchlist-mode #homeRecommendations.visible { display: block; }

/* ===== from main.css lines 1139-1232 ===== */
    /* ---------- Search bar ---------- */
    .search-form {
      display: flex;
      align-items: center;
      gap: 4px;
      flex: 1 1 auto;
      max-width: 572px;
      margin: 0 auto;
      padding: 5px 7px 5px 20px;
      min-height: 53px;
      box-sizing: border-box;
      border-radius: 999px;
      background: var(--panel);
      /* Border (pas outline) : l'outline est peint a l'exterieur du border-box,
         ce qui donnait une hauteur visuelle ~3px plus grande que les boutons du
         header (qui ont un border a l'interieur). On unifie sur border pour que
         tous les elements du header partagent exactement la meme methode et la
         meme hauteur visuelle. */
      border: 1.5px solid var(--line);
      transition: border-color 0.2s ease, background 0.2s ease;
    }
    .search-form:focus-within {
      border-color: var(--header-control-border-hover);
      background: rgba(255, 255, 255, 0.2);
    }

    .search-form {
      background: rgba(255, 255, 255, 0.12);
      -webkit-backdrop-filter: blur(14px) saturate(1.6) brightness(0.78);
      backdrop-filter: blur(14px) saturate(1.6) brightness(0.78);
      border-color: var(--header-control-border);
      color: #fff;
    }
    .search-form .search-input { color: #fff; }
    .search-form .search-input::placeholder { color: rgba(255, 255, 255, 0.7); }
    .search-form .search-button { color: #fff; }

    .search-input {
      flex: 1 1 auto;
      min-width: 0;
      border: 0;
      outline: 0;
      background: transparent;
      padding: 8px 0;
      font-size: var(--fs-base);
      color: var(--text);
    }

    .search-input::placeholder { color: var(--muted); }
    .search-input::-webkit-search-cancel-button,
    .search-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }

    .search-clear {
      min-width: 37px;
      min-height: 37px;
      padding: 0;
      border: 0;
      border-radius: 50%;
      color: var(--text);
      background: rgba(255, 255, 255, 0.14);
      display: none;
      align-items: center;
      justify-content: center;
      cursor: pointer;
      flex: 0 0 auto;
      transition: background 0.2s ease, color 0.2s ease, transform 0.2s ease;
    }
    .search-clear[hidden] { display: none; }
    .search-form:focus-within .search-clear:not([hidden]) { display: inline-flex; }
    .search-clear:hover { background: rgba(255, 255, 255, 0.24); color: var(--accent); }
    .search-clear svg { width: 18px; height: 18px; }

    .search-button {
      min-width: 40px;
      min-height: 40px;
      padding: 0;
      border: 0;
      border-radius: 50%;
      color: var(--text);
      background: transparent;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: background 0.2s ease, color 0.2s ease;
      cursor: pointer;
      flex: 0 0 auto;
    }
    .search-button svg { width: 20px; height: 20px; }

    .search-button:hover { background: rgba(255, 255, 255, 0.08); color: var(--accent); }

    @media (max-width: 480px) {
      body:not(.home-mode) .brand-logo-svg { height: calc(var(--floating-header-row-h) * 0.6875); }
      body:not(.home-mode) .watchlist-toggle { padding: 0; font-size: var(--fs-xs); }
    }

    /* ============================================================
     * [TEST VISUEL] Header flottant — fixe à l'écran, "flottant" sur la page
     * ------------------------------------------------------------
     * Bloc isolé : supprime ce bloc complet pour revenir au header standard.
     * Stratégie :
     *  - .hero-top sort du flux (position: fixed) avec un retrait latéral
     *    pour donner l'impression de flotter au-dessus du contenu.
     *  - Glass panel (blur + halo) ajouté pour le détacher du backdrop.
     *  - .hero récupère un padding-top compensé (= hauteur header + inset
     *    haut + ancien margin-bottom 44px) pour que le contenu sous le
     *    header ne saute pas vers le haut.
     *  - #settingsPanel suit le header flottant via position: fixed
     *    (sinon il s'ancre sur l'ancienne position du parent dans le flux).
     * ============================================================ */
    .hero-top {
      position: fixed;
      top: calc(env(safe-area-inset-top, 0px) + var(--floating-header-top-gap));
      left: clamp(12px, 2vw, 24px);
      right: clamp(12px, 2vw, 24px);
      margin-bottom: 0;
      padding: var(--floating-header-pad-y) var(--floating-header-pad-x);
      background: transparent;
      border: 0;
      box-shadow: none;
      z-index: 80;
    }
    body.onboarding-active .hero-top { display: none !important; }
    .hero {
      padding-top: var(--floating-header-reserve-compact);
    }
    @media (max-width: 480px) {
      :root {
        --floating-header-top-gap: 8px;
        --floating-header-pad-x: 18px;
        --floating-header-pad-y: 6px;
      }
    }
    /* Le settings panel est en position: absolute par défaut, ancré au
       parent .hero-actions qui est dans le flux. Le header passant en
       fixed, .hero-actions devient lui-même un repère fixed → le panel
       suit naturellement le bouton ⚙️. Aucun override nécessaire. */

    /* Modal fiche artiste : doit rester SOUS le header flottant.
       (1) z-index: après le portal JS (.hero-top déplacé à body par
           main.js), .hero-top participe au stacking context racine.
           On lui pousse z:200 pour passer devant .person-modal (z:100).
       (2) y: padding-top du modal ajusté pour démarrer sous le header. */
    .hero-top { z-index: var(--z-app-chrome, 200); }
    /* Spécificité bumpée à `body .person-modal` : header.css est chargé
       AVANT modals.css, donc les media queries de modals.css (720px,
       480px) gagnent à spécificité égale par ordre de source et
       remettent un padding-top neutre. `align-items: flex-start` ancre
       le contenu au padding-top (sinon center le re-centre et il peut
       remonter au-dessus du header). */
    body .person-modal {
      align-items: flex-start;
      padding-top: calc(env(safe-area-inset-top, 0px) + 80px);
    }
    body .person-modal-content {
      max-height: calc(100dvh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) - 100px);
    }
    @media (max-width: 480px) {
      body .person-modal {
        padding-top: calc(env(safe-area-inset-top, 0px) + 72px);
      }
      body .person-modal-content {
        max-height: calc(100dvh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) - 88px);
      }
    }


    /* Boutons à fond transparent : le glass panel du header porte déjà
       le blur + le halo, donc inutile de doubler avec des fonds par
       bouton. On garde uniquement la bordure pour la lisibilité.
       Hover : léger voile blanc pour le retour visuel. */
