/* =====================================================================
   Sounds of Paradise — style.css
   ===================================================================== */

:root {
    --couleur-verte: #00ff00;
    --couleur-rouge: #ff4d4d;
    --couleur-orange: #ffa500;
    --couleur-bleue: #2299ff;
    /* Paliers intermédiaires du profil de fin de partie (cf. #end-result-title) */
    --couleur-tier2: #ff8c42;
    --couleur-tier4: #b6ff3c;
    /* Zone de sécurité HUD : bandeau haut/bas dans lequel une vignette ne
       doit jamais apparaître (chevauchement avec le score/timer en haut,
       les pastilles de sons en bas). Lu dynamiquement par
       Spawner.createVignette (script.js) via getComputedStyle — une seule
       source de vérité entre CSS et JS. */
    --hud-safe-top: 60px;
    --hud-safe-bottom: 50px;
}
body, html {
    margin: 0;
    padding: 0;
    height: 100%;
    overflow: hidden;
    font-family: 'Lato', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background-color: #000;
    color: white;
    -webkit-tap-highlight-color: transparent;
    cursor: default;
    /* Empêche la sélection de texte au cliqué-glissé (souris ou doigt),
       notamment avec les gestes du mode rafale (Alt+clic maintenu,
       appui long) qui impliquent justement ce genre de mouvement. */
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    /* iOS : empêche en plus le menu contextuel (copier/partager) qui
       apparaît sinon après ~0.5s d'appui, avant même que notre propre
       appui long (2s, cf. RafaleMode) ait le temps de se déclencher. */
    -webkit-touch-callout: none;
}

/* Tremblement d'écran (quelques pixels) sur les hits — cf. ScreenShake
   dans script.js. Appliqué sur body directement : body/html ont déjà
   overflow:hidden + height:100% ci-dessus, la boîte de body correspond
   donc exactement au viewport, ce qui permet ce transform sans décaler
   quoi que ce soit par rapport à ce qu'on attend visuellement — y compris
   les éléments position:fixed (HUD, boutons...), qui tremblent avec le
   reste sans bug de repositionnement. */
@keyframes screenShake {
    0% { transform: translate(0, 0); }
    20% { transform: translate(-2px, 1px); }
    40% { transform: translate(2px, -1px); }
    60% { transform: translate(-1px, 2px); }
    80% { transform: translate(1px, -2px); }
    100% { transform: translate(0, 0); }
}
body.screen-shake {
    animation: screenShake 0.15s ease-in-out;
}

/* ---------------------------------------------------------------------
   VIDÉO DE FOND
   --------------------------------------------------------------------- */
.video-layer {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    height: 100dvh;
    object-fit: cover;
    /* Ancre le recadrage en haut : object-fit:cover coupe par défaut de
       façon symétrique (centre), donc peut rogner le haut de l'image sur
       un écran plus étroit/haut que la vidéo (mobile portrait, formats
       ultra-larges...). Ici, seul le bas est jamais rogné — le haut de
       chaque vidéo de fond reste garanti visible quel que soit l'écran. */
    object-position: center top;
    z-index: 0;
    pointer-events: none;
}
/* Calque du dessus pour le fondu enchaîné (crossfade) entre deux vidéos.
   Il reste invisible tant que .visible n'est pas ajoutée. Le calque de
   base (.video-layer seul, sans .video-overlay) reste toujours pleinement
   opaque en dessous : on ne passe donc jamais par du noir pendant la
   transition, contrairement à un simple fondu opacity 1 -> 0 -> 1. */
.video-overlay {
    z-index: 1;
    opacity: 0;
    transition: opacity 0.8s ease;
}
.video-overlay.visible {
    opacity: 1;
}
.game-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.08);
    z-index: 2;
    pointer-events: none;
}

/* ---------------------------------------------------------------------
   ÉCRAN D'ACCUEIL (welcome-screen)
   --------------------------------------------------------------------- */
#welcome-screen {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.88);
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
    gap: 20px;
    z-index: 100;
    text-align: center;
    transition: opacity 0.7s ease, visibility 0.7s ease;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    padding: 20px;
    box-sizing: border-box;
}
#welcome-screen.hidden {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}

/* Colonne centrale : toute la mécanique du jeu (titre, intro, difficulté,
   bouton WELCOME). Reprend l'ancien agencement vertical de #welcome-screen,
   désormais isolé dans son propre conteneur pour laisser la place aux deux
   colonnes pub de part et d'autre. */
#welcome-content {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    flex: 0 1 auto;
    min-width: 0;
}

/* Sélecteur de langue (EN/FR/ES) : 3 petits ronds en haut à droite de
   l'écran d'accueil uniquement. Positionné en absolute : se cale par
   rapport à #welcome-screen (position: fixed, plus proche ancêtre
   positionné), donc bien ancré au coin de l'écran quel que soit le
   contenu de la colonne centrale. Style neutre/discret, cohérent avec
   #start-btn (blanc à la sélection, pas de couleur de niveau ici). */
.lang-switcher {
    position: absolute;
    top: 16px;
    right: 16px;
    display: flex;
    gap: 8px;
    z-index: 10;
}
.lang-btn {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: transparent;
    border: 1.5px solid rgba(255,255,255,0.25);
    color: rgba(255,255,255,0.45);
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.5px;
    cursor: pointer;
    transition: all 0.3s ease;
    font-family: inherit;
    -webkit-appearance: none;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}
.lang-btn:hover {
    border-color: rgba(255,255,255,0.5);
    color: rgba(255,255,255,0.7);
}
.lang-btn.active {
    background: white;
    border-color: white;
    color: black;
}
#welcome-content h1 {
    font-weight: 700;
    letter-spacing: 2px;
    margin-bottom: 5px;
    font-size: 2.2rem;
}

/* Réduction de l'espace demandée */
.game-intro {
    margin-bottom: 30px;
    text-align: center;
}
.game-intro h2 {
    font-size: 1.2rem;
    margin-bottom: 5px;
    color: var(--couleur-verte);
}
.game-intro p {
    font-size: 0.85rem;
    color: rgba(255,255,255,0.6);
    line-height: 1.4;
    font-style: italic;
    margin: 0;
}

.ad-slot {
    flex-shrink: 0;
    width: 100%;
    max-width: 336px;
    min-height: 100px;
    margin: 10px auto;
    display: flex;
    align-items: center;
    justify-content: center;
}
.ad-slot:empty {
    display: none;
    min-height: 0;
    margin: 0;
}

/* Colonnes pub latérales : gauche/droite du bloc central du jeu,
   sur toute la hauteur disponible de l'écran d'accueil. Largeur
   pensée pour un format vertical Google standard (ex. 160x600 /
   300x600) tout en restant flexible via data-full-width-responsive. */
.ad-slot-side {
    flex: 0 0 auto;
    width: 160px;
    max-width: 160px;
    min-height: 0;
    height: 100%;
    max-height: 600px;
    margin: 0;
    align-self: center;
}
@media (min-width: 1100px) {
    .ad-slot-side {
        width: 300px;
        max-width: 300px;
    }
}
/* Écran étroit (mobile portrait notamment) : pas la place pour des
   colonnes latérales sans écraser la mécanique du jeu -> masquées,
   #rotate-prompt invite de toute façon à passer en paysage. */
@media (max-width: 900px) {
    .ad-slot-side {
        display: none;
    }
}

/* ---------------------------------------------------------------------
   DIFFICULTY SECTION & BOUTONS COULEURS (CALM / NERVOUS / MAD)
   --------------------------------------------------------------------- */
.difficulty-section {
    margin-bottom: 15px;
}
.difficulty-label {
    font-size: 0.75rem;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: rgba(255,255,255,0.35);
    margin-bottom: 12px;
}
.difficulty-slider {
    display: flex;
    gap: 16px;
    align-items: center;
    justify-content: center;
}

