/* 1. On définit la couleur par défaut ici */
/* Transition douce des couleurs de thème entre deux chansons :
   pilotée côté JS (player.js → applyAmbientColorsSmooth avec lerpCssColor).
   Le CSS ne sait pas interpoler un custom property de manière fiable sur
   toutes les plateformes sans @property, donc on anime les variables
   depuis player.js via requestAnimationFrame (smoothstep, 1200ms). */
:root {
    --main-color: #2a2e2a;
    --bg-color-2: rgb(39, 39, 39);
}

/* Animation de défilement du titre (utilisée par player.js sur .track-info h3) */
@keyframes scroll-text {
    0%   { transform: translateX(100%); }
    100% { transform: translateX(-100%); }
}

.track-info {
    overflow: hidden;
    white-space: nowrap;
    /* FIX « GROS RECTANGLE GRIS » 2026-07-30 : on retire le mask-image
       du base rule. Le fade transparent aux bords (alpha 0 sur 8% des
       côtés) laissait paraître le fond `.opening` (rgba(18,18,18,0.9) →
       gris foncé) à travers les zones de mask. Effet visuel : titre
       court noyé dans un grand bloc transparent montrant le fond, lu
       comme « gros rectangle gris ». Le mask n'avait de sens que pour
       le mode scroll-text (titre qui défile, fade aux bords), mais ce
       mode boucle hors-vue dès que le conteneur est étroit (mode
       horizontal 220px), donc le mask ne servait qu'à buguer. On
       retire globalement : rendu propre en tous modes. */
}

.track-info h3 {
    display: inline-block;
    white-space: nowrap;
    will-change: transform;
    transition: opacity 220ms ease, transform 220ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
.track-info:hover > h3 {
    animation-play-state: paused;
}

/* === Mode "static" : titre wrap multi-lignes, pas d'animation === */
html[data-title-mode="static"] .track-info {
    overflow: visible !important;
    white-space: normal !important;
    -webkit-mask-image: none !important;
            mask-image: none !important;
}
html[data-title-mode="static"] .track-info h3 {
    white-space: normal !important;
    display: block !important;
    word-break: break-word !important;
    animation: none !important;
    transform: none !important;
    will-change: auto !important;
}

/* === Animation de transition entre deux morceaux (cover + titre + artiste) === */
.track-cover {
    transition: opacity 220ms ease, transform 220ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
    will-change: opacity, transform;
}
.track-cover.is-changing {
    opacity: 0;
    transform: scale(0.94);
}
.track-info h3.is-changing,
.track-info p.is-changing {
    opacity: 0;
    transform: translateY(8px);
}

body {
    background-image: linear-gradient(135deg, var(--bg-color-2) 0%, var(--main-color) 100%);
    background-attachment: fixed;
    background-size: cover;
    margin: 0;
    height: 100vh;
    color: rgb(255, 255, 255);
    font-family: sans-serif;
    transition: background 0.8s ease;
    overflow: hidden;
}

.main-title {
    text-align: center;
    margin-top: 20px;
    font-size: 3rem;
}

h2 { text-align: center; }

/* AJUSTEMENT : On stabilise le conteneur pour les grands écrans */
.main-container {
    display: flex;
    justify-content: center;
    align-items: flex-start;
    gap: 2vw; /* Espace proportionnel entre colonnes */
    padding: 20px 40px;
    width: 100%;
    max-width: 1800px; /* Empêche l'éclatement sur TV */
    margin: 0 auto;
    box-sizing: border-box;
    height: calc(100vh - 120px); 
}

/* 3. Lecteur Gauche - AJUSTEMENT : Largeur proportionnelle */
.left-column {
    flex: 0 0 22vw; 
    min-width: 320px;
    max-width: 400px;
}

.opening {
    width: 100%; 
    background: rgba(18, 18, 18, 0.9);
    padding: 25px;
    border-radius: 15px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.5);
    text-align: center;
    box-sizing: border-box;
}

.track-cover { 
    width: 100%; 
    aspect-ratio: 1/1; 
    border-radius: 8px; 
    object-fit: cover; 
    margin-bottom: 15px; 
}

/* Playlist Milieu - AJUSTEMENT : Prend l'espace restant sans s'écraser */
.middle-column {
    flex: 1;
    display: flex;
    flex-direction: column;
    height: 100%;
    min-width: 0;
}

.playlist-sidebar {
    background: rgba(0, 0, 0, 0.8);
    border-radius: 15px;
    padding: 20px;
    overflow-y: auto; 
    flex: 1; 
    -ms-overflow-style: none;
    scrollbar-width: none;
}

.playlist-sidebar::-webkit-scrollbar {
    display: none;
}

.playlist-sidebar h3, .playlist-sidebar h4 { 
    text-align: left;  
    border-bottom: 1px solid var(--main-color); 
    padding-bottom: 10px; 
}

.playlist-sidebar ul { list-style: none; padding: 0; }
.playlist-sidebar li {
    padding: 15px;
    cursor: pointer;
    border-radius: 8px;
    transition: 0.3s;
    text-align: left;
    border-bottom: 1px solid rgba(255,255,255,0.05);
}

/* Hover élégant des items musicaux : barre d'accent qui glisse à gauche + décalage */
.playlist-sidebar li {
    transition: padding-left 0.3s ease, background 0.3s ease;
    position: relative;
}
.playlist-sidebar li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 0;
    background: var(--main-color);
    border-radius: 0 4px 4px 0;
    box-shadow: 0 0 6px var(--main-color);
    transition: height 0.3s ease;
}
.playlist-sidebar li:hover {
    background: rgba(255, 255, 255, 0.1);
    padding-left: 14px;
}
.playlist-sidebar li:hover::before {
    height: 60%;
}
.playlist-sidebar li.active { background-color: var(--main-color); font-weight: bold; color: black; }

/* Player UI */
.time-wrapper { display: flex; align-items: center; gap: 10px; font-size: 12px; margin: 15px 0; }
.progress-bar { flex-grow: 1; height: 5px; background: #4f4f4f; border-radius: 10px; cursor: pointer; position: relative; }
.progress { width: 0%; height: 100%; background-color: var(--main-color); border-radius: 10px; }

/* Container des contrôles (ajoute cette classe à la div qui entoure tes boutons) */
.controls {
    display: flex;
    align-items: center; /* Aligne verticalement au centre */
    justify-content: center; /* Centre le groupe horizontalement */
    gap: 20px;
}/* Style unifié pour TOUS les boutons du lecteur */
.btn-random,
.btn-repeat,
.btn-prev,
.btn-next,
#play-pause {
    background: none;
    border: none;
    color: white;
    cursor: pointer;
    transition: all 0.3s ease;

    /* On force une boîte de même taille pour tout le monde */
    display: flex;
    align-items: center;
    justify-content: center;
    width: 50px;  /* Ajuste selon tes besoins */
    height: 50px;

    font-size: 1.8rem; /* Taille uniforme des symboles */
    line-height: 1;    /* Supprime les espaces de texte parasites */
    padding: 0;
}

/* Spécificité pour les modes (opacité) */
.btn-random, .btn-repeat {
    opacity: 0.5;
}

.btn-random.active, .btn-repeat.active {
    opacity: 1;
    color: var(--main-color);
    text-shadow: 0 0 10px var(--main-color);
}/* On ajuste Play/Pause s'il paraît trop petit ou gros */
#play-pause {
    font-size: 2.5rem;
}

/* Menu Droite - AJUSTEMENT : Largeur proportionnelle */
/* Le panneau flottant + la sphère audio partagent la même colonne flex (.nav-column)
   afin de pouvoir respirer indépendamment du conteneur du panneau. */
.nav-column {
    flex: 0 0 15vw;
    min-width: 200px;
    max-width: 280px;
    display: flex;
    flex-direction: column;
    align-items: center;
    box-sizing: border-box;
}
.navigation-panel {
    width: 100%;
    background: rgba(18, 18, 18, 0.9);
    padding: 25px;
    border-radius: 15px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.5);
    box-sizing: border-box;
}

.search-box input {
    width: 100%;
    box-sizing: border-box;
    padding: 15px;
    border-radius: 12px;
    border: 2px solid var(--main-color);
    background: rgba(18, 18, 18, 0.9);
    color: white;
    font-size: 1rem;
    outline: none;
    box-shadow: 0 4px 15px rgba(0,0,0,0.4);
    margin-bottom: 20px;
}

.nav-links { list-style: none; padding: 0; text-align: left; }
.nav-links li { padding: 10px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.1); }
.nav-links a { color: white; text-decoration: none; transition: 0.3s; }
.nav-links a:hover { color: var(--main-color); }

/* === MENU BOUTONS ESTHÉTIQUES (accueil.html uniquement) === */
/* Remplace les hypertextes <a> par des <button> full stylés. Animations
   d'entrée staggered, hover lift + halo coloré, ripple au click, état
   "page courante" auto-détecté par aria-current="page" côté JS. */
.nav-buttons {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.nav-btn-wrap {
    /* Stagger d'entrée : chaque ligne apparaît en décalé.
       --i varie 0..N pour N wraps présents dans le DOM. Inline style
       pose l'explicit index sur chaque <li> ; :last-child fallback
       assure qu'un éventuel ajout futur reste correctement indexé
       même si l'auteur oublie l'inline style. */
    opacity: 0;
    transform: translateY(8px);
    animation: nav-btn-rise 0.55s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
    animation-delay: calc(var(--i, 0) * 80ms + 120ms);
}
/* 2026-08-09 : upload button retiré. Nav = Home(0) | Library(1) |
   Settings(2). Le :last-child fallback doit désormais pointer --i:2
   (et non 3 comme avant quand Upload=3) pour que la 3e entrée
   conserve son animation-delay cohérent avec les autres. Important :
   cette valeur fallback DOIT toujours matcher le dernier inline
   style="--i:N" du dernier wrap quand le DOM est conforme — sinon
   l'animation fire deux fois (CSS layer conflict). */
.nav-btn-wrap:last-child { --i: 2; }

html.no-animations .nav-btn-wrap {
    animation: none;
    opacity: 1;
    transform: none;
}

@keyframes nav-btn-rise {
    to { opacity: 1; transform: translateY(0); }
}

/* Bouton de base : full-width, pill, fond subtil, bordure color-tier */
.nav-btn {
    appearance: none;
    -webkit-tap-highlight-color: transparent;
    width: 100%;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 16px;
    text-align: left;
    font-family: inherit;
    font-size: 0.95rem;
    font-weight: 500;
    letter-spacing: 0.3px;
    color: rgba(255, 255, 255, 0.92);
    cursor: pointer;
    border-radius: 14px;
    border: 1px solid rgba(255, 255, 255, 0.10);
    background:
        linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%);
    position: relative;
    overflow: hidden;
    isolation: isolate;
    /* Sweep gradient subtil au hover */
    background-size: 220% 220%;
    background-position: 0% 50%;
    transition:
        background-position 0.55s ease,
        border-color 0.3s ease,
        transform 0.25s cubic-bezier(0.2, 0.7, 0.3, 1),
        box-shadow 0.3s ease,
        color 0.3s ease;
}

/* Halo sheen : sweep diagonal qui balaie le bouton au hover */
.nav-btn::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(110deg,
        transparent 25%,
        color-mix(in srgb, var(--main-color) 45%, transparent) 50%,
        transparent 75%);
    opacity: 0;
    transform: translateX(-100%);
    transition: opacity 0.35s ease, transform 0.65s cubic-bezier(0.2, 0.7, 0.3, 1);
    pointer-events: none;
    z-index: -1;
}

.nav-btn:hover {
    color: #ffffff;
    border-color: var(--main-color);
    background-position: 100% 50%;
    transform: translateY(-2px);
    box-shadow:
        0 6px 18px rgba(0, 0, 0, 0.35),
        0 0 24px color-mix(in srgb, var(--main-color) 40%, transparent);
}

.nav-btn:hover::before {
    opacity: 1;
    transform: translateX(0%);
}

.nav-btn:focus-visible {
    outline: none;
    border-color: var(--main-color);
    box-shadow:
        0 0 0 3px color-mix(in srgb, var(--main-color) 30%, transparent),
        0 0 24px color-mix(in srgb, var(--main-color) 40%, transparent);
}

.nav-btn:active {
    transform: translateY(0) scale(0.985);
    transition-duration: 0.1s;
}

/* Chip icône : carré arrondi à gauche, qui se teinte au hover */
.nav-btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--main-color) 18%, transparent);
    color: var(--main-color);
    flex-shrink: 0;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.06);
    transition:
        background 0.3s ease,
        color 0.3s ease,
        transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1),
        box-shadow 0.3s ease;
}
.nav-btn-icon svg {
    width: 20px;
    height: 20px;
    display: block;
}

.nav-btn:hover .nav-btn-icon {
    background: var(--main-color);
    color: #0a0a0a;
    transform: rotate(-6deg) scale(1.06);
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.25),
        0 0 18px color-mix(in srgb, var(--main-color) 55%, transparent);
}

.nav-btn-label {
    flex: 1 1 auto;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Page courante (détectée par JS sur aria-current="page") */
.nav-btn[aria-current="page"] {
    border-color: var(--main-color);
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--main-color) 22%, transparent) 0%,
        color-mix(in srgb, var(--main-color) 11%, transparent) 100%);
    color: #ffffff;
}
.nav-btn[aria-current="page"] .nav-btn-icon {
    background: var(--main-color);
    color: #0a0a0a;
    animation: nav-btn-pulse 2.4s ease-in-out infinite;
}

