/* ══════════════════════════════════════════════════════════════════
   Beartify – background.css  v2
   Styles du mode immersif (overlay plein écran cover + paroles)

   Stratégie de fond :
     dynbg ON  → #immBgCanvas (WebGL) fournit le fond.
                 #spicyGlobalBg est masqué via JS.
                 .imv-overlay → background:transparent (posé en JS).
     dynbg OFF → #immBgCanvas invisible.
                 #spicyGlobalBg restauré, visible à travers l'overlay
                 dont le background reste transparent (posé en JS).
     Fermeture → background inline retiré, CSS reprend la main.

   Le background CSS de .imv-overlay sert uniquement de :
     • Fallback de chargement (premier frame avant WebGL)
     • Fallback si WebGL est indisponible
   Il est systématiquement écrasé en JS à l'ouverture.
══════════════════════════════════════════════════════════════════ */

/* ── Overlay principal ───────────────────────────────────────────── */
.imv-overlay {
  position: fixed;
  inset: 0;
  z-index: 2900; /* au-dessus de top-bar (200) et player-bar (100) */
  display: flex;
  align-items: stretch;
  /* Réduit : moins de gaspillage latéral, plus de place pour cover + paroles */
  gap: clamp(16px, 2.5vw, 48px);
  padding: 44px clamp(16px, 3.5vw, 52px) 24px;

  /*
   * Fallback sombre uniquement visible pendant le premier frame
   * ou si WebGL est indisponible.
   * En conditions normales, le JS pose background:transparent
   * dès l'ouverture (via _initRenderer() ou le chemin dynbg-off).
   */
  background: #0a0a12;

  animation: imvFadeIn 0.3s cubic-bezier(0.22, 1, 0.36, 1);

  /*
   * PAS de isolation:isolate : avec z-index:-1 sur le canvas,
   * isolation:isolate le ferait peindre DERRIÈRE le background
   * de l'overlay (#0a0a12 par défaut) et il resterait invisible
   * jusqu'au repaint JS → flash noir au chargement.
   * On utilise à la place z-index:0 sur le canvas et z-index:1
   * sur les colonnes de contenu (ordre de DOM explicite).
   */
}

@keyframes imvFadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ── Canvas WebGL du fond dynamique ─────────────────────────────── */
.imv-bg-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;

  /*
   * z-index: 0 → le canvas est la première couche visible.
   * Les colonnes .imv-left et .imv-lyrics-slot ont z-index:1,
   * donc elles s'affichent toujours par-dessus le canvas.
   * Pas besoin de isolation:isolate avec cette approche explicite.
   */
  z-index: 0;
  display: block;
  pointer-events: none;

  /*
   * ★ FILTRE CRITIQUE — identique à .spicy-dynamic-bg dans analyse.js :
   *   filter: saturate(2.5) brightness(.65)
   *
   * Sans ce filtre, les couleurs WebGL (saturation=1.5) restent
   * environ 2.5× moins éclatantes que l'original SpicyLyrics.
   * saturate(2.5)  → pousse les teintes pour qu'elles ressortent
   * brightness(.65) → assombrit l'arrière-plan pour la lisibilité
   *
   * Référence : ligne 15626 de analyse.js
   *   .spicy-dynamic-bg { filter: saturate(2.5) brightness(.65) }
   */
  filter: saturate(2.5) brightness(.65);

  /* Transition douce à l'activation / désactivation du toggle */
  transition: opacity 0.4s ease, filter 0.4s ease;
  will-change: contents;
}

/*
 * Quand l'immersif est ouvert :
 *   – on masque l'UI principale pour que seul le canvas (ou le thème
 *     si dynbg OFF) soit visible derrière l'overlay transparent.
 *   – pointer-events:none bloque les clics fantômes sous l'overlay.
 */
body.imv-open {
  overflow: hidden;
}

body.imv-open .top-bar,
body.imv-open .app-body,
body.imv-open .player-bar {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
}

/* Sur mobile, .imv-cover-controls (transport intégré à imv-left) est
   masqué exprès (@media 768px, plus bas dans ce fichier) au profit de
   la vraie player-bar — "la barre de lecture mobile existante les
   couvre déjà" comme l'indique le commentaire de ce bloc. Mais la règle
   ci-dessus l'éteint aussi (opacity:0), pensée uniquement pour le
   desktop où imv-left gère seul la lecture. Résultat sur mobile : ni
   les contrôles intégrés ni la vraie player-bar ne s'affichaient. */