/* Base des boutons de difficulté : anneau et libellé neutres par défaut,
   comme sur la capture de référence — seule la sélection les fait
   passer au vert. Le chiffre, lui, reste toujours coloré selon le
   niveau (repère visuel constant, cf. capture). */
.difficulty-btn {
    width: 70px;
    height: 70px;
    border-radius: 50%;
    background: transparent;
    border: 2px solid rgba(255,255,255,0.25);
    color: rgba(255,255,255,0.4);
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-transform: uppercase;
    cursor: pointer;
    transition: all 0.3s ease;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 2px;
    font-family: inherit;
    -webkit-appearance: none;
}
.difficulty-btn .level-num {
    font-size: 1.6rem;
    font-weight: 400;
}

/* Le chiffre est toujours dans la couleur de son niveau, sélectionné ou non. */
.difficulty-btn[data-level="1"] .level-num {
    color: var(--couleur-verte);
}
.difficulty-btn[data-level="2"] .level-num {
    color: var(--couleur-orange);
}
.difficulty-btn[data-level="3"] .level-num {
    color: var(--couleur-rouge);
}

/* Effet au survol : léger indice de la couleur du niveau concerné */
.difficulty-btn[data-level="1"]:hover {
    border-color: rgba(0, 255, 0, 0.5);
}
.difficulty-btn[data-level="2"]:hover {
    border-color: rgba(255, 165, 0, 0.5);
}
.difficulty-btn[data-level="3"]:hover {
    border-color: rgba(255, 77, 77, 0.5);
}

/* Bouton sélectionné : anneau ET libellé ("CALM"/"NERVOUS"/"MAD") passent
   du neutre au vert — indicateur de sélection, toujours la même couleur
   quel que soit le niveau. Le chiffre garde sa couleur de niveau (déjà
   appliquée ci-dessus, plus spécifique que ce `color` hérité). Pas
   d'animation. */
.difficulty-btn.active {
    border-color: var(--couleur-verte);
    color: var(--couleur-verte);
    box-shadow: 0 0 20px rgba(0, 255, 0, 0.35);
}

#start-btn {
    background: transparent;
    border: 2px solid white;
    color: white;
    padding: 12px 45px;
    font-size: 1rem;
    cursor: pointer;
    transition: all 0.3s ease;
    border-radius: 50px;
    letter-spacing: 3px;
    text-transform: uppercase;
    font-family: inherit;
    -webkit-appearance: none;
}
#start-btn:hover {
    background: white;
    color: black;
}

/* ---------------------------------------------------------------------
   COMPTE À REBOURS
   --------------------------------------------------------------------- */
#countdown-screen {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 90;
    background: rgba(0,0,0,0.7);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.5s ease, visibility 0.5s ease;
}
#countdown-screen.visible {
    opacity: 1;
    visibility: visible;
}

/* Écran de transition en fin de partie — même famille visuelle que
   #countdown-screen ci-dessus (assombri, anneau de respiration
   réutilisé tel quel), délibérément pour faire écho au début de partie.
   z-index EN DESSOUS de #end-screen (200) : contrairement à l'entrée
   (assombrissement volontairement lent, 3s, pour laisser la vidéo de
   fond encore visible un moment), la sortie doit rester rapide — quand
   #end-screen apparaît par-dessus (Screens.showEnd, transition 0.6s),
   il masque naturellement cet écran encore en train de s'effacer, sans
   avoir à gérer une durée de transition différente à la sortie. */
#gameover-screen {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 195;
    background: rgba(0,0,0,0.92);
    opacity: 0;
    visibility: hidden;
    transition: opacity 3s ease, visibility 3s ease;
}
#gameover-screen.visible {
    opacity: 1;
    visibility: visible;
}
.gameover-text {
    font-size: 3.2rem;
    font-weight: 700;
    letter-spacing: 6px;
    text-transform: uppercase;
    color: var(--couleur-verte);
    text-shadow: 0 0 40px rgba(0,255,0,0.4);
    text-align: center;
    padding: 0 20px;
}
@media (max-width: 900px) {
    .gameover-text { font-size: 2rem; letter-spacing: 3px; }
}
/* Sous-titre affiché sous "GAME OVER" (cf. Game.end, DOM.gameoverSubtitle)
   — message d'apaisement (toujours) et/ou teaser sur le Combo non
   débloqué. Volontairement calme et discret (italique, couleur atténuée),
   même famille visuelle que .game-intro p sur l'écran d'accueil : le
   titre au-dessus fait le "wahou", ce texte-ci fait redescendre. */
.gameover-subtitle {
    font-size: 0.95rem;
    color: rgba(255,255,255,0.65);
    line-height: 1.5;
    font-style: italic;
    text-align: center;
    padding: 0 24px;
    margin-top: 14px;
    max-width: 420px;
}
@media (max-width: 900px) {
    .gameover-subtitle { font-size: 0.8rem; margin-top: 10px; }
}
/* Sorti du flux flex de #countdown-screen : sinon, empilé au-dessus de
   .countdown-number, il pesait dans le centrage du groupe et poussait le
   grand chiffre sous le centre réel de l'écran — donc sous le centre du
   cercle de respiration (positionné, lui, en absolute pile à 50%). Ici,
   seul .countdown-number reste dans le flux et se centre exactement sur
   le cercle ; ce petit texte flotte au-dessus, sans influencer ce calcul. */
.countdown-text {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -160px);
    width: 100%;
    box-sizing: border-box;
    font-size: 1rem;
    letter-spacing: 3px;
    text-transform: uppercase;
    color: rgba(255,255,255,0.5);
    text-align: center;
    padding: 0 20px;
}
.countdown-number {
    font-size: 8rem;
    font-weight: 700;
    color: var(--couleur-verte);
    text-shadow: 0 0 60px rgba(0,255,0,0.4);
    animation: countPop 0.8s cubic-bezier(0.34, 1.56, 0.64, 1);
    min-height: 150px;
    display: flex;
    align-items: center;
    justify-content: center;
}
@keyframes countPop {
    0% { transform: scale(0.3); opacity: 0; }
    50% { transform: scale(1.2); opacity: 1; }
    100% { transform: scale(1); opacity: 1; }
}
/* Palier final du 2e countdown (respiration au déblocage du Combo,
   cf. Game.pauseForComboBreath) : remplace "GO!!!" par une exclamation
   plus longue ("DÉGLINGUE TOUT !" / etc., cf. I18N "comboShootAnything")
   qui reste affichée et vibre en orange/rouge pendant 2 secondes pile
   (5 cycles de 0,4s), au lieu du simple pop vert instantané du countdown
   classique — pour bien marquer que ce réveil-là annonce un changement
   de règles (tous les sprites rapportent des points), pas juste un
   lancement de partie. Taille réduite et retour à la ligne autorisé :
   un texte est nettement plus long qu'un chiffre ou "GO". */
.countdown-number.combo-finale {
    font-size: 3rem;
    letter-spacing: 1px;
    white-space: normal;
    text-align: center;
    padding: 0 20px;
    max-width: 90vw;
    animation: comboFinaleVibrate 0.4s ease-in-out 5;
}
@keyframes comboFinaleVibrate {
    0%, 100% {
        transform: translate(0, 0) scale(1);
        color: var(--couleur-orange);
        text-shadow: 0 0 20px rgba(255,165,0,0.85);
    }
    50% {
        transform: translate(3px, -2px) scale(1.05);
        color: var(--couleur-rouge);
        text-shadow: 0 0 26px rgba(255,77,77,0.9);
    }
}
@media (max-width: 900px) {
    .countdown-number.combo-finale { font-size: 1.8rem; }
}
/* Exclamation finale du countdown de LANCEMENT de partie (variant "start",
   cf. Screens.playBreathCountdown) : remplace le générique "GO!!!" par
   l'instruction courte du niveau (ex. "SHOOT HULA!", cf.
   Config.LEVELS[].startShout), pour renforcer la consigne pile au moment
   où le joueur en a le plus besoin — avant même le premier spawn. Même
   principe que .combo-finale ci-dessus (taille réduite, retour à la ligne
   autorisé), mais en vert et avec un pop énergique plutôt qu'un tremblement
   orange/rouge : c'est un lancement enthousiaste, pas une alerte. */