@keyframes nav-btn-pulse {
    0%, 100% {
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, 0.25),
            0 0 12px color-mix(in srgb, var(--main-color) 50%, transparent);
    }
    50% {
        box-shadow:
            inset 0 1px 0 rgba(255, 255, 255, 0.40),
            0 0 28px color-mix(in srgb, var(--main-color) 80%, transparent);
    }
}

/* Ripple au click : élément positionné au point de clic, scale-out */
.nav-btn-ripple {
    position: absolute;
    left: 0;
    top: 0;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    pointer-events: none;
    background: color-mix(in srgb, var(--main-color) 55%, transparent);
    opacity: 0;
    transform: translate(-50%, -50%) scale(0);
}
.nav-btn-ripple.is-active {
    animation: nav-btn-ripple 0.6s cubic-bezier(0.3, 0.7, 0.4, 1);
}

@keyframes nav-btn-ripple {
    0%   { opacity: 0.55; transform: translate(-50%, -50%) scale(0); }
    100% { opacity: 0;    transform: translate(-50%, -50%) scale(8); }
}

/* Thème clair : override pour la lisibilité (le nav-panel passe en clair
   via theme.js). */
html.theme-light .nav-btn {
    background: linear-gradient(135deg, rgba(0,0,0,0.04) 0%, rgba(0,0,0,0.015) 100%);
    border-color: rgba(0,0,0,0.12);
    color: #1a1a1a;
}
html.theme-light .nav-btn:hover {
    color: #1a1a1a;
    box-shadow:
        0 6px 18px rgba(0, 0, 0, 0.10),
        0 0 24px color-mix(in srgb, var(--main-color) 40%, transparent);
}
html.theme-light .nav-btn[aria-current="page"] {
    color: #1a1a1a;
    background: linear-gradient(135deg,
        color-mix(in srgb, var(--main-color) 18%, transparent) 0%,
        color-mix(in srgb, var(--main-color) 8%, transparent) 100%);
}

/* Mode no-animations : tout s'éteint proprement */
html.no-animations .nav-btn,
html.no-animations .nav-btn-icon,
html.no-animations .nav-btn-ripple,
html.no-animations .nav-btn[aria-current="page"] .nav-btn-icon {
    animation: none !important;
    transition: none !important;
}
html.no-animations .nav-btn::before {
    display: none;
}

/* Mobile : resserrer pour gagner de la place */
@media (max-width: 1024px) {
    .nav-buttons { gap: 8px; }
    .nav-btn { padding: 10px 14px; font-size: 0.9rem; }
    .nav-btn-icon { width: 32px; height: 32px; border-radius: 9px; }
    .nav-btn-icon svg { width: 18px; height: 18px; }
}

.hidden-song { display: none !important; }

/* Masque la cover et le titre tant que la première chanson n'est pas chargée */
.opening.player-loading .track-cover,
.opening.player-loading .track-info {
    opacity: 0;
    transition: opacity 0.4s ease;
}

/* Volume-container désormais ENFANT de .opening (cf. *.html de chaque page).
   En mode par défaut, on rajoute un séparateur subtil + un peu d'air au-dessus
   de la pill pour qu'elle ne donne pas l'impression d'être une forme bizarre
   imbriquée dans la card (background identique, border-radius différent).
   Sélecteur `.opening > .volume-container` → spécificité (0,2,0) qui reste
   inférieure à `html.player-horizontal .volume-container` (0,2,1), donc les
   règles horizontales restent prioritaires en mode player-horizontal. */
.opening > .volume-container {
    margin-top: 22px;
    padding-top: 16px;
    border-top: 1px solid rgba(255, 255, 255, 0.06);
}

/* Volume - AJUSTEMENT : Reste aligné sous le lecteur */
.volume-container {
    background: rgba(18, 18, 18, 0.9);
    padding: 12px 25px;
    border-radius: 30px;
    display: flex;
    align-items: center;
    gap: 15px;
    width: 100%; 
    margin: 20px 0; 
    box-shadow: 0 8px 20px rgba(0,0,0,0.4);
    box-sizing: border-box;
}

#volume-slider { flex-grow: 1; accent-color: var(--main-color); }

#volume-icon {
    font-size: 1.2rem;
    cursor: pointer;
}

/* --- RESPONSIVE MOBILE --- */
@media (max-width: 1024px) {
    body { overflow-y: auto; height: auto; }
    .main-container { flex-direction: column; align-items: center; height: auto; padding: 20px; }
    .left-column, .middle-column, .nav-column { width: 100%; max-width: 500px; flex: none; }
    .middle-column { order: -1; height: 600px; }
    .main-title { font-size: 2rem; }
}

/* Style du bouton Afficher plus / moins */
.btn-toggle-category {
    display: block;
    width: fit-content;
    margin: 10px 0 20px 15px; /* Aligné avec le texte de la liste */
    padding: 8px 16px;
    background: rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 20px;
    color: var(--main-color);
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.3s ease;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

.btn-toggle-category:hover {
    background: var(--main-color);
    color: #000; /* Texte noir sur fond vert pour le contraste */
    box-shadow: 0 0 15px var(--main-color);
    transform: translateY(-2px);
}

.btn-toggle-category:active {
    transform: translateY(0);
}

/* Ajustement pour l'espacement des groupes */
.playlist-group {
    margin-bottom: 30px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}

/* --- SECTION BANNIÈRE FINALE (DOUBLE CLIPART) --- */

.custom-header {
    display: flex;
    width: 94vw;
    margin: 20px auto;
    height: 100px;
    gap: 4px;
    filter: drop-shadow(0 10px 20px rgba(0,0,0,0.8));
}

.btn-back {
    flex: 0 0 160px;
    height: 100%;
    background-color: rgba(0,0,0,0.8);
    display: flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
    color: white;
    font-size: 2.8rem;
    /* Tous les coins arrondis (25px sur 100px de haut → forme pilule).
       On supprime le clip-path polygon qui écrasait border-radius au hover
       et révélait des coins angulaires au lieu des coins arrondis attendus. */
    border-radius: 25px;
    z-index: 2;
    transition: background 0.3s;
}

.title-banner {
    flex: 1;
    height: 100%;
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: center;
    /* On met 25px partout, ou au moins sur les 4 coins */
    border-radius: 25px; 
    background-color: rgba(0,0,0,0.8);
    border: 5px solid rgba(0,0,0,0.8); 
    box-sizing: border-box;
    clip-path: none; /* Assure-toi que c'est bien retiré ici */
    text-align: left;
    padding-left: 150px; 
}

/* h1 du title-banner : mirror de album.css pour eviter chevauchement
   avec clipart-left sur la home page (accueil.html ne charge pas
   album.css dynamiquement, donc le mirror est obligatoire ici). */
/* h1 harmonisé avec shared-header.css (famille Norex) : police system-ui,
   dégradé blanc → --main-color, taille clamp. nowrap + ellipsis car
   certaines pages Music portent des titres longs (album / saga). */
.title-banner > h1 {
    position: relative;
    z-index: 2;
    margin: 0;
    min-width: 0;
    max-width: 100%;
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    font-size: clamp(2rem, 5vw, 3.5rem);
    font-weight: 700;
    letter-spacing: 0.6px;
    line-height: 1.1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    background: linear-gradient(90deg, #ffffff 0%, var(--main-color, #FF66B3) 85%);
    -webkit-background-clip: text;
            background-clip: text;
    -webkit-text-fill-color: transparent;
}

/* BASE COMMUNE : On verrouille la hauteur */
.clipart-left, .clipart-right {
    position: absolute;
    top: 0;
    bottom: 0; /* Force l'ancrage vertical */
    height: 100%; /* L'image fera exactement 100px */
    width: auto;  /* La largeur s'adapte au ratio de l'image */
    /* max-width 60px (cap dur pour eviter que le logo domine). Ancien
       100% = sur grand ecran le logo pouvait prendre 200-300px et
       superposer le titre. 60px est le sweet-spot "ico-discret". */
    max-width: 60px;
    /* "contain" assure que l'image est entièrement visible en hauteur */
    object-fit: contain;
    /* z-index 0 : place DERRIERE .title-banner > h1 (z-index:2) pour
       ne jamais chevaucher visuellement le titre. */
    z-index: 0;
    pointer-events: none;
    opacity: 0.75; /* discret */
}

/* IMAGE GAUCHE : Collée à gauche, le "vide" se crée à droite */
.clipart-left {
    left: 0;
    object-position: left center;
    /* padding-left 8px (etait 45px) : le logo est maintenant colle a
       l'edge du banner. L'ancien 45px combinée avec .title-banner
       padding-left:150px = les deux reservaient 195px au total, ecrasant
       la zone du titre ("Norex Music" sur home, titre long sur category). */
    padding-left: 8px;
    box-sizing: border-box;
}

/* IMAGE DROITE : Collée à droite, le "vide" se crée à gauche */
.clipart-right {
    right: 0;
    object-position: right center; 
    padding-right: 0px;
    box-sizing: border-box;
    padding-right: 20px;
}

/* Transitions alignées sur shared-header.css. */
.title-banner {
    transition: background 0.4s ease, box-shadow 0.3s ease, transform 0.3s ease;
}
.btn-back {
    transition: background 0.3s ease, box-shadow 0.3s ease, transform 0.3s ease;
}
.title-banner:hover, .btn-back:hover {
    background-color: var(--main-color);
    border-color: var(--main-color);
    color: white;
    /* Halo + léger lift, comme les autres apps. */
    box-shadow: 0 0 32px var(--main-color);
    transform: translateY(-1px);
}
/* Au survol la pill prend --main-color : on force le titre en blanc
   sinon le dégradé (blanc → main-color) se confond avec le fond. */
.title-banner:hover > h1,
.title-banner:focus-within > h1 {
    background: none;
    -webkit-text-fill-color: #fff;
    color: #fff;
    text-shadow: 0 0 14px rgba(0, 0, 0, 0.45);
}

/* =============================================================
   FAVORITES — Bouton cœur sur chaque carte de morceau (list mode)
   ============================================================= */

/* Le li passe en flex pour aligner le label à gauche et le favori à droite */
.playlist-sidebar li {
    display: flex;
    align-items: center;
    gap: 10px;
}
/* Petite cover (icône du morceau) en début de ligne — DOM créé par
   player.js renderList() avec className playlist-cover-thumb.
   36×36 px, coins arrondis, src = song.cover. Chargement lazy pour ne
   pas bloquer la première peinture quand 100+ tracks. */
.playlist-sidebar li .playlist-cover-thumb {
    flex: 0 0 auto;
    width: 36px;
    height: 36px;
    margin-right: 4px;
    border-radius: 6px;
    object-fit: cover;
    background: rgba(255, 255, 255, 0.06);
    transition: transform 0.25s cubic-bezier(0.2, 0.7, 0.3, 1),
                box-shadow 0.25s ease;
}
.playlist-sidebar li:hover .playlist-cover-thumb {
    transform: scale(1.08);
    box-shadow: 0 0 12px color-mix(in srgb, var(--main-color) 40%, transparent);
}
.playlist-sidebar li.active .playlist-cover-thumb {
    box-shadow: 0 0 14px color-mix(in srgb, var(--main-color) 60%, transparent);
}
/* Fallback pendant le load : on fond subtil pour que la place soit
   réservée même si la cover est lente à arriver (notamment en file://). */
.playlist-sidebar li .playlist-cover-thumb:not([src]),
.playlist-sidebar li .playlist-cover-thumb[src=""] {
    background:
        linear-gradient(135deg,
            color-mix(in srgb, var(--main-color) 30%, transparent),
            rgba(255, 255, 255, 0.06));
}
/* Le label occupe tout l'espace disponible ; le bouton cœur reste coll(é à droite */
.playlist-sidebar li .playlist-item-label {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    /* petit fade gradient côté droit (mieux quand le titre est tronqué) */
    -webkit-mask-image: linear-gradient(to right, black 0%, black 88%, transparent 100%);
            mask-image: linear-gradient(to right, black 0%, black 88%, transparent 100%);
}
.playlist-sidebar li .fav-btn {
    flex: 0 0 auto;
    width: 34px;
    height: 34px;
}
.playlist-sidebar li .fav-btn svg {
    width: 17px;
    height: 17px;
}
/* État actif li : fond vert fluo. Le bouton favori hérite du `color: black`
   imposé par .playlist-sidebar li.active (pour le label). On force `color: white`
   sur le cœur de sorte qu'il reste visible — mais UNIQUEMENT quand le morceau
   actif n'est PAS dans les favoris : si is-favorite, on garde la couleur accent
   qui est déjà imposée par .fav-btn.is-favorite (le cœur rempli vert sur vert
   actif = signal "ce morceau passe en ce moment ET tu l'as liké"). */
.playlist-sidebar li.active .fav-btn:not(.is-favorite) {
    color: white;
    border-color: rgba(255, 255, 255, 0.55);
}
/* Cas actif + favori : sans cette règle, on a un cœur rempli vert sur fond
   vert actif → le cœur se fond visuellement dans la ligne. On pose une
   pastille foncée autour du bouton pour que le cœur vert se détache. */
.playlist-sidebar li.active .fav-btn.is-favorite {
    background: rgba(0, 0, 0, 0.50);
    border-color: rgba(255, 255, 255, 0.55);
    box-shadow: 0 0 14px rgba(0, 0, 0, 0.55),
                0 0 12px color-mix(in srgb, var(--main-color) 70%, transparent);
}

/* ---- Bouton cœur — base partagée avec album.css ---- */
.fav-btn {
    appearance: none;
    -webkit-tap-highlight-color: transparent;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: rgba(255, 255, 255, 0.92);
    background: rgba(0, 0, 0, 0.32);
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 999px;
    cursor: pointer;
    padding: 0;
    width: 36px;
    height: 36px;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
    transition: color 0.25s ease, transform 0.25s cubic-bezier(0.2, 0.7, 0.3, 1),
                background 0.25s ease, border-color 0.25s ease,
                box-shadow 0.25s ease;
    vertical-align: middle;
}
.fav-btn:hover {
    color: var(--main-color);
    border-color: var(--main-color);
    transform: scale(1.08);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35),
                0 0 14px color-mix(in srgb, var(--main-color) 40%, transparent);
}
.fav-btn:active {
    transform: scale(0.94);
}
.fav-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--main-color) 35%, transparent);
}
.fav-btn svg {
    width: 18px;
    height: 18px;
    display: block;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    transition: fill 0.2s ease;
}
/* État favori : cœur rempli + accent color + glow */
.fav-btn.is-favorite {
    color: var(--main-color);
    background: color-mix(in srgb, var(--main-color) 20%, rgba(0, 0, 0, 0.42));
    border-color: var(--main-color);
    box-shadow: 0 0 12px color-mix(in srgb, var(--main-color) 55%, transparent);
}
.fav-btn.is-favorite svg {
    fill: currentColor;
}
/* Animation pop à chaque toggle (JS pose et retire .pop-anim en ~420ms) */
.fav-btn.pop-anim svg {
    animation: fav-pop 0.42s cubic-bezier(0.2, 0.7, 0.3, 1);
}
@keyframes fav-pop {
    0%   { transform: scale(1); }
    30%  { transform: scale(1.40); }
    60%  { transform: scale(0.94); }
    100% { transform: scale(1); }
}
/* Bouton désactivé si library.js n'a pas chargé */
.fav-btn.is-disabled,
.fav-btn[aria-disabled="true"] {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}
/* Mode no-animations : coupe tout proprement */
html.no-animations .fav-btn,
html.no-animations .fav-btn:hover,
html.no-animations .fav-btn:active,
html.no-animations .fav-btn svg,
html.no-animations .fav-btn.pop-anim svg {
    transition: none !important;
    animation: none !important;
}
/* Mode clair : override pour la lisibilité du cœur sur fond clair */
html.theme-light .fav-btn {
    background: rgba(255, 255, 255, 0.6);
    border-color: rgba(0, 0, 0, 0.18);
    color: #1a1a1a;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.10);
}
html.theme-light .fav-btn.is-favorite {
    color: var(--main-color);
    background: color-mix(in srgb, var(--main-color) 22%, rgba(255, 255, 255, 0.6));
    border-color: var(--main-color);
}
/* Theme-light override pour la cover thumb : fond plus contrasté sur
   fond clair pour que la place carrée reste perceptible même sans src. */