html.is-mobile body.imv-open .player-bar {
  opacity: 1 !important;
  pointer-events: auto !important;
  /* Le fond plein de la barre (#121212 sur mobile, ou noir selon thème)
     n'a plus lieu d'être ici : les 5 boutons de lecture ont désormais
     leur propre conteneur visuel (voir html.is-mobile body.imv-open
     .player-center dans style.css), qui suffit à les distinguer du
     fond immersif derrière. Le reste de la barre reste transparent
     pour laisser voir le fond du mode immersif (cover/couleurs
     dominantes ou ciel étoilé selon le thème). */
  background: transparent !important;
}

/* Réapparition fluide à la fermeture */
.top-bar,
.app-body,
.player-bar {
  transition: opacity 0.25s ease;
}

/* ── Bouton fermer (haut centre de l'écran) ─────────────────────── */
/*
 * Bouton Fermer — masqué par défaut (translateY -100% = hors écran).
 * Slide-in via .imv-close--visible ajouté par JS quand la souris
 * approche le haut de l'overlay (clientY < 80px).
 * Évite le conflit visuel avec la barre plein-écran de Chrome/Firefox.
 */
.imv-close {
  position: absolute;
  top: 16px;
  left: 50%;
  z-index: 10;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  border: none;
  background: rgba(20, 20, 20, 0.75);
  color: rgba(255, 255, 255, 0.90);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  /*
   * Masqué par défaut : visibility + opacity + léger décalage vers le haut.
   * La combinaison visibility/opacity est la méthode la plus fiable
   * (évite les bugs cross-browser du translateY négatif).
   * visibility:hidden après la transition (delay = durée de l'opacité).
   */
  /*
   * display:none posé en inline HTML → état masqué garanti sur tous
   * les navigateurs (Firefox safe). JS passe à display:flex via la
   * classe .imv-close--visible.
   */
  display: none !important;
  opacity: 0;
  transform: translateX(-50%) translateY(-8px);
  pointer-events: none;
  transition: opacity 0.25s ease,
              transform 0.30s cubic-bezier(0.22, 1, 0.36, 1),
              background 0.18s;
}
/* Visible quand JS ajoute .imv-close--visible */
.imv-close.imv-close--visible {
  display: flex !important;
  opacity: 1;
  transform: translateX(-50%) translateY(0);
  pointer-events: auto;
}
.imv-close:hover {
  background: rgba(255, 255, 255, 0.22);
  color: #fff;
}

/* ── Colonne gauche (cover + méta) ──────────────────────────────── */
.imv-left {
  flex: 0 0 auto;
  /*
   * Largeur : max 44vw ou 560px, et jamais plus que 80vh - ~100px
   * (espace méta) pour que la cover carrée tienne sans scroller.
   */
  width: min(44vw, 560px, calc(80vh - 100px));
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(10px, 1.5vh, 22px);
  align-self: center;
  /* Au-dessus du canvas (z-index:0) */
  position: relative;
  z-index: 1;
}

/* ── Cover ───────────────────────────────────────────────────────── */
.imv-cover-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 1;
  border-radius: clamp(14px, 1.5vw, 22px);
  overflow: hidden;
  box-shadow:
    0 12px 40px rgba(0, 0, 0, 0.60),
    0 32px 90px rgba(0, 0, 0, 0.40);
}

.imv-cover-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform;
}
.imv-cover-wrap:hover .imv-cover-img {
  transform: scale(1.03);
}

/* ── Contrôles sur la cover (masqués par défaut, visibles au hover) ─ */
.imv-cover-controls {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 14px;
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0.62) 0%,
    rgba(0, 0, 0, 0.00) 32%,
    rgba(0, 0, 0, 0.00) 52%,
    rgba(0, 0, 0, 0.72) 100%
  );
  opacity: 0;
  transition: opacity 0.22s ease;
  border-radius: inherit;
}
.imv-cover-wrap:hover .imv-cover-controls {
  opacity: 1;
}

/* ── Rangée de boutons du haut ───────────────────────────────────── */
.imv-ctrl-top {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
}

/* ⚠️ AMÉLIORATION : rapproché du vrai style ".ViewControl" de l'extension
   Spicy Lyrics (tokens --material-regular-bg/--material-regular-blur
   réels, bevel verre via box-shadow internes superposées, transition
   avec léger rebond au survol) — l'ancienne version était un simple
   cercle translucide flou, plus plat que l'original. */