.countdown-number.start-finale {
    font-size: 3rem;
    letter-spacing: 1px;
    white-space: normal;
    text-align: center;
    padding: 0 20px;
    max-width: 90vw;
    animation: startFinalePop 0.5s ease-in-out 2;
}
@keyframes startFinalePop {
    0%, 100% {
        transform: scale(1);
        color: var(--couleur-verte);
        text-shadow: 0 0 20px rgba(0,255,0,0.5);
    }
    50% {
        transform: scale(1.08);
        color: var(--couleur-verte);
        text-shadow: 0 0 34px rgba(0,255,0,0.9);
    }
}
@media (max-width: 900px) {
    .countdown-number.start-finale { font-size: 1.8rem; }
}
.breath-ring {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 200px;
    height: 200px;
    margin-top: -100px;
    margin-left: -100px;
    border-radius: 50%;
    border: 2px solid rgba(0,255,0,0.15);
    animation: breathe 4s ease-in-out infinite;
    pointer-events: none;
}
@keyframes breathe {
    0%, 100% { transform: scale(0.8); opacity: 0.3; }
    50% { transform: scale(1.4); opacity: 0.8; }
}

/* ---------------------------------------------------------------------
   HUD
   --------------------------------------------------------------------- */
#hud {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    padding: 16px 24px;
    display: flex;
    /* Timer en haut à droite (re-permuté avec le bloc instructions,
       cf. .top-left-text ci-dessous) ; le score de résistance est ancré en
       bas à gauche (position:fixed indépendante, cf. .hud-score plus bas). */
    justify-content: flex-end;
    align-items: center;
    z-index: 50;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.5s ease;
}
#hud.visible {
    opacity: 1;
}
.hud-item {
    background: rgba(0,0,0,0.6);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    padding: 8px 20px;
    border-radius: 25px;
    border: 1px solid rgba(255,255,255,0.1);
    font-size: 0.85rem;
    letter-spacing: 1px;
    /* Glissement doux à l'apparition (indépendant du fondu d'opacité déjà
       géré par #hud lui-même) : chaque pastille du HUD descend légèrement
       depuis le haut au lieu d'apparaître brusquement sur place. */
    transform: translateY(-4px);
    transition: transform 0.3s ease;
}
#hud.visible .hud-item {
    transform: translateY(0);
}
.hud-timer {
    font-variant-numeric: tabular-nums;
    font-size: 1.4rem;
    font-weight: 300;
    min-width: 70px;
    text-align: center;
}
.hud-timer.warning {
    color: var(--couleur-orange);
    text-shadow: 0 0 10px rgba(255, 165, 0, 0.6);
}
.hud-timer.danger {
    color: var(--couleur-rouge);
    text-shadow: 0 0 14px rgba(255, 77, 77, 0.85);
    animation: dangerPulse 0.5s ease-in-out infinite;
}
@keyframes dangerPulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.18); }
}
.hud-score {
    position: fixed;
    bottom: 20px;
    left: 20px;
    font-variant-numeric: tabular-nums;
    font-size: 1.1rem;
    font-weight: 700;
}
.hud-score-label {
    color: white;
    font-weight: 400;
}
#hud-resistance-value {
    color: var(--couleur-verte);
}

/* ---------------------------------------------------------------------
   PASTILLES DE SONS ACTIFS
   --------------------------------------------------------------------- */
.active-sounds-indicator {
    position: fixed;
    top: 20px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 8px;
    z-index: 50;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.5s ease;
}
.active-sounds-indicator.visible {
    opacity: 1;
}
.sound-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: rgba(255,255,255,0.15);
    transition: all 0.3s ease;
    border: 1px solid rgba(255,255,255,0.1);
}
.sound-dot.active {
    background: var(--couleur-verte);
    box-shadow: 0 0 10px rgba(0,255,0,0.5);
    animation: dotPulse 1.2s ease infinite;
}
/* Priorité sur .active (même spécificité de classe, mais déclarée après) :
   la pastille du sprite actuellement en vedette (cf. Spotlight dans
   script.js) passe au rouge, cohérent avec le halo rouge déjà posé sur la
   vignette elle-même et avec la pénalité alourdie si on le touche. */
.sound-dot.active.featured {
    background: var(--couleur-rouge);
    box-shadow: 0 0 10px rgba(255,77,77,0.6);
}
@keyframes dotPulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.4); }
}

/* ---------------------------------------------------------------------
   VIGNETTES
   --------------------------------------------------------------------- */
.vignette {
    position: absolute;
    width: 100px;
    height: 100px;
    z-index: 40;
    transition: transform 0.15s ease, left 2.5s ease-in-out, top 2.5s ease-in-out;
    animation: popIn 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
    filter: drop-shadow(0 2px 8px rgba(0,0,0,0.5));
    /* Même curseur en forme que le crosshair par défaut (cf. Config.CROSSHAIR_CURSOR
       dans script.js), en rouge par défaut sur un sprite ≠ 0 : s'applique
       automatiquement dès que le pointeur survole une cible, sans JS — et
       redevient blanc à contour noir dès qu'il la quitte (cf. Config.CROSSHAIR_CURSOR).
       Le sprite 0 (Berceuse) a son
       propre survol vert (cf. règle [data-sound-index="0"] plus bas), et
       pendant le Combo TOUS les sprites passent en vert (cf. règle
       body.combo-active plus bas, plus spécifique donc prioritaire). */
    cursor: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj48Y2lyY2xlIGN4PSIxNiIgY3k9IjE2IiByPSIxMiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmY0ZDRkIiBzdHJva2Utd2lkdGg9IjEuNSIvPjxsaW5lIHgxPSIxNiIgeTE9IjAiIHgyPSIxNiIgeTI9IjEwIiBzdHJva2U9IiNmZjRkNGQiIHN0cm9rZS13aWR0aD0iMS41Ii8+PGxpbmUgeDE9IjE2IiB5MT0iMjIiIHgyPSIxNiIgeTI9IjMyIiBzdHJva2U9IiNmZjRkNGQiIHN0cm9rZS13aWR0aD0iMS41Ii8+PGxpbmUgeDE9IjAiIHkxPSIxNiIgeDI9IjEwIiB5Mj0iMTYiIHN0cm9rZT0iI2ZmNGQ0ZCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48bGluZSB4MT0iMjIiIHkxPSIxNiIgeDI9IjMyIiB5Mj0iMTYiIHN0cm9rZT0iI2ZmNGQ0ZCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48Y2lyY2xlIGN4PSIxNiIgY3k9IjE2IiByPSIyIiBmaWxsPSIjZmY0ZDRkIi8+PC9zdmc+") 16 16, crosshair;
}
/* Sprite 0 (Berceuse) : survol toujours vert, Combo ou non. */
.vignette[data-sound-index="0"] {
    cursor: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj48Y2lyY2xlIGN4PSIxNiIgY3k9IjE2IiByPSIxMiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDBmZjAwIiBzdHJva2Utd2lkdGg9IjEuNSIvPjxsaW5lIHgxPSIxNiIgeTE9IjAiIHgyPSIxNiIgeTI9IjEwIiBzdHJva2U9IiMwMGZmMDAiIHN0cm9rZS13aWR0aD0iMS41Ii8+PGxpbmUgeDE9IjE2IiB5MT0iMjIiIHgyPSIxNiIgeTI9IjMyIiBzdHJva2U9IiMwMGZmMDAiIHN0cm9rZS13aWR0aD0iMS41Ii8+PGxpbmUgeDE9IjAiIHkxPSIxNiIgeDI9IjEwIiB5Mj0iMTYiIHN0cm9rZT0iIzAwZmYwMCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48bGluZSB4MT0iMjIiIHkxPSIxNiIgeDI9IjMyIiB5Mj0iMTYiIHN0cm9rZT0iIzAwZmYwMCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48Y2lyY2xlIGN4PSIxNiIgY3k9IjE2IiByPSIyIiBmaWxsPSIjMDBmZjAwIi8+PC9zdmc+") 16 16, crosshair;
}
/* Combo actif : tous les sprites (0 compris) passent en vert — spécificité
   plus élevée que la règle [data-sound-index="0"] ci-dessus, donc
   prioritaire sans avoir besoin de !important. */