html.theme-light .playlist-sidebar li .playlist-cover-thumb {
    background: rgba(0, 0, 0, 0.08);
}
html.theme-light .playlist-sidebar li .playlist-cover-thumb:not([src]),
html.theme-light .playlist-sidebar li .playlist-cover-thumb[src=""] {
    background:
        linear-gradient(135deg,
            color-mix(in srgb, var(--main-color) 30%, transparent),
            rgba(0, 0, 0, 0.08));
}

/* Mode no-animations : coupe la transition sur la cover thumb. */
html.no-animations .playlist-sidebar li .playlist-cover-thumb,
html.no-animations .playlist-sidebar li:hover .playlist-cover-thumb {
    transition: none !important;
    transform: none !important;
}

/* === MINI EQ — 3 barres animées purement CSS dans le li actif ===
   Zéro WebAudio, zéro risque de couper le son. Animation @keyframes
   infinie, visible UNIQUEMENT quand body.is-playing (géré par les
   audio listeners dans player.js) ET que le li parent porte la classe
   .active (géré par updateActiveMenu()).
   Couleur secondaire (var(--bg-color-2)), pilotée par player.js selon
   le morceau courant en mode ambient, ou par la couleur user-secondary
   en mode Sombre/Clair (cf. theme.js). */
.mini-eq {
    display: none; /* caché par défaut; display:inline-flex via règle conditionnelle ci-dessous */
    flex: 0 0 auto;
    /* Conteneur 16×16px : intégration propre à côté du fav-btn (34px de hauteur)
       sans déformer le line-height ni casser l'alignement vertical existant. */
    width: 16px;
    height: 16px;
    /* margin-left:auto colle le mini-EQ à droite du label juste avant
       le bouton cœur, sans avoir à toucher au layout flex existant. */
    margin-left: auto;
    align-items: flex-end;
    gap: 2px;
    pointer-events: none; /* déco : on ne capte pas les clics */
}
body.is-playing .playlist-sidebar li.active .mini-eq {
    display: inline-flex;
}
.mini-eq > i {
    display: block;
    /* Largeur 4px (avant 3px) : barres un cran plus solides, mieux visibles
       à distance et contre le fond vert de la ligne active. */
    width: 4px;
    /* Hauteur par défaut (état "off"); l'animation @keyframes ci-dessous
       module la hauteur entre 26% et 92%. Le transform-origin bas
       garantit que les barres poussent depuis le sol du conteneur. */
    height: 26%;
    background: var(--bg-color-2);
    /* Pas de border-radius : sur une barre fine animée qui descend jusqu'à
       26% (≈4px de haut), un radius de 1px mange toute la largeur visible
       et donne un effet "bouton rond" disgracieux à basse amplitude. */
    border-radius: 0;
    transform-origin: bottom;
    opacity: 0.85;
    animation: mini-eq-bar 1.05s ease-in-out infinite;
    will-change: height;
}
/* Délais négatifs pour que les 3 barres soient déphasées dès la première
   frame (sinon elles démarrent toutes en sync puis divergent). */
.mini-eq > i:nth-child(1) { animation-delay: -0.05s; }
.mini-eq > i:nth-child(2) { animation-delay: -0.40s; }
.mini-eq > i:nth-child(3) { animation-delay: -0.78s; }

@keyframes mini-eq-bar {
    0%, 100% { height: 26%; }
    18%      { height: 92%; }
    38%      { height: 40%; }
    56%      { height: 78%; }
    78%      { height: 32%; }
}

/* No-animations : on masque entièrement le mini-EQ. Afficher 3 barres
   statiques figées à 60% de hauteur donnerait un rendu visuellement pauvre
   et incohérent avec le mode normal animé ; mieux vaut désactiv carrément.
   L'indicateur visuel de piste en cours reste assuré par le styling .active
   sur le li parent (background-color: var(--main-color) + font-weight: bold,
   cf. règle .playlist-sidebar li.active plus haut dans ce fichier). */
html.no-animations .mini-eq {
    display: none !important;
}

/* ==============================================================
   LECTEUR HORIZONTAL SPOTIFY-STYLE (opt-in)
   ==============================================================
   Activable depuis Settings → Player → Reader layout. Default OFF.
   Quand html.player-horizontal est posé (et seulement sur desktop via
   le media query) : le lecteur devient une barre fixe de 90px en bas
   de l'écran, à la mode Spotify (cover mini | titre/artiste limité |
   controls + progress | volume). Les panneaux de droite (nav menu +
   audio-sphere canvas) sont masqués pour laisser la playlist respirer.
   QUAND L'OPTION EST OFF : aucun override n'est appliqué, layout
   3 colonnes actuel conservé intact (cf. .main-container standard).
   On utilise display:contents sur .left-column au lieu de display:none
   pour retirer la colonne du flux SANS cacher ses enfants fixes. */
@media (min-width: 1025px) {
    html.player-horizontal .left-column {
        display: contents;
    }
    html.player-horizontal .main-container {
        height: calc(100vh - 120px - 90px);
    }
    /* IMPORTANT : la nav menu (Home/Upload/Library/Settings) reste
       visible à droite en mode horizontal — l'utilisateur veut garder
       l'accès aux boutons de navigation. En revanche on cache la sphère
       audio 3D : en mode Spotify-style, le footer 90px de haut passe
       exactement à la verticale de la nav-column, et le canvas orb qui
       flotte dans la colonne risquait de chevaucher visuellement le
       volume-container ou de s'afficher comme un blob tronqué en bas à
       droite (l'effet « wtf is happening with my soundbar »). Spotify
       n'utilise pas ce genre d'ornement dans son player — on suit la
       même sobriété. La sphère reste parfaitement fonctionnelle
       quand l'option est OFF (le DOM est intact, juste display:none). */
    html.player-horizontal #audio-sphere {
        display: none !important;
    }

    /* ===== Barre du bas — .opening (cover + info + controls + progress + volume) ===== */
    /* Le volume-container a été déplacé dans .opening (cf. chaque page .html de
       NorexMusic) : il ne sert plus à rien de réserver 220px à droite via
       `right: 220px` — la soundbar est désormais un enfant flex direct du
       .opening et se place naturellement à droite du spotify-player (timeline +
       controls). On étend le .opening sur tout l'écran (right: 0) pour que le
       volume-container ait sa place dans la rangée flex. */
    html.player-horizontal .opening {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        height: 90px;
        /* z-index 60 + soundbar en flex child : la soundbar est forcément sous
           le player. Plus de bug "time bar behind soundbar" car visuelle­ment
           elles sont côte-à-côte dans le même bottom-bar. */
        z-index: 60;
        display: flex;
        align-items: center;
        padding: 0 20px;
        border-radius: 0;
        text-align: left;
        box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.4);
        margin: 0;
        animation: none !important;
    }
    html.player-horizontal .track-cover {
        width: 56px;
        height: 56px;
        aspect-ratio: 1 / 1;
        margin: 0 14px 0 0;
        border-radius: 6px;
        flex: 0 0 auto;
    }
    html.player-horizontal .track-info {
        flex: 0 0 220px;
        min-width: 0; /* CRUCIAL : ne pas casser le scroll title + ellipsis */
        margin-right: 16px;
        overflow: hidden;
        /* FIX « GROS RECTANGLE GRIS » 2026-07-30 : on neutralise le
           mask-image gradient du base rule. En narrow + ellipsis, le
           fade transparent->opaque-->transparent sur les bords créait
           une zone grisâtre visible même quand le texte était court.
           L'ellipsis seule suffit en mode horizontal. */
        -webkit-mask-image: none !important;
                mask-image: none !important;
    }
    html.player-horizontal .track-info h3 {
        animation: none !important;
        /* On coupe l'animation scroll-text en narrow. display:block +
           max-width:100% garantissent que l'ellipsis se déclenche sur
           tous les navigateurs (Chromium 70+, Safari 14+, Firefox 70+)
           de façon canonique, plutôt que de s'appuyer sur le quirk
           inline-block + max-width:100% qui peut foirer en bas renderer. */
        display: block;
        max-width: 100%;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        font-size: 0.92rem;
        /* === GARDE-FOUS DEFENSIFS (anti-régression rectangle gris) ===
           background: transparent !important neutralise tout héritage
               parasite (theme.js skeleton, default user-agent, futur
               override) qui pourrait poser un fond gris sur l'élément
               texte en mode narrow. Sans !important, specificity (0,3,2)
               bat déjà le base rule (0,1,1), mais on force la priorité
               pour résister à un futur override plus spécifique.
           padding: 0 ferme toutes les boxes de padding appliqué par
               user-agent sur h3 (qui peut donner l'illusion d'un
               rectangle rempli).
           min-width: 0 désactive tout min-width hérité qui forcerait
               l'inline-block natif à demander plus de largeur → scroll
               horizontal → titre invisible derrière un clip rect. */
        background: transparent !important;
        padding: 0 !important;
        min-width: 0;
    }
    html.player-horizontal .track-info p {
        font-size: 0.78rem;
        background: transparent !important;
    }
    html.player-horizontal .track-info p {
        font-size: 0.78rem;
    }
    html.player-horizontal .spotify-player {
        flex: 1;
        min-width: 0;
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        margin: 0;
        /* Bug fix 2026-07-27 : overflow hidden pour contenir le
           .progress-bar interne (flex-grow:1) dans la colonne.
           Sans ça, le progress-bar peut déborder et créer une fine
           bande noire parasite en haut du player. */
        overflow: hidden;
    }
    /* Inverse l'ordre : controls au-dessus, barre de temps en-dessous (style Spotify) */
    html.player-horizontal .controls {
        order: 1;
        margin: 0 auto;
        gap: 18px;
    }
    /* Play button boost : on le sort du lot pour qu'il soit le point focal
       du bottom bar. Taille up, accent color, halo léger — comme sur
       Spotify où l'œil est attiré directement vers le bouton central. */
    html.player-horizontal #play-pause {
        width: 60px;
        height: 60px;
        font-size: 3rem;
        color: var(--main-color);
        text-shadow: 0 0 14px color-mix(in srgb, var(--main-color) 55%, transparent);
        transition: transform 0.25s cubic-bezier(0.2, 0.7, 0.3, 1),
                    text-shadow 0.25s ease;
    }
    html.player-horizontal #play-pause:hover {
        transform: scale(1.06);
        text-shadow: 0 0 22px color-mix(in srgb, var(--main-color) 75%, transparent);
    }
    html.player-horizontal #play-pause:active {
        transform: scale(0.96);
    }
    /* LÉGÈRE RÉDUCTION de la timeline : max-width 96% au lieu de width:100% plein,
       ce qui la rétrécit de quelques pixels pour laisser respirer la soundbar
       à sa droite. Combiné à l'arrivée du volume-container dans le flux flex,
       le spotify-player (qui contient la timeline) est déjà mécaniquement
       plus étroit d'environ 200px — on évite ici de trop compressor en
       ajoutant une marge visuelle supplémentaire. */
    html.player-horizontal .time-wrapper {
        order: 2;
        margin: 6px auto 0;
        width: 100%;
        max-width: 96%; /* légèrement réduite vs 100% plein */
        gap: 10px;
        /* Bug fix 2026-07-27 : min-width:0 pour permettre au
           .progress-bar enfant (flex-grow:1) de shrink correctement. */
        min-width: 0;
    }
    /* Bar de temps plus épaisse (8px au lieu de 5px) + halo subtil sur
       la fill pour souligner la position de lecture — plus lisible
       dans une barre 90px de haut où le track-info doit rester compact. */
    html.player-horizontal .progress-bar {
        height: 8px;
        border-radius: 4px;
        /* Bug fix 2026-07-27 : min-width:0 pour permettre au
           progress-bar (flex-grow:1) de shrink correctement dans
           son parent flex. */
        min-width: 0;
    }
    html.player-horizontal .progress {
        border-radius: 4px;
        box-shadow: 0 0 10px color-mix(in srgb, var(--main-color) 65%, transparent);
    }

    /* ===== Barre du bas — .volume-container (enfant flex direct de .opening) =====
       Avant : .volume-container était un frère fixed-positionné en bas à droite
       (right: 0 width: 220px) et visuellement distinct du .opening — la soundbar
       apparaissait comme un bloc séparé SOUS la timeline.
       Maintenant : .volume-container est un enfant flex de .opening, à droite
       du spotify-player. Il occupe ~210px de large (assez pour l'icône 🔊 + le
       slider de volume), le reste du space va au spotify-player qui contient
       timeline + controls. Visuellement la soundbar est À CÔTÉ de la timeline.
       Aucun fixed/absolute nécessaire : .opening gère tout via flex row. */
    html.player-horizontal .volume-container {
        flex: 0 0 210px;  /* ~210px à droite, absorbe un peu moins que les 220px
                              d'avant pour laisser respirer la timeline (réduite
                              mécaniquement via le flex-basis du volume). */
        height: 100%;
        margin: 0 0 0 8px;  /* petit gap à gauche pour décoller visuellement du
                                spotify-player */
        padding: 0 14px;
        border-radius: 0;
        box-shadow: none;
        background: transparent;  /* on se fond dans .opening pour l'effet "bar
                                    unifiée" en bas */
        display: flex;
        align-items: center;
        gap: 12px;
    }
    /* En mode player horizontal, l'icône 🔊 du volume garde la même taille
       mais le slider prend la largeur restante dans le bloc 210px. */
    html.player-horizontal .volume-container #volume-slider {
        flex: 1 1 auto;
        min-width: 0;
    }

    /* Theme-light : barre claire pour la lisibilité sur fond pâle.
       On n'applique le background blanc qu'à .opening — .volume-container
       (désormais enfant flex de .opening) se met en `background: transparent`
       par défaut et hérite donc de la couleur de .opening. Effet : la soundbar
       et la timeline/l'ouverture forment UNE seule barre unie en bas, sans
       qu'on devine la frontière entre les deux. */
    html.theme-light.player-horizontal .opening {
        background: rgba(255, 255, 255, 0.95);
        border-top: 1px solid rgba(0, 0, 0, 0.08);
        box-shadow: 0 -5px 18px rgba(0, 0, 0, 0.06);
    }
}