.imv-icon-btn {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  border: none;
  background: rgba(0, 0, 0, 0.1); /* --material-regular-bg (tokens.css) */
  color: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  backdrop-filter: blur(12px) saturate(1.6) brightness(1.05); /* --material-regular-blur */
  -webkit-backdrop-filter: blur(12px) saturate(1.6) brightness(1.05);
  box-shadow:
    0 10px 24px -8px rgba(8, 10, 18, 0.42),
    inset 0 1px 0 rgba(255, 255, 255, 0.36),
    inset 0 0 0 1px rgba(255, 255, 255, 0.16),
    inset 0 -1px 0 rgba(255, 255, 255, 0.18);
  transition:
    background 0.3s cubic-bezier(0.4, 0, 0.2, 1),
    color 0.3s cubic-bezier(0.4, 0, 0.2, 1),
    box-shadow 0.3s cubic-bezier(0.4, 0, 0.2, 1),
    transform 0.28s cubic-bezier(0.34, 1.56, 0.64, 1); /* léger rebond, comme l'original */
}
.imv-icon-btn:hover {
  background: rgba(255, 255, 255, 0.12);
  box-shadow:
    0 14px 32px -8px rgba(8, 10, 18, 0.5),
    0 0 22px -4px rgba(255, 255, 255, 0.24),
    inset 0 1px 0 rgba(255, 255, 255, 0.48),
    inset 0 0 0 1px rgba(255, 255, 255, 0.22),
    inset 0 -1px 0 rgba(255, 255, 255, 0.22);
  transform: scale(1.08);
}
.imv-icon-btn .imv-icon-stroke { display: block; }

/* ⚠️ AMÉLIORATION : #immBtnClose ("Fermer le mode immersif") — teinte
   rouge au survol, pattern standard pour une action de sortie/fermeture
   (cohérent avec Spotify/Apple Music), pour le distinguer visuellement
   des autres boutons utilitaires neutres de la même rangée. */
#immBtnClose:hover {
  background: rgba(255, 76, 76, 0.32);
  color: #fff;
}

.imv-icon-img {
  width: 22px;
  height: 22px;
  object-fit: contain;
  filter: brightness(10) saturate(0);
  opacity: 0.92;
}

/* ── Bouton toggle fond dynamique ★ ──────────────────────────────── */
/*
 * Deux états visuels clairs :
 *   --active   → fond WebGL actif    → légère lueur verte
 *   --inactive → fond WebGL inactif  → bouton atténué + croix barrée
 *
 * La transition background/color/box-shadow est héritée de .imv-icon-btn.
 */
.imv-dynbg-btn {
  position: relative;
  overflow: visible; /* permet au ::after de déborder légèrement */
}

/* État actif : le rendu tourne → légère teinte verte (sans halo) */
/* ⚠️ AMÉLIORATION : box-shadow (glow) retiré — l'aura autour du bouton
   dénotait avec le reste de l'interface, plus discrète/épurée sans. La
   teinte verte sur fond+icône suffit à signaler l'état actif. */
.imv-dynbg-btn--active {
  background: rgba(255, 255, 255, 0.18);
  color: rgba(180, 255, 210, 0.95);
}
.imv-dynbg-btn--active:hover {
  background: rgba(255, 255, 255, 0.28);
  transform: scale(1.1);
}

/* État inactif : arrêté → grisé + barre en diagonale */
.imv-dynbg-btn--inactive {
  background: rgba(255, 255, 255, 0.08);
  color: rgba(255, 255, 255, 0.38);
  box-shadow: none;
}
.imv-dynbg-btn--inactive:hover {
  background: rgba(255, 255, 255, 0.16);
  color: rgba(255, 255, 255, 0.62);
  transform: scale(1.1);
}

/* Barre barrée en diagonale sur l'état inactif */
.imv-dynbg-btn--inactive::after {
  content: '';
  position: absolute;
  /* Légèrement plus grand que le bouton pour une croix lisible */
  inset: 4px;
  border-radius: 50%;
  border-top: 2px solid rgba(255, 255, 255, 0.52);
  transform: rotate(-45deg);
  pointer-events: none;
  /* Hérite de la transition de .imv-icon-btn */
  transition: border-color 0.18s;
}
.imv-dynbg-btn--inactive:hover::after {
  border-color: rgba(255, 255, 255, 0.75);
}