body.combo-active .vignette {
    cursor: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIzMiIgaGVpZ2h0PSIzMiIgdmlld0JveD0iMCAwIDMyIDMyIj48Y2lyY2xlIGN4PSIxNiIgY3k9IjE2IiByPSIxMiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDBmZjAwIiBzdHJva2Utd2lkdGg9IjEuNSIvPjxsaW5lIHgxPSIxNiIgeTE9IjAiIHgyPSIxNiIgeTI9IjEwIiBzdHJva2U9IiMwMGZmMDAiIHN0cm9rZS13aWR0aD0iMS41Ii8+PGxpbmUgeDE9IjE2IiB5MT0iMjIiIHgyPSIxNiIgeTI9IjMyIiBzdHJva2U9IiMwMGZmMDAiIHN0cm9rZS13aWR0aD0iMS41Ii8+PGxpbmUgeDE9IjAiIHkxPSIxNiIgeDI9IjEwIiB5Mj0iMTYiIHN0cm9rZT0iIzAwZmYwMCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48bGluZSB4MT0iMjIiIHkxPSIxNiIgeDI9IjMyIiB5Mj0iMTYiIHN0cm9rZT0iIzAwZmYwMCIgc3Ryb2tlLXdpZHRoPSIxLjUiLz48Y2lyY2xlIGN4PSIxNiIgY3k9IjE2IiByPSIyIiBmaWxsPSIjMDBmZjAwIi8+PC9zdmc+") 16 16, crosshair;
}
.vignette:hover {
    transform: scale(1.2);
    filter: drop-shadow(0 6px 16px rgba(0,0,0,0.7));
    z-index: 45;
}
.vignette.removing {
    animation: popOut 0.25s ease forwards;
    pointer-events: none;
}
/* Hit normal (avant que le Combo ne se déclenche) : flash discret,
   pas de mouvement brusque — reste dans l'esprit "Keep Calm". */
.vignette.hit-effect-zen {
    animation: zenHitFlash 0.3s ease-out;
}
/* .removing et .hit-effect-zen sont posées en même temps sur un hit :
   deux règles qui déclarent chacune `animation` sur le même élément ne
   se cumulent PAS automatiquement — seule la dernière de la cascade
   s'applique en entier. Cette règle combinée (spécificité plus élevée)
   liste donc explicitement les deux animations ensemble pour qu'elles
   jouent réellement en parallèle (éjection sur transform, flash sur filter). */
.vignette.removing.hit-effect-zen {
    animation: popOut 0.25s ease forwards, zenHitFlash 0.3s ease-out;
}
@keyframes zenHitFlash {
    0% { filter: brightness(1) drop-shadow(0 2px 8px rgba(0,0,0,0.5)); }
    40% { filter: brightness(1.7) drop-shadow(0 0 14px rgba(0,255,0,0.55)); }
    100% { filter: brightness(1) drop-shadow(0 2px 8px rgba(0,0,0,0.5)); }
}
/* Hit "pénalité" (n'importe quel sprite ≠ Berceuse touché hors Combo,
   fait perdre 100 points) : même principe que le flash "zen" ci-dessus,
   mais teinté en rouge pour bien signaler la perte de points, sans
   surimpression de chiffres (cf. Scoring.registerHit). */
.vignette.hit-effect-penalty {
    animation: penaltyHitFlash 0.3s ease-out;
}
.vignette.removing.hit-effect-penalty {
    animation: popOut 0.25s ease forwards, penaltyHitFlash 0.3s ease-out;
}
@keyframes penaltyHitFlash {
    0% { filter: brightness(1) drop-shadow(0 2px 8px rgba(0,0,0,0.5)); }
    40% { filter: brightness(1.5) drop-shadow(0 0 14px rgba(255,77,77,0.65)); }
    100% { filter: brightness(1) drop-shadow(0 2px 8px rgba(0,0,0,0.5)); }
}
/* Hit en mode Combo : flash marqué façon arcade — uniquement sur filter
   (pas de transform ici : .removing gère le mouvement d'éjection). */
.vignette.combo-effect {
    animation: comboHitFlash 0.35s ease-out;
    z-index: 46;
}
/* Même principe combiné que ci-dessus, pour le hit en mode Combo. */
.vignette.removing.combo-effect {
    animation: popOut 0.25s ease forwards, comboHitFlash 0.35s ease-out;
    z-index: 46;
}
@keyframes comboHitFlash {
    0% { filter: brightness(1) drop-shadow(0 2px 8px rgba(0,0,0,0.5)); }
    35% { filter: brightness(2.4) drop-shadow(0 0 30px rgba(0,255,0,0.95)); }
    100% { filter: brightness(1) drop-shadow(0 2px 8px rgba(0,0,0,0.5)); }
}
@keyframes popIn {
    0% { transform: scale(0) rotate(-180deg); opacity: 0; }
    100% { transform: scale(1) rotate(0deg); opacity: 1; }
}
/* Éjection au shoot : recul + rotation + réduction, pour donner
   l'impression d'un sprite frappé et projeté en arrière plutôt que
   simplement détruit sur place. */
@keyframes popOut {
    0% { transform: scale(1) rotate(0deg) translateY(0); opacity: 1; }
    100% { transform: scale(0) rotate(320deg) translateY(-22px); opacity: 0; }
}
.vignette-inner {
    width: 100%;
    height: 100%;
    background-size: contain;
    background-position: center;
    background-repeat: no-repeat;
    /* "Respiration" douce : le sprite rétrécit légèrement puis revient à
       sa taille normale, en boucle. Posée sur l'élément interne (et non
       sur .vignette) pour ne jamais entrer en conflit avec les autres
       animations/transitions de l'outer (hover, drift gauche/haut,
       popIn/popOut, flashs de hit) qui utilisent déjà `transform`. Le
       délai négatif aléatoire (cf. script.js, Spawner.createVignette)
       désynchronise les sprites entre eux pour un effet plus naturel. */
    animation: spriteBreathe 3.2s ease-in-out infinite;
}
@keyframes spriteBreathe {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(0.82); }
}

/* Spotlight (cf. script.js, module Spotlight) : sprite "parasite" mis en
   vedette à tour de rôle — plus gros, agité, teinté d'une lueur rouge pour
   signaler le risque (pénalité alourdie s'il est touché, cf.
   Config.SPOTLIGHT.PENALTY). Posé sur .vignette-inner (spécificité plus
   élevée que la simple classe .vignette-inner ci-dessus, donc remplace
   naturellement spriteBreathe le temps du spotlight, sans !important).
   z-index sur l'outer .vignette pour qu'il se démarque visuellement des
   sprites voisins, cohérent avec les autres paliers de survol/hit
   (hover: 45, spotlight: 44, combo-effect: 46).
   Progressif plutôt que brutal : une SEULE itération de featuredPulse,
   calée sur toute la durée du spotlight (5s, doit correspondre à
   Config.SPOTLIGHT.DURATION_MS dans script.js) plutôt qu'une boucle
   courte démarrant à pleine amplitude. La taille ET le filtre (halo
   rouge) sont animés ENSEMBLE dans les mêmes keyframes : montée en
   puissance sur le premier palier, agitation au milieu, redescente
   symétrique sur le dernier palier — jamais de saut instantané, que ce
   soit à l'apparition ou à la disparition du spotlight. */