/* Sous 1024px, l'option est désactivée par construction (media query ci-dessus
   ignore l'override structure), donc mobile conserve le layout empilé normal.
   En complément : forcer le player à réapparaitre dans la colonne normale
   même si .nav-column.display:none a fui (sécurité). */
@media (max-width: 1024px) {
    /* Sécurité mobile : si l'option a été activée puis l'écran rétréci,
       on force la nav column à réapparaitre avec display:flex (valeur
       explicite, plus prévisible que le mot-clé `revert` qui dépend du
       navigateur). */
    html.player-horizontal .nav-column { display: flex !important; }
    html.player-horizontal .navigation-panel { display: block !important; }
    html.player-horizontal #audio-sphere { display: block !important; }
}

/* =====================================================================
   === MOBILE SHELL REWORK 2026-08-14 ====================================
   Spotify-like bottom-stack layout (≤1024px) :
     - Tab bar (Home / Library / Liked / Settings) : fixed bottom 56px
     - Mini-player (cover + title/artist + prev + play) : above tabbar 64px
     - Now Playing overlay : quand html.np-open, le `.left-column` existant
       devient un overlay slide-up full-screen.

   Le player DOM (cover/titre/controls/volume) reste dans `.left-column`. La
   seule chose qui change : sur mobile, .left-column est caché par défaut et
   révélé en overlay (z-index 50) quand l'user tape le mini-player. Un bouton
   "↓" (.norex-mobile-np-collapse) dans le coin top permet de refermer.

   L'ancien pattern (cue pill en haut, swipe-down pour ouvrir la liste,
   peek overlay en bas, sheet qui slide-down) est SUPPRIMÉ. La liste
   (.middle-column) reste désormais toujours visible en aire de contenu
   principale. Search est accessible via la search-box déjà présente dans
   header de la liste.
   ===================================================================== */

/* Variables globales (cascadent sur .left-column / .middle-column / etc.)
   Sortent de la media query pour être réutilisables côté JS (calcul du
   padding-bottom via getComputedStyle). */
:root {
    --mobile-tabbar-h: 56px;
    --mobile-mini-h:   64px;
    --mobile-np-collapse-h: 44px;
    --mobile-safe-bottom: env(safe-area-inset-bottom, 0px);
    --mobile-safe-top:    env(safe-area-inset-top, 0px);
    --mobile-bottom-h: calc(var(--mobile-tabbar-h) + var(--mobile-mini-h) + var(--mobile-safe-bottom));
}

/* === Hide legacy mobile shell (cue / peek / settings corner) ============ */
.norex-mobile-cue,
.norex-mobile-settings,
.norex-mobile-peek {
    display: none !important;
}