/* ── Zone de contrôles du bas (transport + progress) ─────────────── */
.imv-ctrl-bottom {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.imv-transport {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
}

.imv-ctrl-btn {
  background: none;
  border: none;
  cursor: pointer;
  padding: 10px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: opacity 0.18s, transform 0.15s;
  opacity: 0.75;
}
.imv-ctrl-btn:hover {
  opacity: 1;
  transform: scale(1.12);
}
.imv-ctrl-icon {
  width: 26px;
  height: 26px;
  object-fit: contain;
  /* ⚠️ FIX : cette classe visait des <img> PNG ; filter:brightness(10) est
     multiplicatif et ne peut PAS éclaircir du noir pur (0×10=0), ce qui
     rendait les SVG inline (fill="currentColor") noirs faute de `color`
     hérité explicite. On fixe donc la couleur directement en blanc — le
     filter est conservé pour ne rien casser côté PNG résiduels ailleurs. */
  color: #fff;
  filter: brightness(10) saturate(0);
}

/* Bouton play/pause (rond blanc, plus grand) */
.imv-play-btn {
  width: 62px;
  height: 62px;
  border-radius: 50%;
  border: none;
  background: #fff;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: transform 0.18s, box-shadow 0.18s;
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.40);
}
.imv-play-btn:hover {
  transform: scale(1.08);
  box-shadow: 0 6px 26px rgba(0, 0, 0, 0.50);
}
.imv-play-icon {
  width: 26px;
  height: 26px;
  object-fit: contain;
}

/* ── Barre de progression ────────────────────────────────────────── */
.imv-progress-row {
  display: flex;
  align-items: center;
  gap: 9px;
}

.imv-time {
  font-size: 0.70rem;
  color: rgba(255, 255, 255, 0.78);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  font-family: 'DM Sans', sans-serif;
  letter-spacing: 0.02em;
  min-width: 30px;
}

.imv-prog-track {
  flex: 1;
  height: 4px;
  background: rgba(255, 255, 255, 0.26);
  border-radius: 2px;
  cursor: pointer;
  position: relative;
  transition: height 0.15s ease;
}
.imv-prog-track:hover {
  height: 6px;
}
.imv-prog-fill {
  height: 100%;
  width: 0%;
  background: #fff;
  border-radius: inherit;
  pointer-events: none;
}

/* ── Méta (titre + artiste) sous la cover ────────────────────────── */
.imv-track-meta {
  text-align: center;
  padding: 0 6px;
  width: 100%;
}

/* Wrappers marquee — overflow:hidden obligatoire pour le défilement */
.imv-meta-title-wrap,
.imv-meta-artist-wrap {
  overflow: hidden;
  width: 100%;
}

.imv-meta-title {
  font-size: clamp(1.2rem, 1.6vw, 2rem);
  font-weight: 700;
  color: #fff;
  margin-bottom: clamp(4px, 0.5vh, 8px);
  white-space: nowrap;
  letter-spacing: -0.02em;
  /*
   * width:max-content → force l'élément à sa largeur naturelle de texte
   * indépendamment du wrapper. scrollWidth > wrap.clientWidth quand le
   * titre déborde → déclenche le marquee. SANS ça, scrollWidth = wrap
   * width et le marquee ne se déclenche jamais.
   */
  display: block;
  width: max-content;
  max-width: none;
}

.imv-meta-artist {
  font-size: clamp(0.9rem, 1.1vw, 1.35rem);
  color: rgba(255, 255, 255, 0.60);
  white-space: nowrap;
  display: block;
  width: max-content;
  max-width: none;
}

/* Animation défilement — identique à applyMarquee() de script.js */
.imv-meta-title.marquee-on,
.imv-meta-artist.marquee-on {
  display: flex;
  flex-wrap: nowrap;
  width: max-content;
  animation: immMarqueeScroll var(--marquee-duration, 12s) linear infinite;
  animation-delay: 0.8s;          /* pause initiale avant défilement */
  animation-fill-mode: both;      /* reste à translateX(0) pendant le delay */
}
@keyframes immMarqueeScroll {
  0%   { transform: translateX(0); }
  100% { transform: translateX(var(--marquee-offset, -100%)); }
}

/* ── Colonne droite : slot paroles ───────────────────────────────── */
.imv-lyrics-slot {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  /* Au-dessus du canvas (z-index:0) */
  position: relative;
  z-index: 1;
}

/*
 * Quand #lyricsDisplay est dans le slot immersif :
 *  – flex:1 + height:0 = s'étire correctement dans le flex container
 *  – --DefaultLyricsSize agrandi pour la zone plus large
 */