.vignette.featured {
    z-index: 44;
}
.vignette-inner.featured {
    animation: featuredPulse 5s ease-in-out 1 both;
}
@keyframes featuredPulse {
    0%   { transform: scale(1)     rotate(0deg); filter: brightness(1)    drop-shadow(0 2px 8px rgba(0,0,0,0.5)); }
    15%  { transform: scale(1.22)  rotate(0deg); filter: brightness(1.15) drop-shadow(0 0 12px rgba(255,77,77,0.65)); }
    30%  { transform: scale(1.28)  rotate(-4deg); }
    45%  { transform: scale(1.18)  rotate(0deg); }
    60%  { transform: scale(1.28)  rotate(4deg); }
    75%  { transform: scale(1.2)   rotate(0deg); }
    85%  { transform: scale(1.22)  rotate(0deg); filter: brightness(1.15) drop-shadow(0 0 12px rgba(255,77,77,0.65)); }
    100% { transform: scale(1)     rotate(0deg); filter: brightness(1)    drop-shadow(0 2px 8px rgba(0,0,0,0.5)); }
}

/* Points flottants (+1000) affichés brièvement sur l'impact d'un hit en
   mode Combo, pour visualiser les points gagnés à chaque tir. */
.floating-points {
    position: fixed;
    z-index: 47;
    color: var(--couleur-verte);
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: 1px;
    text-shadow: 0 0 8px rgba(0,255,0,0.85);
    pointer-events: none;
    animation: floatingPointsRise 0.7s ease-out forwards;
}
/* Variante "négative" : texte (pas un score) affiché sur les mauvaises
   cibles, tant que le Combo n'est pas actif — "Reste calme" /
   "Reprends-toi" / "Respire" (cf. Scoring.showFloatingText, appelé
   depuis le branchement pénalité de registerHit).
   Lisibilité : la première version ne reposait que sur une lueur rouge
   floue (text-shadow flou), sans aucun bord net — sur un fond vidéo déjà
   chargé en rouge/orange, le texte s'y fondait. Un contour noir plein
   (4 ombres non floutées) est donc ajouté pour un vrai contraste sur
   n'importe quel fond, l'italique est retiré (moins lisible en lecture
   rapide) et une animation dédiée (floatingTextRise, palier de maintien
   à opacité pleine plus long que floatingPointsRise) laisse le temps de
   lire une phrase, plus longue qu'un simple "+100". */
.floating-points.negative {
    color: var(--couleur-rouge);
    text-shadow:
        -1px -1px 0 #000,  1px -1px 0 #000,
        -1px  1px 0 #000,  1px  1px 0 #000,
        0 0 10px rgba(0,0,0,0.7);
    font-style: normal;
    font-weight: 900;
    font-size: 1.05rem;
    letter-spacing: 0;
    white-space: nowrap;
    animation: floatingTextRise 1.8s ease-out forwards;
}
@keyframes floatingTextRise {
    0% { transform: translate(-50%, -50%) scale(0.8); opacity: 0; }
    10% { transform: translate(-50%, -70%) scale(1.05); opacity: 1; }
    80% { transform: translate(-50%, -130%) scale(1); opacity: 1; }
    100% { transform: translate(-50%, -170%) scale(1); opacity: 0; }
}
@keyframes floatingPointsRise {
    0% { transform: translate(-50%, -50%) scale(0.8); opacity: 0; }
    20% { transform: translate(-50%, -65%) scale(1.1); opacity: 1; }
    100% { transform: translate(-50%, -150%) scale(1); opacity: 0; }
}

/* ---------------------------------------------------------------------
   EFFETS DE COMBO — texte dramatique, vignette en combo, écran COMBO!
   --------------------------------------------------------------------- */
/* Pas d'agrandissement de la boîte pendant le Combo (cf. demande) : seul
   le poids/l'espacement des lettres reste plus marqué, la taille et le
   padding restent ceux de .top-left-text de base. Le clignotement de
   couleur (.blink ci-dessous) reste inchangé. */
.top-left-text.dramatic-effect {
    font-weight: 900;
    letter-spacing: 2px;
}
/* Clignotement 100% opaque (jamais de fondu d'opacité) : le bloc reste
   plein et à la même taille, seules ses couleurs alternent entre les
   deux paires noir/vert et rouge/jaune — pas de second élément qui
   apparaîtrait "dessous" pendant la transition. */