@media (max-width: 1024px) {
    /* === Hide nav-column : replaced by bottom tabbar === */
    .nav-column { display: none !important; }

    /* === Body / main-container reset === */
    body { overflow-y: auto; height: auto; }
    .main-container {
        display: block;
        height: auto;
        padding: 0;
        /* padding-bottom laisse place au tabbar + mini-player
           (= --mobile-bottom-h calculé plus haut) */
        padding-bottom: var(--mobile-bottom-h);
        align-items: initial;
        flex-direction: initial;
    }

    /* === .left-column : HIDDEN by default on mobile =================
       Visible UNIQUEMENT quand html.np-open est posé (= Now Playing
       overlay ouvert). Le contenu du player (cover/titre/controls/volume)
       est inchangé : il réutilise les styles .left-column .opening etc.
       définis un peu plus bas dans ce fichier. */
    .left-column { display: none !important; }
    html.np-open .left-column {
        display: flex !important;
        position: fixed;
        inset: 0;
        z-index: 50;
        /* Slide-up from bottom (Spotify-like). 320ms cubic-bezier agressif
           pour snap, sans rebond (le reverse est instant quand close). */
        animation: norex-np-rise 0.32s cubic-bezier(0.32, 0.72, 0, 1);
        transform: translateZ(0); /* GPU layer pour animation fluide */
    }
    @keyframes norex-np-rise {
        from { transform: translate(0, 100%); }
        to   { transform: translate(0, 0); }
    }

    /* === .middle-column : main content area =================
       Sur mobile c'est l'aire scrollable principale. Plus de fixed
       positioning (l'ancien pattern de sheet qui slide-down est retiré). */
    .middle-column {
        position: static;
        inset: auto;
        z-index: auto;
        width: 100%;
        max-width: 100%;
        flex: none;
        height: auto;
        min-height: 60vh;
        display: flex;
        flex-direction: column;
        background: transparent;
        backdrop-filter: none;
        -webkit-backdrop-filter: none;
        transform: none !important;
        transition: none !important;
        padding: 0;
    }

    /* === Search-box : padded from top, larger touch target === */
    .middle-column > .search-box {
        flex: 0 0 auto;
        padding: 14px 16px 8px;
    }
    .middle-column > .search-box input {
        font-size: 16px; /* >= 16px = coupe le zoom auto iOS */
        height: 44px;
        padding: 0 14px;
        border-radius: 22px;
    }

    /* === Tunings for nested views (hub / favs / playlist) === */
    .middle-column #playlist-container,
    .middle-column #library-hub-root,
    .middle-column #favs-view-root,
    .middle-column #playlist-view-root {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
        padding: 0 12px 16px;
    }

    /* === Tab bar : Spotify-like bottom navigation ================= */
    .norex-mobile-tabbar {
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        height: calc(var(--mobile-tabbar-h) + var(--mobile-safe-bottom));
        padding-bottom: var(--mobile-safe-bottom);
        z-index: 30;
        display: flex;
        align-items: stretch;
        background:
            linear-gradient(180deg,
                rgba(20, 20, 20, 0.94) 0%,
                rgba(12, 12, 12, 0.97) 100%);
        backdrop-filter: blur(22px) saturate(160%);
        -webkit-backdrop-filter: blur(22px) saturate(160%);
        border-top: 1px solid rgba(255, 255, 255, 0.05);
        user-select: none;
        -webkit-user-select: none;
    }
    .norex-mobile-tab {
        flex: 1 1 0;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        padding: 4px 4px 0;
        background: transparent;
        border: none;
        color: rgba(255, 255, 255, 0.55);
        font: inherit;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
        transition: color 0.2s ease, transform 0.15s ease;
        min-height: 56px;
    }
    .norex-mobile-tab:active {
        transform: scale(0.93);
    }
    .norex-mobile-tab.is-active {
        color: var(--main-color, #ffffff);
    }
    .norex-mobile-tab-icon {
        font-size: 22px;
        line-height: 1;
        font-weight: 500;
        display: block;
    }
    .norex-mobile-tab-label {
        font-size: 10px;
        font-weight: 600;
        letter-spacing: 0.4px;
        text-transform: uppercase;
        line-height: 1.2;
        margin-top: 2px;
    }

    /* === Mini-player : persistent above tabbar ===================== */
    .norex-mobile-mini {
        position: fixed;
        left: 0;
        right: 0;
        bottom: calc(var(--mobile-tabbar-h) + var(--mobile-safe-bottom));
        height: var(--mobile-mini-h);
        z-index: 30;
        display: flex;
        align-items: center;
        gap: 10px;
        padding: 0 10px 0 12px;
        background:
            linear-gradient(180deg,
                rgba(30, 30, 30, 0.94) 0%,
                rgba(20, 20, 20, 0.96) 100%);
        backdrop-filter: blur(22px) saturate(160%);
        -webkit-backdrop-filter: blur(22px) saturate(160%);
        border-top: 1px solid rgba(255, 255, 255, 0.05);
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
        transition: transform 0.15s ease;
        user-select: none;
        -webkit-user-select: none;
    }
    .norex-mobile-mini:active {
        transform: scale(0.985);
    }
    .norex-mobile-mini[hidden] { display: none !important; }
    .norex-mobile-mini-cover {
        width: 48px;
        height: 48px;
        border-radius: 6px;
        flex-shrink: 0;
        object-fit: cover;
        background: rgba(255, 255, 255, 0.06);
    }
    .norex-mobile-mini-text {
        flex: 1 1 0;
        min-width: 0;
        display: flex;
        flex-direction: column;
        gap: 2px;
        pointer-events: none; /* tap sur le texte déclenche le openNowPlaying */
    }
    .norex-mobile-mini-title {
        font-size: 0.92rem;
        font-weight: 700;
        line-height: 1.2;
        color: rgba(255, 255, 255, 0.95);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .norex-mobile-mini-artist {
        font-size: 0.78rem;
        font-weight: 500;
        line-height: 1.2;
        color: rgba(255, 255, 255, 0.62);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .norex-mobile-mini-btn-prev,
    .norex-mobile-mini-btn-play {
        width: 44px;
        height: 44px;
        flex-shrink: 0;
        border-radius: 50%;
        background: transparent;
        color: rgba(255, 255, 255, 0.92);
        border: none;
        padding: 0;
        cursor: pointer;
        font-size: 1.65rem;
        line-height: 1;
        display: flex;
        align-items: center;
        justify-content: center;
        -webkit-tap-highlight-color: transparent;
        transition: background 0.15s ease, transform 0.10s ease;
    }
    .norex-mobile-mini-btn-prev:active,
    .norex-mobile-mini-btn-play:active {
        background: rgba(255, 255, 255, 0.10);
        transform: scale(0.92);
    }
    .norex-mobile-mini-btn-play[data-state="playing"] {
        color: var(--main-color, #ffffff);
    }

    /* === Now Playing collapse button (np-back) ===================== *
       v42 (2026-08-14) — bouton spec user "remonter a l'accueil".
       En haut du lecteur (NP overlay, html.np-open posé sur <html>).
       - LÉGÈRE MARGE latérale (8px de chaque côté) + COINS ARRONDIS (20px)
         → forme "pill" rectangulaire, ne touche pas les bords de l'écran.
       - Fond LÉGÈREMENT TRANSLUCIDE + backdrop-filter blur (effet glass).
       - V inversé (chevron up) ÉLARGI à la largeur du bouton via SVG
         preserveAspectRatio="none" + width 100%, marge 4% sur les bords.
       - height bouton 96px + SVG 52px + stroke-width 0.10.
       - Tap = closeNowPlaying() (JS déjà câblé) → ferme le NP, retour à
         la vue précédente (Home / Library / Favorites). ============= */
    html.np-open .np-back {
        position: fixed !important;
        top: calc(var(--mobile-safe-top, 0px) + 6px);
        left: 50% !important;              /* centré horizontalement */
        right: auto !important;
        transform: translateX(-50%);
        z-index: 51;
        width: 56px !important;            /* petit bouton compact, pas un bandeau */
        height: 44px !important;
        background: rgba(255, 255, 255, 0.08) !important;
        border: none !important;
        border-radius: 20px !important;   /* COINS ARRONDIS */
        color: rgba(255, 255, 255, 0.96);
        font-size: 0 !important;
        line-height: 0;
        padding: 0 !important;
        cursor: pointer;
        backdrop-filter: blur(20px) saturate(180%) !important;
        -webkit-backdrop-filter: blur(20px) saturate(180%) !important;
        -webkit-tap-highlight-color: rgba(255, 255, 255, 0.10);
        display: flex !important;
        align-items: center;
        justify-content: center;
        transition: opacity 0.2s ease, transform 0.2s ease, background 0.2s ease;
        overflow: hidden;                  /* clip le SVG aux coins arrondis */
    }
    html.np-open .np-back-icon {
        width: 100% !important;
        height: 24px !important;
        display: block !important;
        color: inherit;
    }
    html.np-open .np-back[hidden] { display: none !important; }
    html.np-open .np-back:active {
        opacity: 0.78;
        transform: scale(0.985);
        background: rgba(255, 255, 255, 0.14) !important;
    }
    html.theme-light.np-open .np-back {
        background: rgba(0, 0, 0, 0.05) !important;
        color: rgba(0, 0, 0, 0.85);
    }
    html.theme-light.np-open .np-back:active {
        background: rgba(0, 0, 0, 0.10) !important;
    }
}

/* === Theme-light overrides for new mobile shell ========================= */
@media (max-width: 1024px) {
    html.theme-light .norex-mobile-tabbar {
        background:
            linear-gradient(180deg,
                rgba(248, 248, 248, 0.95) 0%,
                rgba(240, 240, 240, 0.97) 100%);
        border-top-color: rgba(0, 0, 0, 0.08);
    }
    html.theme-light .norex-mobile-tab { color: rgba(0, 0, 0, 0.55); }
    html.theme-light .norex-mobile-tab.is-active {
        color: var(--main-color, #000);
    }
    html.theme-light .norex-mobile-mini {
        background:
            linear-gradient(180deg,
                rgba(252, 252, 252, 0.95) 0%,
                rgba(245, 245, 245, 0.97) 100%);
        border-top-color: rgba(0, 0, 0, 0.07);
    }
    html.theme-light .norex-mobile-mini-cover {
        background: rgba(0, 0, 0, 0.06);
    }
    html.theme-light .norex-mobile-mini-title { color: rgba(0, 0, 0, 0.88); }
    html.theme-light .norex-mobile-mini-artist { color: rgba(0, 0, 0, 0.55); }
    html.theme-light .norex-mobile-mini-btn-prev,
    html.theme-light .norex-mobile-mini-btn-play {
        color: rgba(0, 0, 0, 0.82);
    }
    html.theme-light .norex-mobile-mini-btn-prev:active,
    html.theme-light .norex-mobile-mini-btn-play:active {
        background: rgba(0, 0, 0, 0.08);
    }
    html.theme-light .norex-mobile-np-collapse {
        background: rgba(0, 0, 0, 0.10);
        color: rgba(0, 0, 0, 0.85);
        border-color: rgba(0, 0, 0, 0.16);
    }
    html.theme-light .norex-mobile-np-collapse:active {
        background: rgba(0, 0, 0, 0.18);
    }
}

/* === Reduced-motion ====================================================== */
@media (max-width: 1024px) and (prefers-reduced-motion: reduce) {
    .left-column,
    .middle-column,
    .norex-mobile-mini,
    .norex-mobile-tab,
    .norex-mobile-tabbar,
    .norex-mobile-np-collapse {
        transition-duration: 0.01ms !important;
        transition-timing-function: step-end !important;
        animation-duration: 0.01ms !important;
    }
}
/* =====================================================================
   === MOBILE PLAYER FULLSCREEN (Spotify-style) ==========================
   Le .left-column occupe tout l'écran (cf. bloc précédent). On calibre
   maintenant ce qui se voit à l'intérieur : cover, titre, progress,
   contrôles, volume. Objectif : rendu proche de l'app Spotify mobile.
     - Cover : carré, capé à 360px via min(80vw, 360px) (sur iPhone
       ~390px de large = ~310px ; sur Pixel ~412px = ~330px). Plus petit
       que les 400px+ d'avant, ne mange pas tout l'écran.
     - Title : 1.5rem (24px) bold, jusqu'à 2 lignes avec line-clamp.
     - Artist : 1.05rem (~17px) en opacité reduced.
     - Time + progress : 0.85rem (~14px) labels, bar 6px de haut.
     - Controls : repeat/random 44px, prev/next 56px, play 80px.
       Distribution `justify-content: space-between` pour spread
       régulier (Spotify-like, pas 20px de gap fixe).
     - Volume : on retire la "pill" card .volume-container (slim, sans
       bg/shadow, max-width 320px).
     - .opening : on retire le card-feeling (background, shadow, radius),
       on centre verticalement avec justify-content: space-around +
       padding-top qui clear le cue (72px+) et le peek-bar quand ouvert.

   Tous les règles sont préfixées par `.left-column` pour ne pas
   impacter les vues desktop (où `.left-column` a `flex: 0 0 22vw;
   max-width: 400px` côté desktop et le player est dans un card).
   ===================================================================== */
@media (max-width: 1024px) {
    /* Layout : cover+info prennent le haut, controls+volume se collent
       en bas via margin-top:auto sur spotify-player. Tous les éléments
       sont rapprochés — finis les "space-around" qui étalaient tout
       verticalement sur un grand écran. On supprime le card-feel. */
    .left-column .opening {
        width: 100%;
        max-width: 100%;
        height: 100%;
        background: transparent !important;
        box-shadow: none !important;
        border-radius: 0 !important;
        padding: 0 !important;
        margin: 0 !important;
        text-align: center;
        box-sizing: border-box;
        display: flex;
        flex-direction: column;
        align-items: center;
        /* default = flex-start ; contrôle via margin-top sur chaque enfant
           pour des écarts FIXES entre eux (pas de redistribution dynamique
           liée à la hauteur — on veut que la cover soit toujours près
           du haut et les controls toujours près du bas). */
        justify-content: flex-start;
        /* Padding top clear le cue (env ~14+46 = ~60 du haut) + safe-area.
           Padding bottom : safe-area + un peu d'air — le peek-bar est
           `translateY(100%)` par défaut, donc hors-champ. */
        padding-top: calc(72px + env(safe-area-inset-top, 0px)) !important;
        padding-bottom: calc(20px + env(safe-area-inset-bottom, 0px)) !important;
        padding-left: 24px !important;
        padding-right: 24px !important;
    }

    /* Cover : 95vw capé à 480px pour emplir ~45-50% du viewport
       vertical sur téléphone standard (Galaxy S25 ~400×880).
       flex-shrink:0 empêche la cover de se compresser. */

    /* === overlay sombre : .left-column === Avant : le player était
       transparent et le gradient bg (souvent violet/bleu) rendait
       les blocks blancs illisibles. Maintenant : on applique un
       fond sombre + backdrop-blur sur .left-column (le wrapper).
       Tous les enfants (cover, titre, controls) profitent de ce
       fond homogène pour le contraste. */
    .left-column {
        background:
            linear-gradient(180deg,
                rgba(0, 0, 0, 0.55) 0%,
                rgba(0, 0, 0, 0.78) 100%);
        backdrop-filter: blur(36px) saturate(140%);
        -webkit-backdrop-filter: blur(36px) saturate(140%);
    }
    /* Theme-light : fond plus subtil en haut, plus marqué en bas. */
    html.theme-light .left-column {
        background:
            linear-gradient(180deg,
                rgba(255, 255, 255, 0.35) 0%,
                rgba(255, 255, 255, 0.65) 100%);
        backdrop-filter: blur(24px) saturate(140%);
    }
    .left-column .track-cover {
        width: min(95vw, 480px);
        max-width: 480px;
        aspect-ratio: 1 / 1;
        border-radius: 18px;
        margin: 0;
        box-shadow: 0 22px 50px rgba(0, 0, 0, 0.65);
        flex-shrink: 0;
    }

    /* Track-info : collé sous cover. Pas de max-width : full-width centré.
       Le line-clamp du h3 limite le wrap à 2 lignes (très long titre). */
    .left-column .track-info {
        width: 100%;
        max-width: 100%;
        margin-top: 24px;
        text-align: center;
        overflow: hidden;
    }
    .left-column .track-info h3 {
        font-size: 2.10rem;        /* ~34px */
        font-weight: 800;
        line-height: 1.18;
        margin: 0;
        color: rgba(255, 255, 255, 0.97);
        display: -webkit-box;
        -webkit-line-clamp: 2;
        line-clamp: 2;
        -webkit-box-orient: vertical;
        white-space: normal;
        word-break: break-word;
        overflow: hidden;
        animation: none !important;
        transform: none !important;
        will-change: auto !important;
    }
    .left-column .track-info p {
        font-size: 1.35rem;        /* ~22px */
        font-weight: 500;
        color: rgba(255, 255, 255, 0.70);
        margin: 8px 0 0;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* Spotify-player : margin-top minimal (16px) pour rester
       collé au bloc info. flex-shrink:0 lui interdit de se faire
       écraser par la cover si la hauteur manque. */
    .left-column .spotify-player {
        width: 100%;
        margin-top: 16px;
        flex-shrink: 0;
    }

    /* Time wrapper : progress + current/duration en ligne */
    .left-column .time-wrapper {
        width: 100%;
        margin: 0;
        font-size: 1.00rem;
        color: rgba(255, 255, 255, 0.75);
        gap: 16px;
        letter-spacing: 0.4px;
    }
    .left-column .progress-bar {
        height: 8px;
        border-radius: 8px;
    }

    /* Controls : plus grands qu'avant (repeat/random 48, prev/next 60,
       play 88). Distribution space-between sans gap fixe (les boutons
       extrêmes touchent les bords du conteneur, le centre reste centré
       via flex grow automatique). */
    .left-column .controls {
        width: 100%;
        max-width: 100%;
        margin-top: 10px;
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 0;
        flex-shrink: 0;
    }
    .left-column .btn-repeat,
    .left-column .btn-random {
        width: 60px;
        height: 60px;
        font-size: 1.65rem;
    }
    .left-column .btn-prev,
    .left-column .btn-next {
        width: 76px;
        height: 76px;
        font-size: 2.20rem;
    }
    .left-column #play-pause {
        width: 112px;
        height: 112px;
        font-size: 3.40rem;
        /* Couleur SOLID bassée sur --main-color (et non un
           blanc à 12% alpha qui disparaît sur gradient). Le bouton
           voit sa couleur user comme bg, avec texte dark (noir) pour
           contraste. Fallback: blanc opaque si pas de main-color. */
        background: var(--main-color, #ffffff);
        color: #000;
        border: none;
        border-radius: 50%;
        box-shadow: 0 8px 26px rgba(0, 0, 0, 0.55);
    }
    .left-column #play-pause:active {
        transform: scale(0.96);
        filter: brightness(0.9);
    }
    /* Theme-light : main-color peut être sombre, on inverse la logique. */
    html.theme-light .left-column #play-pause {
        background: var(--main-color, rgba(0,0,0,0.85));
        color: #fff;
    }

    /* Volume : juste sous les controls, slim (pas de pill card). */
    .left-column .opening > .volume-container {
        width: 100%;
        max-width: 100%;
        margin-top: 12px;
        padding: 0 !important;
        background: transparent !important;
        box-shadow: none !important;
        border-radius: 0 !important;
        border-top: none !important;
        gap: 18px;
        flex-shrink: 0;
    }
    .left-column #volume-icon {
        font-size: 1.30rem;
        opacity: 0.85;
        font-weight: 500;
    }
    .left-column #volume-slider {
        height: 6px;
        cursor: pointer;
    }

    /* Theme-light : couleurs du player */
    html.theme-light .left-column {
        color: rgba(0, 0, 0, 0.88);
    }
    html.theme-light .left-column .track-info h3 {
        color: rgba(0, 0, 0, 0.92);
    }
    html.theme-light .left-column .track-info p {
        color: rgba(0, 0, 0, 0.60);
    }
    html.theme-light .left-column #play-pause {
        background: var(--main-color, rgba(0,0,0,0.85));
        color: #fff;
    }
    html.theme-light .left-column .time-wrapper {
        color: rgba(0, 0, 0, 0.65);
    }
}



/* =====================================================================
   === MOBILE SHELL REWORK 2026-08-14 v2 (Spotify EXACT clone) ==========
   ZÉRO héritage PC. Sur ≤1024px le DOM PC est totalement masqué et le
   mobile a ses propres blocs dédiés (.mobile-appbar, .mini-player,
   .mobile-tabs, .np-back). Le `.left-column` du desktop devient l'overlay
   Now Playing quand html.np-open est posé (tap mini → open).

   Dimensions Spotify-like FIXES :
     - App bar (top)            : 56px (+ safe-area-top)
     - Mini-player              : 64px height, cover 56×56 r=4, titre 15px bold
     - Tab bar (bottom)         : 56px + safe-area-bottom, icônes SVG 24px + label 11px UPPER
     - Now Playing cover        : min(80vw, 380px), square, radius 8
     - Now Playing controls     : shuffle/random 44px, prev/next 60px, play 76px (Spotify EXACT)
   ===================================================================== */