.imv-lyrics-slot .lyrics-display {
  flex: 1 1 auto !important;
  height: 0 !important;
  /*
   * Taille des paroles : clamp pour couvrir tous les écrans.
   * SpicyLyrics : max(1.85rem, min(7cqw, 3.5rem)) → max 3.5rem en fullscreen
   * Ici : clamp fidèle avec vw (slot ≈ 50% écran → 3vw ≈ 1.5cqw de moins que 7cqw)
   * À 1440px : 3vw = 43px ≈ 2.7rem  — ~10-12 lignes visibles ✓
   * À 1920px : 3vw = 57px ≈ 3.6rem  → plafonné à 3.5rem  ✓
   * À 1024px : 3vw = 30px → retombe sur 1.85rem  ✓
   * À 768px  : breakpoint mobile → 1.4-2rem
   */
  padding: 0 clamp(20px, 3.5vw, 60px) 24px !important;
  /*
   * Taille : clamp(2.2rem, 3.2vw, 3.8rem) → ~15 lignes visibles.
   * Avant : clamp(1.85rem, 3vw, 3.5rem) → ~26 lignes (trop petites).
   * Après : 2.2rem × 1.35 line-height ≈ 47px/ligne → ~700px/47 ≈ 15 lignes.
   */
  /*
   * clamp(2.8rem, 4vw, 5rem) → ~11-14 lignes visibles selon l'écran.
   * Augmenté depuis 2.2rem sur demande de l'utilisateur.
   * À 1440px : 4vw = 57.6px ≈ 3.6rem.
   */
  --DefaultLyricsSize: clamp(2.8rem, 4vw, 5rem);
  /* Décale les paroles de quelques pixels pour éviter la troncature */
  padding-top: 28px !important;
}

/* Espacement inter-lignes dans le slot immersif */
.imv-lyrics-slot .spicy-scroll-container .line:not(.musical-line) {
  margin-bottom: 0.22em;
}

/*
 * Dots inter-phrases (musical-line) : largement espacés en mode immersif.
 */
.imv-lyrics-slot .line.musical-line.Active {
  margin-top:    1.1em !important;
  margin-bottom: 1.1em !important;
  height: calc(var(--DefaultLyricsSize) * 2.8) !important;
}

/* ════════════════════════════════════════════════════════════════
   RESPONSIVE — points de rupture du mode immersif
   ════════════════════════════════════════════════════════════════ */

/* ── Très grands écrans (≥ 1920px) ──────────────────────────────── */
@media (min-width: 1920px) {
  .imv-overlay {
    gap: clamp(40px, 3vw, 72px);
    padding: 52px clamp(48px, 4vw, 80px) 32px;
  }
  .imv-left {
    /* Plafond augmenté : écrans 4K / ultrawide */
    width: min(42vw, 680px, calc(80vh - 100px));
  }
  .imv-lyrics-slot .lyrics-display {
    --DefaultLyricsSize: clamp(2.5rem, 3.2vw, 4.2rem) !important;
  }
}

/* ── Écrans standard 1280-1440px ─────────────────────────────── */
@media (max-width: 1440px) {
  .imv-left {
    width: min(42vw, 480px, calc(80vh - 100px));
  }
  .imv-lyrics-slot .lyrics-display {
    --DefaultLyricsSize: clamp(2.4rem, 3.8vw, 4.2rem) !important;
  }
}

/* ── Petits PC / tablette paysage (≤ 1100px) ─────────────────── */
@media (max-width: 1100px) {
  .imv-overlay {
    gap: clamp(12px, 2vw, 28px);
    padding: 44px clamp(12px, 2.5vw, 32px) 20px;
  }
  .imv-left {
    width: min(40vw, 400px, calc(78vh - 100px));
  }
  .imv-lyrics-slot .lyrics-display {
    --DefaultLyricsSize: clamp(2rem, 4vw, 3.5rem) !important;
    padding: 0 clamp(14px, 2.5vw, 36px) 20px !important;
  }
  .imv-meta-title  { font-size: clamp(1.1rem, 1.8vw, 1.6rem); }
  .imv-meta-artist { font-size: clamp(0.85rem, 1.2vw, 1.1rem); }
}