.top-left-text.blink {
    animation: colorBlink 0.5s steps(1) infinite;
}
@keyframes colorBlink {
    0%, 49% { background: #000; color: var(--couleur-verte); }
    50%, 100% { background: var(--couleur-rouge); color: #ffe600; }
}
.combo-fullscreen {
    position: fixed;
    inset: 0;
    z-index: 500;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 6rem;
    font-weight: 900;
    letter-spacing: 6px;
    color: var(--couleur-verte);
    text-shadow: 0 0 30px rgba(0,255,0,0.9), 0 0 90px rgba(0,255,0,0.6);
    background: radial-gradient(circle, rgba(0,255,0,0.18), transparent 65%);
    pointer-events: none;
    animation: comboSlam 2s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@keyframes comboSlam {
    0% { transform: scale(2.6) rotate(-8deg); opacity: 0; }
    12% { transform: scale(0.9) rotate(3deg); opacity: 1; }
    22% { transform: scale(1.12) rotate(-2deg); }
    32% { transform: scale(1) rotate(0deg); }
    78% { transform: scale(1) rotate(0deg); opacity: 1; }
    100% { transform: scale(1.15) rotate(0deg); opacity: 0; }
}
@media (max-width: 900px) {
    .combo-fullscreen { font-size: 3.2rem; letter-spacing: 3px; }
}

/* Bravo affiché juste avant la 2e respiration, quand le Combo vient de se
   débloquer (cf. Scoring.showComboCongratsEffect) — même famille visuelle
   que .combo-fullscreen ci-dessus (réutilise l'animation comboSlam), mais
   taille réduite : le texte ("TU AS TENU BON !"...) est une phrase
   complète, plus longue qu'un simple "COMBO!". */
.congrats-fullscreen {
    position: fixed;
    inset: 0;
    z-index: 500;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 3.2rem;
    font-weight: 900;
    letter-spacing: 2px;
    text-align: center;
    padding: 0 30px;
    color: var(--couleur-verte);
    text-shadow: 0 0 30px rgba(0,255,0,0.9), 0 0 90px rgba(0,255,0,0.5);
    background: radial-gradient(circle, rgba(0,255,0,0.16), transparent 65%);
    pointer-events: none;
    animation: comboSlam 1.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@media (max-width: 900px) {
    .congrats-fullscreen { font-size: 1.9rem; letter-spacing: 1px; }
}

/* Effet plein écran des paliers MULTI (cf. Scoring.showMultiEffect) —
   même famille visuelle que .combo-fullscreen ci-dessus, mais en orange
   et légèrement plus discret (taille, durée, z-index) pour rester bien
   distinct du Combo, plus rare et plus marquant. */
.multi-fullscreen {
    position: fixed;
    inset: 0;
    z-index: 499;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 5rem;
    font-weight: 900;
    letter-spacing: 4px;
    color: var(--couleur-orange);
    text-shadow: 0 0 30px rgba(255,165,0,0.9), 0 0 90px rgba(255,165,0,0.6);
    background: radial-gradient(circle, rgba(255,165,0,0.18), transparent 65%);
    pointer-events: none;
    animation: multiSlam 1.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@keyframes multiSlam {
    0% { transform: scale(2.2) rotate(6deg); opacity: 0; }
    14% { transform: scale(0.92) rotate(-3deg); opacity: 1; }
    26% { transform: scale(1.08) rotate(2deg); }
    38% { transform: scale(1) rotate(0deg); }
    75% { transform: scale(1) rotate(0deg); opacity: 1; }
    100% { transform: scale(1.1) rotate(0deg); opacity: 0; }
}
@media (max-width: 900px) {
    .multi-fullscreen { font-size: 2.6rem; letter-spacing: 2px; }
}

/* Effet plein écran de déblocage du mode Rafale (cf.
   Scoring.showRafaleUnlockEffect) — même animation (multiSlam) que
   .multi-fullscreen ci-dessus, mais en blanc à contour noir pour faire
   écho à l'identité visuelle du curseur Rafale (cf. le curseur croix et
   le viseur à coins, tous deux blancs à contour noir). Taille de police
   plus modeste : le texte ("MODE RAFALE DÉBLOQUÉ") est nettement plus
   long qu'un "MULTI x10!" ou "COMBO!". z-index identique à
   .multi-fullscreen (ce sont deux variantes du même "tier" d'effet, ne
   se déclenchent jamais en même temps pour le même hit).
   Lisibilité : l'ancienne version reposait uniquement sur
   -webkit-text-stroke (invisible hors navigateurs webkit, donc pas de
   contour du tout sur Firefox) + un text-shadow flou (un flou ne crée
   jamais un bord net) sur un fond éclairci en blanc — qui délavait
   justement le texte blanc au lieu de le faire ressortir. Le contour
   est donc désormais aussi assuré par 8 ombres pleines (non floutées)
   décalées dans toutes les directions, ce qui donne un liseré net et
   fonctionne sur tous les navigateurs ; le fond est passé en dégradé
   sombre pour créer un vrai contraste derrière le blanc du texte.
   -webkit-text-stroke a été retiré : contrairement à text-shadow (garanti
   peint DERRIÈRE le texte par la spec), un text-stroke est centré sur le
   contour des lettres et mord donc pour moitié sur le remplissage blanc —
   visible comme un contour qui "passe sur" le texte plutôt que dessous,
   surtout sur mobile à cette taille de police. */
.rafale-unlock-fullscreen {
    position: fixed;
    inset: 0;
    z-index: 499;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 3rem;
    font-weight: 900;
    letter-spacing: 2px;
    text-align: center;
    padding: 0 20px;
    color: #fff;
    text-shadow:
        -2px -2px 0 #000,  2px -2px 0 #000,
        -2px  2px 0 #000,  2px  2px 0 #000,
        -3px  0    0 #000,  3px  0    0 #000,
         0   -3px 0 #000,   0    3px 0 #000,
        0 0 22px rgba(0,0,0,0.85);
    background: radial-gradient(circle, rgba(0,0,0,0.55), transparent 65%);
    pointer-events: none;
    animation: multiSlam 1.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}
@media (max-width: 900px) {
    .rafale-unlock-fullscreen { font-size: 1.8rem; letter-spacing: 1px; }
}

/* ---------------------------------------------------------------------
   ÉCRAN DE FIN (end-screen) - Version Compacte
   --------------------------------------------------------------------- */
#end-screen {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: rgba(0,0,0,0.92);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    z-index: 200;
    opacity: 0;
    visibility: hidden;
    transition: all 0.6s ease;
    text-align: center;
    gap: 4px;
}
#end-screen.visible {
    opacity: 1;
    visibility: visible;
}
.end-difficulty-badge {
    display: inline-block;
    padding: 4px 18px;
    margin-bottom: 16px;
    border-radius: 20px;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 2px;
    text-transform: uppercase;
    border: 1.5px solid currentColor;
}
.end-difficulty-badge[data-level="1"] {
    color: var(--couleur-verte);
    background: rgba(0, 255, 0, 0.1);
}
.end-difficulty-badge[data-level="2"] {
    color: var(--couleur-orange);
    background: rgba(255, 165, 0, 0.1);
}
.end-difficulty-badge[data-level="3"] {
    color: var(--couleur-rouge);
    background: rgba(255, 77, 77, 0.1);
}
.end-label {
    font-size: 0.75rem;
    color: rgba(255,255,255,0.4);
    letter-spacing: 2px;
    text-transform: uppercase;
    margin-bottom: 0;
}
.end-big-score {
    font-size: 4.5rem;
    font-weight: 300;
    color: white;
    text-shadow: 0 0 40px rgba(0,255,0,0.3);
    margin-bottom: 2px;
    font-variant-numeric: tabular-nums;
}
.end-stats {
    font-size: 0.85rem;
    color: rgba(255,255,255,0.5);
    margin-bottom: 2px;
    letter-spacing: 1px;
}

/* ---------------------------------------------------------------------
   PROFIL DE FIN DE PARTIE (ResultProfile) — titre + phrase sarcastique
   --------------------------------------------------------------------- */
.end-result-title {
    font-size: 1.05rem;
    font-weight: 900;
    letter-spacing: 2px;
    text-transform: uppercase;
    margin: 4px 0 4px;
}
.end-result-title[data-tier="1"] { color: var(--couleur-rouge); }
.end-result-title[data-tier="2"] { color: var(--couleur-tier2); }
.end-result-title[data-tier="3"] { color: var(--couleur-orange); }
.end-result-title[data-tier="4"] { color: var(--couleur-tier4); }
.end-result-title[data-tier="5"] { color: var(--couleur-verte); }

.end-result-phrase {
    font-size: 0.8rem;
    font-style: italic;
    color: rgba(255,255,255,0.55);
    max-width: 320px;
    margin: 0 auto 12px;
    line-height: 1.4;
    padding: 0 14px;
}
#restart-btn {
    background: transparent;
    border: 2px solid white;
    color: white;
    padding: 12px 45px;
    font-size: 0.9rem;
    cursor: pointer;
    transition: all 0.3s ease;
    border-radius: 50px;
    letter-spacing: 2px;
    text-transform: uppercase;
    font-family: inherit;
    -webkit-appearance: none;
    margin-top: 15px;
}
#restart-btn:hover {
    background: white;
    color: black;
}
.high-score {
    font-size: 0.85rem;
    color: var(--couleur-orange);
    margin-top: 2px;
}
/* Bannière de déblocage de niveau (cf. LevelUnlock dans script.js) —
   événement rare et spécial, distinct du reste de l'écran de fin :
   reprend l'orange déjà utilisé pour le meilleur score, mais en badge
   avec une légère lueur pour bien le faire ressortir. Vide par défaut
   (aucun déblocage cette partie) => invisible sans JS supplémentaire. */
.level-unlock-banner {
    font-size: 0.85rem;
    font-weight: 700;
    letter-spacing: 0.5px;
    color: var(--couleur-orange);
    background: rgba(255, 165, 0, 0.12);
    border: 1px solid var(--couleur-orange);
    border-radius: 20px;
    padding: 6px 16px;
    margin: 6px 0 2px;
    box-shadow: 0 0 14px rgba(255, 165, 0, 0.35);
}
.level-unlock-banner:empty {
    display: none;
    margin: 0;
    padding: 0;
    border: none;
    box-shadow: none;
}

/* ---------------------------------------------------------------------
   ÉCRAN DE SÉLECTION DE NIVEAU
   --------------------------------------------------------------------- */
#level-select-screen {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.88);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 101;
    text-align: center;
    transition: opacity 0.7s ease, visibility 0.7s ease;
}
#level-select-screen.hidden {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
}
.level-btn {
    background: rgba(0,255,0,0.08);
    border: 2px solid var(--couleur-verte);
    color: var(--couleur-verte);
    padding: 15px 30px;
    font-size: 1.1rem;
    cursor: pointer;
    transition: all 0.3s ease;
    border-radius: 50px;
    letter-spacing: 2px;
    text-transform: uppercase;
    font-family: inherit;
    -webkit-appearance: none;
    margin: 10px;
    min-width: 200px;
}
.level-btn:hover {
    background: var(--couleur-verte);
    color: black;
}
.level-btn.disabled {
    opacity: 0.4;
    cursor: not-allowed;
    border-color: rgba(255,255,255,0.1);
    color: rgba(255,255,255,0.3);
}
/* Badge "Désactivé" (cf. I18N.levelDisabled) : masqué par défaut, révélé
   uniquement quand le bouton parent porte .disabled — un seul point de
   vérité (LevelUnlock.applyToButtons ne touche qu'à cette classe). */
.level-lock-label {
    display: none;
    margin-top: 4px;
    font-size: 0.65rem;
    letter-spacing: 2px;
    text-transform: uppercase;
    opacity: 0.7;
}
.level-btn.disabled .level-lock-label {
    display: block;
}