/* Variables globales — aussi référencées depuis le JS pour calculs de padding. */
:root {
    /* === MOBILE FIX v55 (2026-08-14) : REPART DE LA VERSION PC =======
       User (répété plusieurs fois) : « trop collé et disproportionné.
       repars de la version PC ». On RETIRE toutes les sur-couches
       mobile custom (v45→v54) et on PART des valeurs PC.

       Les vars ci-dessous restent utiles pour calculer le padding +
       bottom du .middle-column (cf. ligne 1949 mobile @media), mais
       on RETOURNE à des proportions PC :
         • Appbar / tabbar / mini : tailles PC standard (44px / 56px /
           64px) ≈ meme ratio que sur desktop.
         • Aucun scale-up agressif. Les composants mobile-shell restent
           visibles mais à des tailles sobres.
       =============================================================== */
    --mobile-safe-top:    env(safe-area-inset-top, 0px);
    --mobile-safe-bottom: env(safe-area-inset-bottom, 0px);
    --mobile-tabbar-h: 52px;        /* v59 -5% */
    --mobile-appbar-h:  52px;       /* PC-like -5% */
    /* === MOBILE FIX v59 (2026-08-14) : mini-player AGRANDI =============
       User : « aggrandi le lecteur qui se trouve en bas de page ». 64→110
       (≈ +72%) pour avoir un vrai player compacte-style Spotify natif :
       cover 64, play 56, textes 18/15 dans 110px de haut.
       v59+ (2026-08-15) : poussé à 140px — revenu à 110px (trop gros). */
    --mobile-mini-h:   104px;      /* -5% */
}