/* ── Tablette portrait / mobile paysage (≤ 768px) ────────────── */
@media (max-width: 768px) {
  .imv-overlay {
    flex-direction: column;
    align-items: center;
    padding: calc(56px + env(safe-area-inset-top, 0px)) 16px 16px;
    gap: 14px;
    overflow-y: auto;
  }

  /* En portrait : cover + méta côte à côte (compact) */
  .imv-left {
    width: 100%;
    max-width: 480px;
    width: auto; /* override la valeur desktop */
    flex-direction: row;
    align-self: stretch;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 14px;
  }

  .imv-cover-wrap {
    width: min(40vw, 160px);
    flex-shrink: 0;
    border-radius: 12px;
  }

  .imv-track-meta {
    text-align: left;
    padding: 6px 0 0;
    /* ⚠️ Le width:100% de base ne se résout pas correctement dans un
       conteneur flex row dont le parent (.imv-left) est passé à width:auto
       ci-dessus — résultat : la zone de texte s'effondrait à ~0px de large,
       et comme les wrappers ont overflow:hidden, le titre/artiste étaient
       bien dans le DOM mais totalement invisibles. On force explicitement
       la zone à occuper l'espace restant à côté de la cover (largeur fixe). */
    flex: 1 1 0;
    min-width: 0;
  }

  .imv-meta-title  { font-size: clamp(1rem, 4.5vw, 1.4rem); white-space: normal; }
  .imv-meta-artist { font-size: clamp(0.8rem, 3.5vw, 1rem); }

  /* Calque de contrôles (lecture/cœur/plein écran…) pensé pour un survol
     souris sur une grosse cover desktop — sur tactile, ":hover" reste
     "collé" après un tap (pas de vraie sortie de survol), donc le dégradé
     sombre restait visible en permanence ("zone grisée"). Ces contrôles
     n'ont de toute façon pas leur place sur une vignette de 160px, la
     barre de lecture mobile existante les couvre déjà. */
  .imv-cover-controls { display: none !important; }

  /* Paroles : prennent toute la largeur sous la cover */
  .imv-lyrics-slot {
    width: 100%;
    flex: 1;
    min-height: 220px;
  }
  .imv-lyrics-slot .lyrics-display {
    --DefaultLyricsSize: clamp(1.8rem, 5.5vw, 2.6rem) !important;
    padding: 0 14px 16px !important;
    /* La ligne active grossit de 5% (scale: 1.05, voir style.css) au moment
       où elle s'active. Avec la marge par défaut (0.15em) et une police
       aussi grande ici, cette expansion mordait visuellement sur la ligne
       du dessus — d'où l'effet de "texte fantôme" superposé au début de
       chaque phrase. On donne plus d'air entre les lignes spécifiquement
       dans ce contexte compact (le desktop, avec plus d'espace disponible,
       n'a jamais eu ce problème — pas touché). */
    --SpicyLyrics-LineSpacing: 0.4em 0 !important;
  }
}

/* ── Mobile portrait étroit (≤ 480px) ───────────────────────── */
@media (max-width: 480px) {
  .imv-overlay { padding: 52px 12px 12px; gap: 10px; }

  .imv-left { gap: 10px; }

  .imv-cover-wrap { width: min(38vw, 130px); }

  .imv-lyrics-slot .lyrics-display {
    --DefaultLyricsSize: clamp(1.5rem, 6vw, 2.2rem) !important;
    padding: 0 10px 12px !important;
    --SpicyLyrics-LineSpacing: 0.4em 0 !important;
  }

  .imv-meta-title  { font-size: clamp(0.95rem, 4vw, 1.2rem); }
  .imv-meta-artist { font-size: 0.78rem; }
}
/* ════════════════════════════════════════════════════════════════
   CROSSFADE COVER ART (fi_FromImage / ti_ToImage — analyse.js)
   ════════════════════════════════════════════════════════════════ */

.imv-cover-wrap {
  position: relative; /* contexte pour les couches absolues */
}

/* Deux couches superposées pour le fondu entre pochettes */
.imv-cover-from,
.imv-cover-to {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  will-change: opacity, transform;
}
.imv-cover-from {
  z-index: 1;
  opacity: 1;
  transition: opacity 0.55s ease, transform 0.45s cubic-bezier(0.22,1,0.36,1);
}
.imv-cover-to {
  z-index: 2;
  opacity: 0;
  transition: opacity 0.55s ease, transform 0.45s cubic-bezier(0.22,1,0.36,1);
}
.imv-cover-wrap.imv-cover-fading .imv-cover-to  { opacity: 1; }
.imv-cover-wrap.imv-cover-fading .imv-cover-from { opacity: 0; }
.imv-cover-wrap.imv-cover-no-transition .imv-cover-from,
.imv-cover-wrap.imv-cover-no-transition .imv-cover-to {
  transition: none !important;
}
.imv-cover-wrap:hover .imv-cover-from,
.imv-cover-wrap:hover .imv-cover-to {
  transform: scale(1.03);
}

/* Contrôles au-dessus des deux couches */
.imv-cover-controls {
  z-index: 3;
}

/* ════════════════════════════════════════════════════════════════
   BOUTON CŒUR CENTRAL
   Changements demandés :
     – Plus grand (clamp 72px → 108px)
     – liked → cœur plein blanc (fill:#fff + stroke:#fff)
     – non liked → outline uniquement (fill:none)
   ════════════════════════════════════════════════════════════════ */

.imv-ctrl-center {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1;
  pointer-events: none;
}