/* Bouton retour vers l'accueil, sur l'écran de sélection de niveau
   (Vamos / Raclette / Disable). Style neutre (blanc) pour bien le
   distinguer des boutons de niveau (verts), cohérent avec #start-btn
   et #restart-btn sur les autres écrans. */
#back-to-welcome-btn {
    background: transparent;
    border: 2px solid rgba(255,255,255,0.4);
    color: rgba(255,255,255,0.7);
    padding: 10px 30px;
    font-size: 0.85rem;
    cursor: pointer;
    transition: all 0.3s ease;
    border-radius: 50px;
    letter-spacing: 2px;
    text-transform: uppercase;
    font-family: inherit;
    -webkit-appearance: none;
    margin: 20px 10px 0;
}
#back-to-welcome-btn:hover {
    background: rgba(255,255,255,0.15);
    border-color: white;
    color: white;
}

/* ---------------------------------------------------------------------
   BOUTON PLEIN ÉCRAN & TEXTES FIXES
   --------------------------------------------------------------------- */
/* Cercle 32px (même gabarit que .lang-btn), aspect vert/néon conservé,
   même emplacement bas-droite. Le symbole ⤡ remplace le texte
   "⛶ FULLSCREEN" — cf. index.html. */
#fullscreen-btn {
    position: fixed;
    bottom: 20px;
    right: 20px;
    z-index: 1000;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: rgba(0,255,0,0.1);
    border: 1.5px solid var(--couleur-verte);
    color: var(--couleur-verte);
    font-size: 1.1rem;
    line-height: 1;
    cursor: pointer;
    transition: all 0.3s ease;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 0;
    font-family: inherit;
    -webkit-appearance: none;
}
#fullscreen-btn.visible {
    display: flex;
}
#fullscreen-btn:hover {
    background: var(--couleur-verte);
    color: black;
}
/* État temporaire (iOS, API Fullscreen indisponible) : le bouton
   s'élargit le temps d'afficher le message explicatif complet, avant de
   revenir à sa forme ronde compacte — cf.
   FullscreenManager.showUnsupportedHint dans script.js. */
#fullscreen-btn.hint {
    width: auto;
    height: auto;
    max-width: 220px;
    border-radius: 20px;
    padding: 8px 14px;
    font-size: 0.7rem;
    line-height: 1.3;
    white-space: normal;
    text-align: center;
}

.top-left-text {
    /* Nom de classe conservé pour ne pas toucher au JS/HTML : le bloc
       instructions est de nouveau affiché en haut à gauche (re-permuté
       avec le timer, cf. #hud ci-dessus). */
    position: fixed;
    top: 20px;
    left: 20px;
    z-index: 50;
    background: rgba(0,0,0,0.6);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    padding: 8px 15px;
    border-radius: 25px;
    border: 1px solid rgba(255,255,255,0.1);
    font-size: 0.9rem;
    letter-spacing: 1px;
    pointer-events: none;
    opacity: 1;
    transition: opacity 0.3s ease;
    /* Largeur plafonnée : sans ça, un texte de niveau long (ex. "Garde ton
       calme & SHOOT LA CLOCHE !") peut s'étendre très loin vers la gauche
       et déborder sur des écrans étroits. Le score est maintenant ancré en
       bas à gauche (cf. .hud-score) donc ce n'est plus un risque de
       chevauchement avec lui, mais la contrainte reste utile pour la
       lisibilité générale ; le texte passe sur 2 lignes si besoin plutôt
       que de déborder. */
    max-width: calc(50vw - 70px);
    text-align: center;
    line-height: 1.3;
}
.top-left-text.hidden {
    opacity: 0;
}

#rotate-prompt {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: #000;
    color: white;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 20px;
}
.rotate-icon {
    font-size: 4rem;
    margin-bottom: 20px;
    animation: rotateHint 1.6s ease-in-out infinite;
}
@keyframes rotateHint {
    0%, 100% { transform: rotate(0deg); }
    50% { transform: rotate(90deg); }
}

/* ---------------------------------------------------------------------
   MODE RAFALE — viseur agrandi, traces d'impact qui s'estompent,
   réticule mobile. Débloqué en touchant la Berceuse 10 fois (cf.
   Config.MULTI_MILESTONES dans script.js), quelle que soit la difficulté.
   --------------------------------------------------------------------- */

/* Curseur "viseur à coins" dédié au mode rafale — 64px (au lieu du
   simple crosshair 32px/48px des essais précédents), posé sur <body>.
   La classe rafale-active est ajoutée dès que la touche Alt est tenue
   (même sans clic) OU qu'un tir est en cours — cf. RafaleMode.updateCursorVisual
   dans script.js. */
/* !important nécessaire ici : Screens.goToLevelSelect (script.js) pose le
   crosshair standard en style inline sur <body> dès la sélection de
   niveau ; un style inline l'emporte toujours sur une règle de classe
   normale, quelle que soit sa spécificité — sans !important, ce curseur
   ne s'affichait donc jamais malgré l'ajout/retrait de la classe
   rafale-active. */
body.rafale-active {
    cursor: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NCIgaGVpZ2h0PSI2NCIgdmlld0JveD0iMCAwIDY0IDY0Ij48cGF0aCBkPSJNNiAyMCBMNiA2IEwyMCA2IiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Ik00NCA2IEw1OCA2IEw1OCAyMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjQiLz48cGF0aCBkPSJNNTggNDQgTDU4IDU4IEw0NCA1OCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjQiLz48cGF0aCBkPSJNMjAgNTggTDYgNTggTDYgNDQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSI0Ii8+PGxpbmUgeDE9IjMyIiB5MT0iMjUiIHgyPSIzMiIgeTI9IjI5IiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMy41Ii8+PGxpbmUgeDE9IjMyIiB5MT0iMzUiIHgyPSIzMiIgeTI9IjM5IiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMy41Ii8+PGxpbmUgeDE9IjI1IiB5MT0iMzIiIHgyPSIyOSIgeTI9IjMyIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMy41Ii8+PGxpbmUgeDE9IjM1IiB5MT0iMzIiIHgyPSIzOSIgeTI9IjMyIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMy41Ii8+PGNpcmNsZSBjeD0iMzIiIGN5PSIzMiIgcj0iMi44IiBmaWxsPSIjMDAwIi8+PHBhdGggZD0iTTYgMjAgTDYgNiBMMjAgNiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIuNSIvPjxwYXRoIGQ9Ik00NCA2IEw1OCA2IEw1OCAyMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIuNSIvPjxwYXRoIGQ9Ik01OCA0NCBMNTggNTggTDQ0IDU4IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMi41Ii8+PHBhdGggZD0iTTIwIDU4IEw2IDU4IEw2IDQ0IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMi41Ii8+PGxpbmUgeDE9IjMyIiB5MT0iMjUiIHgyPSIzMiIgeTI9IjI5IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIvPjxsaW5lIHgxPSIzMiIgeTE9IjM1IiB4Mj0iMzIiIHkyPSIzOSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiLz48bGluZSB4MT0iMjUiIHkxPSIzMiIgeDI9IjI5IiB5Mj0iMzIiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyIi8+PGxpbmUgeDE9IjM1IiB5MT0iMzIiIHgyPSIzOSIgeTI9IjMyIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIvPjxjaXJjbGUgY3g9IjMyIiBjeT0iMzIiIHI9IjIiIGZpbGw9IiNmZmYiLz48L3N2Zz4=') 32 32, crosshair !important;
}

/* Trace d'impact : un rond qui se rétracte et s'estompe, laissé à
   chaque tir de la rafale (touché ou raté) pour visualiser la
   trajectoire du viseur. Élément jetable créé/détruit par
   RafaleMode.spawnTrail — à ~12 tirs/sec le coût DOM est négligeable. */