@media (max-width: 1024px) {
    /* ============================================================
       Step 1 : on ÉTEINT tout le DOM PC. Aucun héritage ne doit
       polluer l'UI mobile.
       ============================================================ */
    .nav-column,
    .navigation-panel,
    #audio-sphere,
    .main-title,
    .custom-header,
    .left-column,
    .norex-mobile-cue,
    .norex-mobile-settings,
    .norex-mobile-peek {
        display: none !important;
    }

    /* ============================================================
       Step 2 : reset base mobile
       ============================================================ */
    html, body {
        margin: 0;
        padding: 0;
        background: var(--bg-color, #131313);
        height: 100dvh;
        overflow: hidden;
        -webkit-font-smoothing: antialiased;
        -webkit-tap-highlight-color: transparent;
        text-rendering: optimizeLegibility;
    }
    body { overflow: hidden; }
    .main-container {
        display: block !important;
        padding: 0 !important;
        margin: 0 !important;
        height: auto !important;
        width: auto !important;
        position: static !important;
        align-items: initial !important;
        flex-direction: initial !important;
        background: var(--bg-color, #131313);
    }

    /* ============================================================
       Step 3 : contenu central
       v58 (2026-08-14) : mobile-tabs est passé AU-DESSUS (top), donc
       .middle-column commence APRES tabs + appbar et finit AVANT
       mini-player (qui est seul en bas).
       Layout de haut en bas :
         [tabs (top:0)]
         [appbar (top: tabbar-h)]
         [middle-column (top: tabbar-h + appbar-h + safe-top)]
         [mini-player (bottom:0)]
       ============================================================ */
    .middle-column {
        position: fixed;
        top: calc(var(--mobile-tabbar-h, 80px) + var(--mobile-appbar-h, 56px) + var(--mobile-safe-top, 0px));
        left: 0;
        right: 0;
        width: auto; /* neutralise le width:100% du bloc 1323 (content-box) qui débordait de 32px */
        bottom: calc(var(--mobile-mini-h, 180px) + var(--mobile-safe-bottom, 0px));
        padding: 12px 24px 24px;
        overflow-y: auto;
        overflow-x: hidden;
        background: var(--bg-color, #131313);
        display: flex;
        flex-direction: column;
        height: auto;
        min-height: 0;
        z-index: 10;
    }
    /* Le search-box par défaut du desktop devient un input mobile
       elegant. Si l'appbar-title est "Search", ça prend focus.
       v48 (2026-08-14) : scale-up agressif — height 52→60, font 17→18.
       v49 (2026-08-14) : « la barre de recherche est trop petite,
       augmente largement » → height 60→76 (+27%), font 18→20 (+11%).
       = barre massive qui s'impose, pas un petit détail en haut. */
    .middle-column .search-box {
        flex: 0 0 auto;
        padding: 0 0 14px;
        width: 100%;
        box-sizing: border-box;
    }
    .middle-column .search-box input {
        font-size: 16px !important; /* 16px ≥ 16px : pas de zoom auto iOS */
        height: 48px !important;    /* 48px : sobre, pas de bandeau imposant */
        padding: 0 16px !important;
        border-radius: 24px !important;
        background: rgba(255, 255, 255, 0.07);
        border: none;
        color: rgba(255, 255, 255, 0.96);
        width: 100%;
        box-sizing: border-box;
        font-weight: 500 !important;
        letter-spacing: 0.2px;
    }
    .middle-column .search-box input::placeholder {
        color: rgba(255, 255, 255, 0.45);
    }
    /* Listes (sidebar) : Spotify-style rows */
    .middle-column #playlist-container,
    .middle-column .playlist-sidebar {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
        padding: 0;
        margin: 0;
        background: transparent;
    }
    .middle-column .playlist-sidebar li {
        display: flex;
        align-items: center;
        gap: 10px;
        padding: 4px 0;
        height: 44px;
    }
    .middle-column .playlist-sidebar li img,
    .middle-column .playlist-sidebar li .pl-cover,
    .middle-column .playlist-sidebar li .album-cover-thumb {
        width: 36px;
        height: 36px;
        flex-shrink: 0;
        border-radius: 4px;
        object-fit: cover;
    }
    .middle-column .playlist-sidebar li .pl-text {
        flex: 1;
        min-width: 0;
    }
    .middle-column .playlist-sidebar li .playlist-item-label {
        font-size: 14px;
        font-weight: 600;
        color: rgba(255, 255, 255, 0.96);
    }
    /* Titres de catégories (h3 générés par renderList) : plus petits
       et décalés du bord comme les listes. */
    .middle-column .playlist-sidebar .playlist-group > h3,
    .middle-column .playlist-sidebar .playlist-group > .category-clickable h3 {
        font-size: 14px !important;
        font-weight: 700;
        margin: 18px 0 6px;
        padding: 0 0 8px;
        line-height: 1.2;
    }
    .middle-column .playlist-sidebar li .pl-title {
        font-size: 14px;
        font-weight: 600;
        color: rgba(255, 255, 255, 0.96);
        line-height: 1.2;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .middle-column .playlist-sidebar li .pl-artist {
        font-size: 12px;
        font-weight: 500;
        color: rgba(255, 255, 255, 0.55);
        line-height: 1.2;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    /* Hub cards (library page) : horizontal list of square cover cards */
    /* v50 (2026-08-14) : « boutons d'accès aux favoris et aux playlist
       trop gros » — le single-column forçait chaque tile à width viewport
       entière → covers 400×400px. On passe à 3 colonnes (desktop-like
       mais plus dense). Les tiles logent en cover 1:1 ~125px wide. */
    .middle-column .lib-hub-grid,
    .middle-column .album-grid {
        /* minmax(0,1fr) : sans le 0, `1fr` = minmax(auto,1fr) et le
           min-content des cartes (taille naturelle des images) force
           des colonnes inégales qui débordent de l'écran. */
        grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
        gap: 14px !important;
        padding: 8px 8px !important;
    }
    /* Reset le flex-row override qui transformait .album-card en row
       compacte (cassé avec le 3-col grid : on veut le layout desktop
       cover au-dessus titre en dessous). */
    .middle-column .lib-hub-grid .album-card,
    .middle-column .album-grid .album-card {
        display: block !important;
        padding: 0 !important;
        border-radius: 12px !important;
        background: rgba(18, 18, 18, 0.6) !important;
        height: auto !important;
        min-height: 0 !important;
        min-width: 0 !important;
        align-items: stretch !important;
    }
    .middle-column .album-card .album-cover-wrapper,
    .middle-column .album-card .album-cover,
    .middle-column .album-card .pl-cover,
    .middle-column .album-card img {
        width: 100% !important;
        height: auto !important;
        aspect-ratio: 1/1;
        flex: 0 0 auto;
        min-width: 0 !important;
        border-radius: 10px !important;
        margin: 0;
        object-fit: cover;
        box-shadow: none;
    }
    .middle-column .album-card .album-info {
        flex: initial !important;
        text-align: left;
        padding: 8px 4px 6px !important;
    }
    .middle-column .album-card .album-title {
        font-size: 9.5px !important;
        font-weight: 700;
        line-height: 1.2;
        margin: 0;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        color: rgba(255, 255, 255, 0.96);
    }
    .middle-column .album-card .album-artist {
        font-size: 11px !important;
        font-weight: 500;
        line-height: 1.2;
        margin: 2px 0 0;
        color: rgba(255, 255, 255, 0.55);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .middle-column .album-card:hover,
    .middle-column .album-card:hover .album-cover {
        transform: none;
    }
    .middle-column .album-card .play-overlay,
    .middle-column .album-card .album-play-btn { display: none !important; }

    /* ============================================================
       Step 4 : mobile-appbar (top bar : back + title + ⚙)
       v58 (2026-08-14) : tabs sont passées en haut, donc appbar
       descend juste en dessous. top = tabbar-h + safe-top.
       Stack visuel de haut en bas :
         1. mobile-tabs    (top: 0)
         2. mobile-appbar  (top: tabbar-h + safe-top)
         3. middle-column  (top: tabbar-h + appbar-h + safe-top)
         4. mini-player    (bottom: 0)
       ============================================================ */
    .mobile-appbar {
        display: flex;
        align-items: center;
        position: fixed;
        top: calc(var(--mobile-tabbar-h, 80px) + var(--mobile-safe-top, 0px));
        left: 0;
        right: 0;
        height: var(--mobile-appbar-h, 56px);
        padding: 0 12px 0;
        background: var(--bg-color, #131313);
        z-index: 40;
    }
    .mobile-appbar[hidden] { display: none !important; }
    /* === MOBILE FIX v37 (2026-08-14) bouton back REMONTER FULL WIDTH
       Le user veut un bouton "remonter dans les listes" :
         - Plus gros
         - Centré (horizontalement sur la largeur de l'écran)
         - Fait la largeur de l'écran
         - Rectangle invisible (background transparent)
         - V inversé (chevron up) très large comme contenu
       On transforme .mobile-appbar-back :
       - width 100%, height 100% → couvre toute l'appbar
       - background transparent (invisible)
       - ↑ caractère unicode (V inversé) en font-size 36px
         (très large et lisible)
       - position absolute pour overlay la zone title (qui devient non-tapable
         mais reste visible SEO/accessibility).
       - justify-content + align-items center → ↑ centré visuellement. */
    .mobile-appbar-back {
        position: absolute !important;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        width: 100% !important;
        height: 100% !important;
        background: transparent !important;
        border: none !important;
        color: rgba(255, 255, 255, 0.96);
        font-size: 36px !important;
        font-weight: 100 !important;
        line-height: 1;
        cursor: pointer;
        display: flex !important;
        align-items: center;
        justify-content: center;
        padding: 0 !important;
        z-index: 3;
        /* Tap target full-width, touch-friendly */
        -webkit-tap-highlight-color: rgba(255, 255, 255, 0.08);
        transition: opacity 0.2s ease;
    }
    .mobile-appbar-back:active { opacity: 0.55; }
    .mobile-appbar-back[hidden] { display: none !important; }
    /* v48 (2026-08-14) : titre 19→22px (de vrai HEADER element, pas
       détail de UI), line-height suit la nouvelle appbar height 72. */
    .mobile-appbar-title {
        flex: 1;
        text-align: center;
        font-size: 18px !important;
        font-weight: 700 !important;
        color: rgba(255, 255, 255, 0.96);
        margin: 0;
        padding: 0;
        line-height: 52px;
        text-overflow: ellipsis;
        overflow: hidden;
        white-space: nowrap;
        letter-spacing: 0.2px;
    }
    /* v48 : settings 48×48 → 52×52 (tap cible encore plus grande),
       svg 26→28. */
    .mobile-appbar-settings {
        width: 48px !important;
        height: 48px !important;
        background: transparent;
        border: none;
        color: rgba(255, 255, 255, 0.85);
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0;
        text-decoration: none;
    }
    .mobile-appbar-settings svg {
        width: 26px !important;
        height: 26px !important;
    }

    /* ============================================================
       Step 5 : mini-player (persistent at bottom, Spotify EXACT)
       v59 (2026-08-14) : tabs ne sont plus en bas, mini-player est
       seul en `bottom: 0`. Height bumpé 64 → 110 → 140 (+118%) pour
       vrai "agrandissement" demandé par user. Cover 88, play 84,
       textes 22/18 — Spotify-like imposant. */
    .mini-player {
        position: fixed;
        left: 0;
        right: 0;
        bottom: var(--mobile-safe-bottom, 0px);
        height: var(--mobile-mini-h, 140px);
        z-index: 35;
        display: flex;
        align-items: center;
        gap: 12px;
        padding: 0 14px 0 14px;
        /* === MOBILE COLOR REACT (2026-08-15) ============================
           Le mini-player réagit à la couleur de la piste en cours
           (player.js pose --main-color sur <html> au loadSong). Avant, fond
           gris/blur figé -> "grey and sad". Maintenant : backdrop tinté
           par --bg-color-2 + glow lumineux issu de --main-color. Si les
           vars ne sont pas encore posées (cold load), les fallbacks ramènent
           aux valeurs grey d'origine pour ne pas casser l'UI. */
        background:
            radial-gradient(circle at 18% 50%,
                color-mix(in srgb, var(--main-color, rgb(170,40,40)) 8%, transparent) 0%,
                transparent 60%),
            linear-gradient(180deg,
                color-mix(in srgb, var(--bg-color-2, rgb(50,50,50)) 92%, rgba(0,0,0,0.85)) 0%,
                color-mix(in srgb, var(--bg-color-2, rgb(30,30,30)) 90%, rgba(0,0,0,0.92)) 100%);
        backdrop-filter: blur(16px) saturate(160%);
        -webkit-backdrop-filter: blur(16px) saturate(160%);
        border-top: 0.5px solid rgba(255, 255, 255, 0.08);
        box-shadow:
            0 -1px 0 color-mix(in srgb, var(--main-color, rgb(255,255,255)) 22%, transparent) inset,
            0 -8px 32px color-mix(in srgb, var(--main-color, rgb(170,40,40)) 28%, transparent);
        transition: box-shadow 0.6s ease, background 0.6s ease;
        user-select: none;
        -webkit-user-select: none;
    }
    .mini-player[hidden] { display: none !important; }
    /* v59 (2026-08-14) : box 110→140, contenu suit : cover 72→88 (+22%),
       title 19→22 (+16%), artist 16→18 (+13%), play 64→84 rond
       (svg 34→44). Lecture confortable, généreux, look Spotify-like. */
    /* MOBILE COLOR REACT : glow colorisé sur la cover, ring de contraste
       en main-color pour delimiter la pochette sur le fond glassmorph. */
    .mini-cover {
        width: 56px;
        height: 56px;
        border-radius: 8px;
        object-fit: cover;
        background: rgba(255, 255, 255, 0.06);
        flex: 0 0 56px;
        pointer-events: none;
        box-shadow:
            0 0 0 1px color-mix(in srgb, var(--main-color, rgb(255,255,255)) 30%, transparent),
            0 4px 18px color-mix(in srgb, var(--main-color, rgb(0,0,0)) 40%, transparent);
        transition: box-shadow 0.6s ease;
    }
    .mini-text {
        flex: 1;
        min-width: 0;
        display: flex;
        flex-direction: column;
        gap: 6px;
        pointer-events: none;
        padding: 8px 0;
    }
    /* v59 : title 18, artist 15 — lisibles sans être envahissants. */
    .mini-title {
        font-size: 15px !important;
        font-weight: 700 !important;
        line-height: 1.2;
        color: rgba(255, 255, 255, 0.96);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .mini-artist {
        font-size: 12px !important;
        font-weight: 500 !important;
        line-height: 1.2;
        color: rgba(255, 255, 255, 0.62);
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    /* v59 : mini-play 56 rond, svg 36 — bouton play compact. */
    /* MOBILE COLOR REACT : le bouton prend la couleur de la piste. Ring
       exterieur en --main-color, fond verre translucent, hover/active
       plus opaque. */
    .mini-play {
        width: 44px !important;
        height: 44px !important;
        background: rgba(255, 255, 255, 0.10);
        border: 1.5px solid color-mix(in srgb, var(--main-color, rgb(255,255,255)) 55%, transparent);
        border-radius: 999px;
        color: rgba(255, 255, 255, 0.96);
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0;
        /* PAS de margin-right : le gap du .mini-controls suffit, sinon
           le play semble plus éloigné du next que du prev. */
        -webkit-tap-highlight-color: rgba(255, 255, 255, 0.10);
        box-shadow:
            0 0 0 4px color-mix(in srgb, var(--main-color, rgb(170,40,40)) 18%, transparent),
            0 4px 24px color-mix(in srgb, var(--main-color, rgb(170,40,40)) 45%, transparent);
        transition: transform 0.15s ease, background 0.15s ease, box-shadow 0.6s ease, border-color 0.6s ease;
    }
    .mini-play:active {
        transform: scale(0.94);
        background: color-mix(in srgb, var(--main-color, rgb(255,255,255)) 22%, rgba(255, 255, 255, 0.20));
    }
    .mini-play[data-state="playing"] svg { color: var(--main-color, rgb(255,255,255)); }
    .mini-play svg {
        width: 24px !important;
        height: 24px !important;
    }
    .mini-play[data-state="paused"] .mini-play-icon-pause { display: none; }
    .mini-play[data-state="playing"] .mini-play-icon-play { display: none; }

    /* ============================================================
       Step 6 : tab bar (3 tabs Spotify EXACT)
       v58 (2026-08-14) : tabs AU-DESSUS (top: 0 + safe-top). User
       « déplace cette foutue barre avec les boutons de navigation en
       haut de page ». On retire la `border-bottom` qui faisait office
       de séparation bas → on met `border-bottom` horizontale entre
       tabs et l'appbar juste en dessous.
       ============================================================ */
    .mobile-tabs {
        position: fixed;
        top: var(--mobile-safe-top, 0px);
        left: 0;
        right: 0;
        height: var(--mobile-tabbar-h, 80px);
        padding: 0;
        z-index: 50;          /* au-dessus du appbar (z=40) */
        display: flex;
        background: rgba(20, 20, 20, 0.97);
        backdrop-filter: blur(20px) saturate(140%);
        -webkit-backdrop-filter: blur(20px) saturate(140%);
        border-bottom: 0.5px solid rgba(255, 255, 255, 0.10);
    }
    /* v48 : mobile-tab encore plus gros : min-height 64 → 76
       (via --mobile-tabbar-h v48), label 13→14.5px, icon 26→30px.
       Assez d'air pour qu'on lise sans effort. */
    .mobile-tab {
        flex: 1;
        background: transparent;
        border: none;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 4px;
        padding: 8px 0 10px;
        color: rgba(255, 255, 255, 0.50);
        cursor: pointer;
        min-height: 52px !important;
        font-family: inherit;
        transition: color 0.15s ease;
    }
    .mobile-tab-icon {
        width: 24px !important;
        height: 24px !important;
        fill: currentColor;
    }
    .mobile-tab-label {
        font-size: 12px !important;
        font-weight: 700;
        letter-spacing: 0.4px;
        line-height: 1;
        text-transform: uppercase;
    }
    /* MOBILE COLOR REACT : tab actif prend la couleur de la piste. */
    .mobile-tab.is-active {
        color: var(--main-color, rgba(255, 255, 255, 0.96));
    }
    /* Indicateur barre fine en haut du tab actif (spotify-like underline). */
    .mobile-tab.is-active {
        position: relative;
    }
    .mobile-tab.is-active::before {
        content: "";
        position: absolute;
        top: 4px;
        left: 22%;
        right: 22%;
        height: 3px;
        border-radius: 999px;
        background: var(--main-color, rgba(255,255,255));
        box-shadow: 0 0 8px color-mix(in srgb, var(--main-color, rgb(170,40,40)) 60%, transparent);
        transition: background 0.6s ease, box-shadow 0.6s ease;
    }
    /* Ping live : pulse subtil lors d'un changement de piste. */
    @keyframes mini-tab-pulse {
        0%   { transform: scaleY(0.6); opacity: 0.4; }
        40%  { transform: scaleY(1.2); opacity: 1; }
        100% { transform: scaleY(1);   opacity: 1; }
    }
    /* Quand body.is-playing (player.js toggle) ET tab actif -> pulse joué 1x. */
    body.is-playing .mobile-tab.is-active::before {
        animation: mini-tab-pulse 0.6s ease-out 1;
    }

    /* ============================================================
       Step 7 : Now Playing toolbar (top-left back arrow)
       ============================================================ */
    .np-back {
        position: fixed;
        top: calc(var(--mobile-safe-top) + 8px);
        left: 12px;
        z-index: 60;
        width: 44px;
        height: 44px;
        background: rgba(255, 255, 255, 0.10);
        color: rgba(255, 255, 255, 0.96);
        border: none;
        border-radius: 22px;
        font-size: 22px;
        line-height: 1;
        font-weight: 300;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        backdrop-filter: blur(12px);
        -webkit-backdrop-filter: blur(12px);
        transition: transform 0.20s ease;
    }
    .np-back[hidden] { display: none !important; }

    /* ============================================================
       Step 8 : quand html.np-open : .left-column devient overlay
                Spotify-like. Reset TOTAL de son inner layout via all:unset
                puis re-style from scratch (cover center, controls row).
       ============================================================ */
    html.np-open .left-column {
        display: flex !important;
        position: fixed;
        inset: 0;
        z-index: 50;
        /* MOBILE COLOR REACT : radial gradient qui tire vers --main-color
           en haut (echo de la couleur de la pochette sous le titre).
           Fallback gris pour cold-load avant que player.js pose main-color. */
        background:
            radial-gradient(ellipse at top,
                color-mix(in srgb, var(--main-color, rgb(170,40,40)) 22%, transparent) 0%,
                color-mix(in srgb, var(--bg-color-2, rgb(39,39,39)) 92%, transparent) 55%,
                transparent 100%),
            var(--bg-color, #131313);
        padding: 0;
        margin: 0;
        overflow-y: auto;
        animation: np-rise 0.32s cubic-bezier(0.32, 0.72, 0, 1);
        transition: background 0.6s ease;
    }
    @keyframes np-rise {
        from { transform: translate(0, 100%); }
        to   { transform: translate(0, 0); }
    }
    html.np-open .opening {
        all: unset;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 24px;
        width: 100%;
        height: 100%;
        padding: calc(60px + var(--mobile-safe-top)) 24px calc(60px + var(--mobile-safe-bottom));
        box-sizing: border-box;
        text-align: center;
    }
    html.np-open .track-cover {
        width: min(80vw, 380px);
        max-width: 380px;
        aspect-ratio: 1 / 1;
        border-radius: 8px;
        box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
        flex-shrink: 0;
        background: rgba(255, 255, 255, 0.04);
        object-fit: cover;
    }
    html.np-open .track-info {
        align-self: stretch;
        text-align: center;
        margin: 0;
        padding: 0;
        max-width: 100%;
        overflow: hidden;
    }
    html.np-open .track-info h3 {
        font-size: 22px !important;
        font-weight: 700 !important;
        line-height: 1.25 !important;
        margin: 0 !important;
        color: rgba(255, 255, 255, 0.96);
        overflow: hidden !important;
        text-overflow: ellipsis !important;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        line-clamp: 2;
        -webkit-box-orient: vertical;
        white-space: normal;
        word-break: break-word;
        animation: none !important;
        transform: none !important;
    }
    html.np-open .track-info p {
        font-size: 15px !important;
        font-weight: 500 !important;
        color: rgba(255, 255, 255, 0.65);
        margin: 4px 0 0 !important;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    html.np-open .spotify-player {
        align-self: stretch;
        display: flex;
        flex-direction: column;
        gap: 12px;
        margin: 0;
        padding: 0;
    }
    html.np-open .time-wrapper {
        display: flex;
        align-items: center;
        gap: 12px;
        font-size: 12px;
        color: rgba(255, 255, 255, 0.65);
        font-variant-numeric: tabular-nums;
    }
    html.np-open .progress-bar {
        flex: 1;
        height: 4px;
        border-radius: 4px;
        background: rgba(255, 255, 255, 0.12);
        overflow: hidden;
    }
    html.np-open .time-wrapper span { font-size: 12px; }
    html.np-open .controls {
        display: flex;
        align-items: center;
        justify-content: space-between;
        width: 100%;
        margin: 0;
        padding: 0;
        gap: 0;
    }
    html.np-open .btn-repeat,
    html.np-open .btn-random {
        width: 52px;
        height: 52px;
        background: transparent;
        border: none;
        color: rgba(255, 255, 255, 0.65);
        font-size: 1.6rem;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0;
        margin: 0;
        border-radius: 50%;
    }
    html.np-open .btn-prev,
    html.np-open .btn-next {
        width: 48px;
        height: 48px;
        background: transparent;
        border: none;
        color: rgba(255, 255, 255, 0.96);
        font-size: 1.6rem;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0;
        margin: 0;
        border-radius: 50%;
    }
    html.np-open #play-pause {
        width: 64px;
        height: 64px;
        background: rgba(255, 255, 255, 0.96);
        color: #131313;
        font-size: 1.6rem;
        border: none;
        border-radius: 50%;
        cursor: pointer;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 0;
        margin: 0;
        box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4);
    }
    html.np-open #play-pause:active { transform: scale(0.96); }
    /* === Bouton play/pause du NP : SVG propre au lieu de l'emoji ⏸/▶ ===
       Le JS pose `⏸` / `▶` via textContent (parfait sur PC). Sur mobile
       on masque ce caractère (font-size:0) et on affiche des icônes
       SVG via pseudo-élément, pilotées par body.is-playing (posé par
       player.js). ZÉRO impact sur la version PC (bloc préfixé np-open
       dans @media mobile). */
    html.np-open #play-pause {
        font-size: 0 !important;
    }
    html.np-open #play-pause::before {
        content: "";
        width: 28px;
        height: 28px;
        display: block;
        background: #131313;
        -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M8 5v14l11-7z'/%3E%3C/svg%3E") center/contain no-repeat;
        mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M8 5v14l11-7z'/%3E%3C/svg%3E") center/contain no-repeat;
    }
    html.np-open body.is-playing #play-pause::before {
        -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 4h4v16H6zM14 4h4v16h-4z'/%3E%3C/svg%3E") center/contain no-repeat;
        mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 4h4v16H6zM14 4h4v16h-4z'/%3E%3C/svg%3E") center/contain no-repeat;
    }
    /* Barre de son masquée dans le NP plein écran (demande user) :
       le volume reste réglable sur le mini-player/desktop, mais le
       plein écran reste épuré Spotify-like. */
    html.np-open .volume-container,
    html.np-open #volume-slider,
    html.np-open #volume-icon {
        display: none !important;
    }
}

/* =====================================================================
   === MOBILE THEME LIGHT (mobile shell uniquement) ====================
   ===================================================================== */
@media (max-width: 1024px) {
    /* Theme-light ne réinitialise pas : on override juste les surfaces */
    html.theme-light body { background: #f7f7f7; color: rgba(0, 0, 0, 0.88); }
    /* v60 (2026-08-17) : le gradient ambient du body (couleur de la chanson,
       ré-appliqué par album.css injecté dynamiquement par la SPA) se voyait
       dans l'interstice en haut (sous la tabbar) et teintait la tabbar via
       son backdrop-filter saturate → petite bande colorée sur toutes les
       pages. Sur mobile : fond gris plein partout ; l'ambient reste porté
       par le mini-player et le Now Playing (leurs propres dégradés). */
    html.theme-ambient body {
        background: var(--bg-color, #131313);
        background-image: none !important;
    }
    html.theme-light .mobile-appbar { background: #f7f7f7; border-bottom-color: rgba(0, 0, 0, 0.08); }
    html.theme-light .mobile-appbar-title { color: rgba(0, 0, 0, 0.94); }
    html.theme-light .mobile-appbar-back { color: rgba(0, 0, 0, 0.94); }
    html.theme-light .mobile-appbar-settings { color: rgba(0, 0, 0, 0.85); }
    html.theme-light .middle-column { background: #f7f7f7; }
    html.theme-light .middle-column .search-box input {
        background: rgba(0, 0, 0, 0.06);
        color: rgba(0, 0, 0, 0.92);
    }
    html.theme-light .middle-column .search-box input::placeholder { color: rgba(0, 0, 0, 0.40); }
    html.theme-light .middle-column .playlist-sidebar li .pl-title { color: rgba(0, 0, 0, 0.92); }
    html.theme-light .middle-column .playlist-sidebar li .pl-artist { color: rgba(0, 0, 0, 0.55); }
    html.theme-light .middle-column .album-card .album-title { color: rgba(0, 0, 0, 0.92); }
    html.theme-light .middle-column .album-card .album-artist { color: rgba(0, 0, 0, 0.55); }

    html.theme-light .mini-player {
        background:
            radial-gradient(circle at 18% 50%,
                color-mix(in srgb, var(--main-color, rgb(170,40,40)) 10%, transparent) 0%,
                transparent 60%),
            linear-gradient(180deg,
                color-mix(in srgb, var(--bg-color-2, rgb(252,252,252)) 95%, rgba(255,255,255,0.95)) 0%,
                color-mix(in srgb, var(--bg-color-2, rgb(245,245,245)) 95%, rgba(245,245,245,0.95)) 100%);
        border-top-color: rgba(0, 0, 0, 0.08);
        box-shadow:
            0 -1px 0 color-mix(in srgb, var(--main-color, rgb(0,0,0)) 22%, transparent) inset,
            0 -6px 32px color-mix(in srgb, var(--main-color, rgb(170,40,40)) 24%, transparent);
    }
    html.theme-light .mini-title { color: rgba(0, 0, 0, 0.92); }
    html.theme-light .mini-artist { color: rgba(0, 0, 0, 0.55); }
    html.theme-light .mini-play {
        color: rgba(0, 0, 0, 0.92);
        border-color: color-mix(in srgb, var(--main-color, rgb(0,0,0)) 50%, transparent);
        box-shadow:
            0 0 0 4px color-mix(in srgb, var(--main-color, rgb(170,40,40)) 16%, transparent),
            0 4px 24px color-mix(in srgb, var(--main-color, rgb(170,40,40)) 35%, transparent);
    }

    html.theme-light .mobile-tabs {
        background: rgba(248, 248, 248, 0.96);
        border-top-color: rgba(0, 0, 0, 0.08);
    }
    html.theme-light .mobile-tab { color: rgba(0, 0, 0, 0.45); }
    html.theme-light .mobile-tab.is-active { color: var(--main-color, rgba(0, 0, 0, 0.94)); }
    html.theme-light .mobile-tab.is-active::before {
        background: var(--main-color, rgba(0,0,0));
        box-shadow: 0 0 8px color-mix(in srgb, var(--main-color, rgb(170,40,40)) 50%, transparent);
    }

    html.theme-light .np-back {
        background: rgba(0, 0, 0, 0.08);
        color: rgba(0, 0, 0, 0.92);
    }

    html.theme-light.np-open .left-column {
        background:
            radial-gradient(ellipse at top,
                color-mix(in srgb, var(--main-color, rgb(170,40,40)) 18%, transparent) 0%,
                transparent 60%),
            #f7f7f7;
    }
    html.theme-light.np-open .track-info h3 { color: rgba(0, 0, 0, 0.94); }
    html.theme-light.np-open .track-info p { color: rgba(0, 0, 0, 0.62); }
    html.theme-light.np-open .time-wrapper { color: rgba(0, 0, 0, 0.62); }
    html.theme-light.np-open .progress-bar { background: rgba(0, 0, 0, 0.10); }
    html.theme-light.np-open .btn-repeat,
    html.theme-light.np-open .btn-random { color: rgba(0, 0, 0, 0.55); }
    html.theme-light.np-open .btn-prev,
    html.theme-light.np-open .btn-next { color: rgba(0, 0, 0, 0.90); }
    html.theme-light.np-open #play-pause {
        background: rgba(0, 0, 0, 0.92);
        color: #fff;
    }
}

/* =====================================================================
   === MOBILE REDUCED MOTION ===========================================
   ===================================================================== */
@media (max-width: 1024px) and (prefers-reduced-motion: reduce) {
    html.np-open .left-column {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
        animation-timing-function: step-end !important;
    }
    .mobile-tab,
    .mini-play,
    .np-back,
    .mobile-appbar-back,
    .mobile-appbar-settings {
        transition-duration: 0.01ms !important;
    }
}



/* === END v2 ============================================ */

/* =====================================================================
   === MOBILE COLOR REACT (2026-08-15) — guard color-mix() ==============
   color-mix(in srgb, …, transparent) est CSS Color Module L5 (Chrome
   111+/Firefox 113+/Safari 16.4+, ≈ 96% en 2026). Au cas où le browser
   ne le supporte pas, le fallback est la valeur D'ORIGINE (rgba grey) —
   on laisse l'UI grise "comme avant" plutôt que de crasher la cascade.

   Les règles DESSOUS sont des OVERRIDES Internet modernes — on ne les
   évalue QUE si le browser supporte color-mix. Pas de color-mix dans
   les fallbacks : évite que la déclaration "valeur d'origine" ci-dessus
   soit entièrement invalidée par une mauvaise interprétation.
   ===================================================================== */
@supports (background: color-mix(in srgb, white 50%, transparent)) {
    /* Re-applique les upgrades mobile-color-react uniquement si supporté.
       (Les overrides principaux sont déjà inline dans les blocs @media
       ci-dessus avec fallbacks rgb(...) — ce bloc-ci n'est qu'un
       "écran de protection" pour rétro-portabilité long terme.) */
    html.is-mobile .mobile-tab.is-active::before {
        background: var(--main-color, rgba(255,255,255,0.96));
    }
}




/* =====================================================================
   === MOBILE FIX v81 (2026-08-17) : DÉGROSSISSEMENT — retour aux
   proportions du shell v2 ============================================
   Les blocs v60→v79c + m2/m3 empilaient +15-20% à chaque passe
   (tabbar 56→100px, appbar 56→82px, mini-player 140→220px, covers
   88→124px, NP play 76→208px…) → résultat « zoomé ×2 ». On supprime
   ces sur-couches et on conserve UNIQUEMENT les fixes fonctionnels
   suivants, aux tailles du shell v2 Spotify-like ci-dessus.
   ===================================================================== */
@media (max-width: 1024px) {
    /* === NP overlay : fullscreen garanti (v3) === */
    html.np-open .left-column {
        display: flex !important;
        position: fixed !important;
        top: 0 !important;
        left: 0 !important;
        right: 0 !important;
        bottom: 0 !important;
        width: 100vw !important;
        height: 100vh !important;
        min-width: 0 !important;
        max-width: none !important;
        margin: 0 !important;
        padding: 0 !important;
        flex: none !important;
        z-index: 50;
        background: var(--bg-color, #131313);
        overflow-y: auto;
        animation: np-rise 0.32s cubic-bezier(0.32, 0.72, 0, 1);
    }
    /* === NP .opening : reset complet depuis scratch (v3) === */
    html.np-open .opening {
        all: unset !important;
        display: flex !important;
        flex-direction: column !important;
        align-items: center !important;
        justify-content: center !important;
        gap: 28px !important;
        width: 100% !important;
        height: 100% !important;
        max-width: none !important;
        min-height: 0 !important;
        padding:
            calc(72px + var(--mobile-safe-top))
            24px
            calc(48px + var(--mobile-safe-bottom)) !important;
        box-sizing: border-box !important;
        text-align: center !important;
        background: transparent !important;
        box-shadow: none !important;
        border-radius: 0 !important;
    }
    /* Cover : tailles du shell v2 (min(80vw, 380px)) */
    html.np-open .track-cover {
        width: min(80vw, 380px) !important;
        max-width: 380px !important;
        aspect-ratio: 1 / 1 !important;
        border-radius: 8px !important;
        box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4) !important;
    }
    /* Transport buttons : ronds garantis même si wrap (v65) */
    html.np-open .controls {
        display: flex !important;
        flex-wrap: wrap !important;
        justify-content: center !important;
        align-items: center !important;
        gap: 10px 12px !important;
        width: 100% !important;
        max-width: 100% !important;
        margin: 0 auto !important;
        padding: 0 12px !important;
        box-sizing: border-box !important; /* v61 : width:100% + padding content-box
           débordait de 24px à droite → rangée décalée de 12px (centre 207 vs 195) */
    }
    html.np-open #play-pause,
    html.np-open .btn-prev,
    html.np-open .btn-next,
    html.np-open .btn-repeat,
    html.np-open .btn-random {
        aspect-ratio: 1 / 1 !important;
        flex-shrink: 0 !important;
        border-radius: 9999px !important;
        padding: 0 !important;
        margin: 0 !important;
        display: flex !important;
        align-items: center !important;
        justify-content: center !important;
    }
    html.np-open #play-pause {
        width: 64px !important;
        height: 64px !important;
        max-width: 64px !important;
        max-height: 64px !important;
        flex: 0 0 64px !important;
        font-size: 0 !important; /* emoji ⏸/▶ masqué → SVG via ::before */
        background: rgba(255, 255, 255, 0.96) !important;
        color: #131313 !important;
        box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4) !important;
    }
    html.np-open .btn-prev,
    html.np-open .btn-next {
        width: 48px !important;
        height: 48px !important;
        max-width: 48px !important;
        max-height: 48px !important;
        flex: 0 0 48px !important;
        font-size: 1.6rem !important;
    }
    html.np-open .btn-repeat,
    html.np-open .btn-random {
        width: 52px !important;
        height: 52px !important;
        max-width: 52px !important;
        max-height: 52px !important;
        flex: 0 0 52px !important;
        font-size: 1.6rem !important;
    }
    /* Cacher la chrome de la page pendant le NP (v65/v72) */
    html.np-open .mini-player { display: none !important; }
    html.np-open .mobile-appbar { display: none !important; }
    html.np-open .mobile-tabs,
    html.np-open .mobile-tabbar { display: none !important; }
    html.np-open .middle-column { display: none !important; }

    /* === Mini-player : boutons prev/next (markup accueil.html) === */
    .mini-controls {
        display: flex !important;
        align-items: center !important;
        justify-content: flex-end !important;
        gap: 8px !important;
        flex: 0 0 auto !important;
    }
    .mini-prev,
    .mini-next {
        width: 38px !important;
        height: 38px !important;
        min-width: 38px !important;
        border-radius: 9999px !important;
        background: rgba(255, 255, 255, 0.10) !important;
        border: none !important;
        color: rgba(255, 255, 255, 0.96) !important;
        display: flex !important;
        align-items: center !important;
        justify-content: center !important;
        padding: 0 !important;
        cursor: pointer !important;
        flex-shrink: 0 !important;
        transition: background 0.16s ease, transform 0.16s ease !important;
    }
    .mini-prev svg,
    .mini-next svg {
        width: 20px !important;
        height: 20px !important;
    }
    .mini-prev:hover,
    .mini-next:hover { background: rgba(255, 255, 255, 0.18) !important; }
    .mini-prev:active,
    .mini-next:active { transform: scale(0.94) !important; }

    /* === iOS autozoom : inputs/textarea >= 16px === */
    input[type="text"],
    input[type="search"],
    input[type="email"],
    input[type="url"],
    input:not([type]),
    textarea {
        font-size: 16px !important;
    }
}