/* ════════════════════════════════════════════════════════════════
   VOLUME — capsule verticale intégrée au hover de la cover
   Reconstruit d'après le vrai style "Skin A / IconOnFill" trouvé dans
   ContentBox.css (Spicy Lyrics) : pas de poignée séparée — le
   remplissage blanc EST le curseur (scaleY piloté par --VolumeLevel),
   et l'icône passe en "encre" sombre quand le fill la recouvre depuis
   le bas, au lieu du fond sombre plaqué derrière l'icône qu'on avait
   bricolé en solution de repli avant d'avoir cette référence.
   ════════════════════════════════════════════════════════════════ */
.VolumeControl {
  --VolumeLevel: 0.7;
  position: absolute;
  top: 50%;
  right: 14px;
  transform: translateY(-50%);
  width: 34px;
  height: 38%;
  min-height: 90px;
  border-radius: 999px;
  overflow: hidden;
  cursor: pointer;
  z-index: 3;
  pointer-events: all;
  background: rgba(0, 0, 0, 0.1); /* --material-regular-bg */
  backdrop-filter: blur(12px) saturate(1.6) brightness(1.05); /* --material-regular-blur */
  -webkit-backdrop-filter: blur(12px) saturate(1.6) brightness(1.05);
  box-shadow:
    0 10px 24px -8px rgba(8, 10, 18, 0.42),
    inset 0 1px 0 rgba(255, 255, 255, 0.36),
    inset 0 0 0 1px rgba(255, 255, 255, 0.16),
    inset 0 -1px 0 rgba(255, 255, 255, 0.18);
  transition: width 0.28s cubic-bezier(0.34, 1.56, 0.64, 1);
  touch-action: none; /* évite le scroll de page pendant le drag tactile */
}
.VolumeControl:hover,
.VolumeControl.Dragging {
  width: 40px;
}

.VolumeFill {
  position: absolute;
  inset: 0;
  background: #fff;
  transform: scaleY(var(--VolumeLevel));
  transform-origin: bottom;
  transition: transform 0.18s cubic-bezier(0.23, 1, 0.32, 1);
  pointer-events: none;
}
/* Suivi 1:1 du curseur pendant le glisser, sans le lissage habituel */
.VolumeControl.Dragging .VolumeFill { transition: none; }

.VolumeIcon {
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  fill: #fff;
  z-index: 1;
  pointer-events: none;
  transition: fill 0.15s ease;
}
/* L'icône s'encre (sombre) quand le fill blanc la recouvre par-dessous —
   technique exacte de l'original, plus lisible qu'un blanc sur blanc. */
.VolumeControl.IconOnFill .VolumeIcon {
  fill: rgba(0, 0, 0, 0.68);
}
.VolumeIcon svg { width: 15px; height: auto; }
.VolumeIcon svg path { fill: inherit; }

/* Ondes/muet : Speaker toujours visible, seules Wave/Mute basculent —
   même logique de seuils que précédemment (0% muet, <50% faible). */
.VolumeIcon svg #SpicyLyrics_VolumeMute { opacity: 0; }
.VolumeControl.Low .VolumeIcon svg #SpicyLyrics_VolumeWaveHigh { opacity: 0; }
.VolumeControl.Muted .VolumeIcon svg #SpicyLyrics_VolumeWaveLow,
.VolumeControl.Muted .VolumeIcon svg #SpicyLyrics_VolumeWaveHigh { opacity: 0; }
.VolumeControl.Muted .VolumeIcon svg #SpicyLyrics_VolumeMute { opacity: 1; }

.imv-heart-btn {
  pointer-events: all;
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 0.22s cubic-bezier(0.22,1,0.36,1), filter 0.18s;
  filter: drop-shadow(0 2px 16px rgba(0,0,0,0.60));
}
.imv-heart-btn:hover  { transform: scale(1.10); filter: drop-shadow(0 4px 22px rgba(0,0,0,0.70)); }
.imv-heart-btn:active { transform: scale(0.93); }