.rafale-trail {
    position: fixed;
    width: 18px;
    height: 18px;
    margin-left: -9px;
    margin-top: -9px;
    border-radius: 50%;
    border: 2px solid var(--couleur-verte);
    box-shadow: 0 0 10px rgba(0, 255, 0, 0.6);
    z-index: 42;
    pointer-events: none;
    animation: rafaleTrailFade 0.45s ease-out forwards;
}
@keyframes rafaleTrailFade {
    0% { transform: scale(1); opacity: 0.9; }
    100% { transform: scale(0.3); opacity: 0; }
}

/* Réticule mobile : même dessin "viseur à coins" que le curseur desktop
   ci-dessus (pas de curseur CSS possible au toucher, donc élément dédié
   en image de fond plutôt qu'un simple rond). Suit le doigt via
   transform (compositor uniquement, pas de reflow) tant que la rafale
   est active. */
.rafale-mobile-reticle {
    position: fixed;
    top: 0;
    left: 0;
    width: 64px;
    height: 64px;
    margin-left: -32px;
    margin-top: -32px;
    background-image: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI2NCIgaGVpZ2h0PSI2NCIgdmlld0JveD0iMCAwIDY0IDY0Ij48cGF0aCBkPSJNNiAyMCBMNiA2IEwyMCA2IiBmaWxsPSJub25lIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iNCIvPjxwYXRoIGQ9Ik00NCA2IEw1OCA2IEw1OCAyMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjQiLz48cGF0aCBkPSJNNTggNDQgTDU4IDU4IEw0NCA1OCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwIiBzdHJva2Utd2lkdGg9IjQiLz48cGF0aCBkPSJNMjAgNTggTDYgNTggTDYgNDQiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzAwMCIgc3Ryb2tlLXdpZHRoPSI0Ii8+PGxpbmUgeDE9IjMyIiB5MT0iMjUiIHgyPSIzMiIgeTI9IjI5IiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMy41Ii8+PGxpbmUgeDE9IjMyIiB5MT0iMzUiIHgyPSIzMiIgeTI9IjM5IiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMy41Ii8+PGxpbmUgeDE9IjI1IiB5MT0iMzIiIHgyPSIyOSIgeTI9IjMyIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMy41Ii8+PGxpbmUgeDE9IjM1IiB5MT0iMzIiIHgyPSIzOSIgeTI9IjMyIiBzdHJva2U9IiMwMDAiIHN0cm9rZS13aWR0aD0iMy41Ii8+PGNpcmNsZSBjeD0iMzIiIGN5PSIzMiIgcj0iMi44IiBmaWxsPSIjMDAwIi8+PHBhdGggZD0iTTYgMjAgTDYgNiBMMjAgNiIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIuNSIvPjxwYXRoIGQ9Ik00NCA2IEw1OCA2IEw1OCAyMCIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIuNSIvPjxwYXRoIGQ9Ik01OCA0NCBMNTggNTggTDQ0IDU4IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMi41Ii8+PHBhdGggZD0iTTIwIDU4IEw2IDU4IEw2IDQ0IiBmaWxsPSJub25lIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMi41Ii8+PGxpbmUgeDE9IjMyIiB5MT0iMjUiIHgyPSIzMiIgeTI9IjI5IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIvPjxsaW5lIHgxPSIzMiIgeTE9IjM1IiB4Mj0iMzIiIHkyPSIzOSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiLz48bGluZSB4MT0iMjUiIHkxPSIzMiIgeDI9IjI5IiB5Mj0iMzIiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyIi8+PGxpbmUgeDE9IjM1IiB5MT0iMzIiIHgyPSIzOSIgeTI9IjMyIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIvPjxjaXJjbGUgY3g9IjMyIiBjeT0iMzIiIHI9IjIiIGZpbGw9IiNmZmYiLz48L3N2Zz4=');
    background-size: contain;
    background-repeat: no-repeat;
    filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.8));
    z-index: 48;
    pointer-events: none;
    display: none;
}
.rafale-mobile-reticle.visible {
    display: block;
}

/* Étiquette flottante au-dessus du curseur (cf. CursorHint dans script.js).
   left/top sont mis à jour à chaque mousemove ; le décalage visuel
   (au-dessus + centré) est purement en CSS via transform, pour ne jamais
   avoir à recalculer une position composée en JS à chaque frame. */
.cursor-hint {
    position: fixed;
    transform: translate(-50%, calc(-100% - 14px));
    pointer-events: none;
    z-index: 60;
    font-size: 0.75rem;
    font-weight: 900;
    letter-spacing: 1px;
    text-transform: uppercase;
    padding: 3px 10px;
    border-radius: 12px;
    background: rgba(0, 0, 0, 0.7);
    white-space: nowrap;
    opacity: 0;
    transition: opacity 0.15s ease;
}
.cursor-hint.visible {
    opacity: 1;
}
.cursor-hint.negative {
    color: var(--couleur-rouge);
    border: 1px solid var(--couleur-rouge);
}
.cursor-hint.positive {
    color: var(--couleur-verte);
    border: 1px solid var(--couleur-verte);
}

/* ---------------------------------------------------------------------
   RESPONSIVE — mobile portrait
   --------------------------------------------------------------------- */
@media (max-width: 600px) and (orientation: portrait) {
    #rotate-prompt { display: flex; }
    #welcome-screen h1 { font-size: 1.6rem; letter-spacing: 2px; }
    .difficulty-btn { width: 55px; height: 55px; font-size: 0.55rem; }
    .difficulty-btn .level-num { font-size: 1.2rem; }
    #start-btn { padding: 10px 30px; font-size: 0.9rem; }
    .lang-switcher { top: 10px; right: 10px; gap: 6px; }
    .lang-btn { width: 26px; height: 26px; font-size: 0.5rem; }
}

/* ---------------------------------------------------------------------
   RESPONSIVE — mobile paysage bas (typiquement un téléphone en paysage,
   ~6.5" en 1920x1080 ou équivalent). Seuil identique à celui utilisé côté
   JS (Spawner.getVignetteSize, script.js) pour rester synchronisé.
   --------------------------------------------------------------------- */
@media (max-height: 400px) {
    /* Vignettes réduites : moins de place verticale disponible entre les
       zones de sécurité HUD haut/bas (cf. --hud-safe-top/bottom). */
    .vignette {
        width: 70px;
        height: 70px;
    }

    /* Timer : reste seul dans le flux flex de #hud (flex-start, comme en
       mode normal). Le score n'est plus fusionné avec lui — il conserve
       son propre ancrage indépendant (position:fixed, bas-gauche, cf.
       .hud-score plus haut dans le fichier), y compris en mode compact. */

    /* Cartouche "Keep Calm" : reste visible en mode compact (le joueur
       mobile en paysage, cas le plus fréquent — cf. #rotate-prompt qui
       impose ce mode — en a justement le plus besoin, pour savoir quel
       sprite viser), mais dans une version resserrée pour ne pas empiéter
       sur le HUD déjà condensé. L'ancienne version le masquait totalement
       (display:none) tant que le Combo n'était pas déclenché, retirant
       cette info précisément là où elle compte le plus. */
    .top-left-text {
        top: 10px;
        left: 10px;
        font-size: 0.75rem;
        padding: 6px 12px;
        max-width: calc(50vw - 60px);
    }
}

/* =====================================================================
   Footer nav (About / Privacy Policy / Contact) — requis pour la
   conformité AdSense (pages légales accessibles + navigation claire).
   Discret, en bas de l'écran d'accueil, ne perturbe pas le layout du jeu.
   ===================================================================== */
.site-footer-nav {
    margin-top: 24px;
    text-align: center;
    font-size: 0.75rem;
    color: rgba(255, 255, 255, 0.45);
}
.site-footer-nav a {
    color: rgba(255, 255, 255, 0.55);
    text-decoration: none;
}
.site-footer-nav a:hover {
    color: #fff;
    text-decoration: underline;
}
.site-footer-nav span {
    margin: 0 8px;
    opacity: 0.4;
}