.imv-heart-icon {
  /* ⚠️ FIX : remplacé <img> Unlike.png/like.png par un <svg fill="currentColor">
     (JS bascule désormais l'attribut `d` du <path> plutôt que `src`).
     `color:#fff` requis pour que currentColor résolve en blanc comme avant. */
  width:  clamp(72px, 14vw, 108px);
  height: clamp(72px, 14vw, 108px);
  display: block;
  color: #fff;
  /* Légère ombre pour ressortir sur n'importe quel fond */
  filter: drop-shadow(0 2px 8px rgba(0,0,0,0.45));
  transition: filter 0.20s ease;
  /* Empêche le drag de l'image */
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* Lueur plus marquée au survol du bouton */
.imv-heart-btn:hover .imv-heart-icon {
  filter: drop-shadow(0 3px 14px rgba(0,0,0,0.60));
}

/* Le swap contour ↔ rempli est géré par JS (attribut `d` du <path>) */

/* Animation clic — deux variantes identiques à SpicyLyrics press02 / reverse_press02 */
@keyframes heartPop {
  0%   { transform: scale(1);    }
  40%  { transform: scale(1.28); }
  70%  { transform: scale(0.92); }
  100% { transform: scale(1);    }
}
@keyframes heartUnpop {
  0%   { transform: scale(1);    }
  30%  { transform: scale(0.82); }
  65%  { transform: scale(1.12); }
  100% { transform: scale(1);    }
}
.imv-heart-btn.press02         { animation: heartPop   0.38s cubic-bezier(0.22,1,0.36,1); }
.imv-heart-btn.reverse_press02 { animation: heartUnpop 0.48s cubic-bezier(0.22,1,0.36,1); }

/* ⚠️ .imv-dynbg-corner retirée : le bouton DynBg a rejoint la rangée du
   haut (.imv-ctrl-top, à gauche du bouton plein écran) avec la taille
   standard .imv-icon-btn (50px), au lieu de son ancien coin isolé 30px. */

/* ════════════════════════════════════════════════════════════════
   TOGGLE GAUCHE / DROITE (fr() dans analyse.js)
   ════════════════════════════════════════════════════════════════ */

.imv-overlay.imv-right-side { flex-direction: row-reverse; }
.imv-overlay .imv-left,
.imv-overlay .imv-lyrics-slot {
  transition: width 0.35s cubic-bezier(0.22,1,0.36,1);
}

/* ════════════════════════════════════════════════════════════════
   NO-LYRICS PLACEHOLDER
   ════════════════════════════════════════════════════════════════ */

.imv-lyrics-placeholder {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  color: rgba(255,255,255,0.28);
  height: 100%;
  pointer-events: none;
  user-select: none;
}
.imv-lyrics-placeholder span {
  font-size: 1rem;
  font-family: 'DM Sans', sans-serif;
  letter-spacing: 0.04em;
}
.imv-overlay.imv-no-lyrics .imv-lyrics-slot {
  display: flex !important;
  flex: 0 0 auto;
  width: min(38vw, 380px);
  align-items: center;
  justify-content: center;
}
.imv-overlay.imv-no-lyrics .imv-lyrics-placeholder { display: flex; }
.imv-overlay.imv-no-lyrics .imv-left {
  margin: 0 auto;
  width: min(56vw, 660px, calc(84vh - 100px));
}

/* ════════════════════════════════════════════════════════════════
   DRAG-TO-SEEK
   ════════════════════════════════════════════════════════════════ */

.imv-prog-track.imv-prog-dragging { height: 8px !important; cursor: grabbing !important; }
.imv-prog-track.imv-prog-dragging .imv-prog-thumb {
  opacity: 1 !important;
  width: 16px !important;
  height: 16px !important;
  right: -8px !important;
}
.imv-overlay.imv-dragging * { user-select: none !important; }

/* ════════════════════════════════════════════════════════════════
   ÉTATS ACTIFS Shuffle / Repeat
   ════════════════════════════════════════════════════════════════ */

/* ⚠️ FIX : l'ancien filter:brightness(10) forçait le blanc pur quelle
   que soit la couleur réellement voulue (même mécanisme que le bug déjà
   rencontré sur .imv-ctrl-icon/.imv-heart-icon — brightness() est
   multiplicatif, il ne peut qu'éclaircir, jamais teinter). Les icônes
   utilisant fill="currentColor", on pilote directement `color` avec la
   variable --green définie par settings.js (couleur d'accentuation
   choisie par l'utilisateur), au lieu de forcer du blanc. */
.imv-ctrl-btn.imv-ctrl-active .imv-ctrl-icon {
  color: var(--green, #1ed760);
  filter: drop-shadow(0 0 5px var(--green, #1ed760));
  opacity: 1;
}

/* Press animation (Pressed class) */
.imv-ctrl-btn.imv-pressed,
.imv-icon-btn.imv-pressed {
  transform: scale(0.88);
}

/* Métadonnées : fade in/out au changement de piste */
@keyframes immMetaFadeIn  { from { opacity:0; } to { opacity:1; } }
@keyframes immMetaFadeOut { from { opacity:1; } to { opacity:0; } }
.imv-meta--fade-out { animation: immMetaFadeOut 0.18s ease forwards; }
.imv-meta--fade-in  { animation: immMetaFadeIn  0.28s ease forwards; }