/**
 * Écran de jeu multijoueur — Ticket Cricket 2026.
 *
 * Règles clés :
 *  - Tour par tour, seul le joueur actif peut piocher.
 *  - Joueur à 10 000 $ de dette totale → éliminé (spectateur).
 *  - Cartes T3 : transfert automatique de dette au joueur suivant.
 *  - Poll toutes les ~1,8 s.
 */
import { useState, useEffect, useRef, useCallback, useMemo } from "react";
import { motion, AnimatePresence } from "motion/react";
import { createPortal } from "react-dom";
import { useLocation } from "wouter";
import {
  Home, Crown, Shuffle, X, ChevronLeft, ChevronRight, ChevronDown,
  Clock, Target, Trophy, Layers, User, ArrowRight, ArrowLeft,
  Banknote, TrendingDown, TrendingUp, Mail, Skull, CheckCircle,
  Eye, EyeOff, History, ListOrdered, UserX, LogOut, Search, Siren, Megaphone, Music, Ticket, Users,
} from "lucide-react";
import {
  getSession, drawCard, resetGame, leaveSession, addDebt, eliminatePlayer,
  endTurn, mpStorage, acknowledgeElimination, kickPlayer, type Session,
} from "@/game/utils/sessionApi";

import {
  getCardConfig, drawerNetAmount, nextPlayerAmount, computePlayerTotal,
  formatPrice, CATEGORY_INFO, CATEGORY_ORDER, TYPE_INFO,
  type CardCategory, type CardConfig,
} from "@/game/utils/cardConfig";
import { filterByCategory } from "@/game/utils/cardCategories";
import { PoliceTape } from "@/game/ui/PoliceUI";
import ticketImg from "@/game/utils/ticketImg";
import { WinnerOverlay } from "@/game/ui/WinnerOverlay";

import { PodiumOverlay, type PodiumPlayer } from "@/game/ui/PodiumOverlay";
import { GeneratedCard, CardBack as GeneratedCardBack } from "@/game/components/GeneratedCard";
import { MiniGame } from "@/game/components/MiniGame";
import { DraggableCard } from "@/game/components/DraggableCard";
import { rollMiniGame, type MiniGameLevel } from "@/game/utils/miniGameUtils";
import { triggerPerquisitionAlert } from "@/game/utils/alertSound";
import { SOLO_MINI_GAME_LEVEL_KEY, SOLO_MINI_GAME_DIFFICULTY_KEY, type MiniGameDifficulty } from "@/game/components/MultiplayerModal";
import { trpc } from "@/lib/trpc";
import { getAvatarDisplay } from "@/game/utils/avatarConfig";
import { BadgeVisual } from "@/components/BadgeVisuals";
import { MusicControl } from "@/game/components/MusicControl";
import { MusicPlayerPage } from "@/game/components/MusicPlayerPage";
import { useGameAuth } from "@/hooks/useGameAuth";

const FONT_BANGERS: React.CSSProperties = { fontFamily: "'Bangers', cursive" };
const FONT_FREDOKA: React.CSSProperties = { fontFamily: "'Fredoka One', cursive" };

// ── Palette de couleurs assignée par ordre de jeu ──────────
const PLAYER_COLOR_PALETTE = [
  { text: "#fb923c", bg: "rgba(249,115,22,0.13)", border: "rgba(249,115,22,0.3)", dot: "#f97316" },  // orange
  { text: "#4ade80", bg: "rgba(34,197,94,0.13)",  border: "rgba(34,197,94,0.3)",  dot: "#22c55e" },  // green
  { text: "#c084fc", bg: "rgba(168,85,247,0.13)", border: "rgba(168,85,247,0.3)", dot: "#a855f7" },  // purple
  { text: "#f472b6", bg: "rgba(236,72,153,0.13)", border: "rgba(236,72,153,0.3)", dot: "#ec4899" },  // pink
  { text: "#2dd4bf", bg: "rgba(20,184,166,0.13)", border: "rgba(20,184,166,0.3)", dot: "#14b8a6" },  // teal
  { text: "#facc15", bg: "rgba(234,179,8,0.13)",  border: "rgba(234,179,8,0.3)",  dot: "#eab308" },  // yellow
  { text: "#f87171", bg: "rgba(239,68,68,0.13)",  border: "rgba(239,68,68,0.3)",  dot: "#ef4444" },  // red
];
// Couleur fixe pour le joueur local : bleu
const MY_COLOR = { text: "#60a5fa", bg: "rgba(59,130,246,0.14)", border: "rgba(59,130,246,0.35)", dot: "#3b82f6" };

// ────────────────────────────────────────────────────────────
// Utilitaire : trouver le prochain joueur actif (T3 sans avancement de tour)
// ────────────────────────────────────────────────────────────
function getNextActivePlayerId(s: Session, currentPlayerId: string): string | null {
  const n = s.turnOrder.length;
  const currentIdx = s.turnOrder.indexOf(currentPlayerId);
  if (currentIdx === -1 || n <= 1) return null;
  const eliminated = s.eliminatedPlayers ?? [];
  let nextIdx = (currentIdx + 1) % n;
  let attempts = 0;
  while (eliminated.includes(s.turnOrder[nextIdx]) && attempts < n) {
    nextIdx = (nextIdx + 1) % n;
    attempts++;
  }
  const nextId = s.turnOrder[nextIdx];
  return nextId !== currentPlayerId ? nextId : null;
}

const POLL_INTERVAL       = 2500;
const TOTAL_CARDS         = 324;
const DEFAULT_ELIMINATION_THRESHOLD = 10_000; // remplacé par session.eliminationThreshold

// ── Registre runtime des cartes personnalisées multijoueur ──
const mpCustomCardRegistry  = new Map<number, CardConfig>();
const mpCustomMefaitRegistry = new Map<number, string>();

function loadMpCustomCards(cards: Array<{
  id: number; category: string; mefait: string | null;
  ticketPrice: number; frais: number; impots: number; taxe: number;
}>): void {
  mpCustomCardRegistry.clear();
  mpCustomMefaitRegistry.clear();
  for (const card of cards) {
    const cat = card.category as "contravention" | "contribuable" | "investisseur";
    const isT3 = cat === "investisseur";
    const isT2 = cat === "contribuable";
    const cardType = isT3 ? 3 : isT2 ? 2 : 1;
    const cfg: CardConfig = {
      id: -card.id,
      category: cat,
      cardType,
      ticketPrice: card.ticketPrice,
      frais: card.frais,
      impots: card.impots,
      taxe: card.taxe,
    } as unknown as CardConfig;
    mpCustomCardRegistry.set(-card.id, cfg);
    // Texte méfait : soit le texte personnalisé, soit le texte par défaut investisseur
    if (card.mefait) {
      mpCustomMefaitRegistry.set(-card.id, card.mefait);
    } else if (cat === "investisseur") {
      mpCustomMefaitRegistry.set(-card.id, "Ticket au prochain criminel");
    }
  }
}

function getCardConfigMp(id: number): CardConfig {
  if (id < 0) {
    const custom = mpCustomCardRegistry.get(id);
    if (custom) return custom;
  }
  return getCardConfig(id);
}

function getMpCustomMefait(id: number): string | undefined {
  if (id < 0) return mpCustomMefaitRegistry.get(id);
  return undefined;
}

function computePlayerTotalMp(cardIds: number[]): number {
  return cardIds.reduce((sum, id) => sum + drawerNetAmount(getCardConfigMp(id)), 0);
}

// ────────────────────────────────────────────────────────────
// Icône main SVG
// ────────────────────────────────────────────────────────────
function HandIcon({ size = 20 }: { size?: number }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round">
      <path d="M18 11V6a2 2 0 0 0-4 0v5" />
      <path d="M14 10V4a2 2 0 0 0-4 0v2" />
      <path d="M10 10.5V6a2 2 0 0 0-4 0v8" />
      <path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15" />
    </svg>
  );
}



// ────────────────────────────────────────────────────────────
// TurnNotification — bulle centrale animée
// ────────────────────────────────────────────────────────────
function TurnNotification({
  isMe, myName, currentName, onDismiss,
  myAvatarDisplay: myAvatarDisplayProp,
  currentAvatarDisplay: currentAvatarDisplayProp,
  myPlayerId,
  currentPlayerId,
  guestEmojis: guestEmojisProp,
}: {
  isMe: boolean;
  myName: string;
  currentName: string;
  onDismiss?: () => void;
  myAvatarDisplay?: { type: "emoji" | "image" | "default"; content: string } | null;
  currentAvatarDisplay?: { type: "emoji" | "image" | "default"; content: string } | null;
  myPlayerId?: string;
  currentPlayerId?: string;
  guestEmojis?: Record<string, string>;
}) {
  // Résoudre l'emoji en interne avec un state local pour se mettre à jour dynamiquement
  // Les avatars sont résolus directement dans le parent (guestEmojis inclus)
  // On utilise les props directement pour éviter les décalages de timing
  const myAvatarDisplay = myAvatarDisplayProp ?? null;
  const currentAvatarDisplay = currentAvatarDisplayProp ?? null;

  return (
    <motion.div
      initial={{ opacity: 0, scale: 0.7 }}
      animate={{ opacity: 1, scale: 1 }}
      exit={{ opacity: 0, scale: 0.7 }}
      transition={{ type: "spring", stiffness: 380, damping: 26 }}
      className={`fixed inset-0 z-[70] flex items-center justify-center px-7 ${isMe ? "" : "pointer-events-none"}`}
      style={isMe ? { background: "rgba(0,0,0,0.6)", backdropFilter: "blur(2px)" } : {}}
    >
      <motion.div
        animate={isMe ? { scale: [1, 1.02, 1], rotate: [0, -2, 2, 0] } : { y: [0, -4, 0] }}
        transition={isMe ? { duration: 1.5, repeat: Infinity, ease: "easeInOut" } : { duration: 2, repeat: Infinity, ease: "easeInOut" }}
        className={`rounded-3xl border-[6px] border-black flex flex-col items-center gap-0 overflow-hidden ${
          isMe ? "" : ""
        }`}
        style={{
          background: isMe
            ? "#1565C0"
            : "linear-gradient(160deg, #1a4a8e 0%, #0d2d5e 100%)",
          boxShadow: isMe
            ? "10px 10px 0px #000, 0 0 50px rgba(220,38,38,0.5), inset 0 0 0 3px #DC2626"
            : "8px 8px 0px #000, 0 0 30px rgba(21,101,192,0.4)",
          maxWidth: "90vw",
        }}
      >
        {/* Corps */}
        <div className="w-full px-6 py-8 flex flex-col items-center gap-4">
          {isMe ? (
            <>
              {/* Avatar du joueur local */}
              <div
                style={{
                  width: 80, height: 80, borderRadius: "50%",
                  border: "4px solid rgba(255,255,255,0.8)",
                  background: "rgba(0,0,0,0.35)",
                  boxShadow: "0 0 24px rgba(255,255,255,0.25)",
                  display: "flex", alignItems: "center", justifyContent: "center",
                  overflow: "hidden", flexShrink: 0,
                  willChange: "transform",
                  position: "relative",
                }}
              >
                {myAvatarDisplay?.type === "emoji" ? (
                  <span style={{
                    fontSize: "2.5rem",
                    lineHeight: 1,
                    display: "block",
                    textAlign: "center",
                    userSelect: "none",
                  }}>{myAvatarDisplay.content}</span>
                ) : myAvatarDisplay?.type === "image" ? (
                  <img src={myAvatarDisplay.content} alt="" style={{ width: "100%", height: "100%", objectFit: "contain" }} />
                ) : (
                  <span style={{ ...FONT_BANGERS, fontSize: "2.2rem", lineHeight: 1, color: "#fff" }}>{(myName || "?")[0].toUpperCase()}</span>
                )}
              </div>
              <motion.span
                initial={{ scale: 0, rotate: -20 }}
                animate={{ scale: 1, rotate: 0 }}
                transition={{ type: "spring", stiffness: 200, damping: 15 }}
                style={{ ...FONT_BANGERS, fontSize: "clamp(2.2rem, 8vw, 3.5rem)", letterSpacing: "0.08em", lineHeight: 1, color: "#fff" }}
                className="text-center font-bold drop-shadow-lg"
              >
                {myName}
              </motion.span>
              
              <motion.div
                animate={{ y: [0, -8, 0] }}
                transition={{ duration: 1.2, repeat: Infinity, ease: "easeInOut" }}
                className="text-center"
              >
                <span style={{ ...FONT_BANGERS, fontSize: "clamp(1rem, 4vw, 1.5rem)", letterSpacing: "0.06em" }} className="text-white/90">
                  À TON TOUR D'AVOIR UN TICKET
                </span>
              </motion.div>
              
              <motion.button
                initial={{ scale: 0, y: 20 }}
                animate={{ scale: 1, y: 0 }}
                transition={{ type: "spring", stiffness: 300, damping: 20, delay: 0.15 }}
                whileTap={{ scale: 0.92 } as any}
                onClick={onDismiss}
                className="flex items-center gap-2 bg-[#22c55e] border-[4px] border-black rounded-2xl px-6 py-3 relative overflow-hidden mt-2"
                style={{ boxShadow: "5px 5px 0px #000" }}
              >
                <motion.div
                  className="absolute inset-0 w-1/2 bg-white/15 skew-x-[-20deg]"
                  animate={{ x: ["-100%", "250%"] }}
                  transition={{ duration: 1.8, repeat: Infinity, ease: "easeInOut", repeatDelay: 0.6 }}
                />
                <CheckCircle className="w-5 h-5 text-white relative z-10" />
                <span style={{ ...FONT_BANGERS, fontSize: "1.1rem", letterSpacing: "0.06em" }} className="text-white relative z-10">
                  D'ACCORD
                </span>
              </motion.button>
            </>
          ) : (
            <>
              <span
                style={{ ...FONT_BANGERS, fontSize: "0.9rem", letterSpacing: "0.08em", lineHeight: 1 }}
                className="text-white/55 text-center uppercase"
              >
                C'est le tour de
              </span>
              {/* Avatar du joueur actif (vue spectateur) */}
              <div
                style={{
                  width: 56, height: 56, borderRadius: "50%",
                  border: "3px solid rgba(234,179,8,0.8)",
                  background: "rgba(0,0,0,0.3)",
                  boxShadow: "0 0 16px rgba(234,179,8,0.3)",
                  display: "flex", alignItems: "center", justifyContent: "center",
                  overflow: "hidden", flexShrink: 0,
                  willChange: "transform",
                  position: "relative",
                }}
              >
                {currentAvatarDisplay?.type === "emoji" ? (
                  <span style={{
                    fontSize: "1.9rem",
                    lineHeight: 1,
                    display: "block",
                    textAlign: "center",
                    userSelect: "none",
                  }}>{currentAvatarDisplay.content}</span>
                ) : currentAvatarDisplay?.type === "image" ? (
                  <img src={currentAvatarDisplay.content} alt="" style={{ width: "100%", height: "100%", objectFit: "contain" }} />
                ) : (
                  <span style={{ ...FONT_BANGERS, fontSize: "1.6rem", lineHeight: 1, color: "#fff" }}>{(currentName || "?")[0].toUpperCase()}</span>
                )}
              </div>
              <span
                style={{ ...FONT_BANGERS, fontSize: "2rem", letterSpacing: "0.04em", lineHeight: 1 }}
                className="text-yellow-400 text-center"
              >
                {currentName.toUpperCase()}
              </span>
            </>
          )}
        </div>
      </motion.div>
    </motion.div>
  );
}

// ────────────────────────────────────────────────────────────
// EliminationBanner — overlay si je suis éliminé
// ────────────────────────────────────────────────────────────
function EliminationBanner({
  name, threshold, activePlayers,
}: {
  name: string;
  threshold: number;
  activePlayers: number;
}) {
  return (
    <motion.div
      initial={{ opacity: 0, y: -8 }}
      animate={{ opacity: 1, y: 0 }}
      exit={{ opacity: 0 }}
      transition={{ type: "spring", stiffness: 300, damping: 24 }}
      className="mx-4 mt-1 rounded-xl border-[3px] border-black overflow-hidden flex-shrink-0"
      style={{ background: "linear-gradient(135deg, #7f1d1d, #991b1b)", boxShadow: "3px 3px 0px #000" }}
    >
      <div className="flex items-center gap-2 px-3 py-2">
        <div className="w-7 h-7 bg-red-500 border-[2px] border-black rounded-lg flex items-center justify-center flex-shrink-0">
          <Skull className="w-3.5 h-3.5 text-white" />
        </div>
        <div className="flex-1 min-w-0">
          <div style={{ ...FONT_BANGERS, fontSize: "0.9rem", letterSpacing: "0.05em" }} className="text-red-300 leading-none">
            ÉLIMINÉ — mode spectateur
          </div>
          <div style={FONT_FREDOKA} className="text-red-400/65 text-[0.68rem] leading-tight mt-0.5 truncate">
            {name} · seuil {formatPrice(threshold)} atteint
          </div>
        </div>
        {activePlayers > 0 && (
          <div
            className="flex-shrink-0 flex items-center gap-1 px-2 py-1 rounded-lg border border-red-500/25"
            style={{ background: "rgba(0,0,0,0.25)" }}
          >
            <Eye className="w-3 h-3 text-red-300/50" />
            <span style={{ ...FONT_BANGERS, fontSize: "0.68rem" }} className="text-red-300/60">
              {activePlayers} restant{activePlayers > 1 ? "s" : ""}
            </span>
          </div>
        )}
      </div>
    </motion.div>
  );
}

// ────────────────────────────────────────────────────────────
// ConfirmResetModal
// ────────────────────────────────────────────────────────────
function ConfirmResetModal({
  onConfirm, onCancel, loading, deckTotal,
}: {
  onConfirm: () => void;
  onCancel: () => void;
  loading: boolean;
  deckTotal: number;
}) {
  return createPortal(
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      className="fixed inset-0 z-[9999] flex items-center justify-center px-6"
      style={{ background: "rgba(0,0,0,0.82)" }}
      onClick={onCancel}
    >
      <motion.div
        initial={{ scale: 0.8, y: 30 }}
        animate={{ scale: 1, y: 0 }}
        exit={{ scale: 0.8, y: 30 }}
        transition={{ type: "spring", stiffness: 320, damping: 26 }}
        className="w-full max-w-xs rounded-3xl border-[5px] border-black overflow-hidden"
        style={{ background: "linear-gradient(160deg, #0c1a4e, #1a083d)", boxShadow: "8px 8px 0px #000" }}
        onClick={(e) => e.stopPropagation()}
      >
        <div className="bg-[#111] border-b-4 border-yellow-400 flex items-center justify-center gap-2 px-4 py-3">
          <Shuffle className="w-5 h-5 text-yellow-400" />
          <span style={{ ...FONT_BANGERS, fontSize: "1.2rem", letterSpacing: "0.06em" }} className="text-yellow-400">
            MÉLANGER LE DECK ?
          </span>
        </div>
        <div className="p-5 flex flex-col gap-3">
          <p style={FONT_FREDOKA} className="text-white/70 text-sm text-center">
            Les {deckTotal} cartes seront remises dans le deck, mélangées et les éliminations seront effacées.
          </p>
          <motion.button
            whileTap={{ scale: 0.95 }}
            onClick={onConfirm}
            disabled={loading}
            className="w-full py-4 bg-[#1565C0] border-[4px] border-black rounded-2xl disabled:opacity-60 flex items-center justify-center gap-2"
            style={{ ...FONT_BANGERS, fontSize: "1.2rem", letterSpacing: "0.08em", boxShadow: "5px 5px 0px #000", color: "#fff" }}
          >
            <Shuffle className="w-5 h-5 text-white" />
            {loading ? "MÉLANGE..." : "OUI, MÉLANGER"}
          </motion.button>
          <motion.button
            whileTap={{ scale: 0.95 }}
            onClick={onCancel}
            disabled={loading}
            className="w-full py-3 bg-white/10 border-[3px] border-white/20 rounded-2xl text-white/60"
            style={{ ...FONT_FREDOKA, fontSize: "1rem" }}
          >
            Annuler
          </motion.button>
        </div>
      </motion.div>
    </motion.div>,
    document.body
  );
}

// ────────────────────────────────────────────────────────────
// PrisonBars — grilles de prison SVG animées
// ────────────────────────────────────────────────────────────
function PrisonBars() {
  return (
    <svg width="100%" height="100%" viewBox="0 0 200 280" preserveAspectRatio="none" className="absolute inset-0 pointer-events-none z-10">
      {[30, 70, 110, 150, 170].map((x, i) => (
        <motion.rect
          key={i}
          x={x} y={0} width={10} height={280}
          fill="rgba(0,0,0,0.75)"
          rx={4}
          initial={{ scaleY: 0, originY: 0 }}
          animate={{ scaleY: 1 }}
          transition={{ delay: i * 0.08, duration: 0.4, ease: "easeOut" }}
        />
      ))}
    </svg>
  );
}

// ────────────────────────────────────────────────────────────
// EliminationPauseOverlay — overlay pour le joueur éliminé
// ────────────────────────────────────────────────────────────
function EliminationPauseOverlay({
  playerName, total, threshold, myCardsCount, lastCardNum, onAcknowledge, isAcknowledging, skinId,
}: {
  playerName: string;
  total: number;
  threshold: number;
  myCardsCount: number;
  lastCardNum?: number | null;
  onAcknowledge: () => void;
  isAcknowledging: boolean;
  skinId?: string;
}) {
  const [showLastCard, setShowLastCard] = useState(false);
  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      className="fixed inset-0 z-[100] flex flex-col items-center justify-start px-4 overflow-y-auto"
      style={{ background: "linear-gradient(160deg, #1a0000 0%, #3b0000 50%, #000 100%)" }}
    >
      {/* Grilles animées en arrière-plan */}
      <div className="absolute inset-0 overflow-hidden opacity-30">
        <PrisonBars />
      </div>

      {/* Conteneur centré — évite le débordement sur mobile */}
      <div className="relative z-10 w-full max-w-xs flex flex-col items-center gap-4 py-6 mx-auto">

      {/* Icône prison */}
      <motion.div
        initial={{ scale: 0, rotate: -20 }}
        animate={{ scale: 1, rotate: 0 }}
        transition={{ type: "spring", stiffness: 280, damping: 18, delay: 0.15 }}
        className="relative z-10"
      >
        <div
          className="w-20 h-20 rounded-3xl border-[5px] border-red-500 flex items-center justify-center relative overflow-hidden"
          style={{ background: "linear-gradient(135deg, #450a0a, #7f1d1d)", boxShadow: "0 0 40px #dc2626, 8px 8px 0px #000" }}
        >
          <Skull className="w-14 h-14 text-red-300 relative z-10" />
          <div className="absolute inset-0 opacity-40">
            <PrisonBars />
          </div>
        </div>
      </motion.div>

      {/* Titre */}
      <motion.div
        initial={{ y: 20, opacity: 0 }}
        animate={{ y: 0, opacity: 1 }}
        transition={{ delay: 0.3 }}
        className="relative z-10 flex flex-col items-center gap-1"
      >
        <div
          style={{ ...FONT_BANGERS, fontSize: "2.2rem", letterSpacing: "0.08em", lineHeight: 1 }}
          className="text-red-400 text-center"
        >
          TU VAS EN PRISON !
        </div>
        <div
          style={{ ...FONT_BANGERS, fontSize: "1.05rem", letterSpacing: "0.04em" }}
          className="text-white/60 text-center"
        >
          {playerName} — éliminé
        </div>
      </motion.div>

      {/* Carte récap dette */}
      <motion.div
        initial={{ y: 24, opacity: 0 }}
        animate={{ y: 0, opacity: 1 }}
        transition={{ delay: 0.45 }}
        className="relative z-10 w-full max-w-xs rounded-3xl border-[4px] border-red-600 overflow-hidden flex-shrink-0"
        style={{ background: "linear-gradient(135deg, #1a0000, #2d0000)", boxShadow: "6px 6px 0px #000" }}
      >
        <div className="bg-red-800 border-b-4 border-red-600 px-4 py-1.5 flex items-center justify-between">
          <span style={{ ...FONT_BANGERS, fontSize: "1rem", letterSpacing: "0.06em" }} className="text-red-200">
            TON BILAN
          </span>
          <Skull className="w-5 h-5 text-red-300" />
        </div>
        <div className="px-5 py-3 flex flex-col gap-2">
          <div className="flex items-center justify-between">
            <span style={FONT_FREDOKA} className="text-red-400/80 text-sm">Dette totale</span>
            <motion.span
              initial={{ scale: 0 }}
              animate={{ scale: 1 }}
              transition={{ type: "spring", stiffness: 260, damping: 14, delay: 0.65 }}
              style={{ ...FONT_BANGERS, fontSize: "1.9rem", letterSpacing: "0.04em" }}
              className="text-red-400"
            >
              {formatPrice(total)}
            </motion.span>
          </div>
          <div className="flex items-center justify-between border-t border-white/10 pt-1.5">
            <span style={FONT_FREDOKA} className="text-white/30 text-xs">Limite d'élimination</span>
            <span style={{ ...FONT_BANGERS, fontSize: "0.95rem" }} className="text-white/30">
              {formatPrice(threshold)}
            </span>
          </div>
          <div className="flex items-center justify-between">
            <span style={FONT_FREDOKA} className="text-white/30 text-xs">Cartes piochées</span>
            <span style={{ ...FONT_BANGERS, fontSize: "0.95rem" }} className="text-white/50">
              {myCardsCount} ticket{myCardsCount > 1 ? "s" : ""}
            </span>
          </div>
        </div>
      </motion.div>

      {/* Message spectateur */}
      <motion.p
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        transition={{ delay: 0.6 }}
        style={FONT_FREDOKA}
        className="relative z-10 text-white/40 text-xs text-center px-4 leading-snug"
      >
        Appuie sur le bouton pour devenir spectateur<br />et laisser la partie continuer.
      </motion.p>

      {/* Bouton voir le dernier ticket */}
      {lastCardNum != null && (
        <motion.div
          initial={{ y: 20, opacity: 0 }}
          animate={{ y: 0, opacity: 1 }}
          transition={{ delay: 0.65 }}
          className="relative z-10 w-full max-w-xs flex-shrink-0"
        >
          <motion.button
            whileTap={{ scale: 0.95 } as any}
            onClick={() => setShowLastCard(true)}
            className="w-full py-3.5 bg-[#1a083d] border-[4px] border-purple-500 rounded-2xl flex items-center justify-center gap-2"
            style={{ ...FONT_BANGERS, fontSize: "1.05rem", letterSpacing: "0.06em", color: "#c084fc", boxShadow: "4px 4px 0px #000" }}
          >
            <Layers className="w-5 h-5" />
            VOIR LE DERNIER TICKET
          </motion.button>
        </motion.div>
      )}

      {/* Bouton terminer */}
      <motion.div
        initial={{ y: 20, opacity: 0 }}
        animate={{ y: 0, opacity: 1 }}
        transition={{ delay: 0.7 }}
        className="relative z-10 w-full max-w-xs flex-shrink-0"
      >
        <motion.div
          className="absolute inset-0 rounded-2xl bg-red-500 -z-10"
          animate={{ scale: [1, 1.08, 1], opacity: [0.5, 0, 0.5] }}
          transition={{ duration: 1.8, repeat: Infinity }}
        />
        <motion.button
          whileTap={{ scale: 0.95 } as any}
          onClick={onAcknowledge}
          disabled={isAcknowledging}
          className="w-full py-4 bg-red-600 border-[5px] border-black rounded-2xl disabled:opacity-60 relative overflow-hidden"
          style={{ ...FONT_BANGERS, fontSize: "1.2rem", letterSpacing: "0.08em", color: "#fff", boxShadow: "6px 6px 0px #000" }}
        >
          <motion.div
            className="absolute inset-0 w-1/3 bg-white/10 skew-x-[-20deg]"
            animate={{ x: ["-100%", "400%"] }}
            transition={{ duration: 2.2, repeat: Infinity, ease: "easeInOut", repeatDelay: 0.8 }}
          />
          <span className="relative z-10 flex items-center justify-center gap-2">
            {isAcknowledging ? "EN COURS..." : <><Skull className="w-6 h-6" /> FINIR MES JOURS EN PRISON</>}
          </span>
        </motion.button>
      </motion.div>

      {/* ── Modal dernier ticket ── */}
      <AnimatePresence>
        {showLastCard && lastCardNum != null && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[110] flex items-center justify-center p-6"
            style={{ background: "rgba(0,0,0,0.90)" }}
            onClick={() => setShowLastCard(false)}
          >
            <motion.div
              initial={{ scale: 0.7, rotate: -5 }}
              animate={{ scale: 1, rotate: 0 }}
              exit={{ scale: 0.7, opacity: 0 }}
              transition={{ type: "spring", stiffness: 340, damping: 22 }}
              className="flex flex-col items-center gap-4"
              onClick={(e) => e.stopPropagation()}
            >
              <div style={{ ...FONT_BANGERS, fontSize: "1.4rem", letterSpacing: "0.08em", color: "#c084fc", textShadow: "2px 2px 0px #000" }}>
                DERNIER TICKET RECU
              </div>
              <DraggableCard style={{ width: 220, height: 310 }}>
              <div
                className="rounded-2xl border-[5px] border-black overflow-hidden w-full h-full"
                style={{ boxShadow: "8px 8px 0px #000, 0 0 40px rgba(192,132,252,0.3)" }}
              >
                <GeneratedCard card={getCardConfigMp(lastCardNum)} size="md" skinId={skinId as any} mefaitOverride={getMpCustomMefait(lastCardNum)} style={{ width: "100%", height: "100%" }} />
              </div>
              </DraggableCard>
              <motion.button
                whileTap={{ scale: 0.93 } as any}
                onClick={() => setShowLastCard(false)}
                className="px-8 py-3 bg-purple-600 border-[4px] border-black rounded-2xl flex items-center gap-2"
                style={{ ...FONT_BANGERS, fontSize: "1.1rem", letterSpacing: "0.06em", color: "#fff", boxShadow: "4px 4px 0px #000" }}
              >
                <X className="w-5 h-5" />
                FERMER
              </motion.button>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      </div>{/* fin conteneur centré */}
    </motion.div>
  );
}

// ────────────────────────────────────────────────────────────
// GamePausedOverlay — notification compacte fixe au centre pour les autres joueurs
// ────────────────────────────────────────────────────────────
function GamePausedOverlay({ eliminatedName, eliminatedTotal, gameFinished = false }: { eliminatedName: string; eliminatedTotal: number; gameFinished?: boolean }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: -18, scale: 0.92 }}
      animate={{ opacity: 1, y: 0, scale: 1 }}
      exit={{ opacity: 0, y: -18, scale: 0.92 }}
      transition={{ type: "spring", stiffness: 340, damping: 26 }}
      className="fixed inset-0 z-[90] flex items-center justify-center px-6 pointer-events-none"
      style={{ background: gameFinished ? "rgba(0,0,0,0.78)" : "transparent" }}
    >
      <div style={{ width: "min(88vw, 320px)" }}>
      <div
        className="rounded-2xl border-[4px] border-red-500 overflow-hidden"
        style={{
          background: "linear-gradient(135deg, #1c0000 0%, #3b0000 100%)",
          boxShadow: "0 0 32px rgba(220,38,38,0.45), 6px 6px 0px #000",
        }}
      >
        {/* Barre top — titre + icône */}
        <div className="flex items-center gap-2.5 px-4 py-2.5 border-b-[3px] border-red-600 bg-red-900/60">
          <motion.div
            animate={{ scale: [1, 1.18, 1] }}
            transition={{ duration: 1.5, repeat: Infinity, ease: "easeInOut" }}
          >
            <Skull className="w-5 h-5 text-red-300 flex-shrink-0" />
          </motion.div>
          <span
            style={{ ...FONT_BANGERS, fontSize: "1.05rem", letterSpacing: "0.07em" }}
            className="text-red-300 leading-none"
          >
            PARTIE EN PAUSE
          </span>
          <motion.div
            animate={{ opacity: [0.3, 1, 0.3] }}
            transition={{ duration: 1.2, repeat: Infinity }}
            className="ml-auto flex items-center gap-1"
          >
            <Clock className="w-3.5 h-3.5 text-red-400/70" />
          </motion.div>
        </div>

        {/* Corps — nom du joueur + dette */}
        <div className="px-4 py-3 flex items-center gap-3">
          {/* Avatar prison */}
          <div
            className="w-11 h-11 rounded-xl border-[3px] border-red-500 flex items-center justify-center relative overflow-hidden flex-shrink-0"
            style={{ background: "linear-gradient(135deg, #450a0a, #7f1d1d)", boxShadow: "3px 3px 0px #000" }}
          >
            <Skull className="w-6 h-6 text-red-300 relative z-10" />
            <div className="absolute inset-0 opacity-40">
              <PrisonBars />
            </div>
          </div>

          {/* Texte */}
          <div className="flex-1 min-w-0">
            <div
              style={{ ...FONT_BANGERS, fontSize: "1.15rem", letterSpacing: "0.05em", lineHeight: 1.1 }}
              className="text-yellow-300 truncate"
            >
              {eliminatedName.toUpperCase()}
            </div>
            <div style={FONT_FREDOKA} className="text-white/55 text-xs leading-tight mt-0.5">
              va en prison…
            </div>
          </div>

          {/* Dette totale */}
          <div className="flex flex-col items-end flex-shrink-0">
            <span style={{ ...FONT_BANGERS, fontSize: "1.35rem", letterSpacing: "0.03em" }} className="text-red-400 leading-none">
              {formatPrice(eliminatedTotal)}
            </span>
            <span style={{ ...FONT_FREDOKA, fontSize: "0.68rem" }} className="text-white/35 leading-none mt-0.5">
              de dette
            </span>
          </div>
        </div>

        {/* Footer — attente */}
        <div className="px-4 pb-3">
          <motion.div
            animate={{ opacity: [0.5, 1, 0.5] }}
            transition={{ duration: 1.6, repeat: Infinity }}
            className="flex items-center justify-center gap-1.5 bg-red-950/60 border border-red-600/30 rounded-xl px-3 py-1.5"
          >
            <Clock className="w-3 h-3 text-red-400" />
            <span style={{ ...FONT_FREDOKA, fontSize: "0.78rem" }} className="text-red-300/90">
              {gameFinished
                ? `En attente que ${eliminatedName} confirme avant l'annonce du gagnant…`
                : `En attente que ${eliminatedName} confirme…`}
            </span>
          </motion.div>
        </div>
      </div>
      </div>
    </motion.div>
  );
}

// ────────────────────────────────────────────────────────────
// MyTicketsPanel — panneau "Mes tickets"
// ────────────────────────────────────────────────────────────
function MyTicketsPanel({
  cards, playerName, receivedDebt = 0, receivedCards = [], isEliminated = false, threshold = 10_000, disabledCardTypes = [], onClose, session, myPlayerId, miniGameHistory = [], skinId,
}: {
  cards:               number[];
  playerName:          string;
  receivedDebt?:       number;
  receivedCards?:      number[];
  isEliminated?:       boolean;
  threshold?:          number;
  disabledCardTypes?:  number[];
  onClose:             () => void;
  session?:            Session | null;
  myPlayerId?:         string;
  miniGameHistory?:    Array<{ success: boolean; amount: number; turnLabel: string }>;
  skinId?:             string;
}) {
  const [activeTab, setActiveTab]         = useState<CardCategory>("contravention");
  const [focusedCard, setFocusedCard]     = useState<number | null>(null);
  const [focusedIsReceived, setFocusedIsReceived] = useState(false);
  const [showHistory, setShowHistory]     = useState(false);


  const myDrawerTotal    = computePlayerTotalMp(cards);
  // receivedDebt = session.playerDebts[playerId] qui contient DÉJÀ les deltas de perquisitions
  // (appliqués via addDebt() côté serveur Supabase). Ne pas recalculer miniGameBonus ici.
  const totalPrice       = myDrawerTotal + receivedDebt;
  const tabCards         = filterByCategory(cards, activeTab);
  const validReceivedCards = receivedCards.filter(id => id !== 0); // Filtrer les IDs invalides
  const tabReceivedCards = activeTab === "investisseur" ? validReceivedCards : [];
  const catInfo          = CATEGORY_INFO[activeTab];

  const allTabCards = [...tabCards, ...tabReceivedCards];
  const zoomedIdx   = focusedCard !== null ? allTabCards.indexOf(focusedCard) : -1;

  const isOverThreshold = totalPrice >= threshold;

  // ── Lookup: pour chaque carte T3 piochée, qui l'a reçue ? ──
  const t3ReceiverMap: Record<number, string> = {};
  if (session && myPlayerId) {
    session.turnOrder.forEach(pid => {
      if (pid !== myPlayerId) {
        const theirReceived = session.playerReceivedCards?.[pid] ?? [];
        theirReceived.forEach(cardNum => {
          if (cards.includes(cardNum)) {
            const receiver = session.players.find(p => p.id === pid);
            if (receiver) t3ReceiverMap[cardNum] = receiver.name;
          }
        });
      }
    });
  }

  // ── Lookup: pour chaque carte T3 reçue, qui l'a envoyée ? ──
  const t3SenderMap: Record<number, string> = {};
  if (session && myPlayerId) {
    const myReceived = validReceivedCards;
    session.turnOrder.forEach(pid => {
      if (pid !== myPlayerId) {
        const theirCards = session.playerCards?.[pid] ?? [];
        theirCards.forEach(cardNum => {
          if (myReceived.includes(cardNum)) {
            const sender = session.players.find(p => p.id === pid);
            if (sender) t3SenderMap[cardNum] = sender.name;
          }
        });
      }
    });
  }

  // ── Construire l'historique enrichi ───────────────────────
  const historyEntries = (() => {
    let running = 0;
    // Cartes piochées
    const drawnEntries = cards.map((cardNum, i) => {
      const cfg = getCardConfigMp(cardNum);
      const net = drawerNetAmount(cfg);
      running += net;
      return {
        idx:          i + 1,
        cardNum,
        category:     cfg.category as "contravention"|"contribuable"|"investisseur",
        cardType:     cfg.cardType,
        ticketPrice:  cfg.ticketPrice ?? 0,
        frais:        cfg.frais       ?? 0,
        impots:       cfg.impots      ?? 0,
        taxe:         cfg.taxe        ?? 0,
        amountSent:   nextPlayerAmount(cfg),
        receiverName: t3ReceiverMap[cardNum] ?? "",
        net,
        runningTotal: running,
        isReceived:   false,
      };
    });
    // Cartes T3 reçues
    const receivedEntries = validReceivedCards.map((cardNum, i) => {
      const cfg = getCardConfigMp(cardNum);
      const amt = nextPlayerAmount(cfg);
      running += amt;
      return {
        idx:           cards.length + i + 1,
        cardNum,
        category:      "investisseur" as const,
        cardType:      3 as const,
        ticketPrice:   cfg.ticketPrice ?? 0,
        frais:         0,
        impots:        0,
        taxe:          cfg.taxe ?? 0,
        amountSent:    0,
        receiverName:  "",
        senderName:    t3SenderMap[cardNum] ?? "",
        net:           amt,
        runningTotal:  running,
        isReceived:    true,
      };
    });
    // Ajouter les perquisitions de groupe
    const raidEntries = ((session as any)?.groupMiniGameHistory || []).map((game: any, i: number) => {
      const totalDelta = game.results.reduce((sum: number, r: any) => 
        sum + (r.success ? -r.amount : r.amount), 0);
      running += totalDelta;
      return {
        idx: cards.length + validReceivedCards.length + i + 1,
        type: "raid",
        triggeredByName: game.triggeredByName,
        results: game.results,
        delta: totalDelta,
        runningTotal: running,
        timestamp: game.timestamp,
      };
    });

    // Fusionner et trier par timestamp
    const allEntries = [...drawnEntries, ...receivedEntries, ...raidEntries];
    
    // Ajouter des timestamps aux cartes (ordre d'ajout)
    allEntries.forEach((entry, idx) => {
      if (!entry.timestamp) {
        entry.timestamp = idx * 1000;
      }
    });
    
    // Trier par timestamp
    allEntries.sort((a, b) => (a.timestamp || 0) - (b.timestamp || 0));
    
    // Recalculer les running totals
    let recalcRunning = 0;
    allEntries.forEach((entry) => {
      if (entry.isReceived || entry.cardNum) {
        recalcRunning += entry.net || 0;
      } else if (entry.type === "raid") {
        recalcRunning += entry.delta || 0;
      }
      entry.runningTotal = recalcRunning;
    });

    return allEntries;
  })();

  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
      className="fixed inset-0 z-50 flex items-end justify-center"
      style={{ background: "rgba(0,0,0,0.85)" }}
      onClick={onClose}
    >
      <motion.div
        initial={{ scale: 0.95, opacity: 0 }}
        animate={{ scale: 1, opacity: 1 }}
        exit={{ scale: 0.95, opacity: 0 }}
        transition={{ type: "spring", stiffness: 300, damping: 30 }}
        className="w-full h-full rounded-none border-0 flex flex-col"
        style={{
          background:  "linear-gradient(160deg, #0c1a4e 0%, #1a083d 100%)",
          boxShadow:   "none",
          maxHeight:   "100dvh",
        }}  
        onClick={(e) => e.stopPropagation()}
      >
        {/* Header */}
        <div className={`border-b-4 flex items-center justify-between px-4 py-3 flex-shrink-0 rounded-t-2xl ${isEliminated ? "bg-[#7f1d1d] border-red-500" : "bg-[#111] border-[#22c55e]"}`}>
          <div className="flex items-center gap-2">
            <div
              className={`w-8 h-8 rounded-lg border-[3px] border-black flex items-center justify-center flex-shrink-0 ${isEliminated ? "bg-red-600" : "bg-[#22c55e]"}`}
              style={{ boxShadow: "2px 2px 0px #000" }}
            >
              {isEliminated ? <Skull className="w-4 h-4 text-white" /> : <HandIcon size={16} />}
            </div>
            <div>
              <div
                style={{ ...FONT_BANGERS, fontSize: "1.1rem", letterSpacing: "0.06em" }}
                className={`leading-none ${isEliminated ? "text-red-300" : "text-[#22c55e]"}`}
              >
                {isEliminated ? "ÉLIMINÉ" : "MES TICKETS"}
              </div>
              <div style={FONT_FREDOKA} className="text-white/50 text-xs leading-none mt-0.5">
                {playerName}
              </div>
            </div>
          </div>
          <div className="flex items-center gap-2">
            <div
              className={`border-[2px] border-black rounded-full px-2.5 py-0.5 ${isEliminated ? "bg-red-500" : "bg-[#22c55e]"}`}
              style={{ boxShadow: "2px 2px 0px #000" }}
            >
              <span style={{ ...FONT_BANGERS, fontSize: "1rem" }} className="text-black">
                {cards.length}
              </span>
            </div>
            {/* Bouton Historique */}
            <motion.button
              whileTap={{ scale: 0.88 }}
              onClick={() => setShowHistory(v => !v)}
              className={`w-9 h-9 border-[3px] border-black rounded-full flex items-center justify-center transition-colors ${
                showHistory ? "bg-yellow-400" : "bg-white/15"
              }`}
              style={{ boxShadow: "2px 2px 0px #000" }}
              title="Historique des dettes"
            >
              <History className={`w-4 h-4 ${showHistory ? "text-black" : "text-white/70"}`} />
            </motion.button>
            <motion.button
              whileTap={{ scale: 0.88 }}
              onClick={onClose}
              className="w-9 h-9 bg-red-500 border-[3px] border-black rounded-full flex items-center justify-center"
              style={{ boxShadow: "3px 3px 0px #000" }}
            >
              <X className="w-5 h-5 text-white" />
            </motion.button>
          </div>
        </div>

        {/* ── Dette totale + limite ── */}
        <div
          className="flex items-center justify-between px-4 py-2.5 flex-shrink-0 border-b border-white/10"
          style={{ background: isOverThreshold ? "rgba(239,68,68,0.12)" : "rgba(255,215,0,0.06)" }}
        >
          <div className="flex flex-col">
            <span style={FONT_FREDOKA} className="text-white/40 text-xs">Dette totale</span>
            <span
              style={{ ...FONT_BANGERS, fontSize: "1.5rem", letterSpacing: "0.04em", lineHeight: 1 }}
              className={isOverThreshold ? "text-red-400" : "text-yellow-400"}
            >
              {formatPrice(totalPrice)}
            </span>
          </div>
          <div className="flex flex-col items-end">
            <span style={FONT_FREDOKA} className="text-white/30 text-xs">Limite</span>
            <span style={{ ...FONT_BANGERS, fontSize: "1.1rem", letterSpacing: "0.03em", lineHeight: 1 }} className="text-white/50">
              {formatPrice(threshold)}
            </span>
          </div>
        </div>

        {/* ── VUE HISTORIQUE ── */}
        {showHistory ? (
          <div className="flex-1 overflow-y-auto px-4 pb-4 pt-3 flex flex-col gap-2" style={{ minHeight: 0 }}>
            {/* Titre */}
            <div className="flex items-center gap-2 mb-1 mt-4">
              <ListOrdered className="w-4 h-4 text-yellow-400/70" />
              <span style={{ ...FONT_BANGERS, fontSize: "1rem", letterSpacing: "0.06em" }} className="text-yellow-400/70">
                HISTORIQUE DES DETTES
              </span>
              <span style={FONT_FREDOKA} className="text-white/30 text-xs ml-auto">
                {historyEntries.length} entrée{historyEntries.length > 1 ? "s" : ""}
              </span>
            </div>

            {historyEntries.length === 0 ? (
              <div className="flex flex-col items-center justify-center py-12 gap-3">
                <History className="w-10 h-10 text-white/15" />
                <p style={FONT_FREDOKA} className="text-white/30 text-sm text-center">
                  Aucun ticket pour l'instant…
                </p>
              </div>
            ) : (
              <>
                {/* ── CARTES UNIQUEMENT ── */}
                {historyEntries.filter((e: any) => e.cardNum !== undefined).map((entry, i) => {
                  const overLimit = entry.runningTotal >= threshold;

                  // ── T1 Contravention (jaune) ──────────────────
                  if (entry.category === "contravention") {
                    const hasFreis = entry.frais > 0;
                    return (
                      <motion.div
                        key={`hist-${entry.cardNum}-${i}`}
                        initial={{ opacity: 0, x: -8 }}
                        animate={{ opacity: 1, x: 0 }}
                        transition={{ delay: Math.min(i * 0.025, 0.45) }}
                        className="flex items-center gap-3 px-4 py-3 rounded-xl border-[2px] bg-yellow-400/5"
                        style={{ borderColor: "rgba(251,191,36,0.2)", minHeight: "3rem" }}
                      >
                        <div className="w-7 h-7 rounded-lg flex items-center justify-center flex-shrink-0" style={{ background: "rgba(251,191,36,0.18)" }}>
                          <TrendingUp className="w-3.5 h-3.5 text-yellow-400" />
                        </div>
                        <div className="flex-1 min-w-0">
                          {hasFreis ? (
                            <span style={FONT_FREDOKA} className="text-yellow-300 text-xs leading-snug">
                              Ticket <strong>{formatPrice(entry.ticketPrice)}</strong>
                              {" + Frais "}
                              <strong>{formatPrice(entry.frais)}</strong>
                              {" = "}
                              <strong className="text-yellow-400">{formatPrice(entry.ticketPrice + entry.frais)}</strong>
                            </span>
                          ) : (
                            <span style={FONT_FREDOKA} className="text-yellow-300 text-xs">
                              Ticket <strong className="text-yellow-400">{formatPrice(entry.ticketPrice)}</strong>
                            </span>
                          )}
                        </div>
                      </motion.div>
                    );
                  }

                  // ── T2 Contribuable (vert) ─────────────────────
                  if (entry.category === "contribuable") {
                    const hasReduction = entry.impots > 0;
                    return (
                      <motion.div
                        key={`hist-${entry.cardNum}-${i}`}
                        initial={{ opacity: 0, x: -8 }}
                        animate={{ opacity: 1, x: 0 }}
                        transition={{ delay: Math.min(i * 0.025, 0.45) }}
                        className="flex items-center gap-3 px-4 py-3 rounded-xl border-[2px] bg-green-500/5"
                        style={{ borderColor: "rgba(34,197,94,0.2)", minHeight: "3rem" }}
                      >
                        <div className="w-7 h-7 rounded-lg flex items-center justify-center flex-shrink-0" style={{ background: "rgba(34,197,94,0.18)" }}>
                          <TrendingDown className="w-3.5 h-3.5 text-green-400" />
                        </div>
                        <div className="flex-1 min-w-0 flex items-center gap-2 flex-wrap">
                          <span style={{ ...FONT_BANGERS, fontSize: "1rem" }} className="text-green-400">0 $</span>
                          {hasReduction && (
                            <span style={FONT_FREDOKA} className="text-green-400 text-xs">
                              – Réduction impôts <strong>{formatPrice(entry.impots)}</strong>
                            </span>
                          )}
                        </div>
                      </motion.div>
                    );
                  }

                  // ── T3 Investisseur REÇUE (rose) ───────────────
                  if (entry.isReceived) {
                    const total = (entry.ticketPrice) + (entry.taxe);
                    return (
                      <motion.div
                        key={`hist-${entry.cardNum}-${i}`}
                        initial={{ opacity: 0, x: -8 }}
                        animate={{ opacity: 1, x: 0 }}
                        transition={{ delay: Math.min(i * 0.025, 0.45) }}
                        className="flex items-center gap-3 px-4 py-3 rounded-xl border-[2px] bg-pink-500/5"
                        style={{ borderColor: "rgba(236,72,153,0.3)", minHeight: "3rem" }}
                      >
                        <div className="w-7 h-7 rounded-lg flex items-center justify-center flex-shrink-0" style={{ background: "rgba(236,72,153,0.2)" }}>
                          <Mail className="w-3.5 h-3.5 text-pink-400" />
                        </div>
                        <div className="flex-1 min-w-0">
                          <div style={FONT_FREDOKA} className="text-pink-300 text-xs leading-snug">
                            Ticket investisseur reçu{entry.senderName ? <> de <strong className="text-pink-400">{entry.senderName}</strong></> : ""}
                          </div>
                          <div style={FONT_FREDOKA} className="text-pink-400 text-xs font-bold">
                            +{formatPrice(total)} ajouté à ta dette
                          </div>
                          {entry.taxe > 0 && (
                            <div style={FONT_FREDOKA} className="text-pink-400/60 text-[0.62rem]">
                              Prix {formatPrice(entry.ticketPrice)} + Taxe {formatPrice(entry.taxe)}
                            </div>
                          )}
                        </div>
                      </motion.div>
                    );
                  }

                  // ── T3 Investisseur ENVOYÉE (mauve) ────────────
                  if (entry.category === "investisseur" && !entry.isReceived) {
                    const totalSent = entry.amountSent; // ticketPrice + taxe
                    return (
                      <motion.div
                        key={`hist-${entry.cardNum}-${i}`}
                        initial={{ opacity: 0, x: -8 }}
                        animate={{ opacity: 1, x: 0 }}
                        transition={{ delay: Math.min(i * 0.025, 0.45) }}
                        className="flex items-center gap-3 px-4 py-3 rounded-xl border-[2px] bg-purple-500/5"
                        style={{ borderColor: "rgba(124,58,237,0.3)", minHeight: "3rem" }}
                      >
                        <div className="w-7 h-7 rounded-lg flex items-center justify-center flex-shrink-0" style={{ background: "rgba(124,58,237,0.2)" }}>
                          <ArrowRight className="w-3.5 h-3.5 text-purple-400" />
                        </div>
                        <div className="flex-1 min-w-0">
                          <div style={FONT_FREDOKA} className="text-purple-300 text-xs leading-snug">
                            Ticket investisseur envoyé{entry.receiverName ? <> à <strong className="text-purple-400">{entry.receiverName}</strong></> : ""}
                          </div>
                          <div style={FONT_FREDOKA} className="text-green-400 text-xs font-bold">
                            -{formatPrice(totalSent)} remboursé sur ta dette
                          </div>
                          {entry.taxe > 0 && (
                            <div style={FONT_FREDOKA} className="text-purple-400/60 text-[0.62rem]">
                              Prix {formatPrice(entry.ticketPrice)} + Taxe {formatPrice(entry.taxe)}
                            </div>
                          )}
                        </div>
                      </motion.div>
                    );
                  }

                  return null;
                })}

                {/* ── SÉPARATION : CARTES vs PERQUISITIONS ── */}
                <div className="h-px bg-gradient-to-r from-transparent via-white/20 to-transparent my-2 sm:my-3" />

                {/* Titre des perquisitions */}
                {historyEntries.filter((e: any) => e.type === "raid").length > 0 && (
                  <div className="flex items-center gap-2 mb-2 mt-3">
                    <Search className="w-4 h-4 text-yellow-400/70" />
                    <span style={{ ...FONT_BANGERS, fontSize: "1rem", letterSpacing: "0.06em" }} className="text-yellow-400/70">
                      HISTORIQUE DES PERQUISITIONS
                    </span>
                  </div>
                )}

                {/* ── PERQUISITIONS UNIQUEMENT ── */}
                {historyEntries.filter((e: any) => e.type === "raid").map((entry, idx) => {
                  return (
                    <motion.div
                      key={`h-raid-${entry.idx}`}
                      initial={{ opacity: 0, x: -8 }}
                      animate={{ opacity: 1, x: 0 }}
                      transition={{ delay: Math.min(idx * 0.05, 0.3) }}
                      className="flex items-start gap-3 px-4 py-3 rounded-xl border-[2px] sm:gap-3 sm:px-4 sm:py-3 sm:rounded-xl"
                      style={{
                        borderColor: "rgba(34,197,94,0.3)",
                        background: "rgba(34,197,94,0.05)",
                        minHeight: "3rem",
                        flex: "0 0 auto",
                        position: "relative",
                        zIndex: "auto",
                      }}
                    >
                      <div
                        className="w-7 h-7 rounded-lg flex items-center justify-center flex-shrink-0"
                        style={{
                          background: "rgba(34,197,94,0.18)",
                        }}
                      >
                        <Search
                          className="w-3.5 h-3.5 text-green-400"
                        />
                      </div>
                      <div className="flex-1 min-w-0">
                        <div
                          style={FONT_FREDOKA}
                          className="text-xs leading-snug text-green-300"
                        >
                          <strong className="text-green-400">
                            Perquisition de groupe
                          </strong>
                          {" — "}
                          <span className="text-green-300">
                            {entry.delta > 0 ? "+" : ""}{formatPrice(entry.delta)}
                          </span>
                       </div>
                      </div>
                    </motion.div>
                  );
                })}


                {/* Entrées de perquisition personnelles — avec tri optionnel */}
                {miniGameHistory.length > 0 && (
                  <div className="flex items-center gap-2 mt-1 mb-0.5">
                    <Search className="w-3 h-3 text-blue-400/50" />
                    <span style={{ ...FONT_BANGERS, fontSize: "0.62rem", letterSpacing: "0.08em" }} className="text-blue-400/50 uppercase flex-1">
                      Perquisitions
                    </span>
                  </div>
                )}
                {miniGameHistory.map((mg, i) => (
                  <motion.div
                    key={`mg-${i}`}
                    initial={{ opacity: 0, x: -8 }}
                    animate={{ opacity: 1, x: 0 }}
                    transition={{ delay: Math.min((historyEntries.length + i) * 0.025, 0.45) }}
                    className="flex items-center gap-3 px-4 py-3 rounded-xl border-[2px]"
                    style={{ borderColor: mg.success ? "rgba(34,197,94,0.3)" : "rgba(239,68,68,0.3)", background: mg.success ? "rgba(34,197,94,0.05)" : "rgba(239,68,68,0.05)", minHeight: "3rem" }}
                  >
                    <div className="w-7 h-7 rounded-lg flex items-center justify-center flex-shrink-0" style={{ background: mg.success ? "rgba(34,197,94,0.18)" : "rgba(239,68,68,0.18)" }}>
                      <Search className={`w-3.5 h-3.5 ${mg.success ? "text-green-400" : "text-red-400"}`} />
                    </div>
                    <div className="flex-1 min-w-0">
                      <div style={FONT_FREDOKA} className={`text-xs leading-snug ${mg.success ? "text-green-300" : "text-red-300"}`}>
                        Perquisition — {mg.success ? (
                          <><strong className="text-green-400">Réduction {formatPrice(mg.amount)}</strong></>
                        ) : (
                          <><strong className="text-red-400">Ticket {formatPrice(mg.amount)}</strong></>
                        )}
                      </div>
                      <div style={{ ...FONT_FREDOKA, fontSize: "0.65rem" }} className="text-white/30">{mg.turnLabel}</div>
                    </div>

                  </motion.div>
                ))}

                {/* Récapitulatif final — SUPPRIMÉ (déjà affiché en haut du panneau) */}
              </>
            )}
          </div>
        ) : (

        <>{/* Onglets catégories — nouveau design segmenté */}
        <div className="px-4 pt-3 pb-0 flex-shrink-0">
          <div
            className="flex rounded-2xl overflow-hidden border-[3px] border-black"
            style={{ boxShadow: "3px 3px 0px #000" }}
          >
            {CATEGORY_ORDER.filter((cat) => {
              // Masquer les catégories dont le type est désactivé
              if (cat === "contribuable" && disabledCardTypes.includes(2)) return false;
              if (cat === "investisseur" && disabledCardTypes.includes(3)) return false;
              return true;
            }).map((cat, catIdx, visibleCats) => {
              const info     = CATEGORY_INFO[cat];
              const count    = filterByCategory(cards, cat).length + (cat === "investisseur" ? validReceivedCards.length : 0);
              const isActive = activeTab === cat;
              const isLast   = catIdx === visibleCats.length - 1;
              return (
                <motion.button
                  key={cat}
                  whileTap={{ scale: 0.97 }}
                  onClick={() => setActiveTab(cat)}
                  className={`flex-1 relative flex flex-col items-center justify-center py-3 overflow-hidden ${!isLast ? "border-r-[3px] border-black" : ""}`}
                  style={{ background: isActive ? info.color : "rgba(255,255,255,0.05)" }}
                >
                  {isActive && (
                    <motion.div
                      className="absolute inset-0 w-1/2 bg-white/10 skew-x-[-20deg]"
                      animate={{ x: ["-100%", "250%"] }}
                      transition={{ duration: 2.5, repeat: Infinity, ease: "easeInOut", repeatDelay: 1.5 }}
                    />
                  )}
                  <span
                    style={{ ...FONT_BANGERS, fontSize: "0.62rem", letterSpacing: "0.06em", lineHeight: 1 }}
                    className={`relative z-10 ${isActive ? (cat === "contravention" ? "text-black" : "text-white") : "text-white/35"}`}
                  >
                    {info.label}
                  </span>
                  <div
                    className="relative z-10 mt-1 min-w-[20px] h-[18px] px-1.5 rounded-full flex items-center justify-center border-[2px] border-black/40"
                    style={{ background: isActive ? "rgba(0,0,0,0.22)" : (count > 0 ? info.color : "#374151") }}
                  >
                    <span
                      style={{ ...FONT_BANGERS, fontSize: "0.58rem" }}
                      className={isActive ? (cat === "contravention" ? "text-black/80" : "text-white/90") : (count > 0 ? (cat === "contravention" ? "text-black" : "text-white") : "text-white/40")}
                    >
                      {count}
                    </span>
                  </div>
                </motion.button>
              );
            })}
          </div>
        </div>

        {/* Séparateur */}
        <div className="mx-4 mt-2 mb-1 h-[3px] rounded-full flex-shrink-0" style={{ background: catInfo.color, opacity: 0.6 }} />

        {/* Sous-total */}
        <div className="flex items-center justify-between px-5 pb-2 flex-shrink-0">
          <span style={FONT_FREDOKA} className="text-white/50 text-xs">
            {catInfo.label} — {tabCards.length + tabReceivedCards.length} ticket{(tabCards.length + tabReceivedCards.length) > 1 ? "s" : ""}
          </span>
          <span style={{ ...FONT_BANGERS, fontSize: "0.95rem" }} className="text-white/70">
            {formatPrice(computePlayerTotalMp(tabCards) + (activeTab === "investisseur" ? receivedDebt : 0))}
          </span>
        </div>

        {/* Grille de cartes */}
        <div className="flex-1 overflow-y-auto px-4 pb-4">
          <AnimatePresence mode="wait">
            {tabCards.length === 0 && tabReceivedCards.length === 0 ? (
              <motion.div
                key={`empty-${activeTab}`}
                initial={{ opacity: 0, y: 10 }}
                animate={{ opacity: 1, y: 0 }}
                exit={{ opacity: 0 }}
                className="flex flex-col items-center justify-center gap-3 py-10"
              >
                <div className="w-12 h-12 rounded-2xl border-[3px] border-black flex items-center justify-center opacity-30" style={{ background: catInfo.color }}>
                  <Layers className="w-6 h-6 text-white" />
                </div>
                <p style={FONT_FREDOKA} className="text-white/30 text-center text-sm">
                  Aucun ticket {catInfo.label.toLowerCase()} pour l'instant…
                </p>
              </motion.div>
            ) : (
              <motion.div
                key={activeTab}
                initial={{ opacity: 0, x: 16 }}
                animate={{ opacity: 1, x: 0 }}
                exit={{ opacity: 0, x: -16 }}
                transition={{ duration: 0.2 }}
                className="flex flex-col gap-3 pt-1"
              >
                {/* Cartes piochées */}
                {tabCards.length > 0 && (
                  <div className="flex flex-col gap-1.5">
                    {tabReceivedCards.length > 0 && (
                      <div className="flex items-center gap-2">
                        <div className="h-px flex-1 bg-white/10" />
                        <span style={FONT_FREDOKA} className="text-white/30 text-xs">Mes cartes piochées</span>
                        <div className="h-px flex-1 bg-white/10" />
                      </div>
                    )}
                    <div className="grid grid-cols-3 gap-4">
                      {tabCards.map((cardNum, idx) => {
                        const cfg = getCardConfigMp(cardNum);
                        const net = drawerNetAmount(cfg);
                        const bgC = cfg.cardType === 2 ? "#16A34A" : cfg.cardType === 3 ? "#7C3AED" : catInfo.color;
                        const ti  = TYPE_INFO[cfg.cardType];
                        return (
                          <motion.div
                            key={`drawn-${cardNum}-${idx}`}
                            initial={{ scale: 0, opacity: 0 }}
                            animate={{ scale: 1, opacity: 1 }}
                            transition={{ delay: Math.min(idx * 0.025, 0.4), type: "spring", stiffness: 320, damping: 22 }}
                            whileTap={{ scale: 0.93 } as any}
                            onClick={() => { setFocusedCard(cardNum); setFocusedIsReceived(false); }}
                            className="relative rounded-xl border-[3px] overflow-hidden cursor-pointer"
                            style={{
                              aspectRatio: "5/7", boxShadow: "4px 4px 0px #000", background: "#0c1a4e",
                              borderColor: cfg.cardType === 2 ? "#16A34A" : cfg.cardType === 3 ? "#7C3AED" : "#000",
                              minHeight: "120px",
                            }}
                          >
                         <GeneratedCard card={getCardConfigMp(cardNum)} size="xs" skinId={skinId as any} mefaitOverride={getMpCustomMefait(cardNum)} style={{ width: '100%', height: '100%' }} />
                      <div className="absolute bottom-0 left-0 right-0 py-0.5 flex items-center justify-center" style={{ background: catInfo.color + "ee" }}>                              <span style={{ ...FONT_BANGERS, fontSize: "0.52rem" }} className="text-white leading-none">
                                {net >= 0 ? "+" : ""}{formatPrice(net)}
                              </span>
                            </div>
                            <div className="absolute top-0.5 right-0.5 px-0.5 rounded border border-black" style={{ background: ti.color + "bb" }}>
                              <span style={{ ...FONT_BANGERS, fontSize: "0.4rem" }} className="text-white leading-none">{ti.shortLabel}</span>
                            </div>
                          </motion.div>
                        );
                      })}
                    </div>
                  </div>
                )}

                {/* Cartes T3 reçues */}
                {tabReceivedCards.length > 0 && (
                  <div className="flex flex-col gap-1.5">
                    <div className="flex items-center gap-2">
                      <div className="h-px flex-1 bg-pink-400/30" />
                      <span style={FONT_FREDOKA} className="text-pink-300/70 text-xs">
                        Reçues d'un autre joueur ({tabReceivedCards.length})
                      </span>
                      <div className="h-px flex-1 bg-pink-400/30" />
                    </div>
                    <div className="grid grid-cols-3 gap-4">
                      {tabReceivedCards.map((cardNum, idx) => {
                        const cfg     = getCardConfigMp(cardNum);
                        const nextAmt = nextPlayerAmount(cfg);
                        return (
                          <motion.div
                            key={`recv-${cardNum}-${idx}`}
                            initial={{ scale: 0, opacity: 0 }}
                            animate={{ scale: 1, opacity: 1 }}
                            transition={{ delay: Math.min(idx * 0.025, 0.4), type: "spring", stiffness: 320, damping: 22 }}
                            whileTap={{ scale: 0.93 } as any}
                            onClick={() => { setFocusedCard(cardNum); setFocusedIsReceived(true); }}
                            className="relative rounded-xl overflow-hidden cursor-pointer"
                            style={{
                              aspectRatio: "5/7",
                              border: "3px solid #EC4899",
                              boxShadow: "4px 4px 0px #000",
                              background: "#0c1a4e",
                              minHeight: "120px",
                            }}
                          >
                            <GeneratedCard card={getCardConfigMp(cardNum)} size="xs" skinId={skinId as any} mefaitOverride={getMpCustomMefait(cardNum)} style={{ width: '100%', height: '100%' }} />                           <div className="absolute bottom-0 left-0 right-0 py-0.5 flex items-center justify-center" style={{ background: "#EC4899ee" }}>
                              <span style={{ ...FONT_BANGERS, fontSize: "0.52rem" }} className="text-white leading-none">
                                +{formatPrice(nextAmt)}
                              </span>
                            </div>
                            <div className="absolute top-0.5 left-0.5 px-0.5 rounded border border-black" style={{ background: "#EC4899cc" }}>
                              <span style={{ ...FONT_BANGERS, fontSize: "0.38rem" }} className="text-white leading-none">REÇU</span>
                            </div>
                          </motion.div>
                        );
                      })}
                    </div>
                  </div>
                )}
              </motion.div>
            )}
          </AnimatePresence>
        </div>
        </>
        )}

        {/* Safe area bottom */}
        <div className="h-safe flex-shrink-0" style={{ height: "env(safe-area-inset-bottom, 12px)" }} />
      </motion.div>

      {/* Vue zoom d'une carte */}
      <AnimatePresence>
        {focusedCard !== null && (() => {
          const cfg      = getCardConfigMp(focusedCard);
          const net      = drawerNetAmount(cfg);
          const nextAmt  = nextPlayerAmount(cfg);
          const ti       = TYPE_INFO[cfg.cardType];
          const headerBg = focusedIsReceived ? "#EC4899" : ti.color;
          const fCatInfo = CATEGORY_INFO[cfg.category];
          return (
            <motion.div
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              className="fixed inset-0 z-[60] flex flex-col items-center justify-center px-6 gap-4"
              style={{ background: "rgba(0,0,0,0.93)" }}
              onClick={() => { setFocusedCard(null); setFocusedIsReceived(false); }}
            >
              <motion.div
                initial={{ scale: 0.72, rotateY: -40 }}
                animate={{ scale: 1, rotateY: 0 }}
                exit={{ scale: 0.72, opacity: 0 }}
                transition={{ type: "spring", stiffness: 280, damping: 22 }}
                className="rounded-3xl border-[5px] overflow-hidden flex-shrink-0"
                style={{ width: "min(78vw, 260px)", aspectRatio: "5/7", boxShadow: "10px 10px 0px #000", borderColor: focusedIsReceived ? "#EC4899" : "#000" }}
                onClick={(e) => e.stopPropagation()}
              >
                <GeneratedCard card={getCardConfigMp(focusedCard)} size="md" skinId={skinId as any} mefaitOverride={getMpCustomMefait(focusedCard)} style={{ width: '100%', height: '100%' }} />
              </motion.div>

              <div
                className="w-full max-w-sm rounded-2xl border-[3px] border-black overflow-hidden"
                style={{ borderColor: headerBg, boxShadow: "6px 6px 0px #000" }}
                onClick={(e) => e.stopPropagation()}
              >
                <div className="flex items-center justify-between px-4 py-2" style={{ background: headerBg }}>
                  <div className="flex items-center gap-1.5">
                    {focusedIsReceived && <Mail className="w-4 h-4 text-white flex-shrink-0" />}
                    <span style={{ ...FONT_BANGERS, fontSize: "0.95rem", letterSpacing: "0.05em" }} className="text-white">
                      {focusedIsReceived ? "REÇUE" : ti.shortLabel} — #{String(focusedCard).padStart(3, "0")}
                    </span>
                  </div>
                  <span style={{ ...FONT_BANGERS, fontSize: "0.9rem" }} className="text-white/80">
                    {fCatInfo.label}
                  </span>
                </div>
                <div className="px-4 py-2.5 flex flex-col gap-1.5" style={{ background: headerBg + "22" }}>
                  {focusedIsReceived ? (
                    <>
                      <div className="flex justify-between items-center">
                        <span style={FONT_FREDOKA} className="text-pink-300 text-sm flex items-center gap-1">
                          <Mail className="w-3.5 h-3.5" /> Dette reçue{focusedCard !== null && t3SenderMap[focusedCard] ? <> de <strong>{t3SenderMap[focusedCard]}</strong></> : ""}
                        </span>
                        <span style={{ ...FONT_BANGERS, fontSize: "1.05rem" }} className="text-pink-300">+{formatPrice(nextAmt)}</span>
                      </div>
                      <div className="flex justify-between">
                        <span style={FONT_FREDOKA} className="text-white/50 text-xs">Ticket de base</span>
                        <span style={{ ...FONT_BANGERS, fontSize: "0.85rem" }} className="text-white/60">+{formatPrice(cfg.ticketPrice ?? 0)}</span>
                      </div>
                      {(cfg.taxe ?? 0) > 0 && (
                        <div className="flex justify-between">
                          <span style={FONT_FREDOKA} className="text-white/50 text-xs">Taxe incluse</span>
                          <span style={{ ...FONT_BANGERS, fontSize: "0.85rem" }} className="text-white/60">+{formatPrice(cfg.taxe ?? 0)}</span>
                        </div>
                      )}
                    </>
                  ) : (
                    <>
                      <div className="flex justify-between items-center">
                        <span style={FONT_FREDOKA} className="text-white/70 text-sm flex items-center gap-1">
                          <User className="w-3.5 h-3.5" /> Effet sur toi
                        </span>
                        <span style={{ ...FONT_BANGERS, fontSize: "1.05rem" }} className={net >= 0 ? "text-red-400" : "text-green-400"}>
                          {net >= 0 ? "+" : ""}{formatPrice(net)}
                        </span>
                      </div>
                      {nextAmt > 0 && (
                        <div className="flex justify-between items-center">
                          <span style={FONT_FREDOKA} className="text-pink-300 text-sm flex items-center gap-1">
                            <ArrowRight className="w-3.5 h-3.5" /> Joueur suivant
                          </span>
                          <span style={{ ...FONT_BANGERS, fontSize: "1.05rem" }} className="text-pink-300">+{formatPrice(nextAmt)}</span>
                        </div>
                      )}
                    </>
                  )}
                </div>
              </div>

              {/* Navigation */}
              <div className="flex items-center gap-3" onClick={(e) => e.stopPropagation()}>
                <motion.button
                  whileTap={{ scale: 0.9 }}
                  onClick={() => {
                    if (zoomedIdx > 0) {
                      const prev = allTabCards[zoomedIdx - 1];
                      setFocusedCard(prev);
                      setFocusedIsReceived(tabReceivedCards.includes(prev));
                    }
                  }}
                  disabled={zoomedIdx <= 0}
                  className="w-12 h-12 bg-white/10 border-[2px] border-white/20 rounded-xl flex items-center justify-center text-white/60 disabled:opacity-20"
                >
                  <ChevronLeft className="w-5 h-5" />
                </motion.button>
                <span style={FONT_FREDOKA} className="text-white/40 text-sm min-w-[4rem] text-center">
                  {zoomedIdx + 1} / {allTabCards.length}
                </span>
                <motion.button
                  whileTap={{ scale: 0.9 }}
                  onClick={() => {
                    if (zoomedIdx < allTabCards.length - 1) {
                      const next = allTabCards[zoomedIdx + 1];
                      setFocusedCard(next);
                      setFocusedIsReceived(tabReceivedCards.includes(next));
                    }
                  }}
                  disabled={zoomedIdx >= allTabCards.length - 1}
                  className="w-12 h-12 bg-white/10 border-[2px] border-white/20 rounded-xl flex items-center justify-center text-white/60 disabled:opacity-20"
                >
                  <ChevronRight className="w-5 h-5" />
                </motion.button>
                <motion.button
                  whileTap={{ scale: 0.9 }}
                  onClick={() => { setFocusedCard(null); setFocusedIsReceived(false); }}
                  className="w-12 h-12 bg-red-500 border-[3px] border-black rounded-full flex items-center justify-center ml-1"
                  style={{ boxShadow: "3px 3px 0px #000" }}
                >
                  <X className="w-5 h-5 text-white" />
                </motion.button>
              </div>
            </motion.div>
          );
        })()}
      </AnimatePresence>
    </motion.div>
  );
}

// ────────────────────────────────────────────────────────────
// MultiplayerGameScreen — écran principal
// ────────────────────────────────────────────────────────────
export function MultiplayerGameScreen() {
  const [, navigate] = useLocation();
  const { code, playerId, playerName, isHost, guestEmoji } = mpStorage.load();
  const { isAuthenticated } = useGameAuth();

  // ─ Statistiques de jeu ─
  const recordResultMutation = trpc.stats.recordResult.useMutation();
  const statsRecordedRef = useRef(false);
  const endGameMutation = trpc.badges.endGame.useMutation();
  const badgesRecordedRef = useRef(false);

  const [session, setSession]                   = useState<Session | null>(null);
  const [error, setError]                       = useState("");
  const [isDrawing, setIsDrawing]               = useState(false);
  const [isResetting, setIsResetting]           = useState(false);
  const [showNotif, setShowNotif]               = useState(false);
  const [showCard, setShowCard]                 = useState(true);
  const [showCardFront, setShowCardFront]       = useState(true); // false = dos, true = face
  const [showMyTickets, setShowMyTickets]       = useState(false);
  const [showConfirmReset, setShowConfirmReset] = useState(false);
  const [showConfirmLeave, setShowConfirmLeave] = useState(false);
  const [showMusicPlayer, setShowMusicPlayer] = useState(false);
  const [justEliminated, setJustEliminated]     = useState<string | null>(null); // kept for flash notif minor uses
  const [isEndingTurn, setIsEndingTurn]         = useState(false);
  // State séparé pour la fin de tour après perquisition — indépendant de isEndingTurn
  const [isEndingTurnPerquisition, setIsEndingTurnPerquisition] = useState(false);
  const isEndingTurnPerquisitionRef = useRef(false);
  const [bubbleCard, setBubbleCard]             = useState<{ cardNum: number; playerName: string; playerId?: string } | null>(null);
  const [showPrevCard, setShowPrevCard]         = useState(false);

  // ─ Masquer la carte (pour les non-actifs) ─
  const [cardHiddenByViewer, setCardHiddenByViewer] = useState(false);

  // ─ Élimination avec pause ─
  const [showMyEliminationOverlay, setShowMyEliminationOverlay] = useState(false);
  const [isAcknowledging, setIsAcknowledging] = useState(false);
  const prevPendingAck = useRef<string[]>([]);

  // ─ Ref emoji persistant (local + serveur) pour éviter les flashs dans les notifs ─
  const myEmojiRef = useRef<string>(guestEmoji || "");
  const [myEmojiResolved, setMyEmojiResolved] = useState<string>(guestEmoji || "");

  // ─ Flux carte T3 investisseur ─
  const [pendingT3, setPendingT3] = useState<{
    nextPlayerId: string; nextAmt: number; taxAmt: number; nextPlayerName: string; totalRefund: number;
  } | null>(null);
  const [isSendingT3, setIsSendingT3]                         = useState(false);
  // Modal de sélection du destinataire T3
  const [showT3TargetModal, setShowT3TargetModal]             = useState(false);
  const [t3ConfirmTarget, setT3ConfirmTarget]                 = useState<string | null>(null);
  const [showTaxNotif, setShowTaxNotif]                       = useState<{ amount: number } | null>(null);
  const prevT3ReceivedRef                                     = useRef<Record<string, number>>({}); // pid -> count (conservé pour usage futur)
  const [showReceivedTicketNotif, setShowReceivedTicketNotif] = useState<{
    amount: number; fromName: string;
  } | null>(null);
  // Notification spectateur : "X envoie un ticket à Y" (pour les joueurs non impliqués)
  const [showT3SpectatorNotif, setShowT3SpectatorNotif] = useState<{
    senderName: string; receiverName: string;
    senderId: string; receiverId: string;
  } | null>(null);
  // ref gardée mais plus utilisée pour la détection
  const t3NotifReceiverCountRef = useRef<number>(0);

  // ─ Notification "joueur a quitté/été expulsé" ─
  const [playerLeftNotif, setPlayerLeftNotif] = useState<{
    playerName: string; wasKicked: boolean;
  } | null>(null);
  const playerLeftTimeout = useRef<ReturnType<typeof setTimeout> | null>(null);
  const lastRecentLeaveTs = useRef<number>(0); // timestamp déjà affiché

  // ─ Modal d'expulsion (host) ─
  const [showKickModal, setShowKickModal] = useState(false);
  const [showTransactionDrawer, setShowTransactionDrawer] = useState(false);
  const [isKicking, setIsKicking] = useState(false);

  // ─ Dropdown joueurs ─
  const [showPlayerDropdown, setShowPlayerDropdown] = useState(false);
  const [showHistoryPanel, setShowHistoryPanel]     = useState(false);

  // ─ Podium classement final ─
  const [showPodium, setShowPodium] = useState(false);

  // ─ Perquisition (synchronisée via tRPC) ─
  // Mode du mini-jeu en cours pour CE joueur (null = pas de mini-jeu)
  const [miniGameMode, setMiniGameMode] = useState<"run" | "hide" | null>(null);
  // ID de l'événement mini-jeu en cours
  const [miniGameEventId, setMiniGameEventId] = useState<number | null>(null);
  // Nombre total de joueurs actifs pour ce mini-jeu
  const [miniGameTotalPlayers, setMiniGameTotalPlayers] = useState<number>(0);
  // Le joueur qui a déclenché le mini-jeu attend que tous aient terminé
  const [waitingForAllPlayers, setWaitingForAllPlayers] = useState(false);
  // ID du joueur qui a déclenché le mini-jeu (pour savoir qui doit attendre)
  const [miniGameTriggeredBy, setMiniGameTriggeredBy] = useState<string | null>(null);
  const miniGameTriggeredByRef = useRef<string | null>(null); // Ref pour éviter les problèmes de closure dans fetchMiniGameStatus
  // Résultats de la Perquisition (affichés après résolution)
  const [miniGameResultsData, setMiniGameResultsData] = useState<Array<{ playerId: string; success: boolean; amount: number }> | null>(null);
  // Phase d'alerte perquisition : "trigger-alert" (piocheur voit message) | "common-alert" (tous voient message) | null
  const [miniGameAlertPhase, setMiniGameAlertPhase] = useState<"trigger-alert" | "common-alert" | null>(null);
  // Mode du mini-jeu en attente (avant que le joueur clique PAS LE CHOIX)
  const [pendingMiniGameMode, setPendingMiniGameMode] = useState<"run" | "hide" | null>(null);
  // Vrai si une perquisition a eu lieu ce tour → le joueur actif ne pioche pas
  const [miniGameSkippedDraw, setMiniGameSkippedDraw] = useState(false);
  // Ref miroir de miniGameSkippedDraw pour éviter les problèmes de stale closure dans handleEndTurn
  const miniGameSkippedDrawRef = useRef(false);
  // Historique des perquisitions pour l'affichage dans "Mes tickets" et le journal
  const [miniGameHistory, setMiniGameHistory] = useState<Array<{ success: boolean; amount: number; turnLabel: string }>>([]);
  // Historique de groupe des perquisitions (pour le journal de partie)
  const [groupMiniGameHistory, setGroupMiniGameHistory] = useState<Array<{ triggeredByName: string; results: Array<{ playerName: string; success: boolean; amount: number }>; timestamp: number }>>([]);
  const miniGamePollRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const miniGameStatusPollRef = useRef<ReturnType<typeof setInterval> | null>(null);
  // Refs pour stocker la version la plus récente des fonctions de polling (évite les stale closures)
  const fetchActiveMiniGameRef = useRef<() => Promise<void>>(async () => {});
  const fetchMiniGameStatusRef = useRef<() => Promise<void>>(async () => {});
  const lastMiniGameId = useRef<number | null>(null);
  const resolvedMiniGameIds = useRef<Set<number>>(new Set()); // IDs des événements déjà résolus — ignorés par fetchActiveMiniGame
  const drawsSinceLastMiniGameRef = useRef<number>(0); // Compteur de tirages depuis la dernière perquisition
  const trpcUtils = trpc.useUtils();
  const triggerMiniGame = trpc.miniGame.trigger.useMutation();
  const submitMiniGameResult = trpc.miniGame.submitResult.useMutation();
  const resolveMiniGame = trpc.miniGame.resolve.useMutation();
  // Historique des perquisitions résolues depuis la DB (source de vérité)
  // Intervalle augmenté à 4000ms (au lieu de 3000ms) : l'historique des perquisitions
  // n'est pas critique en temps réel (affiché dans un panneau secondaire)
  const miniGameHistoryQuery = trpc.miniGame.getHistory.useQuery(
    { sessionCode: code ?? "" },
    { enabled: !!(code), refetchInterval: 4000, staleTime: 0 },
  );
  const dbMiniGameHistory = miniGameHistoryQuery.data ?? [];

  // ─ Options de session (skins + extensions) — chargées depuis la DB du host ─
  // IMPORTANT : staleTime: 0 pour forcer une lecture fraîche à chaque fois
  // refetchInterval: 1000 pour mettre à jour la difficulté toutes les 1 seconde
  // Intervalle augmenté à 2000ms (au lieu de 1000ms) : les options de session changent rarement
  // pendant une partie, et réduire la fréquence allège la charge réseau avec 10 joueurs
  const sessionOptionsQuery = trpc.sessionOptions.getOptions.useQuery(
    { sessionCode: code ?? "" },
    { enabled: !!(code), refetchOnWindowFocus: false, staleTime: 0, refetchInterval: 2000 },
  );
  const sessionSkinsEnabled = sessionOptionsQuery.data?.skinsEnabled ?? false;
  const sessionSkinMode = sessionOptionsQuery.data?.skinMode ?? "off";
  // Options de perquisition depuis notre DB (source de vérité, car Supabase ne retourne pas ces champs)
  const sessionMiniGameLevel = (sessionOptionsQuery.data?.miniGameLevel ?? null) as MiniGameLevel | null;
  const sessionMiniGameDifficulty = sessionOptionsQuery.data?.miniGameDifficulty ?? null;
  const sessionMiniGameEnabled = sessionOptionsQuery.data?.miniGameEnabled ?? null;

  // Fonction pour obtenir la difficulté actuelle (lue à chaque utilisation, pas de cache)
  const getMultiplayerMiniGameDifficulty = (): MiniGameDifficulty => {
    // Priorité : notre DB (sessionMiniGameDifficulty) > Supabase > localStorage > défaut
    const raw = sessionMiniGameDifficulty ?? session?.miniGameDifficulty ?? localStorage.getItem(SOLO_MINI_GAME_DIFFICULTY_KEY) ?? "tranquille";
    return (raw === "hardcore" ? "hardcore" : "tranquille") as MiniGameDifficulty;
  };

  // ── Historique par tour - optimisé avec useMemo ──
  const mpGlobalHistoryTours = useMemo(() => {
    if (!session || !session.playerCards || Object.keys(session.playerCards).length === 0) return [];
    const tours: any[] = [];
    const counts: Record<string, number> = {};
    session.turnOrder.forEach((pid: string) => {
      counts[pid] = ((session as any).playerCards?.[pid] ?? []).length;
    });
    const maxCards = Math.max(...Object.values(counts), 0);
    for (let t = 0; t < maxCards; t++) {
      const txs: any[] = [];
      session.turnOrder.forEach((pid: string) => {
        const cards = ((session as any).playerCards?.[pid] ?? []);
        if (t < cards.length) {
          const name = session.players.find((p: any) => p.id === pid)?.name ?? "?";
          const cfg = getCardConfigMp(cards[t]);
          const cat = CATEGORY_INFO[cfg.category];
          
          // Pour les cartes T3 (Investisseur), afficher deux lignes : piocheur et récepteur
          if (cfg.category === "investisseur") {
            const amountSent = nextPlayerAmount(cfg);
            // Ligne 1 : piocheur (montant négatif = réduction de dette)
            txs.push({ type: "card", name, amt: -amountSent, cat, isT3Sender: true });
            // Ligne 2 : récepteur (montant positif = augmentation de dette)
            const nextPlayerId = getNextActivePlayerId(session, pid);
            const receiverName = nextPlayerId ? session.players.find((p: any) => p.id === nextPlayerId)?.name ?? "?" : "?";
            txs.push({ type: "card", name: receiverName, amt: amountSent, cat, isT3Receiver: true });
          } else {
            // Pour T1 et T2, une seule ligne
            const amt = drawerNetAmount(cfg);
            txs.push({ type: "card", name, amt, cat });
          }
        }
      });
      if (txs.length > 0) tours.push({ num: t + 1, txs });
    }
    return tours.reverse();
  }, [session?.turnOrder, session?.playerCards, session?.players]);

  // ── Historique des perquisitions - source de vérité = DB via dbMiniGameHistory ──
  const mpGlobalHistoryRaids = useMemo(() => {
    if (!dbMiniGameHistory || dbMiniGameHistory.length === 0) return null;
    const allResults: Array<{ gameIdx: number; resultIdx: number; playerId: string; success: boolean; amount: number }> = [];
    dbMiniGameHistory.forEach((game: any, gIdx: number) => {
      if (game?.results) {
        game.results.forEach((result: any, rIdx: number) => {
          allResults.push({ gameIdx: gIdx, resultIdx: rIdx, playerId: result.playerId, success: result.success, amount: result.amount });
        });
      }
    });
    return allResults.length > 0 ? allResults : null;
  }, [dbMiniGameHistory]);


  // Skin actif du joueur local (pour l'enregistrement)
  // Toujours charger le skin actif, même si skinsEnabled n'est pas encore confirmé
  // Pour les joueurs non connectés, la query échouera silencieusement (retry: false)
  const { data: myActiveSkinId, isError: skinQueryError, isFetched: skinQueryFetched } = trpc.skins.getActiveSkin.useQuery(undefined, {
    retry: false,
    staleTime: 60_000,
  });

  // Skin effectif : skin actif du joueur connecté, ou "classique" par défaut pour les invités
  const effectiveSkinId: string = (myActiveSkinId as string | undefined) ?? "classique";

  // Mutation pour enregistrer le skin du joueur local dans la session
  const registerPlayerSkinMutation = trpc.sessionOptions.registerPlayerSkin.useMutation();
  const skinRegisteredRef = useRef(false);

  // Enregistrer le skin du joueur local quand la session démarre et que skinsEnabled est actif
  // Se déclenche dès que : sessionSkinsEnabled est true + code + playerId + skin query terminée
  useEffect(() => {
    if (!sessionSkinsEnabled || !code || !playerId) return;
    // Attendre que la query skin soit terminée (succès ou erreur)
    if (!skinQueryFetched && !skinQueryError) return;
    // Éviter les enregistrements multiples
    if (skinRegisteredRef.current) return;
    skinRegisteredRef.current = true;
    registerPlayerSkinMutation.mutate({
      sessionCode: code,
      playerId,
      skinId: effectiveSkinId,
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [sessionSkinsEnabled, code, playerId, effectiveSkinId, skinQueryFetched, skinQueryError]);

  // Skins des joueurs : map playerId -> skinId (chargé depuis la DB)
  // Rafraîchir régulièrement pour détecter les skins des nouveaux joueurs
  const playerSkinsQuery = trpc.sessionOptions.getPlayerSkins.useQuery(
    { sessionCode: code ?? "" },
    // Intervalle augmenté à 5000ms (au lieu de 3000ms) : les skins sont enregistrés au début
    // de la partie et ne changent pas pendant le jeu
    { enabled: !!(code) && sessionSkinsEnabled, refetchOnWindowFocus: false, staleTime: 5_000, refetchInterval: 5_000 },
  );
  // Map playerId -> skinId pour l'affichage des cartes
  const playerSkinMap: Record<string, string> = (playerSkinsQuery.data as Record<string, string>) ?? {};

  // Identifier le host (premier joueur dans turnOrder) et son skin
  const hostPlayerId = session?.turnOrder?.[0] ?? "";
  const hostSkinId: string | undefined = playerSkinMap[hostPlayerId] ?? undefined;

  // Skin du joueur local : en mode "shared", tous utilisent le skin du host
  const mySkinId: string | undefined = sessionSkinsEnabled
    ? (sessionSkinMode === "shared"
        ? (hostSkinId ?? effectiveSkinId)
        : (playerSkinMap[playerId ?? ""] ?? effectiveSkinId))
    : undefined;

  /** Résoudre le skin d'un joueur selon le mode (shared → host skin, individual → son propre skin) */
  const resolvePlayerSkin = (pid: string): string | undefined => {
    if (!sessionSkinsEnabled) return undefined;
    if (sessionSkinMode === "shared") return hostSkinId ?? "classique";
    // En mode individual, utiliser le skin enregistré du joueur, ou "classique" par défaut
    return playerSkinMap[pid] ?? "classique";
  };

  const pollRef                = useRef<ReturnType<typeof setInterval> | null>(null);
  const prevTurnIdx            = useRef<number>(-1);
  const prevLastCard           = useRef<number | null>(null);
  const notifTimeout           = useRef<ReturnType<typeof setTimeout> | null>(null);
  const elimTimeout            = useRef<ReturnType<typeof setTimeout> | null>(null);
  const firstLoadDone          = useRef(false);
  const prevReceivedCardCount  = useRef<number>(0);
  // Compteurs de retries réseau — protègent contre les faux positifs transitoires
  const networkErrorCount      = useRef<number>(0); // erreurs réseau consécutives
  const notInGameCount         = useRef<number>(0); // fois consécutives où stillInGame=false
  const sessionNotFoundCount   = useRef<number>(0); // fois consécutives où session introuvable

  // Déduplication des notifications de tour : mémorise le turnIndex déjà notifié
  const lastNotifTurnIdx       = useRef<number>(-1);
  // Clé incrémentale pour forcer AnimatePresence à remonter proprement la notif
  const [notifMountKey, setNotifMountKey] = useState(0);
  // Ref synchrone pour savoir si la notif est à l'écran (évite les closures stales)
  const showNotifRef           = useRef(false);

  // Redirection si pas de session
  useEffect(() => {
    if (!code || !playerId) navigate("/");
  }, []);

  // ── Charger les cartes personnalisées de l'hôte pour cette session ──
  const sessionCustomCardsQuery = trpc.sessionCustomCards.getForSession.useQuery(
    { sessionCode: code ?? "" },
    { enabled: !!(code), refetchOnWindowFocus: false, staleTime: 60_000 },
  );
  useEffect(() => {
    if (sessionCustomCardsQuery.data) {
      loadMpCustomCards(sessionCustomCardsQuery.data as any);
    }
  }, [sessionCustomCardsQuery.data]);

  // ── Profils joueurs (avatar + badge) pour l'affichage dans le scoreboard ──
  const mpPlayerNames = useMemo(
    () => (session?.players ?? []).map((p) => p.name),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [(session?.players ?? []).map((p) => p.name).join(",")]
  );
  const { data: mpPlayerProfiles } = trpc.gameAuth.getPlayerProfiles.useQuery(
    { playerNames: mpPlayerNames },
    { enabled: mpPlayerNames.length > 0, staleTime: 0, refetchOnWindowFocus: false }
  );

  // ─ Emojis des joueurs invités (sans compte) ─
  // Intervalle augmenté à 3000ms (au lieu de 2000ms) : les emojis invités changent rarement
  // pendant la partie (enregistrés au montage), réduit la charge avec 10 joueurs
  const { data: guestEmojis } = trpc.guestAvatar.getEmojis.useQuery(
    { sessionCode: code },
    { enabled: !!code, staleTime: 0, refetchInterval: 3_000, refetchOnMount: true, refetchOnWindowFocus: false }
  );
  // Enregistrer son propre emoji au montage si on est un invité avec un emoji
  const setGuestEmojiMutation = trpc.guestAvatar.setEmoji.useMutation();
  useEffect(() => {
    if (guestEmoji && playerId && code) {
      setGuestEmojiMutation.mutate({ sessionCode: code, playerId, emoji: guestEmoji });
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Mettre à jour myEmojiRef + myEmojiResolved dès que guestEmojis arrive du serveur
  useEffect(() => {
    if (!playerId) return;
    const serverEmoji = (guestEmojis as Record<string, string> | undefined)?.[playerId];
    const resolved = serverEmoji || guestEmoji || "";
    if (resolved) {
      myEmojiRef.current = resolved;
      setMyEmojiResolved(resolved);
    }
  }, [guestEmojis, playerId, guestEmoji]);

  // Réinitialiser le masquage à chaque nouvelle carte
  useEffect(() => {
    setCardHiddenByViewer(false);
  }, [session?.lastCard]);

  const isMyTurn = useCallback(
    (s: Session) => s.state === "playing" && s.turnOrder[s.currentTurnIndex] === playerId,
    [playerId],
  );

  /**
   * Affiche la notification de tour de manière idempotente.
   * - Ignore si ce turnIndex a déjà déclenché une notif (anti-doublon).
   * - Si une notif est déjà visible, coupe-la 80 ms avant de relancer
   *   pour forcer AnimatePresence à démonter/remonter l'ancien composant.
   */
  const triggerTurnNotif = useCallback((s: Session, forceAutoClose: boolean) => {
    const idx = s.currentTurnIndex;
    // Anti-doublon strict : même tour → on ignore
    if (lastNotifTurnIdx.current === idx) return;
    lastNotifTurnIdx.current = idx;

    const isMeTurn = s.turnOrder[idx] === playerId;

    const doShow = () => {
      if (notifTimeout.current) clearTimeout(notifTimeout.current);
      setNotifMountKey(k => k + 1); // nouveau montage = nouvelle animation d'entrée
      showNotifRef.current = true;
      setShowNotif(true);
      if (!isMeTurn || forceAutoClose) {
        // Auto-dismiss pour les spectateurs ou après handleEndTurn
        notifTimeout.current = setTimeout(() => {
          showNotifRef.current = false;
          setShowNotif(false);
        }, 2400);
      }
    };

    // Attendre que guestEmojis soit chargé avant d'afficher la notif pour tout joueur invité
    // (joueur local sans emoji résolu OU spectateur regardant un joueur invité)
    const needEmojiWait = !isAuthenticated && (!myEmojiRef.current || !isMeTurn);
    const baseDelay = needEmojiWait ? 800 : 0;

    if (showNotifRef.current) {
      // Une notif est déjà visible → on la fait sortir proprement puis on relance
      if (notifTimeout.current) clearTimeout(notifTimeout.current);
      showNotifRef.current = false;
      setShowNotif(false);
      setTimeout(doShow, 120 + baseDelay); // laisse exit animation se jouer
    } else if (baseDelay > 0) {
      setTimeout(doShow, baseDelay);
    } else {
      doShow();
    }
  }, [playerId, isAuthenticated, myEmojiRef]);

  // ── Polling ──────────────────────────────────────────────
  const fetchSession = useCallback(async () => {
    if (!code) return;
    try {
      const { session: s } = await getSession(code);
      setError("");

      // Réinitialiser les compteurs d'erreur à chaque succès
      networkErrorCount.current = 0;
      sessionNotFoundCount.current = 0;

      // Si ce joueur a été expulsé (plus dans la liste des joueurs)
      // Protection : attendre 3 confirmations consécutives avant de naviguer
      // (évite les faux positifs dus à des réponses API transitoires ou en retard)
      if (firstLoadDone.current) {
        const stillInGame = s.players.some(p => p.id === playerId);
        if (!stillInGame) {
          notInGameCount.current += 1;
          if (notInGameCount.current >= 3) {
            mpStorage.clear();
            navigate("/");
            return;
          }
          // Pas encore confirmé — ignorer cette réponse et attendre le prochain poll
          return;
        } else {
          notInGameCount.current = 0;
        }
      }

      const turnChanged = prevTurnIdx.current !== s.currentTurnIndex;
      const cardChanged = prevLastCard.current !== s.lastCard;

      if (turnChanged || cardChanged) {
        setShowCard(false);
        setTimeout(() => setShowCard(true), 50);
      }

      // FIX: Réinitialiser miniGameSkippedDraw quand le tour change
      // Sinon, le joueur suivant verra "TERMINER MON TOUR" au lieu de "RECEVOIR UN TICKET"
      if (turnChanged) {
        setMiniGameSkippedDraw(false);
        miniGameSkippedDrawRef.current = false; // Ref miroir
        resolvedMiniGameIds.current.clear(); // Réinitialiser aussi les IDs résolus
        setMiniGameAlertPhase(null);
        setPendingMiniGameMode(null);
        // NOTE : drawsSinceLastMiniGameRef n'est PAS réinitialisé ici.
        // Le compteur s'accumule sur tous les tours du joueur local jusqu'à une perquisition.
        // Il est réinitialisé uniquement quand une perquisition se déclenche (dans handleDraw).
      }

      // Notification de changement de tour (sauf au premier chargement)
      if (firstLoadDone.current && turnChanged && s.state === "playing") {
        // Mettre à jour la bulle "carte précédente" avec la carte du joueur qui vient de terminer
        if (s.lastCard !== null && s.lastCardDrawnBy) {
          const bPlayer = s.players.find((p) => p.id === s.lastCardDrawnBy);
          if (bPlayer) setBubbleCard({ cardNum: s.lastCard, playerName: bPlayer.name, playerId: bPlayer.id });
        }
        // Utiliser triggerTurnNotif pour éviter les doublons (race condition poll + handleEndTurn)
        triggerTurnNotif(s, false);
      }

      prevTurnIdx.current  = s.currentTurnIndex;
      prevLastCard.current = s.lastCard;

      // ─ Détecter si JE suis nouvellement dans pendingEliminationAck ─
      const pending = s.pendingEliminationAck ?? [];
      const wasInPending = prevPendingAck.current.includes(playerId);
      const nowInPending = pending.includes(playerId);
      if (!wasInPending && nowInPending) {
        setShowMyEliminationOverlay(true);
        // Fermer la notif "ticket reçu" si elle est encore affichée,
        // pour que l'overlay d'élimination (z-100) soit bien visible
        setShowReceivedTicketNotif(null);
      }
      prevPendingAck.current = pending;

      // ─ Détecter un nouveau ticket T3 reçu (pour le joueur destinataire) ─
      const newReceivedCards = s.playerReceivedCards?.[playerId] ?? [];
      const newReceivedCount = newReceivedCards.length;
      if (
        firstLoadDone.current &&
        newReceivedCount > prevReceivedCardCount.current &&
        s.lastCardDrawnBy !== playerId
      ) {
        // Ne pas afficher la notif "ticket reçu" pendant ou juste après une perquisition
        const perquisitionActive = miniGameAlertPhase !== null || miniGameMode !== null || waitingForAllPlayers || miniGameResultsData !== null;
        // Vérifier aussi le dernier cardId reçu : ignorer cardId=0 (perquisition auto-dette)
        const lastReceivedCardId = newReceivedCards[newReceivedCards.length - 1];
        const isPerquisitionDebt = lastReceivedCardId === 0 || lastReceivedCardId === null || lastReceivedCardId === undefined;
        if (!perquisitionActive && !isPerquisitionDebt) {
          const drawerPlayer = s.players.find((p) => p.id === s.lastCardDrawnBy);
          // Ignorer cardId=0 (perquisition auto-dette) et lastCard null
          if (s.lastCard !== null && s.lastCard !== 0) {
            const cfg = getCardConfigMp(s.lastCard);
            const receivedAmt = nextPlayerAmount(cfg);
            if (receivedAmt > 0) {
              setShowReceivedTicketNotif({
                amount: receivedAmt,
                fromName: drawerPlayer?.name ?? "un joueur",
              });
            }
          }
        }
      }
      prevReceivedCardCount.current = newReceivedCount;

      // ─ Détecter si la carte qui vient d'être piochée est T3 (notif spectateur dès la pioche) ─
      if (firstLoadDone.current && cardChanged && s.lastCard !== null) {
        const drawnCfg = getCardConfigMp(s.lastCard);
        if (drawnCfg.cardType === 3 && s.lastCardDrawnBy && s.lastCardDrawnBy !== playerId) {
          const nextReceiverId = getNextActivePlayerId(s, s.lastCardDrawnBy);
          if (nextReceiverId && nextReceiverId !== playerId) {
            // Je suis spectateur (ni l'envoyeur ni le receveur désigné)
            const senderPlayer   = s.players.find((p) => p.id === s.lastCardDrawnBy);
            const receiverPlayer = s.players.find((p) => p.id === nextReceiverId);
            if (senderPlayer && receiverPlayer) {
              setShowT3SpectatorNotif({
                senderName:   senderPlayer.name,
                receiverName: receiverPlayer.name,
                senderId:     senderPlayer.id,
                receiverId:   nextReceiverId,
              });
            }
          }
        } else if (drawnCfg.cardType !== 3) {
          // Nouvelle carte non-T3 piochée → fermer toute notif spectateur T3 résiduelle
          setShowT3SpectatorNotif(null);
        }
      }

      // ── Détecter si un joueur vient de quitter / être expulsé ──
      if (
        firstLoadDone.current &&
        s.recentLeave &&
        s.recentLeave.timestamp > lastRecentLeaveTs.current
      ) {
        lastRecentLeaveTs.current = s.recentLeave.timestamp;
        // Ne pas afficher la notif pour soi-même (le joueur qui quitte navigue déjà)
        if (s.recentLeave.playerName !== playerName) {
          if (playerLeftTimeout.current) clearTimeout(playerLeftTimeout.current);
          setPlayerLeftNotif({
            playerName: s.recentLeave.playerName,
            wasKicked: !!s.recentLeave.kickedBy,
          });
          playerLeftTimeout.current = setTimeout(() => setPlayerLeftNotif(null), 5000);
        }
      }

      setSession(s);
      firstLoadDone.current = true;

      if (s.state === "lobby") navigate("/lobby");

      // ─ Redirection globale quand le gagnant quitte ─
      // Si la partie est terminée et qu'il ne reste plus qu'un seul joueur dans la session
      // (le gagnant a quitté), les spectateurs encore connectés sont redirigés au menu.
      if (s.state === "finished") {
        // Calculer le gagnant côté client : dernier joueur actif (non-éliminé)
        const activeInFinished = s.players.filter(
          (p: { id: string }) => !(s.eliminatedPlayers ?? []).includes(p.id)
        );
        // Si le gagnant n'est plus dans la session et que je ne suis pas le gagnant
        if (activeInFinished.length === 0 && !s.players.some((p: { id: string }) => p.id === playerId)) {
          // Je suis un spectateur et la session est vide — retour au menu
          mpStorage.clear();
          navigate("/");
          return;
        }
      }

      // ─ Dernier joueur restant = gagnant automatique ─
      // Si la partie est en cours et qu'il ne reste qu'un seul joueur non-éliminé,
      // ce joueur est déclaré gagnant côté client (les autres ont tous quitté).
      if (s.state === "playing") {
        const activePlayers = s.players.filter(
          (p: { id: string }) => !(s.eliminatedPlayers ?? []).includes(p.id)
        );
        if (activePlayers.length === 1 && activePlayers[0].id === playerId) {
          // Je suis le dernier joueur restant — victoire automatique côté client
          setSession({ ...s, state: "finished" });
          return;
        }
      }
    } catch (e: any) {
      if (e.message?.includes("introuvable") || e.message?.includes("expirée")) {
        // Protection : attendre 3 erreurs consécutives avant de naviguer
        // (évite les redirections sur erreur réseau temporaire ou timeout Supabase)
        sessionNotFoundCount.current += 1;
        if (sessionNotFoundCount.current >= 3) {
          mpStorage.clear();
          navigate("/");
        } else {
          setError("Connexion instable…");
        }
      } else {
        networkErrorCount.current += 1;
        setError("Connexion instable…");
      }
    }
  }, [code, isMyTurn, navigate, triggerTurnNotif]);

  useEffect(() => {
    fetchSession();
    pollRef.current = setInterval(fetchSession, POLL_INTERVAL);
    return () => {
      if (pollRef.current)  clearInterval(pollRef.current);
      if (notifTimeout.current) clearTimeout(notifTimeout.current);
      if (elimTimeout.current)  clearTimeout(elimTimeout.current);
      if (playerLeftTimeout.current) clearTimeout(playerLeftTimeout.current);
    };
  }, [fetchSession]);

  // ── Polling mini-jeu pour les spectateurs ───────────────────────────────────
  // Interroge getActive toutes les 500ms pour détecter un mini-jeu déclenché par un autre joueur
  // Utilise trpcUtils.fetch() au lieu de raw fetch pour gérer automatiquement superjson
  const fetchActiveMiniGame = useCallback(async () => {
    if (!code || miniGameMode !== null) return; // Déjà en train de jouer un mini-jeu
    if (miniGameAlertPhase !== null) return; // Déjà en phase d'alerte
    if (waitingForAllPlayers) return; // Déjà en attente des résultats — ne pas redéclencher
    if (miniGameResultsData !== null) return; // Résultats en cours d'affichage — ne pas redéclencher
    try {
      const event = await trpcUtils.miniGame.getActive.fetch({ sessionCode: code }, { staleTime: 0 });
      if (event && event.id !== lastMiniGameId.current && !resolvedMiniGameIds.current.has(event.id)) {
        lastMiniGameId.current = event.id;
        setMiniGameEventId(event.id);
        setMiniGameTriggeredBy(event.triggeredBy ?? null);
        miniGameTriggeredByRef.current = event.triggeredBy ?? null;
        setPendingMiniGameMode(event.mode);
        // Utiliser le totalPlayers stocké dans l'event en DB (source de vérité définie par le déclencheur)
        setMiniGameTotalPlayers(event.totalPlayers ?? 1);
        // Fermer toute notification en cours pour laisser place à la perquisition
        setShowReceivedTicketNotif(null);
        showNotifRef.current = false;
        setShowNotif(false);
        // Son d'alerte + vibration pour prévenir le joueur
        triggerPerquisitionAlert();
        // Si c'est mon tour et que je suis le déclencheur, marquer que la pioche est remplacée
        if (event.triggeredBy === playerId) {
          setMiniGameSkippedDraw(true);
          miniGameSkippedDrawRef.current = true;
        }
        // Afficher le message commun ("Prêt à t'enfuir/te cacher ?") + bouton "COMMENCER"
        setMiniGameAlertPhase("common-alert");
      }
    } catch (e) {
      // Silencieux — le polling réessaiera
    }
  }, [code, miniGameMode, miniGameAlertPhase, waitingForAllPlayers, miniGameResultsData, trpcUtils]);
  
  // Mettre à jour la ref avec la version la plus récente de fetchActiveMiniGame
  useEffect(() => {
    fetchActiveMiniGameRef.current = fetchActiveMiniGame;
  }, [fetchActiveMiniGame]);

  // Initialiser et gérer le polling du mini-jeu — utiliser useEffect avec dépendances minimales
  useEffect(() => {
    // Appel immédiat pour détection rapide
    fetchActiveMiniGameRef.current();
    // Polling toutes les 250ms — appelle toujours la version la plus récente via la Ref
    miniGamePollRef.current = setInterval(() => {
      fetchActiveMiniGameRef.current();
    }, 250);
    return () => {
      if (miniGamePollRef.current) clearInterval(miniGamePollRef.current);
    };
  }, []);

  // ── Polling du statut de la Perquisition (piocheur attend tous les joueurs) ──
  // Ref pour tracker si on a déjà ajouté les résultats à l'historique (éviter les doublons)
  const miniGameHistoryProcessedRef = useRef<Set<number>>(new Set());
  // Ref pour tracker si on a déjà appliqué la dette (éviter les appels multiples à addDebt)
  const miniGameDebtAppliedRef = useRef<Set<number>>(new Set());
  // Verrou synchrone pour éviter la race condition : deux appels async simultanés qui passent
  // tous les deux la garde has() avant que le premier ait terminé son addDebt
  const miniGameDebtLockRef = useRef<boolean>(false);
  
  const fetchMiniGameStatus = useCallback(async () => {
    if (!code || !waitingForAllPlayers || miniGameEventId === null || miniGameTotalPlayers === 0) return;
    try {
      const status = await trpcUtils.miniGame.getStatus.fetch({ sessionCode: code, eventId: miniGameEventId, totalPlayers: miniGameTotalPlayers }, { staleTime: 0 });
      if (status?.allDone) {
        // Stopper le polling de statut immédiatement pour éviter les doubles appels
        if (miniGameStatusPollRef.current) {
          clearInterval(miniGameStatusPollRef.current);
          miniGameStatusPollRef.current = null;
        }
        // Tous ont terminé : résoudre et afficher les résultats
        setWaitingForAllPlayers(false);
        setMiniGameResultsData(status.results);

        // ── CORRECTION BUG DETTE ──
        // Problème : avec 10 joueurs, chaque joueur appelait addDebt pour lui-même simultanément.
        // Supabase fait un UPDATE JSON non-atomique : les écritures simultanées s'écrasent mutuellement.
        // Solution : SEUL le piocheur (déclencheur) applique les dettes de TOUS les joueurs
        // séquentiellement (un par un), garantissant qu'il n'y a jamais de race condition.
        // Les autres joueurs ne font rien ici : leur dette sera visible via le polling de session.
        if (status.results && session) {
          // Utiliser la ref pour éviter les problèmes de closure (miniGameTriggeredBy peut être null dans la closure)
          const isDrawer = (miniGameTriggeredByRef.current ?? miniGameTriggeredBy) === playerId;
          if (isDrawer && !miniGameDebtAppliedRef.current.has(miniGameEventId) && !miniGameDebtLockRef.current) {
            // Poser le verrou IMMEDÍATEMENT (synchrone) avant tout await
            miniGameDebtLockRef.current = true;
            miniGameDebtAppliedRef.current.add(miniGameEventId);
            try {
              // Appliquer les dettes de TOUS les joueurs séquentiellement (pas en parallèle)
              // pour éviter les race conditions sur le JSON Supabase
              let updatedSession = session;
              for (const r of status.results as { playerId: string; success: boolean; amount: number }[]) {
                const delta = r.success ? -r.amount : r.amount;
                try {
                  const res = await addDebt(code, playerId, r.playerId, delta, 0);
                  updatedSession = res.session;
                  // Vérifier l'élimination après chaque dette positive (augmentation)
                  if (delta > 0) {
                    const targetPlayer = updatedSession.players.find((p: { id: string; name: string }) => p.id === r.playerId);
                    if (targetPlayer) {
                      updatedSession = await checkAndEliminate(updatedSession, r.playerId, targetPlayer.name);
                    }
                  }
                } catch (e) {
                  // Silencieux pour ce joueur, continuer avec les suivants
                }
              }
              setSession(updatedSession);
            } catch (e) {
              // Silencieux
            }
            // Libérer le verrou après tous les appels
            miniGameDebtLockRef.current = false;
          }
          // Les non-piocheurs : pas d'appel addDebt ici.
          // Leur dette sera mise à jour via le polling fetchSession (toutes les 2s).
          // Ajouter les résultats à l'historique SEULEMENT si on ne l'a pas déjà fait
          if (!miniGameHistoryProcessedRef.current.has(miniGameEventId)) {
            miniGameHistoryProcessedRef.current.add(miniGameEventId);
            
            const myResult = status.results.find((r: { playerId: string; success: boolean; amount: number }) => r.playerId === playerId);
            if (myResult) {
              const turnLabel = `Tour ${session.drawn.length}`;
              setMiniGameHistory(prev => [...prev, { success: myResult.success, amount: myResult.amount, turnLabel }]);
            }
            // Alimenter l'historique de groupe
            const triggererPlayer = session.players.find((p: { id: string; name: string }) => p.id === miniGameTriggeredBy);
            const groupResults = status.results.map((r: { playerId: string; success: boolean; amount: number }) => {
              const p = session.players.find((pl: { id: string; name: string }) => pl.id === r.playerId);
              return { playerName: p?.name ?? r.playerId, success: r.success, amount: r.amount };
            });
            setGroupMiniGameHistory(prev => [...prev, {
              triggeredByName: triggererPlayer?.name ?? "?",
              results: groupResults,
              timestamp: Date.now(),
              // Stocker l'index de tirage au moment de la perquisition pour l'ordre chronologique
              drawnIndex: session.drawn.length,
            }]);
          }
        }
        // Marquer l'événement comme résolu et l'ajouter aux IDs résolus pour bloquer fetchActiveMiniGame
        if (miniGameEventId !== null) resolvedMiniGameIds.current.add(miniGameEventId);
        resolveMiniGame.mutateAsync({ sessionCode: code, eventId: miniGameEventId }).catch(() => {});
        setMiniGameEventId(null);
        // miniGameSkippedDraw reste true pour que le bouton "TERMINER MON TOUR" soit disponible
        // Fermer les résultats après 2s SEULEMENT pour les spectateurs (pas pour le piocheur)
        // Le piocheur doit cliquer le bouton TERMINER MON TOUR pour fermer l'overlay
        const isDrawerPlayer = session?.turnOrder[session?.currentTurnIndex] === playerId;
        if (!isDrawerPlayer) {
          setTimeout(() => setMiniGameResultsData(null), 2000);
        }
      }
    } catch (e) {
      // Silencieux
    }
  }, [code, waitingForAllPlayers, miniGameEventId, miniGameTotalPlayers, resolveMiniGame, session, playerId, miniGameTriggeredBy, trpcUtils]);
  useEffect(() => {
    if (!waitingForAllPlayers) return;
    // Appel immédiat pour éviter d'attendre 200ms
    fetchMiniGameStatus();
    miniGameStatusPollRef.current = setInterval(() => fetchMiniGameStatusRef.current(), 200);
    return () => {
      if (miniGameStatusPollRef.current) clearInterval(miniGameStatusPollRef.current);
    };
  }, [waitingForAllPlayers]); // CORRECTION : Dépendance minimale pour éviter la réinitialisation du polling

  // Mettre à jour la ref avec la version la plus récente de fetchMiniGameStatus
  useEffect(() => {
    fetchMiniGameStatusRef.current = fetchMiniGameStatus;
  }, [fetchMiniGameStatus]);

  // ── Auto-fermeture de la notif spectateur T3 ──────────────
  // Se ferme quand l'envoyeur termine son tour (currentTurnIndex change)
  useEffect(() => {
    if (!showT3SpectatorNotif || !session) return;
    const { senderId } = showT3SpectatorNotif;
    const senderNoLongerCurrent = session.turnOrder[session.currentTurnIndex] !== senderId;
    if (senderNoLongerCurrent) {
      setShowT3SpectatorNotif(null);
    }
  }, [session, showT3SpectatorNotif]);

  // ── Vérifier l'élimination après draw ou addDebt ──────────
  const checkAndEliminate = useCallback(async (
    s: Session,
    targetId: string,
    targetName: string,
  ): Promise<Session> => {
    const cards = s.playerCards?.[targetId] ?? [];
    const debt  = s.playerDebts?.[targetId] ?? 0;
    // playerDebts contient déjà tous les deltas (cartes T3 + perquisitions via addDebt)
    const total = computePlayerTotalMp(cards) + debt;

    // Lire le seuil depuis la session (dynamique selon la difficulté choisie)
    const sessionThreshold = s.eliminationThreshold ?? DEFAULT_ELIMINATION_THRESHOLD;
    const alreadyElim = (s.eliminatedPlayers ?? []).includes(targetId);
    if (!alreadyElim && total >= sessionThreshold) {
      try {
        const { session: sElim } = await eliminatePlayer(code, targetId);
        // Le polling détectera pendingEliminationAck et affichera les overlays
        setJustEliminated(targetName); // petit flash court pour les spectateurs non-paused
        if (elimTimeout.current) clearTimeout(elimTimeout.current);
        elimTimeout.current = setTimeout(() => setJustEliminated(null), 1800);
        return sElim;
      } catch (e) {
        console.error("Erreur élimination:", e);
      }
    }
    return s;
  }, [code]);

  // ──  // ── Piocher ───────────────────────────────────────
  const handleDraw = async () => {
    if (!session || isDrawing || !isMyTurn(session)) return;
    const isEliminated = (session.eliminatedPlayers ?? []).includes(playerId);
    if (isEliminated) return;
    // Note: miniGameSkippedDraw est réinitialisé avant d'appeler drawCard depuis l'overlay des résultats

    // ── VÉRIFIER SI UNE PERQUISITION DOIT APPARAÎTRE ──
    // Priorité : sessionOptionsQuery (notre DB) > session Supabase > localStorage > défaut
    // Supabase ne retourne pas miniGameEnabled/miniGameLevel, donc on utilise notre DB comme source de vérité
    const miniGameEnabledCheck = sessionMiniGameEnabled !== null
      ? sessionMiniGameEnabled
      : (session.miniGameEnabled !== false); // défaut: activé

    if (miniGameEnabledCheck) {
      // Lire le niveau depuis notre DB, sinon depuis localStorage (fallback)
      let miniGameLevel: MiniGameLevel = sessionMiniGameLevel ?? 1;
      if (!sessionMiniGameLevel) {
        try {
          const stored = localStorage.getItem(SOLO_MINI_GAME_LEVEL_KEY);
          if (stored) miniGameLevel = (parseInt(stored, 10) as MiniGameLevel) || 1;
        } catch { /* ignore */ }
      }
      const { triggered, mode } = rollMiniGame(miniGameLevel, drawsSinceLastMiniGameRef.current);
      
      if (triggered) {
        // Réinitialiser le compteur de tirages
        drawsSinceLastMiniGameRef.current = 0;
        setMiniGameSkippedDraw(true); // Bloquer la pioche
        miniGameSkippedDrawRef.current = true; // Ref miroir pour handleEndTurn
        // Étape 1 : Afficher le message d'alerte au piocheur ("le groupe va devoir se sauver")
        setPendingMiniGameMode(mode);
        setMiniGameAlertPhase("trigger-alert");
        return;
      }
      // Incrémenter le compteur de tirages sans perquisition
      drawsSinceLastMiniGameRef.current++;
    }

    // ── PIOCHE NORMALE (pas de perquisition) ──
    setIsDrawing(true);
    showNotifRef.current = false;
    setShowNotif(false);
    setShowCardFront(false); // Montrer le dos en premier (comme en solo)
    try {
      let s = (await drawCard(code, playerId)).session;
      setSession(s);
      prevTurnIdx.current  = s.currentTurnIndex;
      prevLastCard.current = s.lastCard;
      setShowCard(false);
      setTimeout(() => {
        setShowCard(true);
        // Retourner la carte face visible après l'animation d'entrée (350ms)
        setTimeout(() => setShowCardFront(true), 320);
      }, 50);

      // ─ Vérifier l'élimination IMMÉDIATEMENT après la pioche ─
      // Si le joueur dépasse la limite avec cette carte, il est éliminé sans attendre handleEndTurn.
      s = await checkAndEliminate(s, playerId, playerName);
      setSession(s);
      // Si le joueur vient d'être éliminé, on ne continue pas (pendingEliminationAck prend le relais)
      if ((s.eliminatedPlayers ?? []).includes(playerId)) {
        return;
      }

      // Carte Type 3 : préparer l'envoi manuel (via bouton "Envoyer le ticket")
      if (s.lastCard !== null && s.turnOrder.length > 1 && s.state === "playing") {
        const cfg     = getCardConfigMp(s.lastCard);
        const nextAmt = nextPlayerAmount(cfg);
        if (nextAmt > 0) {
          const nextPlayerId = getNextActivePlayerId(s, playerId);
          if (nextPlayerId) {
            const nextPlayer = s.players.find((p) => p.id === nextPlayerId);
            setPendingT3({
              nextPlayerId,
              nextAmt,
              taxAmt: cfg.taxe ?? 0,
              totalRefund: nextAmt, // Le remboursement total = nextAmt (prix + taxe)
              nextPlayerName: nextPlayer?.name ?? "joueur suivant",
            });
          }
        }
      }
    } catch (e: any) {
      setError(e.message ?? "Erreur lors du tirage");
      } finally {
        setIsDrawing(false);
      }
  };

  // ── Ouvrir le modal de sélection du destinataire T3 ────
  const handleSendT3 = () => {
    if (!pendingT3 || isSendingT3) return;
    setShowT3TargetModal(true);
  };

  // ── Envoyer le ticket T3 au joueur choisi ────
  const handleConfirmT3Target = async (targetPlayerId: string) => {
    if (!pendingT3 || !session || isSendingT3) return;
    setShowT3TargetModal(false);
    setIsSendingT3(true);
    const { nextAmt } = pendingT3;
    try {
      let s2 = (await addDebt(code, playerId, targetPlayerId, nextAmt, session.lastCard!)).session;
      setSession(s2);
      setPendingT3(null);

      // ─ Vérifier l'élimination du destinataire T3 immédiatement après l'envoi ─
      const t3Target = s2.players.find((p: any) => p.id === targetPlayerId);
      if (t3Target) {
        s2 = await checkAndEliminate(s2, targetPlayerId, t3Target.name);
        setSession(s2);
      }

      // Afficher la notification de remboursement pour le piocheur (toujours, même si taxe=0)
      const { totalRefund } = pendingT3;
      setShowTaxNotif({ amount: totalRefund });
    } catch (e: any) {
      setError(e.message ?? "Erreur lors de l'envoi du ticket");
    } finally {
      setIsSendingT3(false);
    }
  };
  // ── Terminer le tour ────────────────────────────────────────
  // L'élimination est vérifiée ICI (après que le joueur a lu sa carte)
  // et non pas immédiatement après la pioche.
  const handleEndTurn = async () => {
    if (!session || isEndingTurn) return;
    
    // Vérifier que le joueur a bien pioché (après perquisition, drawCard est appelé depuis l'overlay)
    if (!hasDrawnThisTurn) {
      setError("Vous devez piocher une carte avant de terminer votre tour");
      return;
    }
    
    setIsEndingTurn(true);
    try {
      // Vérifier l'élimination du joueur AVANT de terminer le tour
      // Cela garantit que le joueur a eu le temps de lire sa carte
      let currentSession = session;
      currentSession = await checkAndEliminate(currentSession, playerId, playerName);
      setSession(currentSession);

      // Vérifier aussi l'élimination du destinataire T3 s'il y en avait un
      if (currentSession.lastCard !== null) {
        const lastCfg = getCardConfigMp(currentSession.lastCard);
        if (lastCfg.cardType === 3 && currentSession.lastCardDrawnBy === playerId) {
          const t3TargetId = getNextActivePlayerId(currentSession, playerId);
          if (t3TargetId) {
            const t3Target = currentSession.players.find((p) => p.id === t3TargetId);
            if (t3Target) {
              currentSession = await checkAndEliminate(currentSession, t3TargetId, t3Target.name);
              setSession(currentSession);
            }
          }
        }
      }

      // Si le joueur vient d'être éliminé, ne pas terminer le tour
      // (le système de pendingEliminationAck prend le relais)
      const justElim = (currentSession.eliminatedPlayers ?? []).includes(playerId);
      if (justElim) {
        setIsEndingTurn(false);
        return;
      }

      const { session: s } = await endTurn(code, playerId);
      // Mettre à jour la bulle immédiatement pour le joueur courant
      if (s.lastCard !== null && s.lastCardDrawnBy) {
        const prevPlayer = s.players.find((p) => p.id === s.lastCardDrawnBy);
        if (prevPlayer) setBubbleCard({ cardNum: s.lastCard, playerName: prevPlayer.name, playerId: prevPlayer.id });
      }
      // Mettre à jour prevTurnIdx AVANT triggerTurnNotif pour que le prochain poll ne redéclenche pas
      prevTurnIdx.current = s.currentTurnIndex;
      setSession(s);
      // Réinitialiser le flag de perquisition après la fin du tour
      setMiniGameSkippedDraw(false);
      miniGameSkippedDrawRef.current = false; // Ref miroir
      // Afficher la notif "Tour de [suivant]" — forceAutoClose=true car ce n'est plus mon tour
      if (s.state === "playing") {
        triggerTurnNotif(s, true);
      }
    } catch (e: any) {
      setError(e.message ?? "Erreur fin de tour");
    } finally {
      setIsEndingTurn(false);
    }
  };

  // ── Fin de tour PERQUISITION — Fonction séparée, PRIORITÉ ABSOLUE ──────────
  // Cette fonction est TOTALEMENT indépendante de handleEndTurn.
  // Elle n'a AUCUNE garde : pas de hasDrawnThisTurn, pas de checkAndEliminate,
  // pas de pendingAck, pas de showTaxNotif, pas de miniGameSkippedDraw check.
  // Elle appelle endTurn() directement et passe le tour au joueur suivant.
  const forceEndTurnPerquisition = async () => {
    // Double-protection via ref pour éviter les appels multiples
    if (isEndingTurnPerquisitionRef.current) return;
    if (!session) return;
    isEndingTurnPerquisitionRef.current = true;
    setIsEndingTurnPerquisition(true);
    try {
      // 1. Fermer immédiatement l'overlay des résultats
      setMiniGameResultsData(null);
      // 2. Appel DIRECT à endTurn — aucune vérification d'élimination, aucune garde
      const { session: s } = await endTurn(code, playerId);
      // 3. Mettre à jour la bulle de carte précédente
      if (s.lastCard !== null && s.lastCardDrawnBy) {
        const prevPlayer = s.players.find((p: any) => p.id === s.lastCardDrawnBy);
        if (prevPlayer) setBubbleCard({ cardNum: s.lastCard, playerName: prevPlayer.name, playerId: prevPlayer.id });
      }
      // 4. Mettre à jour prevTurnIdx AVANT triggerTurnNotif
      prevTurnIdx.current = s.currentTurnIndex;
      setSession(s);
      // 5. Réinitialiser TOUS les états de perquisition
      setMiniGameSkippedDraw(false);
      miniGameSkippedDrawRef.current = false;
      setWaitingForAllPlayers(false);
      setMiniGameAlertPhase(null);
      setPendingMiniGameMode(null);
      setMiniGameMode(null);
      resolvedMiniGameIds.current.clear();
      // 6. Afficher la notif "Tour de [suivant]"
      if (s.state === "playing") {
        triggerTurnNotif(s, true);
      }
    } catch (e: any) {
      setError(e.message ?? "Erreur fin de tour (perquisition)");
    } finally {
      isEndingTurnPerquisitionRef.current = false;
      setIsEndingTurnPerquisition(false);
    }
  };

  // ── Mélanger (host) ───────────────────────────────────
  const handleReset = async () => {
    if (!isHost || isResetting) return;
    setIsResetting(true);
    try {
      const { session: s } = await resetGame(code, playerId);
      // Forcer la réintégration des éliminés et la remise à zéro des dettes côté client
      // (le serveur Supabase peut ne pas vider ces champs selon sa version)
      const resetSession = {
        ...s,
        eliminatedPlayers: [],
        pendingEliminationAck: [],
        playerCards: Object.fromEntries(s.turnOrder.map((pid: string) => [pid, []])),
        playerDebts: Object.fromEntries(s.turnOrder.map((pid: string) => [pid, 0])),
        playerReceivedCards: Object.fromEntries(s.turnOrder.map((pid: string) => [pid, []])),
        lastCard: null,
        lastCardDrawnBy: null,
      };
      setSession(resetSession);
      prevTurnIdx.current  = s.currentTurnIndex;
      prevLastCard.current = s.lastCard;
      firstLoadDone.current = false; // Éviter la notif immédiate
      lastNotifTurnIdx.current = -1;
      showNotifRef.current = false;
      setShowNotif(false);
      setNotifMountKey(0);
      setJustEliminated(null);
      setBubbleCard(null);
      setShowPrevCard(false);
      setShowCardFront(true);
      setShowConfirmReset(false);
      setPendingT3(null);
      setShowTaxNotif(null);
      setShowReceivedTicketNotif(null);
      setShowT3SpectatorNotif(null);
      setShowMyEliminationOverlay(false);
      setMiniGameTriggeredBy(null);
      miniGameTriggeredByRef.current = null;
      setWaitingForAllPlayers(false);
      setMiniGameMode(null);
      setMiniGameEventId(null);
      setMiniGameSkippedDraw(false);
      miniGameSkippedDrawRef.current = false; // Ref miroir
      setMiniGameResultsData(null); // Reset overlay résultats perquisition
      setIsEndingTurnPerquisition(false);
      isEndingTurnPerquisitionRef.current = false;
      setMiniGameHistory([]);
      setGroupMiniGameHistory([]);
      prevPendingAck.current = [];
      // Réinitialiser les guards de stats/badges pour la nouvelle partie
      statsRecordedRef.current = false;
      badgesRecordedRef.current = false;
    } catch (e: any) {
      setError(e.message ?? "Erreur mélange");
    } finally {
      setIsResetting(false);
    }
  };

  // ── Expulser un joueur (host) ────────────────────────────
  const handleKick = async (targetId: string) => {
    if (!isHost || isKicking) return;
    setIsKicking(true);
    try {
      const { session: s } = await kickPlayer(code, playerId, targetId);
      setSession(s);
      setShowKickModal(false);
    } catch (e: any) {
      setError(e.message ?? "Erreur expulsion");
    } finally {
      setIsKicking(false);
    }
  };

  // ── Quitter ─────────────────────────────────────────────
  const handleLeave = async () => {
    try { await leaveSession(code, playerId); } catch {}
    mpStorage.clear();
    navigate("/");
  };

  // ── Confirmer l'élimination (devient spectateur) ─────────
  const handleAcknowledge = async () => {
    if (isAcknowledging) return;
    setIsAcknowledging(true);
    try {
      const { session: s } = await acknowledgeElimination(code, playerId);
      setSession(s);
      setShowMyEliminationOverlay(false);
      prevPendingAck.current = s.pendingEliminationAck ?? [];
    } catch (e: any) {
      setError(e.message ?? "Erreur confirmation");
    } finally {
      setIsAcknowledging(false);
    }
  };

  // ─ Enregistrer le résultat de la partie multi (une seule fois) ─
  // NOTE: Ce useEffect DOIT être avant le guard if (!session) pour respecter les règles des hooks React
  useEffect(() => {
    if (!session || !isAuthenticated || statsRecordedRef.current) return;
    const _isFinished = session.state === "finished";
    const _pendingAck = session.pendingEliminationAck ?? [];
    if (!_isFinished || _pendingAck.length > 0) return;
    const _eliminated = session.eliminatedPlayers ?? [];
    const _amEliminated = _eliminated.includes(playerId);
    const _myCards: number[] = session.playerCards?.[playerId] ?? [];
    const _myReceivedDebt: number = session.playerDebts?.[playerId] ?? 0;
    const _myTotal = computePlayerTotalMp(_myCards) + _myReceivedDebt;
    const _playerTotals = session.turnOrder.map((pid: string) => ({
      pid,
      total: computePlayerTotalMp(session.playerCards?.[pid] ?? []) + (session.playerDebts?.[pid] ?? 0),
    }));
    const _activePlayers = _playerTotals.filter((t: { pid: string; total: number }) => !_eliminated.includes(t.pid));
    const _winner = _isFinished && _activePlayers.length === 1
      ? session.players.find((p: { id: string }) => p.id === _activePlayers[0]?.pid)
      : null;
    const _isDraw = _isFinished && _activePlayers.length > 1;
    statsRecordedRef.current = true;
    const isWinner = _winner != null && _winner.id === playerId;
    const isLoser = _amEliminated || (_isDraw ? false : _winner != null && _winner.id !== playerId);
    if (isWinner) {
      recordResultMutation.mutate({ mode: "multi", result: "win", finalDebt: _myTotal, cardsDrawn: _myCards.length });
    } else if (isLoser) {
      recordResultMutation.mutate({ mode: "multi", result: "loss", finalDebt: _myTotal, cardsDrawn: _myCards.length });
    }
  }, [session, isAuthenticated, playerId, recordResultMutation]);

  // ─ Enregistrer la fin de partie pour les badges (TOUS les joueurs) ─
  // Chaque joueur enregistre ses propres stats et débloquer ses badges
  // quand la partie se termine réellement (victoire ou élimination).
  useEffect(() => {
    if (!session || !isAuthenticated || badgesRecordedRef.current) return;
    const _isFinished = session.state === "finished";
    const _pendingAck = session.pendingEliminationAck ?? [];
    if (!_isFinished || _pendingAck.length > 0) return;
    const _eliminated = session.eliminatedPlayers ?? [];
    const _myCards: number[] = session.playerCards?.[playerId] ?? [];
    const _myReceivedDebt: number = session.playerDebts?.[playerId] ?? 0;
    const _myTotal = computePlayerTotalMp(_myCards) + _myReceivedDebt;
    const _playerTotals = session.turnOrder.map((pid: string) => ({
      pid,
      total: computePlayerTotalMp(session.playerCards?.[pid] ?? []) + (session.playerDebts?.[pid] ?? 0),
    }));
    const _activePlayers = _playerTotals.filter((t: { pid: string; total: number }) => !_eliminated.includes(t.pid));
    const _winner = _isFinished && _activePlayers.length === 1
      ? session.players.find((p: { id: string }) => p.id === _activePlayers[0]?.pid)
      : null;
    const _amEliminated = _eliminated.includes(playerId);
    const _isDraw = _isFinished && _activePlayers.length > 1;
    badgesRecordedRef.current = true;
    const isWinner = _winner != null && _winner.id === playerId;
    const isLoser = _amEliminated || (_isDraw ? false : _winner != null && _winner.id !== playerId);
    const result = isWinner ? "win" : isLoser ? "loss" : "draw";
    // Calculer les compteurs par type de carte piochée par le host
    let contrventionsDrawn = 0;
    let contribuablesDrawn = 0;
    let investisseursDrawn = 0;
    for (const cardId of _myCards) {
      const cfg = getCardConfigMp(cardId);
      if (cfg.category === "contravention") contrventionsDrawn++;
      else if (cfg.category === "contribuable") contribuablesDrawn++;
      else if (cfg.category === "investisseur") investisseursDrawn++;
    }
    endGameMutation.mutate({
      mode: "multi",
      result,
      finalDebt: _myTotal,
      cardsDrawn: _myCards.length,
      contrventionsDrawn,
      contribuablesDrawn,
      investisseursDrawn,
    });
  }, [session, isAuthenticated, isHost, playerId, endGameMutation]);

  // ── Calculs dérivés mémoïsés — DOIVENT être avant tout return conditionnel (règles des hooks) ──
  // Mémoïser pour éviter les recalculs à chaque render (hot path en multijoueur 10 joueurs)
  const playerTotals = useMemo(() => (session?.turnOrder ?? []).map((pid) => ({
    pid,
    total: computePlayerTotalMp(session?.playerCards?.[pid] ?? []) + (session?.playerDebts?.[pid] ?? 0),
  })), [session?.turnOrder, session?.playerCards, session?.playerDebts]);
  const eliminatedForMemo = session?.eliminatedPlayers ?? [];
  const minTotal = useMemo(() => {
    const active = playerTotals.filter(t => !eliminatedForMemo.includes(t.pid));
    if (active.length === 0) return 0;
    return Math.min(...active.map(t => t.total));
  }, [playerTotals, eliminatedForMemo]);

  // ── Rendu de chargement ──────────────────────────────────
  if (!session) {
    return (
      <div className="h-[100dvh] max-w-md md:max-w-lg lg:max-w-xl mx-auto flex flex-col items-center justify-center gap-4"
        style={{ background: "linear-gradient(160deg, #0c1a4e 0%, #1a083d 100%)" }}>
        <motion.div animate={{ rotate: [-10, 10, -10], scale: [1, 1.1, 1] }} transition={{ duration: 1.5, repeat: Infinity }}>
          <img src={ticketImg} alt="" style={{ width: "5rem" }} />
        </motion.div>
        <span style={FONT_FREDOKA} className="text-white/50 text-sm">Connexion à la session…</span>
        {error && <span style={FONT_FREDOKA} className="text-red-400 text-sm">{error}</span>}
      </div>
    );
  }

  const ELIMINATION_THRESHOLD = session.eliminationThreshold ?? DEFAULT_ELIMINATION_THRESHOLD;
  const disabledCardTypes: number[] = session.disabledCardTypes ?? [];

  const myTurn        = isMyTurn(session);
  const amEliminated  = (session.eliminatedPlayers ?? []).includes(playerId);
  const currentPlayer = session.players.find((p) => p.id === session.turnOrder[session.currentTurnIndex]);
  const remaining     = session.deck.length;
  const drawnCount    = session.drawn.length;
  const isFinished    = session.state === "finished";
  // Taille réelle du deck (filtrée selon les préférences de la session)
  const deckTotal     = (remaining + drawnCount) || (session.allowedCardIds?.length ?? TOTAL_CARDS);
  const lastCardBy    = session.players.find((p) => p.id === session.lastCardDrawnBy);

  const myCards:          number[] = session.playerCards?.[playerId] ?? [];
  const myReceivedDebt:   number   = session.playerDebts?.[playerId] ?? 0;
  const myReceivedCards:  number[] = session.playerReceivedCards?.[playerId] ?? [];

  // Vrai si le joueur actif a déjà pioché sa carte ce tour
  const hasDrawnThisTurn      = myTurn && session.lastCardDrawnBy === playerId;
  // Vrai si le joueur dont c'est le tour a pioché (utile pour les autres)
  // FIX: Vérifier aussi que lastCard n'est pas null (sinon affichage buggé)
  const currentPlayerHasDrawn = session.lastCard !== null && session.lastCardDrawnBy === session.turnOrder[session.currentTurnIndex];

  // Calcul des totaux pour le classement.
  // session.playerDebts[pid] contient DÉJÀ les deltas de perquisitions (via addDebt serveur Supabase).
  // Ne pas recalculer les perquisitions ici pour éviter le doublon.
  // playerTotals et minTotal sont déjà calculés avant le return conditionnel (voir ci-dessus).
  const eliminated = session.eliminatedPlayers ?? [];

  // Vainqueur : dernier actif si jeu fini, ou joueur avec la dette la plus faible
  const activePlayers = playerTotals.filter(t => !eliminated.includes(t.pid));

  // ─ T3 : identifier si la carte courante est un investisseur et qui est le receveur ─
  const lastCardIsT3 = session.lastCard !== null && currentPlayerHasDrawn && getCardConfigMp(session.lastCard).cardType === 3;
  const t3ReceiverId = lastCardIsT3 && session.lastCardDrawnBy
    ? getNextActivePlayerId(session, session.lastCardDrawnBy)
    : null;
  // Je ne suis ni l'envoyeur ni le receveur → spectateur T3
  const isT3Spectator = lastCardIsT3 && session.lastCardDrawnBy !== playerId && t3ReceiverId !== playerId;
  const winner = isFinished && activePlayers.length === 1
    ? session.players.find((p) => p.id === activePlayers[0]?.pid)
    : null;
  // Match nul : partie terminée avec plusieurs joueurs encore en jeu (deck épuisé)
  const isDraw = isFinished && activePlayers.length > 1;

  // Pause élimination : autres joueurs en attente
  const pendingAck = session.pendingEliminationAck ?? [];
  const gamePausedFor = !amEliminated && pendingAck.length > 0
    ? session.players.find(p => p.id === pendingAck[0])
    : null;
  // Dette totale du joueur en attente d'élimination (pour la notif des autres)
  const gamePausedForTotal = gamePausedFor
    ? computePlayerTotalMp(session.playerCards?.[gamePausedFor.id] ?? []) + (session.playerDebts?.[gamePausedFor.id] ?? 0)
    : 0;

  // Total pour l'overlay d'élimination du joueur local
  const myTotal = computePlayerTotalMp(myCards) + myReceivedDebt;

  return (
    <div
      className="h-[100dvh] w-full md:max-w-none mx-auto flex flex-col overflow-hidden select-none relative"
      style={{ background: "linear-gradient(160deg, #0c1a4e 0%, #1a083d 60%, #0c1a4e 100%)", paddingBottom: "env(safe-area-inset-bottom, 0px)" }}
    >
      {/* ── Halos de police — coins ── */}
      <motion.div className="absolute pointer-events-none z-0" style={{ top: -60, left: -60, width: 220, height: 220, borderRadius: "50%" }}
        animate={{ background: ["radial-gradient(circle, rgba(255,40,30,0.55) 0%, rgba(255,40,30,0.18) 38%, transparent 68%)","radial-gradient(circle, rgba(255,40,30,0.08) 0%, transparent 55%)","radial-gradient(circle, rgba(0,100,255,0.08) 0%, transparent 55%)","radial-gradient(circle, rgba(0,100,255,0.55) 0%, rgba(0,100,255,0.18) 38%, transparent 68%)","radial-gradient(circle, rgba(255,40,30,0.55) 0%, rgba(255,40,30,0.18) 38%, transparent 68%)"], scale: [1, 1.08, 1.03, 1.08, 1] }}
        transition={{ duration: 1.1, repeat: Infinity, ease: "easeInOut", delay: 0 }} />
      <motion.div className="absolute pointer-events-none z-0" style={{ top: -60, right: -60, width: 220, height: 220, borderRadius: "50%" }}
        animate={{ background: ["radial-gradient(circle, rgba(0,100,255,0.55) 0%, rgba(0,100,255,0.18) 38%, transparent 68%)","radial-gradient(circle, rgba(0,100,255,0.08) 0%, transparent 55%)","radial-gradient(circle, rgba(255,40,30,0.08) 0%, transparent 55%)","radial-gradient(circle, rgba(255,40,30,0.55) 0%, rgba(255,40,30,0.18) 38%, transparent 68%)","radial-gradient(circle, rgba(0,100,255,0.55) 0%, rgba(0,100,255,0.18) 38%, transparent 68%)"], scale: [1, 1.08, 1.03, 1.08, 1] }}
        transition={{ duration: 1.1, repeat: Infinity, ease: "easeInOut", delay: 0.55 }} />
      <motion.div className="absolute pointer-events-none z-0" style={{ bottom: -60, left: -60, width: 200, height: 200, borderRadius: "50%" }}
        animate={{ background: ["radial-gradient(circle, rgba(0,100,255,0.45) 0%, rgba(0,100,255,0.15) 38%, transparent 68%)","radial-gradient(circle, rgba(0,100,255,0.06) 0%, transparent 55%)","radial-gradient(circle, rgba(255,40,30,0.06) 0%, transparent 55%)","radial-gradient(circle, rgba(255,40,30,0.45) 0%, rgba(255,40,30,0.15) 38%, transparent 68%)","radial-gradient(circle, rgba(0,100,255,0.45) 0%, rgba(0,100,255,0.15) 38%, transparent 68%)"] }}
        transition={{ duration: 1.1, repeat: Infinity, ease: "easeInOut", delay: 0.55 }} />
      <motion.div className="absolute pointer-events-none z-0" style={{ bottom: -60, right: -60, width: 200, height: 200, borderRadius: "50%" }}
        animate={{ background: ["radial-gradient(circle, rgba(255,40,30,0.45) 0%, rgba(255,40,30,0.15) 38%, transparent 68%)","radial-gradient(circle, rgba(255,40,30,0.06) 0%, transparent 55%)","radial-gradient(circle, rgba(0,100,255,0.06) 0%, transparent 55%)","radial-gradient(circle, rgba(0,100,255,0.45) 0%, rgba(0,100,255,0.15) 38%, transparent 68%)","radial-gradient(circle, rgba(255,40,30,0.45) 0%, rgba(255,40,30,0.15) 38%, transparent 68%)"] }}
        transition={{ duration: 1.1, repeat: Infinity, ease: "easeInOut", delay: 0 }} />

      {/* ── Page lecteur de musique ── */}
      <AnimatePresence>
        {showMusicPlayer && (
          <MusicPlayerPage onClose={() => setShowMusicPlayer(false)} />
        )}
      </AnimatePresence>

      {/* ── Notification de tour ── */}
      <AnimatePresence>
        {showNotif && !isFinished && (
          <TurnNotification
            key={notifMountKey}
            isMe={myTurn}
            myName={playerName}
            currentName={currentPlayer?.name ?? ""}
            myPlayerId={playerId ?? undefined}
            currentPlayerId={currentPlayer?.id ?? undefined}
            guestEmojis={(guestEmojis as Record<string, string> | undefined) ?? {}}
            myAvatarDisplay={(() => {
              const myProfile = mpPlayerProfiles?.[playerName];
              if (myProfile) return getAvatarDisplay(myProfile.avatarType as "emoji" | "custom", myProfile.avatarId);
              // Résoudre l'emoji invité directement ici (source de vérité = guestEmojis du serveur)
              const myGuestEmoji = playerId ? (guestEmojis as Record<string, string> | undefined)?.[playerId] : null;
              const myLocalEmoji = playerId ? (localStorage.getItem(`mp_guestEmoji_${playerId}`) || sessionStorage.getItem("mp_guestEmoji") || "") : "";
              const myResolved = myGuestEmoji || myLocalEmoji || myEmojiRef.current || "";
              if (myResolved) return { type: "emoji" as const, content: myResolved };
              return null;
            })()}
            currentAvatarDisplay={(() => {
              const cp = currentPlayer;
              if (!cp) return null;
              const cpProfile = mpPlayerProfiles?.[cp.name];
              if (cpProfile) return getAvatarDisplay(cpProfile.avatarType as "emoji" | "custom", cpProfile.avatarId);
              // Résoudre l'emoji invité du joueur actif directement ici
              const cpGuestEmoji = (guestEmojis as Record<string, string> | undefined)?.[cp.id];
              if (cpGuestEmoji) return { type: "emoji" as const, content: cpGuestEmoji };
              return null;
            })()}
            onDismiss={async () => {
              if (notifTimeout.current) clearTimeout(notifTimeout.current);
              showNotifRef.current = false;
              setShowNotif(false);
              // NOTE : Le déclenchement des perquisitions est géré UNIQUEMENT dans handleDraw.
              // Ce chemin (onDismiss "JE COMMENCE") ne déclenche plus de perquisition
              // car handleDraw est appelé juste après la fermeture de la notification.
            }}
          />
        )}
      </AnimatePresence>

      {/* ── Overlay élimination — pour le joueur éliminé ── */}
      <AnimatePresence>
        {showMyEliminationOverlay && (
          <EliminationPauseOverlay
            playerName={playerName}
            total={myTotal}
            threshold={ELIMINATION_THRESHOLD}
            myCardsCount={myCards.length}
            lastCardNum={myCards.length > 0 ? myCards[myCards.length - 1] : null}
            onAcknowledge={handleAcknowledge}
            isAcknowledging={isAcknowledging}
            skinId={mySkinId}
          />
        )}
      </AnimatePresence>

      {/* ── Overlay GAGNANT plein écran ── */}
      <AnimatePresence>
        {isFinished && winner !== null && pendingAck.length === 0 && !showPodium && (
          <WinnerOverlay
            winnerName={winner!.name}
            isMe={winner!.id === playerId}
            totalDebt={playerTotals.find(t => t.pid === winner!.id)?.total ?? 0}
            mode="multi"
            onMenu={() => setShowConfirmLeave(true)}
            avatarDisplay={(() => {
              const wp = mpPlayerProfiles?.[winner!.name];
              return wp ? getAvatarDisplay(wp.avatarType as "emoji" | "custom", wp.avatarId) : undefined;
            })()}
            onShowPodium={() => setShowPodium(true)}
          />
        )}
      </AnimatePresence>

      {/* ── Podium classement final ── */}
      <AnimatePresence>
        {isFinished && showPodium && (() => {
          // Construire la liste classée : survivants (par dette croissante) puis éliminés (par ordre d'élimination inversé)
          const survivorsSorted = playerTotals
            .filter(t => !eliminated.includes(t.pid))
            .sort((a, b) => a.total - b.total);
          const eliminatedOrdered = (session.eliminatedPlayers ?? []).slice().reverse()
            .map(pid => playerTotals.find(t => t.pid === pid))
            .filter(Boolean) as typeof playerTotals;
          const allRanked = [...survivorsSorted, ...eliminatedOrdered];
          const podiumPlayers: PodiumPlayer[] = allRanked.map((t, i) => {
            const p = session.players.find((pl) => pl.id === t.pid);
            const prof = mpPlayerProfiles?.[p?.name ?? ""];
            // Résoudre l'avatar : profil connecté > emoji invité serveur > localStorage
            let avatar: PodiumPlayer["avatar"] = undefined;
            if (prof) {
              avatar = getAvatarDisplay(prof.avatarType as "emoji" | "custom", prof.avatarId);
            } else {
              const guestEmojiServer = (guestEmojis as Record<string, string> | undefined)?.[t.pid];
              const guestEmojiLocal = localStorage.getItem(`mp_guestEmoji_${t.pid}`) || "";
              const resolvedEmoji = guestEmojiServer || guestEmojiLocal || "";
              if (resolvedEmoji) avatar = { type: "emoji", content: resolvedEmoji };
            }
            return {
              pid: t.pid,
              name: p?.name ?? t.pid,
              total: t.total,
              isEliminated: eliminated.includes(t.pid),
              isMe: t.pid === playerId,
              avatar,
              rank: i + 1,
            };
          });
          return (
            <PodiumOverlay
              players={podiumPlayers}
              onClose={() => setShowPodium(false)}
              onMenu={() => { setShowPodium(false); setShowConfirmLeave(true); }}
            />
          );
        })()}
      </AnimatePresence>

      {/* ── Overlay MATCH NUL plein écran (deck épuisé, plusieurs joueurs en jeu) ── */}
      <AnimatePresence>
        {isDraw && pendingAck.length === 0 && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[88] flex items-center justify-center"
            style={{ background: "rgba(0,0,0,0.88)", backdropFilter: "blur(6px)" }}
          >
            {/* Confettis décoratifs */}
            {[...Array(18)].map((_, i) => (
              <motion.div
                key={i}
                className="absolute w-3 h-3 rounded-sm"
                style={{
                  background: ["#FFD700","#FF4081","#00E676","#007AFF","#FF6B00"][i % 5],
                  left: `${(i * 5.5 + 3) % 100}%`,
                  top: `${(i * 7.3 + 5) % 60}%`,
                }}
                animate={{
                  y: [0, 120 + (i % 4) * 40, 280 + (i % 3) * 60],
                  x: [0, (i % 2 === 0 ? 1 : -1) * (20 + i * 3), (i % 2 === 0 ? -1 : 1) * 30],
                  rotate: [0, 180 + i * 15, 360 + i * 30],
                  opacity: [0, 1, 0],
                }}
                transition={{ duration: 2.5 + (i % 4) * 0.4, repeat: Infinity, delay: (i % 6) * 0.3, ease: "easeIn" }}
              />
            ))}

            <motion.div
              initial={{ scale: 0.7, y: 40, rotate: -4 }}
              animate={{ scale: 1, y: 0, rotate: 0 }}
              transition={{ type: "spring", stiffness: 280, damping: 22, delay: 0.1 }}
              className="relative rounded-3xl border-[6px] border-black p-8 flex flex-col items-center gap-5 max-w-sm w-full mx-4"
              style={{
                background: "linear-gradient(160deg, #1a1a2e 0%, #16213e 60%, #0f3460 100%)",
                boxShadow: "10px 10px 0px #000, 0 0 60px rgba(255,215,0,0.25)",
              }}
            >
              {/* Badge égalité animé */}
              <motion.div
                animate={{ rotate: [0, -8, 8, -5, 5, 0], scale: [1, 1.08, 1] }}
                transition={{ duration: 3, repeat: Infinity, ease: "easeInOut" }}
                className="w-20 h-20 rounded-2xl border-[5px] border-black flex items-center justify-center"
                style={{ background: "linear-gradient(135deg, #FFD700 0%, #FF8C00 100%)", boxShadow: "5px 5px 0px #000" }}
              >
                <Trophy className="w-10 h-10 text-black" />
              </motion.div>

              {/* Titre */}
              <div className="flex flex-col items-center gap-1">
                <motion.span
                  style={{ fontFamily: "'Bangers', cursive", fontSize: "2.6rem", letterSpacing: "0.1em", lineHeight: 1 }}
                  className="text-yellow-400 text-center"
                  animate={{ scale: [1, 1.04, 1], textShadow: ["3px 3px 0px #000, 0 0 20px rgba(255,215,0,0.4)", "3px 3px 0px #000, 0 0 40px rgba(255,215,0,0.7)", "3px 3px 0px #000, 0 0 20px rgba(255,215,0,0.4)"] }}
                  transition={{ duration: 2, repeat: Infinity }}
                >
                  MATCH NUL !
                </motion.span>
                <span style={{ fontFamily: "'Fredoka One', cursive", fontSize: "0.95rem" }} className="text-white/60 text-center">
                  Le deck est épuisé — personne ne gagne !
                </span>
              </div>

              {/* Classement des survivants */}
              <div className="w-full flex flex-col gap-2">
                <span style={{ fontFamily: "'Bangers', cursive", fontSize: "1.1rem", letterSpacing: "0.08em" }} className="text-white/50 text-center">
                  SURVIVANTS
                </span>
                {activePlayers
                  .sort((a, b) => a.total - b.total)
                  .map((t, i) => {
                    const p = session.players.find(pl => pl.id === t.pid);
                    const isMe = t.pid === playerId;
                    return (
                      <motion.div
                        key={t.pid}
                        initial={{ x: -30, opacity: 0 }}
                        animate={{ x: 0, opacity: 1 }}
                        transition={{ delay: 0.3 + i * 0.12 }}
                        className="flex items-center justify-between rounded-xl border-[3px] border-black px-4 py-2"
                        style={{
                          background: isMe ? "linear-gradient(135deg, #1a3a1a 0%, #0d2a0d 100%)" : "rgba(255,255,255,0.06)",
                          borderColor: isMe ? "#00E676" : "rgba(255,255,255,0.15)",
                          boxShadow: isMe ? "3px 3px 0px #000" : "none",
                        }}
                      >
                        <div className="flex items-center gap-2">
                          <span style={{ fontFamily: "'Bangers', cursive", fontSize: "1.1rem" }} className="text-yellow-400">#{i + 1}</span>
                          <span style={{ fontFamily: "'Fredoka One', cursive", fontSize: "0.95rem" }} className={isMe ? "text-green-400" : "text-white/80"}>
                            {p?.name ?? t.pid}{isMe ? " (toi)" : ""}
                          </span>
                        </div>
                        <span style={{ fontFamily: "'Bangers', cursive", fontSize: "1.1rem" }} className="text-white/70">
                          {formatPrice(t.total)}
                        </span>
                      </motion.div>
                    );
                  })}
              </div>

              {/* Boutons */}
              <div className="flex gap-3 w-full">
                {isHost && (
                  <motion.button
                    whileTap={{ scale: 0.93 } as any}
                    onClick={() => setShowConfirmReset(true)}
                    className="flex-1 py-3.5 bg-yellow-400 border-[4px] border-black rounded-2xl text-black"
                    style={{ fontFamily: "'Bangers', cursive", fontSize: "1.2rem", letterSpacing: "0.06em", boxShadow: "4px 4px 0px #000" }}
                  >
                    REJOUER
                  </motion.button>
                )}
                <motion.button
                  whileTap={{ scale: 0.93 } as any}
                  onClick={() => setShowConfirmLeave(true)}
                  className="flex-1 py-3.5 bg-white/10 border-[3px] border-white/20 rounded-2xl text-white/70"
                  style={{ fontFamily: "'Bangers', cursive", fontSize: "1.2rem", letterSpacing: "0.06em", boxShadow: "3px 3px 0px rgba(0,0,0,0.5)" }}
                >
                  MENU
                </motion.button>
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ── Overlay pause — pour les autres joueurs ── */}
      <AnimatePresence>
        {gamePausedFor && (
          <GamePausedOverlay
            eliminatedName={gamePausedFor.name}
            eliminatedTotal={gamePausedForTotal}
            gameFinished={isFinished}
          />
        )}
      </AnimatePresence>

      {/* ── Notif centrale : joueur parti / expulsé ── */}
      <AnimatePresence>
        {playerLeftNotif && (
          <motion.div
            initial={{ opacity: 0, y: -24, scale: 0.92 }}
            animate={{ opacity: 1, y: 0, scale: 1 }}
            exit={{ opacity: 0, y: -16, scale: 0.92 }}
            transition={{ type: "spring", stiffness: 360, damping: 26 }}
            className="fixed top-20 left-0 right-0 z-[88] flex justify-center px-5 pointer-events-none"
          >
            <div
              className="pointer-events-auto w-full max-w-[300px] rounded-2xl border-[3px] overflow-hidden"
              style={{
                background: playerLeftNotif.wasKicked
                  ? "linear-gradient(135deg, #1c0808 0%, #3b1010 100%)"
                  : "linear-gradient(135deg, #081828 0%, #0f2848 100%)",
                boxShadow: `6px 6px 0px #000, 0 0 28px ${playerLeftNotif.wasKicked ? "rgba(239,68,68,0.28)" : "rgba(59,130,246,0.25)"}`,
                borderColor: playerLeftNotif.wasKicked ? "#ef4444" : "#3b82f6",
              }}
            >
              {/* Bande titre */}
              <div
                className="w-full py-2 px-4 flex items-center gap-2"
                style={{
                  background: playerLeftNotif.wasKicked ? "rgba(239,68,68,0.22)" : "rgba(59,130,246,0.2)",
                  borderBottom: `2px solid ${playerLeftNotif.wasKicked ? "rgba(239,68,68,0.35)" : "rgba(59,130,246,0.3)"}`,
                }}
              >
                {playerLeftNotif.wasKicked
                  ? <UserX className="w-3.5 h-3.5 text-red-400 flex-shrink-0" />
                  : <LogOut className="w-3.5 h-3.5 text-blue-400 flex-shrink-0" />
                }
                <span
                  style={{ ...FONT_BANGERS, fontSize: "0.75rem", letterSpacing: "0.12em" }}
                  className={playerLeftNotif.wasKicked ? "text-red-400" : "text-blue-400"}
                >
                  {playerLeftNotif.wasKicked ? "JOUEUR EXPULSÉ" : "JOUEUR PARTI"}
                </span>
                {/* Bouton fermer */}
                <motion.button
                  whileTap={{ scale: 0.88 }}
                  onClick={() => { if (playerLeftTimeout.current) clearTimeout(playerLeftTimeout.current); setPlayerLeftNotif(null); }}
                  className="w-6 h-6 bg-white/10 border border-white/15 rounded-full flex items-center justify-center flex-shrink-0 ml-auto"
                >
                  <X className="w-3 h-3 text-white/50" />
                </motion.button>
              </div>
              {/* Corps */}
              <div className="px-4 py-2.5 flex items-center gap-3">
                <div
                  className="w-9 h-9 rounded-xl border-[2px] border-black flex items-center justify-center flex-shrink-0"
                  style={{ background: playerLeftNotif.wasKicked ? "rgba(239,68,68,0.18)" : "rgba(59,130,246,0.18)" }}
                >
                  <User className={`w-4 h-4 ${playerLeftNotif.wasKicked ? "text-red-400" : "text-blue-400"}`} />
                </div>
                <div className="flex flex-col min-w-0">
                  <span
                    style={{ ...FONT_BANGERS, fontSize: "1rem", letterSpacing: "0.04em", lineHeight: 1.15 }}
                    className={`truncate ${playerLeftNotif.wasKicked ? "text-red-300" : "text-blue-300"}`}
                  >
                    {playerLeftNotif.playerName}
                  </span>
                  <span style={FONT_FREDOKA} className="text-white/50 text-xs leading-tight">
                    {playerLeftNotif.wasKicked ? "a été expulsé de la partie" : "a quitté la partie"}
                  </span>
                </div>
              </div>
            </div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ── Modal d'expulsion (host) ── */}
      <AnimatePresence>
        {showKickModal && session && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.18 }}
            className="fixed inset-0 z-[92] flex items-center justify-center px-5"
            style={{ background: "rgba(0,0,0,0.72)", backdropFilter: "blur(4px)" }}
          >
            <motion.div
              initial={{ scale: 0.84, y: 20 }}
              animate={{ scale: 1, y: 0 }}
              exit={{ scale: 0.87, y: 14, opacity: 0 }}
              transition={{ type: "spring", stiffness: 320, damping: 26 }}
              className="w-full max-w-xs rounded-3xl border-[4px] border-black overflow-hidden"
              style={{
                background: "linear-gradient(160deg, #1a0808 0%, #3b0f0f 60%, #1a0808 100%)",
                boxShadow: "8px 8px 0px #000, 0 0 40px rgba(239,68,68,0.35)",
                borderColor: "#ef4444",
              }}
            >
              {/* Titre */}
              <div
                className="w-full py-2.5 px-4 flex items-center gap-2 border-b-[2px]"
                style={{ background: "rgba(239,68,68,0.15)", borderColor: "rgba(239,68,68,0.35)" }}
              >
                <UserX className="w-4 h-4 text-red-400" />
                <span style={{ ...FONT_BANGERS, fontSize: "1rem", letterSpacing: "0.08em" }} className="text-red-300 flex-1">
                  EXPULSER UN JOUEUR
                </span>
                <motion.button
                  whileTap={{ scale: 0.88 }}
                  onClick={() => setShowKickModal(false)}
                  className="w-7 h-7 bg-white/10 border-[2px] border-white/15 rounded-full flex items-center justify-center"
                >
                  <X className="w-3.5 h-3.5 text-white/50" />
                </motion.button>
              </div>

              {/* Liste des joueurs */}
              <div className="px-4 py-3 flex flex-col gap-2 max-h-64 overflow-y-auto">
                {session.players
                  .filter(p => p.id !== playerId) // Exclure l'host
                  .map(p => {
                    const isElim = (session.eliminatedPlayers ?? []).includes(p.id);
                    return (
                      <motion.button
                        key={p.id}
                        whileTap={{ scale: 0.96 }}
                        onClick={() => handleKick(p.id)}
                        disabled={isKicking}
                        className="w-full flex items-center gap-3 px-3 py-2.5 rounded-2xl border-[2px] border-black text-left"
                        style={{
                          background: isElim ? "rgba(255,255,255,0.04)" : "rgba(239,68,68,0.08)",
                          borderColor: isElim ? "rgba(255,255,255,0.1)" : "rgba(239,68,68,0.3)",
                          boxShadow: "3px 3px 0px rgba(0,0,0,0.5)",
                          opacity: isKicking ? 0.6 : 1,
                        }}
                      >
                        <div
                          className="w-9 h-9 rounded-xl border-[2px] border-black flex items-center justify-center flex-shrink-0"
                          style={{ background: isElim ? "rgba(255,255,255,0.06)" : "rgba(239,68,68,0.15)" }}
                        >
                          {isElim
                            ? <Skull className="w-4 h-4 text-white/40" />
                            : <User className="w-4 h-4 text-red-400" />
                          }
                        </div>
                        <div className="flex flex-col min-w-0 flex-1">
                          <span
                            style={{ ...FONT_BANGERS, fontSize: "1rem", letterSpacing: "0.04em", lineHeight: 1.1 }}
                            className={isElim ? "text-white/40" : "text-red-300"}
                          >
                            {p.name}
                          </span>
                          {isElim && (
                            <span style={FONT_FREDOKA} className="text-white/30 text-xs">Éliminé</span>
                          )}
                        </div>
                        <UserX className={`w-4 h-4 flex-shrink-0 ${isElim ? "text-white/20" : "text-red-400"}`} />
                      </motion.button>
                    );
                  })
                }
              </div>

              {/* Footer */}
              <div className="px-4 pb-4">
                <p style={FONT_FREDOKA} className="text-white/35 text-xs text-center">
                  Le joueur expulse sera immediatement retire de la partie.
                </p>
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* Drawer historique des transactions */}
      <AnimatePresence>
        {showTransactionDrawer && (
          <>
            {/* Overlay */}
            <motion.div
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              onClick={() => setShowTransactionDrawer(false)}
              className="fixed inset-0 bg-black/50 z-50"
            />
            {/* Drawer */}
            <motion.div
              initial={{ x: "100%" }}
              animate={{ x: 0 }}
              exit={{ x: "100%" }}
              transition={{ type: "spring", damping: 25, stiffness: 200 }}
              className="fixed right-0 top-0 h-[100dvh] w-full sm:w-80 bg-[#0a0a0a] border-l-4 border-yellow-400 z-50 flex flex-col"
            >
              {/* Header du drawer */}
              <div className="flex items-center justify-between px-4 py-3 border-b-2 border-yellow-400/30 flex-shrink-0">
                <div style={FONT_BANGERS} className="text-white text-lg">
                  HISTORIQUE
                </div>
                <motion.button
                  whileTap={{ scale: 0.9 }}
                  onClick={() => setShowTransactionDrawer(false)}
                  className="w-8 h-8 bg-red-600 border-[2px] border-black rounded-lg flex items-center justify-center"
                  style={{ boxShadow: "2px 2px 0px #000" }}
                >
                  <X className="w-4 h-4 text-white" />
                </motion.button>
              </div>

              {/* Contenu du drawer — pattern identique à MyTicketsPanel pour scroll iOS */}
              <div
                className="flex-1 overflow-y-auto px-3 py-3"
                style={{ minHeight: 0, WebkitOverflowScrolling: "touch" } as React.CSSProperties}
              >
                {session && (session as any).playerCards && Object.keys((session as any).playerCards).length > 0 ? (
                  <div className="flex flex-col gap-3">
                    {/* Historique par tour */}
                    {mpGlobalHistoryTours.map((tour) => (
                      <div key={`tour-${tour.num}`} className="flex flex-col gap-2">
                        {/* En-tête du tour */}
                        <div className="flex items-center gap-2 py-2 border-b-2 border-yellow-400/30">
                          <div className="w-6 h-6 rounded-full flex items-center justify-center flex-shrink-0" style={{ background: "linear-gradient(135deg, #FCD34D, #F59E0B)" }}>
                            <span style={{ ...FONT_BANGERS, fontSize: "0.7rem", color: "#1a1a1a" }}>{tour.num}</span>
                          </div>
                          <span style={FONT_BANGERS} className="text-yellow-300 text-sm flex-1">Tour {tour.num}</span>
                          <span style={FONT_FREDOKA} className="text-white/40 text-xs">{tour.txs.length} carte{tour.txs.length > 1 ? "s" : ""}</span>
                        </div>
                        {/* Transactions du tour */}
                        <div className="flex flex-col gap-2">
                          {tour.txs.map((tx: any, i: number) => {
                            const txProfile = mpPlayerProfiles?.[tx.name] ?? null;
                            const txAvatar = txProfile ? getAvatarDisplay(txProfile.avatarType as "emoji" | "custom", txProfile.avatarId) : null;
                            const txPlayerObj = session.players.find((p: any) => p.name === tx.name);
                            const txGuestEmoji = !txAvatar && txPlayerObj ? (guestEmojis as Record<string, string> | undefined)?.[txPlayerObj.id] : null;
                            return (
                              <div key={i} className="flex flex-col rounded-lg border-2 px-3 py-2" style={{ borderColor: tx.cat?.color ?? "#333", background: `${tx.cat?.color ?? "#333"}15` }}>
                                {/* Ligne 1 : avatar + nom + montant */}
                                <div className="flex items-center gap-2">
                                  <div
                                    className="w-7 h-7 rounded-full border-2 flex-shrink-0 overflow-hidden"
                                    style={{
                                      borderColor: tx.cat?.color ?? "#333",
                                      background: `${tx.cat?.color ?? "#333"}30`,
                                      display: "flex", alignItems: "center", justifyContent: "center",
                                    }}
                                  >
                                    {txAvatar?.type === "emoji" ? (
                                      <span style={{ fontSize: "1rem", lineHeight: 1, display: "block", textAlign: "center" }}>{txAvatar.content}</span>
                                    ) : txAvatar?.type === "image" ? (
                                      <img src={txAvatar.content} alt={tx.name} className="w-full h-full object-cover" />
                                    ) : txGuestEmoji ? (
                                      <span style={{ fontSize: "1rem", lineHeight: 1, display: "block", textAlign: "center" }}>{txGuestEmoji}</span>
                                    ) : (
                                      <span style={{ fontFamily: "'Bangers', cursive", fontSize: "0.75rem", lineHeight: 1, color: "rgba(255,255,255,0.6)" }}>{tx.name.charAt(0).toUpperCase()}</span>
                                    )}
                                  </div>
                                  <span style={{ ...FONT_BANGERS, fontSize: "0.8rem" }} className="text-white/90 flex-1 truncate">{tx.name}</span>
                                  <span style={{ ...FONT_BANGERS, fontSize: "0.85rem" }} className={`flex-shrink-0 ${tx.amt > 0 ? "text-red-400" : tx.amt < 0 ? "text-green-400" : "text-white/30"}`}>
                                    {tx.amt > 0 ? `+${formatPrice(tx.amt)}` : tx.amt < 0 ? formatPrice(tx.amt) : "—"}
                                  </span>
                                </div>
                                {/* Ligne 2 : catégorie + indicateur T3 */}
                                <div className="flex items-center gap-1.5 mt-1 pl-9">
                                  <div className="w-3 h-3 rounded flex-shrink-0" style={{ background: tx.cat?.color ?? "#333" }} />
                                  <span style={{ ...FONT_FREDOKA, fontSize: "0.6rem" }} className="text-white/40 uppercase tracking-wide">{tx.cat?.label ?? "?"}</span>
                                  {tx.isT3Sender && <span style={{ fontSize: "0.6rem", color: "#a855f7" }} className="ml-1 font-bold">→ envoyé</span>}
                                  {tx.isT3Receiver && <span style={{ fontSize: "0.6rem", color: "#a855f7" }} className="ml-1 font-bold">← reçu</span>}
                                </div>
                              </div>
                            );
                          })}
                        </div>
                      </div>
                    ))}

                    {/* Séparation entre tours et perquisitions */}
                    {mpGlobalHistoryRaids && mpGlobalHistoryTours.length > 0 && (
                      <div className="flex items-center gap-2 py-2">
                        <div className="flex-1 h-px bg-gradient-to-r from-transparent via-white/20 to-transparent" />
                        <span style={FONT_BANGERS} className="text-yellow-400 text-xs px-2">PERQUISITIONS</span>
                        <div className="flex-1 h-px bg-gradient-to-r from-transparent via-white/20 to-transparent" />
                      </div>
                    )}

                    {/* Historique des perquisitions */}
                    {mpGlobalHistoryRaids && (
                      <div className="flex flex-col gap-2">
                        {mpGlobalHistoryRaids.map((result: any) => {
                          const rPlayer = session?.players.find((p: any) => p.id === result.playerId);
                          const name = rPlayer?.name ?? "?";
                          const pProfile = mpPlayerProfiles?.[name] ?? null;
                          const pAvatar = pProfile ? getAvatarDisplay(pProfile.avatarType as "emoji" | "custom", pProfile.avatarId) : null;
                          // Fallback emoji invité pour les perquisitions
                          const pGuestEmoji = !pAvatar && rPlayer ? (guestEmojis as Record<string, string> | undefined)?.[rPlayer.id] : null;
                          return (
                            <div
                              key={`raid-${result.gameIdx}-${result.resultIdx}`}
                              className="flex flex-col rounded-lg border-2 px-3 py-2"
                              style={{
                                background: result.success ? "rgba(34,197,94,0.08)" : "rgba(239,68,68,0.08)",
                                borderColor: result.success ? "rgba(34,197,94,0.4)" : "rgba(239,68,68,0.4)",
                              }}
                            >
                              {/* Ligne 1 : avatar + nom + montant */}
                              <div className="flex items-center gap-2">
                                <div
                                  className="w-7 h-7 rounded-full border-2 flex-shrink-0 overflow-hidden"
                                  style={{
                                    borderColor: result.success ? "#22C55E" : "#EF4444",
                                    background: result.success ? "rgba(34,197,94,0.2)" : "rgba(239,68,68,0.2)",
                                    display: "flex", alignItems: "center", justifyContent: "center",
                                  }}
                                >
                                  {pAvatar?.type === "emoji" ? (
                                    <span style={{ fontSize: "1rem", lineHeight: 1, display: "block", textAlign: "center" }}>{pAvatar.content}</span>
                                  ) : pAvatar?.type === "image" ? (
                                    <img src={pAvatar.content} alt={name} className="w-full h-full object-cover" />
                                  ) : pGuestEmoji ? (
                                    <span style={{ fontSize: "1rem", lineHeight: 1, display: "block", textAlign: "center" }}>{pGuestEmoji}</span>
                                  ) : (
                                    <span style={{ fontFamily: "'Bangers', cursive", fontSize: "0.75rem", lineHeight: 1, color: "rgba(255,255,255,0.6)" }}>{name.charAt(0).toUpperCase()}</span>
                                  )}
                                </div>
                                <span style={{ ...FONT_BANGERS, fontSize: "0.8rem" }} className="text-white/90 flex-1 truncate">{name}</span>
                                <span
                                  style={{ ...FONT_BANGERS, fontSize: "0.85rem" }}
                                  className={result.success ? "text-green-400 flex-shrink-0" : "text-red-400 flex-shrink-0"}
                                >
                                  {result.success ? `-${formatPrice(result.amount)}` : `+${formatPrice(result.amount)}`}
                                </span>
                              </div>
                              {/* Ligne 2 : résultat */}
                              <div className="flex items-center gap-1.5 mt-1 pl-9">
                                <span style={{ fontSize: "0.75rem" }} className={result.success ? "text-green-400" : "text-red-400"}>{result.success ? "✓" : "✕"}</span>
                                <span style={{ ...FONT_FREDOKA, fontSize: "0.6rem" }} className={result.success ? "text-green-400 uppercase font-bold" : "text-red-400 uppercase font-bold"}>
                                  {result.success ? "Perquisition réussie" : "Perquisition échouée"}
                                </span>
                              </div>
                            </div>
                          );
                        })}
                      </div>
                    )}
                  </div>
                ) : (
                  <div style={FONT_FREDOKA} className="text-white/25 text-sm text-center py-4">Aucune transaction</div>
                )}
              </div>
            </motion.div>
          </>
        )}
      </AnimatePresence>

      {/* ── Header ── */}
      <div className="w-full bg-[#111] border-b-4 border-yellow-400 flex items-center justify-center px-2 sm:px-3 py-2 z-10 flex-shrink-0 gap-1 sm:gap-1.5 flex-wrap">
        {/* Bouton accueil */}
        <motion.button
          whileTap={{ scale: 0.9 }}
          onClick={() => setShowConfirmLeave(true)}
          className="w-10 h-10 bg-yellow-400 border-[3px] border-black rounded-xl flex items-center justify-center flex-shrink-0"
          style={{ boxShadow: "3px 3px 0px #000" }}
        >
          <Home className="w-4 h-4 text-black" />
        </motion.button>
        
        {/* Boutons host uniquement */}
        {isHost && (
          <>
            {session && session.players.filter(p => p.id !== playerId).length > 0 && (
              <motion.button
                whileTap={{ scale: 0.9 }}
                onClick={() => setShowKickModal(true)}
                className="w-10 h-10 bg-red-600 border-[3px] border-black rounded-xl flex items-center justify-center flex-shrink-0"
                style={{ boxShadow: "3px 3px 0px #000" }}
                title="Expulser un joueur"
              >
                <UserX className="w-4 h-4 text-white" />
              </motion.button>
            )}
            <motion.button
              whileTap={{ scale: 0.9 }}
              onClick={() => setShowConfirmReset(true)}
              className="w-10 h-10 bg-[#1565C0] border-[3px] border-black rounded-xl flex items-center justify-center flex-shrink-0"
              style={{ boxShadow: "3px 3px 0px #000" }}
            >
              <Shuffle className="w-4 h-4 text-white" />
            </motion.button>
          </>
        )}
        
        {/* Bouton Musique */}
        <motion.button
          whileTap={{ scale: 0.9 }}
          onClick={() => setShowMusicPlayer(true)}
          className="w-10 h-10 border-[3px] border-black rounded-xl flex items-center justify-center flex-shrink-0"
          style={{
            background: "linear-gradient(135deg, #7c3aed, #4f46e5)",
            boxShadow: "3px 3px 0px #000",
          }}
        >
          <Music className="w-4 h-4 text-white" />
        </motion.button>
        
        {/* Trois boutons (historique, carte précédemment joué, mes tickets) */}
        <div className="flex items-center gap-1 sm:gap-1.5 flex-shrink-0">
          {/* Bouton historique bleu */}
          <motion.button
            whileTap={{ scale: 0.9 }}
            onClick={() => setShowTransactionDrawer(true)}
            className="w-10 h-10 bg-[#1565C0] border-[3px] border-black rounded-xl flex items-center justify-center"
            style={{ boxShadow: "3px 3px 0px #000" }}
            title="Historique"
          >
            <History className="w-4 h-4 text-white" />
          </motion.button>

          {/* Bouton carte précédemment joué orange */}
          <motion.button
            whileTap={bubbleCard !== null ? { scale: 0.9 } : {}}
            onClick={() => bubbleCard !== null && setShowPrevCard(true)}
            disabled={bubbleCard === null}
            className="w-10 h-10 border-[3px] border-black rounded-xl flex items-center justify-center disabled:opacity-50 disabled:cursor-not-allowed"
            style={{
              background: bubbleCard !== null ? "#f97316" : "#9ca3af",
              boxShadow: "3px 3px 0px #000"
            }}
            title="Carte précédemment joué"
          >
            <ArrowLeft className="w-4 h-4 text-white" style={{ strokeWidth: 2.5 }} />
          </motion.button>

          {/* Bouton mes tickets vert */}
          <motion.button
            whileTap={{ scale: 0.9 }}
            onClick={() => setShowMyTickets(true)}
            className="w-10 h-10 bg-[#22c55e] border-[3px] border-black rounded-xl flex items-center justify-center relative"
            style={{ boxShadow: "3px 3px 0px #000" }}
            title="Mes tickets"
          >
            <Ticket className="w-4 h-4 text-black" />
            {myCards.length > 0 && (
              <div className="absolute -top-2 -right-2 w-5 h-5 bg-yellow-400 border-2 border-black rounded-full flex items-center justify-center">
                <span style={{ ...FONT_BANGERS, fontSize: "0.65rem" }} className="text-black leading-none">
                  {myCards.length}
                </span>
              </div>
            )}
          </motion.button>
        </div>
      </div>

      {/* ── Barre avec dette | bouton joueurs | cartes piochées ── */}
      <div className="w-full flex items-center justify-between px-3 sm:px-4 py-2 sm:py-2.5 bg-black/20 flex-shrink-0 border-b border-white/5 gap-2 sm:gap-3">
        {/* Affichage de la dette du joueur à gauche - format horizontal */}
        <div className="flex items-center justify-center px-3 sm:px-4 py-2 sm:py-2.5 rounded-xl sm:rounded-2xl border-[2.5px] border-white/15 bg-white/6 flex-shrink-0 min-w-0" style={{ boxShadow: "3px 3px 0px rgba(0,0,0,0.5)" }}>
          <span style={{ ...FONT_BANGERS, letterSpacing: "0.08em", fontSize: "clamp(0.7rem, 2vw, 0.9rem)" }} className={`leading-none font-bold truncate ${amEliminated ? "text-red-400" : "text-yellow-400"}`}>
            {formatPrice(myTotal)}
          </span>
        </div>
        {/* Bouton joueurs au centre avec animations scintillantes */}
        <div className="relative flex-shrink-0">
          <motion.button
            whileTap={{ scale: 0.97 }}
            onClick={() => setShowPlayerDropdown(v => !v)}
            className="flex items-center justify-center gap-2 px-3 sm:px-4 py-2 sm:py-2.5 rounded-xl sm:rounded-2xl border-[2.5px] text-center text-sm sm:text-base"
            style={{
              borderColor: myTurn ? "rgba(59,130,246,0.9)" : amEliminated ? "rgba(239,68,68,0.35)" : "rgba(255,255,255,0.15)",
              background: myTurn ? "rgba(59,130,246,0.18)" : amEliminated ? "rgba(239,68,68,0.08)" : "rgba(255,255,255,0.06)",
              boxShadow: myTurn ? "3px 3px 0px rgba(0,0,0,0.5), 0 0 20px rgba(59,130,246,0.6), 0 0 40px rgba(59,130,246,0.25)" : "3px 3px 0px rgba(0,0,0,0.5)",
            }}
          >
            {amEliminated
              ? <Skull className="w-4 h-4 sm:w-5 sm:h-5 text-red-400 flex-shrink-0" />
              : myTurn
              ? <motion.div
                  animate={{ scale: [1, 1.3, 1], opacity: [1, 0.5, 1] }}
                  transition={{ duration: 0.45, repeat: Infinity, ease: "easeInOut" }}
                >
                  <Target className="w-4 h-4 sm:w-5 sm:h-5 text-blue-300 flex-shrink-0" />
                </motion.div>
              : <User className="w-4 h-4 sm:w-5 sm:h-5 text-white/40 flex-shrink-0" />
            }
            <motion.span
              style={{ ...FONT_BANGERS, fontSize: myTurn ? "1rem" : "0.95rem", letterSpacing: "0.05em" }}
              className={`leading-none ${
                amEliminated ? "text-red-300" : myTurn ? "text-white" : "text-white/55"
              }`}
              animate={myTurn ? { opacity: [1, 0.05, 1], scale: [1, 1.05, 1], textShadow: ["0 0 0px transparent", "0 0 18px rgba(147,197,253,1)", "0 0 0px transparent"] } : { opacity: 1 }}
              transition={myTurn ? { duration: 0.42, repeat: Infinity, ease: "easeInOut" } : {}}
            >
              {currentPlayer?.name ?? "..."}
              {myTurn && <span className="text-blue-200/80 text-[0.8rem] sm:text-[0.85rem]"> (toi)</span>}
            </motion.span>
            <ChevronDown
              className={`w-3 h-3 sm:w-3.5 sm:h-3.5 flex-shrink-0 transition-transform duration-200 ${
                showPlayerDropdown ? "rotate-180" : ""
              } ${myTurn ? "text-blue-400/55" : "text-white/25"}`}
            />
          </motion.button>

          {/* Dropdown liste joueurs */}
          <AnimatePresence>
            {showPlayerDropdown && (
              <motion.div
                initial={{ opacity: 0, y: -10 }}
                animate={{ opacity: 1, y: 0 }}
                exit={{ opacity: 0, y: -10 }}
                transition={{ duration: 0.2, ease: "easeOut" }}
                className="fixed left-0 right-0 z-[30] rounded-none border-0 overflow-y-auto"
                style={{
              background: "linear-gradient(160deg, #0f1f54 0%, #16063a 100%)",
                boxShadow: "0 -4px 0px rgba(0,0,0,0.3), 0 0 24px rgba(0,0,0,0.8)",
                borderColor: "transparent",
                width: "100vw",
                maxHeight: "70vh",
                top: "auto",
                }}
              >
                <div className="px-4 sm:px-6 py-2 sm:py-3 border-b border-white/8 sticky top-0 bg-gradient-to-b from-[#0f1f54] to-[#16063a] flex items-center justify-between">
                  <span style={{ ...FONT_BANGERS, fontSize: "0.75rem sm:text-sm", letterSpacing: "0.1em" }} className="text-white/40 uppercase">
                    Ordre de jeu
                  </span>
                </div>
                <div className="py-2 sm:py-3 px-4 sm:px-6">
                  <div className="space-y-1.5 sm:space-y-2">
                  {session.turnOrder.map((pid, idx) => {
                    const player = session.players.find(p => p.id === pid);
                    if (!player) return null;
                    const isElim   = eliminated.includes(pid);
                    const isActive = idx === session.currentTurnIndex && !isFinished;
                    const isMe     = pid === playerId;
                    const pTotal   = playerTotals.find(t => t.pid === pid)?.total ?? 0;
                    const isLeader = !isElim && pTotal === minTotal && drawnCount > 0 && activePlayers.length > 1;
                    const pColor = isMe
                      ? MY_COLOR
                      : PLAYER_COLOR_PALETTE[idx % PLAYER_COLOR_PALETTE.length];
                    return (
                      <div
                        key={pid}
                        className="flex items-center justify-between px-6 sm:px-8 py-3 sm:py-4 border-b border-white/5 last:border-0 rounded-xl mb-2 last:mb-0"
                        style={{
                          background: isElim
                            ? "rgba(239,68,68,0.04)"
                            : isMe && isActive
                            ? "rgba(59,130,246,0.22)"
                            : isActive
                            ? pColor.bg
                            : isMe
                            ? "rgba(59,130,246,0.07)"
                            : "transparent",
                          borderLeft: `4px solid ${isElim ? "rgba(239,68,68,0.2)" : isMe && isActive ? "rgba(96,165,250,0.85)" : pColor.border}`,
                          boxShadow: isMe && isActive ? "inset 0 0 0 1px rgba(96,165,250,0.18)" : undefined,
                        }}
                      >
                        <div className="flex items-center gap-3 sm:gap-4 min-w-0 flex-1">
                          <div className="w-6 h-6 sm:w-8 sm:h-8 flex items-center justify-center flex-shrink-0">
                            {isElim
                              ? <Skull className="w-5 h-5 sm:w-6 sm:h-6 text-red-400/55" />
                              : isLeader
                              ? <Crown className="w-5 h-5 sm:w-6 sm:h-6 text-yellow-300/65" />
                              : <div className="w-6 h-6 sm:w-8 sm:h-8" />
                            }
                          </div>
                          {(() => {
                            const pProfile = mpPlayerProfiles?.[player.name];
                            const pAvatar = pProfile ? getAvatarDisplay(pProfile.avatarType as "emoji" | "custom", pProfile.avatarId) : null;
                            // Emoji invité : serveur d'abord, fallback local si c'est le joueur courant
                            const playerObj = session.players.find(p => p.name === player.name);
                            const serverGuestEmoji = !pAvatar && playerObj ? (guestEmojis as Record<string, string> | undefined)?.[playerObj.id] : null;
                            const playerGuestEmoji = serverGuestEmoji || (!pAvatar && pid === playerId ? guestEmoji || null : null);
                            const ringColor = isMe ? "rgba(96,165,250,0.9)" : pColor.dot;
                            return (
                              <div className="relative flex-shrink-0 w-8 h-8 sm:w-10 sm:h-10">
                                {isActive && !isElim && (
                                  <motion.div
                                    className="absolute inset-0 rounded-full"
                                    style={{ border: `2px solid ${ringColor}` }}
                                    animate={{ scale: [1, 1.9, 1], opacity: [0.85, 0, 0.85] }}
                                    transition={{ duration: 1.2, repeat: Infinity, ease: "easeOut" }}
                                  />
                                )}
                                <motion.div
                                  className="w-8 h-8 sm:w-10 sm:h-10 rounded-full border flex items-center justify-center overflow-hidden"
                                  style={{
                                    background: "rgba(0,0,0,0.25)",
                                    opacity: isElim ? 0.4 : 1,
                                    borderColor: isActive && !isElim ? ringColor : "rgba(0,0,0,0.3)",
                                    borderWidth: isActive && !isElim ? "2px" : "1px",
                                  }}
                                  animate={isActive && !isElim
                                    ? { scale: [1, 1.15, 1], boxShadow: [`0 0 0px ${ringColor}`, `0 0 8px ${ringColor}`, `0 0 0px ${ringColor}`] }
                                    : { scale: 1 }
                                  }
                                  transition={isActive && !isElim
                                    ? { duration: 1.2, repeat: Infinity, ease: "easeInOut" }
                                    : {}
                                  }
                                >
                                  {pAvatar?.type === "emoji" ? (
                                    <span style={{ fontSize: "0.8rem", lineHeight: 1 }}>{pAvatar.content}</span>
                                  ) : pAvatar?.type === "image" ? (
                                    <img src={pAvatar.content} alt="" className="w-full h-full object-contain" />
                                   ) : playerGuestEmoji ? (
                                     <span style={{ fontSize: "0.8rem", lineHeight: 1, display: "block", textAlign: "center" }}>{playerGuestEmoji}</span>
                                   ) : (
                                     <span style={{ ...FONT_BANGERS, fontSize: "0.75rem", lineHeight: 1, color: "#fff", display: "block", textAlign: "center" }}>{(player.name || "?")[0].toUpperCase()}</span>
                                  )}
                                </motion.div>
                              </div>
                            );
                          })()}
                          <div className="flex flex-col min-w-0 flex-1">
                            <motion.span
                              style={{
                                ...(isMe && isActive ? FONT_BANGERS : FONT_FREDOKA),
                                color: isElim
                                  ? undefined
                                  : isMe && isActive
                                  ? "#ffffff"
                                  : pColor.text,
                                fontSize: isMe && isActive ? "1.3rem" : "1.1rem",
                                letterSpacing: isMe && isActive ? "0.06em" : "0.02em",
                              }}
                              className={`truncate leading-none ${
                                isElim ? "text-red-400/45 line-through" : ""
                              }`}
                              animate={isMe && isActive
                                ? { opacity: [1, 0.05, 1], scale: [1, 1.06, 1], textShadow: ["0 0 0px transparent", "0 0 16px rgba(147,197,253,1)", "0 0 0px transparent"] }
                                : { opacity: isElim ? 0.45 : 1, scale: 1 }
                              }
                              transition={isMe && isActive
                                ? { duration: 0.42, repeat: Infinity, ease: "easeInOut" }
                                : {}
                              }
                            >
                              {player.name}
                              {isMe && !isActive && <span style={{ opacity: 0.4, fontFamily: "'Fredoka One', cursive", fontSize: "0.6rem" }}> (toi)</span>}
                            </motion.span>
                            {mpPlayerProfiles?.[player.name]?.equippedBadgeId && !isElim && (
                              <div className="w-5 h-5 sm:w-6 sm:h-6 mt-1">
                                <BadgeVisual badgeId={mpPlayerProfiles[player.name].equippedBadgeId!} animate={false} />
                              </div>
                            )}
                          </div>
                        </div>
                        {isElim ? (
                          <div className="flex items-center gap-2 flex-shrink-0 ml-4">
                            <span style={{ ...FONT_BANGERS, fontSize: "0.75rem" }} className="text-red-400/40">ÉLIM.</span>
                            <span style={FONT_FREDOKA} className="text-white/20 text-[0.7rem]">
                              {formatPrice(pTotal)}
                            </span>
                          </div>
                        ) : (
                          <div className="flex flex-col items-end flex-shrink-0 ml-4">
                            <motion.span
                              key={pTotal}
                              initial={{ scale: 1.1 }}
                              animate={{ scale: 1 }}
                              transition={{ duration: 0.2 }}
                              style={{ ...FONT_BANGERS, fontSize: "1rem", letterSpacing: "0.03em", color: isActive ? pColor.text : "rgba(255,255,255,0.35)" }}
                            >
                              {formatPrice(pTotal)}
                            </motion.span>
                            {(session.playerCards?.[pid]?.length ?? 0) > 0 && (
                              <span style={FONT_FREDOKA} className="text-white/20 text-[0.7rem] leading-none">
                                {session.playerCards?.[pid]?.length ?? 0} carte{(session.playerCards?.[pid]?.length ?? 0) > 1 ? "s" : ""}
                              </span>
                            )}
                          </div>
                        )}
                      </div>
                    );
                  })}
                  </div>
                </div>
              </motion.div>
            )}
          </AnimatePresence>
        </div>

        {/* Cartes piochées centrées */}
        <div
          className="flex items-center justify-center px-3 sm:px-4 py-2 sm:py-2.5 rounded-xl sm:rounded-2xl border-[2.5px] border-white/15 bg-white/6 flex-shrink-0"
          style={{ boxShadow: "3px 3px 0px rgba(0,0,0,0.5)" }}
        >
          <span style={{ ...FONT_BANGERS, fontSize: "0.9rem", letterSpacing: "0.08em" }} className="leading-none">
            <span className="text-white/75">{drawnCount}</span>
            <span className="text-white/40 text-[0.7rem]" style={{ marginLeft: "0.25rem" }}>/{deckTotal}</span>
          </span>
        </div>
      </div>

      {/* ── Micro-barre de progression du deck ── */}
      {deckTotal > 0 && (
        <div className="w-full h-[2px] bg-white/6 flex-shrink-0">
          <motion.div
            className="h-full"
            style={{
              background: drawnCount / deckTotal >= 0.85
                ? "linear-gradient(90deg, #f59e0b, #ef4444)"
                : "linear-gradient(90deg, #1565C0, #22c55e)",
              width: `${(drawnCount / deckTotal) * 100}%`,
            }}
            animate={{ width: `${(drawnCount / deckTotal) * 100}%` }}
            transition={{ duration: 0.5, ease: "easeOut" }}
          />
        </div>
      )}

      {/* ── Notification spectateur : transfert T3 — bulle centrale non-bloquante ── */}
      <AnimatePresence>
        {showT3SpectatorNotif && (
          <motion.div
            initial={{ opacity: 0, scale: 0.85, y: 12 }}
            animate={{ opacity: 1, scale: 1, y: 0 }}
            exit={{ opacity: 0, scale: 0.88, y: 8 }}
            transition={{ type: "spring", stiffness: 340, damping: 26 }}
            className="fixed inset-0 z-[85] flex items-center justify-center px-6 pointer-events-none"
          >
            <div
              className="pointer-events-auto relative w-full max-w-[300px] rounded-3xl border-[4px] border-black overflow-hidden"
              style={{
                background: "linear-gradient(160deg, #1a0a2e 0%, #2d0a4e 60%, #1a0526 100%)",
                boxShadow: "8px 8px 0px #000, 0 0 36px rgba(236,72,153,0.3)",
                borderColor: "#EC4899",
              }}
            >
              {/* Bouton X fermer */}
              <motion.button
                whileTap={{ scale: 0.88 } as any}
                onClick={() => setShowT3SpectatorNotif(null)}
                className="absolute top-2.5 right-2.5 w-8 h-8 rounded-full border-[2px] border-black flex items-center justify-center z-10"
                style={{ background: "rgba(255,255,255,0.14)", boxShadow: "2px 2px 0px #000" }}
              >
                <X className="w-4 h-4 text-white/70" />
              </motion.button>

              {/* Bande décorative haut */}
              <div
                className="w-full py-2 flex items-center justify-center gap-2"
                style={{ background: "rgba(236,72,153,0.22)", borderBottom: "2px solid rgba(236,72,153,0.35)" }}
              >
                <Mail className="w-3.5 h-3.5 text-pink-400" />
                <span style={{ ...FONT_BANGERS, fontSize: "0.72rem", letterSpacing: "0.12em" }} className="text-pink-300">
                  TRANSFERT DE TICKET
                </span>
                <Mail className="w-3.5 h-3.5 text-pink-400" />
              </div>

              {/* Contenu */}
              <div className="px-5 py-4 flex flex-col items-center gap-2.5 text-center">
                {/* Icône animée */}
                <motion.div
                  animate={{ scale: [1, 1.1, 1] }}
                  transition={{ duration: 1.8, repeat: Infinity, ease: "easeInOut" }}
                  className="w-12 h-12 rounded-2xl border-[3px] border-pink-400 flex items-center justify-center"
                  style={{ background: "rgba(236,72,153,0.18)", boxShadow: "3px 3px 0px #000" }}
                >
                  <ArrowRight className="w-6 h-6 text-pink-400" />
                </motion.div>

                {/* Noms */}
                <div className="flex flex-col gap-0.5">
                  <span
                    style={{ ...FONT_BANGERS, fontSize: "1.3rem", letterSpacing: "0.04em", lineHeight: 1 }}
                    className="text-pink-300"
                  >
                    {showT3SpectatorNotif.senderName}
                  </span>
                  <span style={FONT_FREDOKA} className="text-white/50 text-xs">
                    envoie un ticket à
                  </span>
                  <span
                    style={{ ...FONT_BANGERS, fontSize: "1.3rem", letterSpacing: "0.04em", lineHeight: 1 }}
                    className="text-yellow-300"
                  >
                    {showT3SpectatorNotif.receiverName}
                  </span>
                </div>

                {/* Hint auto-close */}
                <motion.div
                  animate={{ opacity: [0.4, 0.8, 0.4] }}
                  transition={{ duration: 2, repeat: Infinity }}
                  className="flex items-center gap-1.5 px-3 py-1.5 rounded-xl border border-pink-500/20"
                  style={{ background: "rgba(236,72,153,0.07)" }}
                >
                  <Clock className="w-3 h-3 text-pink-400/60" />
                  <span style={FONT_FREDOKA} className="text-pink-300/55 text-[0.65rem]">
                    Se ferme à la fin du tour
                  </span>
                </motion.div>
              </div>
            </div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ── Bannière élimination personnelle ── */}
      <AnimatePresence mode="wait">
        {amEliminated && (
          <EliminationBanner
            key="elim-banner"
            name={playerName}
            threshold={ELIMINATION_THRESHOLD}
            activePlayers={activePlayers.length}
          />
        )}
      </AnimatePresence>

      {/* ── Sub-header : joueur actif + dropdown ── */}
      <div className="w-full flex items-center justify-center px-2 sm:px-4 pt-2 sm:pt-3 pb-1 sm:pb-2 flex-shrink-0 relative">
        {/* Overlay fermeture dropdowns */}
        {(showPlayerDropdown || showHistoryPanel) && (
          <div
            className="fixed inset-0 z-[28]"
            onClick={() => { setShowPlayerDropdown(false); setShowHistoryPanel(false); }}
          />
        )}


        {/* Bouton Historique — drawer latéral */}



      </div>

      {/* ── Zone carte + bouton piocher ── */}
      <div className="flex-1 flex flex-col md:flex-row items-center md:items-stretch justify-center px-4 gap-4 pb-1 min-h-0 md:gap-6">

        {/* Wrapper qui aligne la carte et les boutons sur la même largeur */}
        <div className="flex flex-col gap-4 items-stretch flex-shrink-0" style={{ width: "min(calc(57dvh * 5 / 7), clamp(280px, 35vw, 420px))" }}>
        {/* Carte */}
        <div className="relative flex-shrink-0" style={{ aspectRatio: "5/7", perspective: "1200px" }}>
          <AnimatePresence mode="wait">
            {isFinished && !winner && pendingAck.length === 0 ? (
              /* Deck épuisé sans gagnant clair (cas rare) */
              <motion.div
                key="gameover-nodeck"
                initial={{ scale: 0.8, opacity: 0 }}
                animate={{ scale: 1, opacity: 1 }}
                className="absolute inset-0 rounded-3xl border-[5px] border-black flex flex-col items-center justify-center gap-3 px-4"
                style={{ background: "linear-gradient(135deg, #FFD700, #FCD34D)", boxShadow: "8px 8px 0px #000" }}
              >
                <Trophy className="w-14 h-14 text-black" />
                <div style={{ ...FONT_BANGERS, fontSize: "1.3rem", letterSpacing: "0.06em" }} className="text-black text-center">
                  TOUTES LES CARTES PIOCHÉES !
                </div>
                <p style={FONT_FREDOKA} className="text-black/60 text-xs text-center">
                  {isHost ? "Utilise le bouton mélanger pour rembattre." : "Le host peut rembattre le deck."}
                </p>
              </motion.div>
            ) : session.lastCard !== null && showCard && currentPlayerHasDrawn ? (
              <DraggableCard className="absolute inset-0">
              <motion.div
                key={`card-${session.lastCard}-${session.currentTurnIndex}`}
                initial={{ rotateY: -180, scale: 0.65, opacity: 0.5 }}
                animate={{ rotateY: 0, scale: 1, opacity: 1 }}
                exit={{ rotateY: 180, scale: 0.65, opacity: 0 }}
                transition={{ type: "spring", stiffness: 200, damping: 22, opacity: { duration: 0.15 } }}
                className="absolute inset-0 rounded-3xl bg-white border-[5px] border-black overflow-hidden"
                style={{ boxShadow: "8px 8px 0px #000", transformStyle: "preserve-3d", backfaceVisibility: "hidden" }}
              >
                {showCardFront && !cardHiddenByViewer && !isT3Spectator
                  ? <div className="w-full h-full"><GeneratedCard card={getCardConfigMp(session.lastCard)} size="md" skinId={resolvePlayerSkin(session.turnOrder[session.currentTurnIndex]) as any} mefaitOverride={getMpCustomMefait(session.lastCard)} style={{ width: '100%', height: '100%' }} /></div>
                  : <div className="w-full h-full"><GeneratedCardBack size="md" style={{ width: '100%', height: '100%' }} /></div>
                }

                {/* Bouton oeil — masquage local pour les non-actifs (masqué pour T3 spectateurs) */}
                {showCardFront && !myTurn && !isT3Spectator && (
                  <motion.button
                    whileTap={{ scale: 0.88 } as any}
                    onClick={() => setCardHiddenByViewer(v => !v)}
                    className="absolute top-2 right-2 w-9 h-9 rounded-xl border-[2px] border-black flex items-center justify-center z-20"
                    style={{
                      background: cardHiddenByViewer ? "rgba(255,255,255,0.9)" : "rgba(0,0,0,0.6)",
                      boxShadow: "2px 2px 0px #000",
                    }}
                    title={cardHiddenByViewer ? "Voir la carte" : "Masquer la carte"}
                  >
                    {cardHiddenByViewer
                      ? <Eye className="w-4 h-4 text-black" />
                      : <EyeOff className="w-4 h-4 text-white" />
                    }
                  </motion.button>
                )}
              </motion.div>
              </DraggableCard>
            ) : (
              <motion.div
                key="empty"
                initial={{ scale: 0.9, opacity: 0 }}
                animate={{ scale: 1, opacity: 1 }}
                className="absolute inset-0 rounded-3xl border-[4px] border-dashed border-yellow-400/40 flex flex-col items-center justify-center gap-4"
                style={{ background: "rgba(26,42,112,0.5)" }}
              >
                <motion.div
                  animate={{ y: [0, -12, 0], rotate: [-5, 5, -5] }}
                  transition={{ duration: 2.5, repeat: Infinity, ease: "easeInOut" }}
                >
                  <img src={ticketImg} alt="" style={{ width: "6rem" }} />
                </motion.div>
              </motion.div>
            )}
          </AnimatePresence>
        </div>

        {/* Bouton piocher */}
        {!isFinished && (
          <div className="flex gap-4 w-full">
            {/* Bouton piocher / envoyer T3 / terminer mon tour */}
            <div className="relative flex-1">
              {myTurn && !amEliminated && (
                <motion.div
                  className="absolute inset-0 rounded-2xl -z-10"
                  style={{
                    background: pendingT3 ? "#EC4899"
                      : (hasDrawnThisTurn && !showTaxNotif) ? "#22c55e"
                      : "#FFD700",
                  }}
                  animate={{ scale: [1, 1.1, 1], opacity: [0.6, 0, 0.6] }}
                  transition={{ duration: 1.8, repeat: Infinity }}
                />
              )}
<motion.button
                whileTap={myTurn && !amEliminated ? { scale: 0.95, y: 2 } as any : {}}
                onClick={
                  pendingT3 ? handleSendT3
                  : hasDrawnThisTurn ? handleEndTurn
                  : handleDraw
                }
                disabled={
                  amEliminated || !myTurn || isDrawing || isSendingT3
                  || isEndingTurn
                  || (hasDrawnThisTurn && !pendingT3 && showTaxNotif !== null)
                  || (pendingAck.length > 0)
                  || waitingForAllPlayers
                }
                className="w-full py-2.5 sm:py-3.5 border-[4px] sm:border-[5px] border-black rounded-xl sm:rounded-2xl relative overflow-hidden disabled:cursor-not-allowed transition-colors"
                style={{
                  ...FONT_BANGERS,
                  letterSpacing: "0.05em",
                  fontSize: "0.8rem",
                  background: amEliminated
                    ? "#7f1d1d"
                    : pendingT3
                    ? "#EC4899"
                    : (hasDrawnThisTurn && !showTaxNotif)
                    ? "#22c55e"
                    : (hasDrawnThisTurn && showTaxNotif)
                    ? "rgba(255,255,255,0.06)"
                    : myTurn
                    ? "#FFD700"
                    : "rgba(255,255,255,0.06)",
                  color: amEliminated
                    ? "#fca5a5"
                    : pendingT3
                    ? "#fff"
                    : (hasDrawnThisTurn && !showTaxNotif)
                    ? "#fff"
                    : (hasDrawnThisTurn && showTaxNotif)
                    ? "rgba(255,255,255,0.28)"
                    : myTurn
                    ? "#000"
                    : "rgba(255,255,255,0.22)",
                  boxShadow:
                    pendingT3
                      ? "7px 7px 0px #000, 0 0 20px rgba(236,72,153,0.3)"
                      : myTurn && !amEliminated && !(hasDrawnThisTurn && showTaxNotif && !pendingT3)
                      ? "7px 7px 0px #000"
                      : "3px 3px 0px rgba(0,0,0,0.3)",
                }}
              >
                {myTurn && !amEliminated && !pendingT3 && !(hasDrawnThisTurn && showTaxNotif) && (
                  <motion.div
                    className="absolute inset-0 w-1/3 skew-x-[-20deg]"
                    style={{ background: hasDrawnThisTurn ? "rgba(255,255,255,0.15)" : "rgba(255,255,255,0.20)" }}
                    animate={{ x: ["-100%", "400%"] }}
                    transition={{ duration: 2.2, repeat: Infinity, ease: "easeInOut", repeatDelay: 0.8 }}
                  />
                )}
                {pendingT3 && !isSendingT3 && (
                  <motion.div
                    className="absolute inset-0 w-1/3 skew-x-[-20deg]"
                    style={{ background: "rgba(255,255,255,0.18)" }}
                    animate={{ x: ["-100%", "400%"] }}
                    transition={{ duration: 2.0, repeat: Infinity, ease: "easeInOut", repeatDelay: 0.6 }}
                  />
                )}
                <span className="flex items-center justify-center gap-2 relative z-10 whitespace-nowrap overflow-hidden px-2">
                  {amEliminated ? (
                    <><Skull className="w-5 h-5" /> ÉLIMINÉ</>
                  ) : pendingT3 ? (
                    <>
                      <Mail className="w-5 h-5 flex-shrink-0" />
                      <span>
                        {isSendingT3 ? "ENVOI EN COURS..." : `ENVOYER LE TICKET`}
                      </span>
                      {!isSendingT3 && <ArrowRight className="w-4 h-4 flex-shrink-0" />}
                    </>
                  ) : hasDrawnThisTurn && showTaxNotif ? (
                    <span style={{ fontSize: "0.78rem" }} className="text-center leading-snug opacity-60">
                      Ferme la notification d'abord
                    </span>
                  ) : hasDrawnThisTurn ? (
                    <><CheckCircle className="w-5 h-5" /> {isEndingTurn ? "EN COURS..." : "TERMINER MON TOUR"}</>
                  ) : myTurn && pendingAck.length > 0 && !hasDrawnThisTurn ? (
                    <span style={{ fontSize: "0.78rem" }} className="text-center leading-snug opacity-60">
                      En pause — élimination en cours…
                    </span>
                  ) : myTurn ? (
                    <>{isDrawing ? "PIOCHE..." : "RECEVOIR UN TICKET"}</>
                  ) : (
                    <span className="flex items-center gap-1.5 flex-wrap justify-center leading-snug">
                      <Clock className="w-4 h-4 flex-shrink-0" style={{ color: "rgba(255,255,255,0.3)" }} />
                      <span style={{ color: "rgba(255,255,255,0.3)" }}>Attends,</span>
                      <span style={{ ...FONT_BANGERS, color: "#FFD700", opacity: 0.75, fontSize: "1rem" }}>
                        {currentPlayer?.name}
                      </span>
                      <span style={{ color: "rgba(255,255,255,0.3)" }}>est en train de jouer</span>
                    </span>
                  )}
                </span>
              </motion.button>
            </div>
          </div>
        )}



        </div>{/* /wrapper */}

        {/* Erreur */}
        {error && (
          <div style={FONT_FREDOKA} className="text-red-400 text-xs text-center px-4">
            {error}
          </div>
        )}

        {/* ── Panneau latéral desktop — classement + historique ── */}
        <div className="hidden md:flex flex-col gap-4 flex-1 min-w-0 py-2 overflow-y-auto">

          {/* Ma dette */}
          <div
            className="rounded-2xl border-[3px] p-4 flex flex-col gap-1"
            style={{
              background: amEliminated ? "rgba(239,68,68,0.12)" : "rgba(255,215,0,0.08)",
              borderColor: amEliminated ? "rgba(239,68,68,0.4)" : "rgba(234,179,8,0.35)",
            }}
          >
            <span style={{ ...FONT_FREDOKA }} className="text-white/40 text-xs uppercase tracking-wider">Ma dette totale</span>
            <span
              style={{ ...FONT_BANGERS, fontSize: "2.2rem", letterSpacing: "0.04em", lineHeight: 1 }}
              className={amEliminated ? "text-red-400" : "text-yellow-400"}
            >
              {formatPrice(myTotal)}
            </span>
            {amEliminated && (
              <span style={FONT_FREDOKA} className="text-red-400/60 text-xs">Éliminé — limite dépassée</span>
            )}
          </div>

          {/* Classement en temps réel */}
          <div
            className="rounded-2xl border-[3px] border-white/10 p-4 flex flex-col gap-3"
            style={{ background: "rgba(0,0,0,0.35)" }}
          >
            <div style={{ ...FONT_BANGERS, fontSize: "1rem", letterSpacing: "0.08em" }} className="text-white/60 flex items-center gap-2">
              <Trophy className="w-4 h-4 text-yellow-400/60" />
              CLASSEMENT
            </div>
            <div className="flex flex-col gap-1.5">
              {playerTotals
                .sort((a, b) => {
                  const aElim = eliminated.includes(a.pid);
                  const bElim = eliminated.includes(b.pid);
                  if (aElim && !bElim) return 1;
                  if (!aElim && bElim) return -1;
                  return a.total - b.total;
                })
                .map((pt, rank) => {
                  const player = session.players.find(p => p.id === pt.pid);
                  const isMe = pt.pid === playerId;
                  const isActive = pt.pid === currentPlayer?.id && !isFinished;
                  const isElim = eliminated.includes(pt.pid);
                  const pIdx = session.turnOrder.indexOf(pt.pid);
                  const pColor = isMe
                    ? MY_COLOR
                    : PLAYER_COLOR_PALETTE[pIdx % PLAYER_COLOR_PALETTE.length];
                  const pProf = mpPlayerProfiles?.[player?.name ?? ""];
                  const pAvatar = pProf ? getAvatarDisplay(pProf.avatarType as "emoji" | "custom", pProf.avatarId) : null;
                  return (
                    <div
                      key={pt.pid}
                      className="flex items-center gap-2 rounded-xl border px-3 py-2"
                      style={{
                        background: isElim
                          ? "rgba(239,68,68,0.06)"
                          : isActive
                          ? (isMe ? "rgba(59,130,246,0.18)" : pColor.bg)
                          : isMe
                          ? "rgba(59,130,246,0.08)"
                          : "rgba(255,255,255,0.04)",
                        borderColor: isElim
                          ? "rgba(239,68,68,0.2)"
                          : isActive
                          ? (isMe ? "rgba(96,165,250,0.7)" : pColor.border)
                          : isMe
                          ? "rgba(96,165,250,0.25)"
                          : "rgba(255,255,255,0.08)",
                        boxShadow: isActive && !isElim ? `0 0 12px ${isMe ? "rgba(59,130,246,0.3)" : pColor.border}` : "none",
                      }}
                    >
                      {/* Rang */}
                      <span
                        style={{ ...FONT_BANGERS, fontSize: "0.85rem" }}
                        className={isElim ? "text-white/20" : "text-yellow-400/70"}
                      >
                        #{rank + 1}
                      </span>
                      {/* Avatar du joueur */}
                      <div
                        className="w-6 h-6 rounded-full border flex items-center justify-center overflow-hidden flex-shrink-0"
                        style={{
                          background: "rgba(0,0,0,0.25)",
                          opacity: isElim ? 0.4 : 1,
                          borderColor: isActive && !isElim ? (isMe ? "rgba(96,165,250,0.7)" : pColor.border) : "rgba(0,0,0,0.3)",
                          borderWidth: isActive && !isElim ? "2px" : "1px",
                        }}
                      >
                        {pAvatar?.type === "emoji" ? (
                          <span style={{ fontSize: "0.75rem", lineHeight: 1 }}>{pAvatar.content}</span>
                        ) : pAvatar?.type === "image" ? (
                          <img src={pAvatar.content} alt="" className="w-full h-full object-contain" />
                        ) : (
                          <span style={{ ...FONT_BANGERS, fontSize: "0.7rem", lineHeight: 1, color: "#fff" }}>{(player?.name || "?")[0].toUpperCase()}</span>
                        )}
                      </div>
                      {/* Icône statut */}
                      <div className="w-5 h-5 flex items-center justify-center flex-shrink-0">
                        {isElim
                          ? <Skull className="w-3.5 h-3.5 text-red-400/50" />
                          : isActive
                          ? <motion.div
                              animate={{ scale: [1, 1.3, 1], opacity: [1, 0.4, 1] }}
                              transition={{ duration: 0.6, repeat: Infinity, ease: "easeInOut" }}
                            >
                              <Target className="w-3.5 h-3.5" style={{ color: isMe ? "#60a5fa" : pColor.dot }} />
                            </motion.div>
                          : pt.pid === session.hostId
                          ? <Crown className="w-3 h-3" style={{ color: pColor.dot, opacity: 0.55 }} />
                          : <div className="w-2 h-2 rounded-full" style={{ background: pColor.dot, opacity: 0.5 }} />
                        }
                      </div>
                      {/* Nom */}
                      <span
                        style={{
                          ...FONT_FREDOKA,
                          color: isElim ? "rgba(255,255,255,0.25)" : isMe ? "#93c5fd" : pColor.text,
                          fontSize: "0.88rem",
                        }}
                        className="flex-1 truncate leading-none"
                      >
                        {isMe ? "Toi" : (player?.name ?? pt.pid)}
                        {isActive && !isElim && (
                          <span style={{ fontSize: "0.65rem", opacity: 0.7 }}> ▶</span>
                        )}
                      </span>
                      {/* Dette */}
                      <span
                        style={{ ...FONT_BANGERS, fontSize: "0.9rem", letterSpacing: "0.03em" }}
                        className={isElim ? "text-red-400/50" : isMe ? "text-yellow-300" : "text-white/65"}
                      >
                        {formatPrice(pt.total)}
                      </span>
                    </div>
                  );
                })}
            </div>
          </div>

          {/* Historique des dernières cartes */}
          <div
            className="rounded-2xl border-[3px] border-white/10 p-4 flex flex-col gap-3 flex-1"
            style={{ background: "rgba(0,0,0,0.3)" }}
          >
            <div style={{ ...FONT_BANGERS, fontSize: "1rem", letterSpacing: "0.08em" }} className="text-white/60">SUIVI DES TRANSACTIONS</div>
            {session.drawn.length === 0 && dbMiniGameHistory.length === 0 ? (
              <div style={FONT_FREDOKA} className="text-white/25 text-sm text-center py-4">Aucun événement</div>
            ) : (
              <div className="flex flex-col gap-3 overflow-y-auto min-h-0" style={{ maxHeight: "100%" }}>
                {(() => {
                  const cardOwnerMap = new Map<number, string>();
                  for (const [pid, cards] of Object.entries(session.playerCards ?? {})) {
                    for (const c of (cards as number[])) cardOwnerMap.set(c, pid);
                  }
                  const cardReceiverMap = new Map<number, string>();
                  for (const [pid, received] of Object.entries(session.playerReceivedCards ?? {})) {
                    for (const c of (received as number[])) {
                      const receiver = session.players.find(p => p.id === pid);
                      if (receiver) cardReceiverMap.set(c, receiver.name);
                    }
                  }

                  // Convertir dbMiniGameHistory (playerId) en format affichable (playerName)
                  const normalizedRaids = dbMiniGameHistory.map((game, mgIdx) => {
                    const triggerer = session.players.find((p: { id: string; name: string }) => p.id === game.triggeredBy);
                    return {
                      triggeredByName: triggerer?.name ?? game.triggeredBy,
                      results: game.results.map((r) => {
                        const rPlayer = session.players.find((p: { id: string; name: string }) => p.id === r.playerId);
                        return { playerName: rPlayer?.name ?? r.playerId, success: r.success, amount: r.amount, playerId: r.playerId };
                      }),
                      timestamp: game.triggeredAt ? new Date(game.triggeredAt).getTime() : mgIdx * 1000,
                      drawnIndex: undefined as number | undefined,
                    };
                  });

                  // Construire une liste chronologique mixte : cartes + perquisitions
                  type CardEntry = { type: 'card'; cardNum: number; index: number };
                  type RaidEntry = { type: 'raid'; mg: typeof normalizedRaids[0]; mgIdx: number };
                  type HistEntry = CardEntry | RaidEntry;

                  const chronoEntries: HistEntry[] = [];
                  session.drawn.forEach((cardNum: number, i: number) => {
                    chronoEntries.push({ type: 'card', cardNum, index: i });
                  });
                  // Ajouter les perquisitions en fin (ordre chronologique DB)
                  normalizedRaids.forEach((mg, mgIdx) => {
                    chronoEntries.push({ type: 'raid', mg, mgIdx });
                  });

                  return (
                    <>
                      {chronoEntries.map((entry, rowIdx) => {
                        if (entry.type === 'card') {
                          const { cardNum, index: i } = entry;
                          const ownerId = cardOwnerMap.get(cardNum);
                          const owner = session.players.find((p: { id: string; name: string }) => p.id === ownerId);
                          const cfg = getCardConfigMp(cardNum);
                          const net = drawerNetAmount(cfg);
                          const nextAmt = nextPlayerAmount(cfg);
                          const receiverName = cardReceiverMap.get(cardNum) ?? "";
                          const isElim = (session.eliminatedPlayers ?? []).includes(ownerId ?? "");
                          const isMe = ownerId === playerId;
                          const rowColor = cfg.cardType === 1
                            ? { dot: "#DC2626", text: "text-red-300", bg: "rgba(220,38,38,0.07)" }
                            : cfg.cardType === 2
                            ? { dot: "#16A34A", text: "text-green-300", bg: "rgba(22,163,74,0.07)" }
                            : { dot: "#7C3AED", text: "text-purple-300", bg: "rgba(124,58,237,0.07)" };
                          const catInfo = CATEGORY_INFO[cfg.category];
                          return (
                            <div
                              key={`hist-${i}-${cardNum}`}
                              className="flex items-center gap-2 px-4 py-3 rounded-lg border-2 border-white/12"
                              style={{ background: rowIdx % 2 === 0 ? "rgba(255,255,255,0.06)" : "rgba(255,255,255,0.09)", minHeight: "3rem" }}
                            >
                              <div className="w-2 h-2 rounded-full flex-shrink-0" style={{ background: rowColor.dot }} />
                              <span style={{ ...FONT_BANGERS, fontSize: "0.65rem" }} className="text-white/60 flex-shrink-0 min-w-fit">
                                {catInfo?.label ?? "Inconnu"}
                              </span>
                              <div className="flex-1 min-w-0">
                                <div className="flex items-center gap-1 flex-wrap">
                                  {/* Mini-avatar : photo, emoji profil ou emoji invité ou lettre */}
                                  {(() => {
                                    const ownerProfile = owner ? mpPlayerProfiles?.[owner.name] : null;
                                    const ownerAvatar = ownerProfile ? getAvatarDisplay(ownerProfile.avatarType as "emoji" | "custom", ownerProfile.avatarId) : null;
                                    const ownerGuestEmoji = !ownerAvatar && owner ? (guestEmojis as Record<string, string> | undefined)?.[owner.id] : null;
                                    if (ownerAvatar?.type === "image") {
                                      return (
                                        <span className="w-4 h-4 rounded-full flex-shrink-0 overflow-hidden">
                                          <img src={ownerAvatar.content} alt="" className="w-full h-full object-cover" />
                                        </span>
                                      );
                                    }
                                    const displayEmoji = ownerAvatar?.type === "emoji" ? ownerAvatar.content : ownerGuestEmoji;
                                    return (
                                      <span className="w-4 h-4 rounded-full flex items-center justify-center flex-shrink-0 text-center overflow-hidden"
                                        style={{ background: "rgba(255,255,255,0.12)", fontSize: displayEmoji ? "0.55rem" : "0.5rem", lineHeight: 1 }}>
                                        {displayEmoji ?? (owner?.name ?? "?")[0].toUpperCase()}
                                      </span>
                                    );
                                  })()}
                                  <span style={{ ...FONT_BANGERS, fontSize: "0.7rem", letterSpacing: "0.04em" }} className={`${isMe ? "text-blue-300" : "text-white/70"} leading-none`}>
                                    {isMe ? "Toi" : (owner?.name ?? "?")}
                                  </span>
                                  {isElim && <Skull className="w-2.5 h-2.5 text-red-400/50 flex-shrink-0" />}
                                </div>
                                {cfg.cardType === 3 && receiverName && (
                                  <div className="flex items-center gap-0.5 mt-0.5">
                                    <ArrowRight className="w-2.5 h-2.5 text-purple-400/60 flex-shrink-0" />
                                    <span style={{ ...FONT_FREDOKA, fontSize: "0.58rem" }} className="text-purple-300/60 leading-none truncate">
                                      → {receiverName} +{formatPrice(nextAmt)}
                                    </span>
                                  </div>
                                )}
                              </div>
                              <span style={{ ...FONT_BANGERS, fontSize: "0.7rem", letterSpacing: "0.03em" }} className={`flex-shrink-0 ${net < 0 ? "text-green-400" : "text-red-400"}`}>
                                {net >= 0 ? "+" : ""}{formatPrice(net)}
                              </span>
                            </div>
                          );
                        } else {
                          // Entrée de type perquisition
                          const { mg, mgIdx } = entry;
                          return (
                            <div
                              key={`mg-group-${mgIdx}`}
                              className="flex flex-col gap-1 px-4 py-3 rounded-lg border-2"
                              style={{ borderColor: "rgba(59,130,246,0.35)", background: "rgba(59,130,246,0.07)", minHeight: "3rem" }}
                            >
                              <div className="flex items-center gap-2">
                                <Siren className="w-3 h-3 text-blue-400 flex-shrink-0" />
                                <span style={{ ...FONT_BANGERS, fontSize: "0.7rem", letterSpacing: "0.05em" }} className="text-blue-300 leading-none flex-1">
                                  Perquisition — {mg.triggeredByName}
                                </span>
                              </div>
                              <div className="flex flex-col gap-0.5 pl-5">
                                {mg.results.map((r: any, ri: number) => {
                                  const rPlayer = session.players.find((p: { id: string; name: string }) => p.id === (r.playerId ?? "") || p.name === r.playerName);
                                  const isMe = rPlayer?.id === playerId || r.playerId === playerId;
                                  const rProfile = rPlayer ? mpPlayerProfiles?.[rPlayer.name] : null;
                                  const rAvatar = rProfile ? getAvatarDisplay(rProfile.avatarType as "emoji" | "custom", rProfile.avatarId) : null;
                                  const rGuestEmoji = !rAvatar && rPlayer ? (guestEmojis as Record<string, string> | undefined)?.[rPlayer.id] : null;
                                  const rDisplayEmoji = rAvatar?.type === "emoji" ? rAvatar.content : rGuestEmoji;
                                  return (
                                    <div key={ri} className="flex items-center gap-1.5">
                                      {rAvatar?.type === "image" ? (
                                        <span className="w-3.5 h-3.5 rounded-full flex-shrink-0 overflow-hidden">
                                          <img src={rAvatar.content} alt="" className="w-full h-full object-cover" />
                                        </span>
                                      ) : (
                                        <span className="w-3.5 h-3.5 rounded-full flex items-center justify-center flex-shrink-0 text-center overflow-hidden"
                                          style={{ background: "rgba(255,255,255,0.12)", fontSize: rDisplayEmoji ? "0.5rem" : "0.45rem", lineHeight: 1 }}>
                                          {rDisplayEmoji ?? (r.playerName ?? "?")[0].toUpperCase()}
                                        </span>
                                      )}
                                      <span style={{ ...FONT_FREDOKA, fontSize: "0.62rem" }} className={`${isMe ? "font-bold" : ""} ${r.success ? "text-green-300" : "text-red-300"} leading-none`}>
                                        {isMe ? "Toi" : r.playerName} : {r.success ? `-${formatPrice(r.amount)}` : `+${formatPrice(r.amount)}`}
                                        {r.success ? " ✓" : " ✗"}
                                      </span>
                                    </div>
                                  );
                                })}
                              </div>
                            </div>
                          );
                        }
                      })}
                    </>
                  );
                })()}
              </div>
            )}
          </div>
        </div>
      </div>


      {/* ── Aperçu carte précédente ── */}
      <AnimatePresence>
        {showPrevCard && bubbleCard && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[80] flex flex-col items-center justify-center gap-5 px-6"
            style={{ background: "rgba(0,0,0,0.92)" }}
            onClick={() => setShowPrevCard(false)}
          >
            <motion.div
              initial={{ scale: 0.75, rotateY: -30 }}
              animate={{ scale: 1, rotateY: 0 }}
              exit={{ scale: 0.75, opacity: 0 }}
              transition={{ type: "spring", stiffness: 280, damping: 22 }}
              onClick={(e) => e.stopPropagation()}
              className="flex flex-col items-center gap-0"
            >
              {/* Bulle BD style — "Pioché par {joueur}" — attachée au-dessus de la carte */}
              <div
                className="relative px-5 py-2.5 rounded-2xl border-[3px] border-black flex items-center justify-center"
                style={{
                  background: "linear-gradient(135deg, #fff 0%, #f0f0ff 100%)",
                  boxShadow: "4px 4px 0px #000",
                }}
              >
                <span style={{ ...FONT_BANGERS, fontSize: "1.1rem", letterSpacing: "0.06em" }} className="text-black whitespace-nowrap">
                  Pioché par{" "}
                  <span className="text-blue-600">{bubbleCard.playerName}</span>
                </span>
                {/* Pointe de la bulle vers le bas (vers la carte) */}
                <div
                  className="absolute -bottom-[14px] left-1/2 -translate-x-1/2"
                  style={{ width: 0, height: 0, borderLeft: "10px solid transparent", borderRight: "10px solid transparent", borderTop: "14px solid #000" }}
                />
                <div
                  className="absolute -bottom-[10px] left-1/2 -translate-x-1/2"
                  style={{ width: 0, height: 0, borderLeft: "8px solid transparent", borderRight: "8px solid transparent", borderTop: "11px solid #f0f0ff" }}
                />
              </div>

              {/* Carte */}
              <div
                className="rounded-3xl border-[5px] border-yellow-400 overflow-hidden mt-[14px]"
                style={{ width: "min(78vw, 260px)", aspectRatio: "5/7", boxShadow: "10px 10px 0px #000" }}
              >
                <GeneratedCard card={getCardConfigMp(bubbleCard.cardNum)} size="sm" skinId={bubbleCard.playerId ? resolvePlayerSkin(bubbleCard.playerId) as any : mySkinId as any} mefaitOverride={getMpCustomMefait(bubbleCard.cardNum)} style={{ width: '100%', height: '100%' }} />
              </div>
              <motion.button
                whileTap={{ scale: 0.9 } as any}
                onClick={() => setShowPrevCard(false)}
                className="mt-4 w-12 h-12 bg-red-500 border-[3px] border-black rounded-full flex items-center justify-center"
                style={{ boxShadow: "3px 3px 0px #000" }}
              >
                <X className="w-5 h-5 text-white" />
              </motion.button>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ── Panneau "Mes tickets" ── */}
      <AnimatePresence>
        {showMyTickets && (
          <MyTicketsPanel
            cards={myCards}
            playerName={playerName}
            receivedDebt={myReceivedDebt}
            receivedCards={myReceivedCards}
            isEliminated={amEliminated}
            threshold={ELIMINATION_THRESHOLD}
            disabledCardTypes={disabledCardTypes}
            onClose={() => setShowMyTickets(false)}
            session={session}
            myPlayerId={playerId}
            miniGameHistory={miniGameHistory}
            skinId={mySkinId}
          />
        )}
      </AnimatePresence>

      {/* ── Modal confirmation mélange ── */}
      <AnimatePresence>
        {showConfirmReset && (
          <ConfirmResetModal
            onConfirm={handleReset}
            onCancel={() => setShowConfirmReset(false)}
            loading={isResetting}
            deckTotal={session.allowedCardIds?.length ?? deckTotal}
          />
        )}
      </AnimatePresence>

      {/* ── Notification taxe T3 (piocheur) ── */}
      <AnimatePresence>
        {showTaxNotif && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.18 }}
            className="fixed inset-0 z-[95] flex items-center justify-center px-5"
            style={{ background: "rgba(0,0,0,0.78)", backdropFilter: "blur(4px)" }}
          >
            <motion.div
              initial={{ scale: 0.72, y: 40, rotate: -4 }}
              animate={{ scale: 1, y: 0, rotate: 0 }}
              exit={{ scale: 0.72, y: 30, opacity: 0 }}
              transition={{ type: "spring", stiffness: 380, damping: 24 }}
              className="w-full max-w-sm rounded-3xl border-[5px] border-black overflow-hidden"
              style={{
                background: "linear-gradient(160deg, #0f2d0f 0%, #1a3d10 50%, #0f1f0f 100%)",
                boxShadow: "10px 10px 0px #000, 0 0 50px rgba(34,197,94,0.3)",
                borderColor: "#22c55e",
              }}
            >
              {/* Header */}
              <div className="bg-[#22c55e] px-5 py-3 flex items-center gap-3 border-b-[4px] border-black">
                <motion.div
                  animate={{ rotate: [0, -12, 12, 0], scale: [1, 1.15, 1] }}
                  transition={{ duration: 1.6, repeat: Infinity }}
                >
                  <TrendingDown className="w-6 h-6 text-black" />
                </motion.div>
                <span style={{ ...FONT_BANGERS, fontSize: "1.3rem", letterSpacing: "0.08em" }} className="text-black flex-1">
                  Investissement remboursé !
                </span>
                <motion.div
                  animate={{ scale: [1, 1.3, 1], opacity: [0.7, 1, 0.7] }}
                  transition={{ duration: 1.2, repeat: Infinity }}
                  className="w-8 h-8 bg-black/20 rounded-xl flex items-center justify-center"
                >
                  <TrendingDown className="w-4 h-4 text-black/70" />
                </motion.div>
              </div>

              {/* Corps */}
              <div className="px-6 py-5 flex flex-col items-center gap-4">
                {/* Réduction */}
                <div className="w-full rounded-2xl border-[3px] border-green-500/40 px-5 py-4 flex items-center justify-between"
                  style={{ background: "rgba(34,197,94,0.1)" }}>
                  <div>
                    <span style={FONT_FREDOKA} className="text-green-400/70 text-xs uppercase tracking-wider block mb-0.5">
                      Montant remboursé sur ta dette
                    </span>
                    <motion.span
                      initial={{ scale: 0 }}
                      animate={{ scale: 1 }}
                      transition={{ type: "spring", stiffness: 260, damping: 14, delay: 0.2 }}
                      style={{ ...FONT_BANGERS, fontSize: "2rem", letterSpacing: "0.04em" }}
                      className="text-green-400 leading-none block"
                    >
                      -{formatPrice(showTaxNotif.amount)}
                    </motion.span>
                  </div>
                  <div className="w-14 h-14 rounded-2xl border-[3px] border-green-500/40 flex items-center justify-center"
                    style={{ background: "rgba(34,197,94,0.15)" }}>
                    <motion.div
                      animate={{ rotate: [0, -12, 12, 0] }}
                      transition={{ duration: 1.4, repeat: Infinity }}
                    >
                      <TrendingDown className="w-7 h-7 text-green-400" />
                    </motion.div>
                  </div>
                </div>

                <p style={FONT_FREDOKA} className="text-white/55 text-sm text-center leading-snug">
                  En tant qu'investisseur,<br/>
                  <span className="text-green-400">le montant total est remboursé sur ta dette</span> — le joueur suivant assume la dépense.
                </p>

                <motion.button
                  whileTap={{ scale: 0.95 } as any}
                  onClick={() => setShowTaxNotif(null)}
                  className="w-full py-3.5 bg-[#22c55e] border-[4px] border-black rounded-2xl text-black flex items-center justify-center gap-2 relative overflow-hidden"
                  style={{ ...FONT_BANGERS, fontSize: "1.1rem", letterSpacing: "0.08em", boxShadow: "5px 5px 0px #000" }}
                >
                  <motion.div
                    className="absolute inset-0 w-1/3 bg-white/20 skew-x-[-20deg]"
                    animate={{ x: ["-100%", "400%"] }}
                    transition={{ duration: 2.2, repeat: Infinity, ease: "easeInOut", repeatDelay: 0.8 }}
                  />
                  <CheckCircle className="w-5 h-5 relative z-10" />
                  <span className="relative z-10">SUPER, J'AI COMPRIS !</span>
                </motion.button>
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ── Notification ticket reçu T3 (joueur suivant) ── */}
      <AnimatePresence>
        {showReceivedTicketNotif && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.18 }}
            className="fixed inset-0 z-[95] flex items-center justify-center px-5"
            style={{ background: "rgba(0,0,0,0.82)", backdropFilter: "blur(4px)" }}
          >
            <motion.div
              initial={{ scale: 0.72, y: 44, rotate: 3 }}
              animate={{ scale: 1, y: 0, rotate: 0 }}
              exit={{ scale: 0.72, y: 32, opacity: 0 }}
              transition={{ type: "spring", stiffness: 360, damping: 24 }}
              className="w-full max-w-sm rounded-3xl border-[5px] border-black overflow-hidden"
              style={{
                background: "linear-gradient(160deg, #2d0547 0%, #1a083d 60%, #2d0547 100%)",
                boxShadow: "10px 10px 0px #000, 0 0 50px rgba(236,72,153,0.35)",
                borderColor: "#EC4899",
              }}
            >
              {/* Header dramatique */}
              <div
                className="px-5 py-3 flex items-center gap-3 border-b-[4px] border-black"
                style={{ background: "linear-gradient(90deg, #be185d, #9d174d)" }}
              >
                <motion.div
                  animate={{ rotate: [0, -10, 10, 0], scale: [1, 1.2, 1] }}
                  transition={{ duration: 1.2, repeat: Infinity }}
                >
                  <Mail className="w-6 h-6 text-white" />
                </motion.div>
                <span style={{ ...FONT_BANGERS, fontSize: "1.3rem", letterSpacing: "0.07em" }} className="text-white flex-1">
                  Taxe d'investissement reçu !
                </span>
                <motion.div
                  animate={{ opacity: [0.4, 1, 0.4] }}
                  transition={{ duration: 1, repeat: Infinity }}
                >
                  <Mail className="w-4 h-4 text-pink-200/60" />
                </motion.div>
              </div>

              {/* Corps */}
              <div className="px-6 py-5 flex flex-col items-center gap-4">
                {/* Expéditeur */}
                <div className="flex items-center gap-2 px-4 py-2 rounded-xl border border-pink-500/25" style={{ background: "rgba(236,72,153,0.08)" }}>
                  <User className="w-4 h-4 text-pink-400/70" />
                  <span style={FONT_FREDOKA} className="text-white/65 text-sm">
                    De la part de{" "}
                    <strong className="text-pink-300">{showReceivedTicketNotif.fromName}</strong>
                  </span>
                </div>

                {/* Montant */}
                <div
                  className="w-full rounded-2xl border-[3px] border-pink-500/40 px-5 py-4 flex items-center justify-between"
                  style={{ background: "rgba(236,72,153,0.1)" }}
                >
                  <div>
                    <span style={FONT_FREDOKA} className="text-pink-400/70 text-xs uppercase tracking-wider block mb-0.5">
                      Montant ajouté à ta dette
                    </span>
                    <motion.span
                      initial={{ scale: 0 }}
                      animate={{ scale: 1 }}
                      transition={{ type: "spring", stiffness: 280, damping: 16, delay: 0.3 }}
                      style={{ ...FONT_BANGERS, fontSize: "2rem", letterSpacing: "0.04em" }}
                      className="text-red-400 leading-none block"
                    >
                      +{formatPrice(showReceivedTicketNotif.amount)}
                    </motion.span>
                  </div>
                  <div
                    className="w-14 h-14 rounded-2xl border-[3px] border-pink-500/40 flex items-center justify-center"
                    style={{ background: "rgba(236,72,153,0.15)" }}
                  >
                    <TrendingUp className="w-7 h-7 text-red-400" />
                  </div>
                </div>

                {/* Bouton confirmation */}
                <div className="relative w-full">
                  <motion.div
                    className="absolute inset-0 rounded-2xl bg-pink-500 -z-10"
                    animate={{ scale: [1, 1.06, 1], opacity: [0.5, 0, 0.5] }}
                    transition={{ duration: 1.6, repeat: Infinity }}
                  />
                  <motion.button
                    whileTap={{ scale: 0.96 } as any}
                    onClick={async () => {
                      setShowReceivedTicketNotif(null);
                      // Si ce joueur est dans pendingEliminationAck (il vient d'être éliminé par la carte T3),
                      // confirmer l'élimination pour débloquer l'envoyeur immédiatement
                      const pendingAckNow = session?.pendingEliminationAck ?? [];
                      if (pendingAckNow.includes(playerId)) {
                        try {
                          const { session: s } = await acknowledgeElimination(code, playerId);
                          setSession(s);
                          setShowMyEliminationOverlay(false);
                          prevPendingAck.current = s.pendingEliminationAck ?? [];
                        } catch (e) {
                          console.error("Erreur acknowledgeElimination depuis CONFIRMER LA RÉCEPTION:", e);
                        }
                      }
                    }}
                    className="w-full py-4 bg-pink-500 border-[4px] border-black rounded-2xl text-white flex items-center justify-center gap-2 relative overflow-hidden"
                    style={{ ...FONT_BANGERS, fontSize: "1.05rem", letterSpacing: "0.07em", boxShadow: "6px 6px 0px #000" }}
                  >
                    <motion.div
                      className="absolute inset-0 w-1/3 bg-white/15 skew-x-[-20deg]"
                      animate={{ x: ["-100%", "400%"] }}
                      transition={{ duration: 2.2, repeat: Infinity, ease: "easeInOut", repeatDelay: 0.8 }}
                    />
                    <CheckCircle className="w-5 h-5 relative z-10" />
                    <span className="relative z-10">CONFIRMER LA RÉCEPTION</span>
                  </motion.button>
                </div>
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ── Modal confirmation quitter ── */}
      <AnimatePresence>
        {showConfirmLeave && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 bg-black/80 z-[90] flex items-center justify-center p-6"
            onClick={() => setShowConfirmLeave(false)}
          >
            <motion.div
              initial={{ scale: 0.82, rotate: -2 }}
              animate={{ scale: 1, rotate: 0 }}
              exit={{ scale: 0.82, opacity: 0 }}
              transition={{ type: "spring", stiffness: 320, damping: 22 }}
              className="bg-[#111] border-[5px] border-yellow-400 rounded-3xl p-7 flex flex-col items-center gap-5 w-full max-w-sm"
              style={{ boxShadow: "8px 8px 0px #000" }}
              onClick={(e) => e.stopPropagation()}
            >
              <div
                className="w-16 h-16 bg-yellow-400 border-[4px] border-black rounded-2xl flex items-center justify-center"
                style={{ boxShadow: "4px 4px 0px #000" }}
              >
                <Home className="w-8 h-8 text-black" />
              </div>
              <div style={{ ...FONT_BANGERS, fontSize: "1.6rem", letterSpacing: "0.06em" }} className="text-yellow-400 text-center leading-tight">
                QUITTER LA PARTIE ?
              </div>
              <p style={FONT_FREDOKA} className="text-white/50 text-sm text-center">
                Tu ne pourras plus revenir dans la partie en cours.
              </p>
              <div className="flex gap-3 w-full">
                <motion.button
                  whileTap={{ scale: 0.93 } as any}
                  onClick={() => setShowConfirmLeave(false)}
                  className="flex-1 py-3.5 bg-white/10 border-[3px] border-white/20 rounded-2xl text-white/70"
                  style={{ ...FONT_BANGERS, fontSize: "1.2rem", letterSpacing: "0.06em", boxShadow: "3px 3px 0px rgba(0,0,0,0.5)" }}
                >
                  ANNULER
                </motion.button>
                <motion.button
                  whileTap={{ scale: 0.93 } as any}
                  onClick={handleLeave}
                  className="flex-1 py-3.5 bg-red-600 border-[3px] border-black rounded-2xl text-white"
                  style={{ ...FONT_BANGERS, fontSize: "1.2rem", letterSpacing: "0.06em", boxShadow: "4px 4px 0px #000" }}
                >
                  CONFIRMER
                </motion.button>
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ─ Résultats de perquisition ─ */}
      <AnimatePresence>
        {miniGameResultsData && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            transition={{ duration: 0.18 }}
            className="fixed inset-0 z-[85] flex items-center justify-center px-5"
            style={{ background: "rgba(0,0,0,0.82)", backdropFilter: "blur(4px)" }}
          >
            <motion.div
              initial={{ scale: 0.72, y: 44 }}
              animate={{ scale: 1, y: 0 }}
              exit={{ scale: 0.72, y: 32, opacity: 0 }}
              transition={{ type: "spring", stiffness: 360, damping: 24 }}
              className="w-full max-w-sm rounded-3xl border-[5px] border-black overflow-hidden"
              style={{
                background: "linear-gradient(160deg, #1a1a2e 0%, #16213e 60%, #0f1a3e 100%)",
                boxShadow: "10px 10px 0px #000, 0 0 50px rgba(59,130,246,0.35)",
                borderColor: "#3b82f6",
              }}
            >
              {/* Header */}
              <div
                className="px-5 py-3 flex items-center gap-3 border-b-[4px] border-black"
                style={{ background: "linear-gradient(90deg, #1d4ed8, #1e40af)" }}
              >
                <motion.div
                  animate={{ rotate: [0, -10, 10, 0], scale: [1, 1.2, 1] }}
                  transition={{ duration: 1.2, repeat: Infinity }}
                >
                  <Search className="w-6 h-6 text-white" />
                </motion.div>
                <span style={{ ...FONT_BANGERS, fontSize: "1.3rem", letterSpacing: "0.07em" }} className="text-white flex-1">
                  RÉSULTATS PERQUISITION
                </span>
              </div>

              {/* Corps */}
              <div className="px-5 py-4 flex flex-col gap-3">
                {miniGameResultsData.map((r) => {
                  const p = session.players.find(pl => pl.id === r.playerId);
                  const isMe = r.playerId === playerId;
                  return (
                    <div
                      key={r.playerId}
                      className="flex items-center justify-between rounded-xl border-[2px] px-4 py-2.5"
                      style={{
                        borderColor: r.success ? "rgba(34,197,94,0.4)" : "rgba(239,68,68,0.4)",
                        background: r.success ? "rgba(34,197,94,0.08)" : "rgba(239,68,68,0.08)",
                      }}
                    >
                      <div className="flex items-center gap-2">
                        <div className="w-2 h-2 rounded-full flex-shrink-0" style={{ background: r.success ? "#22c55e" : "#ef4444" }} />
                        <span style={FONT_FREDOKA} className={`text-sm ${isMe ? "text-blue-300 font-bold" : "text-white/80"}`}>
                          {isMe ? "Toi" : (p?.name ?? r.playerId)}
                        </span>
                      </div>
                      <span style={{ ...FONT_BANGERS, fontSize: "0.9rem", letterSpacing: "0.04em" }} className={r.success ? "text-green-400" : "text-red-400"}>
                        {r.success ? `-${formatPrice(r.amount)}` : `+${formatPrice(r.amount)}`}
                      </span>
                    </div>
                  );
                })}
                {!myTurn && (
                  <p style={FONT_FREDOKA} className="text-white/40 text-xs text-center mt-1">
                    Cette fenêtre se ferme automatiquement...
                  </p>
                )}
                {/* Bouton PIOCHER MA CARTE pour le piocheur — pioche obligatoire après perquisition */}
                {myTurn && !amEliminated && (
                  <motion.button
                    initial={{ opacity: 0, y: 8 }}
                    animate={{ opacity: 1, y: 0 }}
                    transition={{ delay: 0.3 }}
                    whileTap={{ scale: 0.95 } as any}
                    onClick={async () => {
                      if (isDrawing) return;
                      // Fermer l'overlay immédiatement
                      setMiniGameResultsData(null);
                      // Réinitialiser miniGameSkippedDraw pour que handleDraw fonctionne
                      setMiniGameSkippedDraw(false);
                      miniGameSkippedDrawRef.current = false;
                      // Piocher la carte normalement
                      setIsDrawing(true);
                      showNotifRef.current = false;
                      setShowNotif(false);
                      setShowCardFront(false);
                      try {
                        let s = (await drawCard(code, playerId)).session;
                        setSession(s);
                        prevTurnIdx.current  = s.currentTurnIndex;
                        prevLastCard.current = s.lastCard;
                        setShowCard(false);
                        setTimeout(() => {
                          setShowCard(true);
                          setTimeout(() => setShowCardFront(true), 320);
                        }, 50);
                        // Carte Type 3 : préparer l'envoi manuel
                        if (s.lastCard !== null && s.turnOrder.length > 1 && s.state === "playing") {
                          const cfg = getCardConfigMp(s.lastCard);
                          const nextAmt = nextPlayerAmount(cfg);
                          if (nextAmt > 0) {
                            const nextPlayerId = getNextActivePlayerId(s, playerId);
                            if (nextPlayerId) {
                              const nextPlayer = s.players.find((p) => p.id === nextPlayerId);
                              setPendingT3({
                                nextPlayerId,
                                nextAmt,
                                taxAmt: cfg.taxe ?? 0,
                                totalRefund: nextAmt,
                                nextPlayerName: nextPlayer?.name ?? "joueur suivant",
                              });
                            }
                          }
                        }
                      } catch (e: any) {
                        setError(e.message ?? "Erreur lors du tirage");
                      } finally {
                        setIsDrawing(false);
                      }
                    }}
                    className="w-full py-3 rounded-2xl border-[4px] border-black flex items-center justify-center gap-2"
                    style={{ ...FONT_BANGERS, background: isDrawing ? "#6b7280" : "#FFD700", color: "#000", fontSize: "1.1rem", letterSpacing: "0.06em", boxShadow: "4px 4px 0px #000" }}
                    disabled={isDrawing}
                  >
                    <CheckCircle className="w-5 h-5" /> {isDrawing ? "PIOCHE..." : "PIOCHER MA CARTE"}
                  </motion.button>
                )}
              </div>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ─ Perquisition : Étape 1 — Alerte piocheur ("le groupe va devoir se sauver") ─ */}
      <AnimatePresence>
        {miniGameAlertPhase === "trigger-alert" && pendingMiniGameMode !== null && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[80] flex items-center justify-center"
            style={{ background: "rgba(0,0,0,0.80)", backdropFilter: "blur(6px)" }}
          >
            <motion.div
              initial={{ scale: 0.8, y: 20 }}
              animate={{ scale: 1, y: 0 }}
              className="rounded-3xl border-[5px] border-black p-8 flex flex-col items-center gap-5 max-w-sm mx-4"
              style={{ background: "linear-gradient(160deg, #1a1a2e 0%, #16213e 100%)", boxShadow: "8px 8px 0px #000" }}
            >
              <span className="flex items-center justify-center"><Siren className="w-14 h-14 text-red-400" /></span>
              <span style={{ ...FONT_BANGERS, fontSize: "1.5rem", letterSpacing: "0.06em" }} className="text-red-400 text-center">
                PERQUISITION !
              </span>
              <span style={FONT_FREDOKA} className="text-white/80 text-sm text-center">
                Le groupe va devoir se sauver d'une perquisition à cause de toi !
              </span>
              <button
                className="w-full py-3 rounded-2xl border-[4px] border-black text-black font-bold text-lg active:scale-95 transition-transform"
                style={{ ...FONT_BANGERS, background: "#FFD700", boxShadow: "5px 5px 0px #000", letterSpacing: "0.08em", fontSize: "1.3rem" }}
                onClick={async () => {
                  // Étape 2 : Envoyer l'alerte à tous les joueurs via l'API
                  try {
                    const eliminated = session?.eliminatedPlayers ?? [];
                    const activePlayers = session?.turnOrder.filter((id: string) => !eliminated.includes(id)) ?? [];
                    const totalActive = Math.max(1, activePlayers.length);
                    const result = await triggerMiniGame.mutateAsync({
                      sessionCode: code,
                      playerId,
                      mode: pendingMiniGameMode!,
                      totalPlayers: totalActive,
                    });
                    setMiniGameEventId(result.eventId);
                    setMiniGameTotalPlayers(totalActive);
                    setMiniGameTriggeredBy(playerId);
                    miniGameTriggeredByRef.current = playerId;
                    // 🔊 Son d'alerte + vibration pour le piocheur aussi
                    triggerPerquisitionAlert();
                    // Passer à la phase commune pour le piocheur aussi
                    setMiniGameAlertPhase("common-alert");
                  } catch (e: any) {
                    setError(e.message ?? "Erreur lors du déclenchement du mini-jeu");
                    setMiniGameSkippedDraw(false);
                    setMiniGameAlertPhase(null);
                    setPendingMiniGameMode(null);
                  }
                }}
              >
                <span className="flex items-center justify-center gap-2"><Megaphone className="w-5 h-5" /> ALERTER LES AUTRES</span>
              </button>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ─ Perquisition : Étape 2 — Message commun ("Prêt à t'enfuir/te cacher ?") ─ */}
      <AnimatePresence>
        {miniGameAlertPhase === "common-alert" && pendingMiniGameMode !== null && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[80] flex items-center justify-center"
            style={{ background: "rgba(0,0,0,0.80)", backdropFilter: "blur(6px)" }}
          >
            <motion.div
              initial={{ scale: 0.8, y: 20 }}
              animate={{ scale: 1, y: 0 }}
              className="rounded-3xl border-[5px] border-black p-8 flex flex-col items-center gap-5 max-w-sm mx-4"
              style={{ background: "linear-gradient(160deg, #1a1a2e 0%, #16213e 100%)", boxShadow: "8px 8px 0px #000" }}
            >
              <motion.span
                className="flex items-center justify-center"
                animate={{ scale: [1, 1.2, 1] }}
                transition={{ duration: 1.5, repeat: Infinity }}
              >
                {pendingMiniGameMode === "run" ? <Siren className="w-14 h-14 text-red-400" /> : <Siren className="w-14 h-14 text-blue-400" />}
              </motion.span>
              <span style={{ ...FONT_BANGERS, fontSize: "1.5rem", letterSpacing: "0.06em" }} className="text-yellow-400 text-center">
                {pendingMiniGameMode === "run" ? "Prêt à t'enfuir ?" : "Prêt à te cacher ?"}
              </span>
              <span style={FONT_FREDOKA} className="text-white/60 text-sm text-center">
                Une perquisition a été déclenchée !
              </span>
              <button
                className="w-full py-3 rounded-2xl border-[4px] border-black text-white font-bold text-lg active:scale-95 transition-transform"
                style={{ ...FONT_BANGERS, background: "#e53935", boxShadow: "5px 5px 0px #000", letterSpacing: "0.08em", fontSize: "1.3rem" }}
                onClick={() => {
                  // Lancer le mini-jeu individuellement
                  setMiniGameAlertPhase(null);
                  setMiniGameMode(pendingMiniGameMode);
                  setPendingMiniGameMode(null);
                }}
              >
                COMMENCER
              </button>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ─ Perquisition (multijoueur) ─ */}
      {/* Tous les joueurs jouent le mini-jeu individuellement */}
      <AnimatePresence>
        {miniGameMode !== null && miniGameEventId !== null && !amEliminated && (
          <MiniGame
            mode={miniGameMode}
            difficulty={getMultiplayerMiniGameDifficulty()}
            onComplete={(success, amount) => {
              // Soumettre le résultat individuel
              submitMiniGameResult.mutateAsync({
                sessionCode: code,
                eventId: miniGameEventId,
                playerId,
                success,
                amount,
              }).catch(() => {});
              // Appliquer la pénalité/récompense via addDebt
              // La dette est déjà appliquée dans fetchMiniGameStatus pour tous les joueurs
              // Pas besoin de l'appliquer à nouveau ici
              setMiniGameMode(null);
              // TOUS les joueurs attendent les résultats finaux (pas seulement le déclencheur)
              // Cela permet à chacun de voir les résultats des autres et de mettre à jour son historique
              if (miniGameTotalPlayers > 1) {
                setWaitingForAllPlayers(true);
              } else {
                // Solo ou seul joueur actif : mettre à jour l'historique immédiatement
                if (session) {
                  const turnLabel = `Tour ${session.drawn.length}`;
                  setMiniGameHistory(prev => [...prev, { success, amount, turnLabel }]);
                }
              }
            }}
          />
        )}
      </AnimatePresence>

      {/* Overlay d'attente pour le piocheur : attend que tous aient terminé */}
      <AnimatePresence>
        {waitingForAllPlayers && !amEliminated && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[80] flex items-center justify-center"
            style={{ background: "rgba(0,0,0,0.75)", backdropFilter: "blur(4px)" }}
          >
            <motion.div
              initial={{ scale: 0.8, y: 20 }}
              animate={{ scale: 1, y: 0 }}
              className="rounded-3xl border-[5px] border-black p-8 flex flex-col items-center gap-4 max-w-sm mx-4"
              style={{ background: "linear-gradient(160deg, #1a1a2e 0%, #16213e 100%)", boxShadow: "8px 8px 0px #000" }}
            >
              <motion.div
                animate={{ rotate: 360 }}
                transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
                className="w-12 h-12 border-4 border-yellow-400 border-t-transparent rounded-full"
              />
              <span style={{ ...FONT_BANGERS, fontSize: "1.4rem", letterSpacing: "0.06em" }} className="text-yellow-400 text-center">
                PERQUISITION EN COURS
              </span>
              <span style={FONT_FREDOKA} className="text-white/60 text-sm text-center">
                En attente que tous les joueurs terminent...
              </span>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* Overlay spectateur : perquisition en cours (info seulement) */}
      <AnimatePresence>
        {amEliminated && waitingForAllPlayers && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[80] flex items-center justify-center pointer-events-none"
            style={{ background: "rgba(0,0,0,0.5)", backdropFilter: "blur(2px)" }}
          >
            <motion.div
              initial={{ scale: 0.8, y: 20 }}
              animate={{ scale: 1, y: 0 }}
              className="rounded-3xl border-[4px] border-yellow-400 p-6 flex flex-col items-center gap-3 max-w-sm mx-4"
              style={{ background: "linear-gradient(160deg, #1a1a2e 0%, #16213e 100%)", boxShadow: "6px 6px 0px rgba(250,204,21,0.3)" }}
            >
              <Siren className="w-8 h-8 text-yellow-400" />
              <span style={{ ...FONT_BANGERS, fontSize: "1.2rem", letterSpacing: "0.05em" }} className="text-yellow-400 text-center">
                PERQUISITION EN COURS
              </span>
              <span style={FONT_FREDOKA} className="text-white/70 text-xs text-center">
                Les joueurs en jeu effectuent une perquisition...
              </span>
            </motion.div>
          </motion.div>
        )}
      </AnimatePresence>

      {/* ─ Modal sélection destinataire T3 (investisseur) ─ */}
      <AnimatePresence>
        {showT3TargetModal && pendingT3 && session && (() => {
          const eliminated = session.eliminatedPlayers ?? [];
          // Liste des joueurs actifs sauf le piocheur lui-même
          const targets = session.turnOrder
            .filter((pid: string) => pid !== playerId && !eliminated.includes(pid))
            .map((pid: string) => {
              const player = session.players.find((p: any) => p.id === pid);
              const total = computePlayerTotalMp(session.playerCards?.[pid] ?? []) + (session.playerDebts?.[pid] ?? 0);
              const prof = mpPlayerProfiles?.[player?.name ?? ""];
              const avatar = prof ? getAvatarDisplay(prof.avatarType as "emoji" | "custom", prof.avatarId) : null;
              const guestEmojiForPid = (guestEmojis as Record<string, string> | undefined)?.[pid];
              return { pid, name: player?.name ?? "?", total, avatar, guestEmoji: guestEmojiForPid };
            });
          return (
            <motion.div
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              transition={{ duration: 0.18 }}
              className="fixed inset-0 z-[96] flex items-center justify-center px-5"
              style={{ background: "rgba(0,0,0,0.85)", backdropFilter: "blur(5px)" }}
            >
              <motion.div
                initial={{ scale: 0.75, y: 40, rotate: -2 }}
                animate={{ scale: 1, y: 0, rotate: 0 }}
                exit={{ scale: 0.75, y: 30, opacity: 0 }}
                transition={{ type: "spring", stiffness: 380, damping: 26 }}
                className="w-full max-w-sm rounded-3xl border-[5px] border-black overflow-hidden"
                style={{
                  background: "linear-gradient(160deg, #1a0a2e 0%, #0d0820 60%, #1a0a2e 100%)",
                  boxShadow: "10px 10px 0px #000, 0 0 50px rgba(139,92,246,0.35)",
                  borderColor: "#7C3AED",
                }}
              >
                {/* Header */}
                <div
                  className="px-5 py-3 flex items-center gap-3 border-b-[4px] border-black"
                  style={{ background: "linear-gradient(90deg, #6d28d9, #5b21b6)" }}
                >
                  <motion.div
                    animate={{ rotate: [0, -8, 8, 0], scale: [1, 1.15, 1] }}
                    transition={{ duration: 1.4, repeat: Infinity }}
                  >
                    <Users className="w-6 h-6 text-white" />
                  </motion.div>
                  <span style={{ ...FONT_BANGERS, fontSize: "1.3rem", letterSpacing: "0.07em" }} className="text-white flex-1">
                    Choisir le destinataire
                  </span>
                  <motion.button
                    whileTap={{ scale: 0.9 } as any}
                    onClick={() => { setShowT3TargetModal(false); setT3ConfirmTarget(null); }}
                    className="w-8 h-8 rounded-full bg-white/10 flex items-center justify-center"
                  >
                    <X className="w-4 h-4 text-white/70" />
                  </motion.button>
                </div>

                {t3ConfirmTarget === null ? (
                  <>
                    {/* Sous-titre */}
                    <div className="px-5 pt-4 pb-2">
                      <p style={FONT_FREDOKA} className="text-purple-300 text-sm text-center">
                        À qui veux-tu envoyer ce ticket investisseur ?
                      </p>
                      <p style={FONT_FREDOKA} className="text-white/40 text-xs text-center mt-1">
                        +{formatPrice(pendingT3.nextAmt)} ajouté à la dette du joueur choisi
                      </p>
                    </div>

                    {/* Liste des joueurs */}
                    <div className="px-4 pb-4 flex flex-col gap-2 max-h-72 overflow-y-auto">
                      {targets.map((target) => {
                        const isLeader = target.total === minTotal;
                        return (
                          <motion.button
                            key={target.pid}
                            whileTap={{ scale: 0.96 } as any}
                            onClick={() => setT3ConfirmTarget(target.pid)}
                            className="w-full flex items-center gap-3 px-4 py-3 rounded-2xl border-[3px] border-black text-left relative overflow-hidden"
                            style={{
                              background: "linear-gradient(135deg, rgba(109,40,217,0.25) 0%, rgba(91,33,182,0.15) 100%)",
                              boxShadow: "4px 4px 0px #000",
                              borderColor: isLeader ? "#fbbf24" : "#7C3AED",
                            }}
                          >
                            {/* Avatar */}
                            <div
                              className="w-10 h-10 rounded-xl border-[2px] border-black flex items-center justify-center flex-shrink-0 text-lg"
                              style={{ background: "rgba(255,255,255,0.08)", boxShadow: "2px 2px 0px #000" }}
                            >
                              {target.avatar?.type === "image" ? (
                                <img src={target.avatar.content} alt="" className="w-full h-full object-cover rounded-lg" />
                              ) : target.avatar?.type === "emoji" ? (
                                <span>{target.avatar.content}</span>
                              ) : target.guestEmoji ? (
                                <span>{target.guestEmoji}</span>
                              ) : (
                                <User className="w-5 h-5 text-white/50" />
                              )}
                            </div>

                            {/* Nom + dette */}
                            <div className="flex-1 min-w-0">
                              <div style={FONT_FREDOKA} className="text-white text-sm font-bold truncate">
                                {target.name}
                                {isLeader && <span className="ml-1 text-yellow-400 text-xs">★ En tête</span>}
                              </div>
                              <div style={FONT_FREDOKA} className="text-purple-300 text-xs">
                                Dette actuelle : <span className="text-white font-bold">{formatPrice(target.total)}</span>
                              </div>
                            </div>

                            {/* Flèche */}
                            <ArrowRight className="w-5 h-5 text-purple-400 flex-shrink-0" />
                          </motion.button>
                        );
                      })}
                    </div>
                  </>
                ) : (() => {
                  const confirmTarget = targets.find(t => t.pid === t3ConfirmTarget);
                  if (!confirmTarget) return null;
                  return (
                    <>
                      {/* Écran de confirmation */}
                      <div className="px-5 pt-5 pb-6 flex flex-col items-center gap-4">
                        {/* Avatar du joueur sélectionné */}
                        <div
                          className="w-16 h-16 rounded-2xl border-[3px] border-black flex items-center justify-center text-3xl"
                          style={{ background: "rgba(255,255,255,0.08)", boxShadow: "4px 4px 0px #000" }}
                        >
                          {confirmTarget.avatar?.type === "image" ? (
                            <img src={confirmTarget.avatar.content} alt="" className="w-full h-full object-cover rounded-xl" />
                          ) : confirmTarget.avatar?.type === "emoji" ? (
                            <span>{confirmTarget.avatar.content}</span>
                          ) : confirmTarget.guestEmoji ? (
                            <span>{confirmTarget.guestEmoji}</span>
                          ) : (
                            <User className="w-8 h-8 text-white/50" />
                          )}
                        </div>

                        {/* Texte de confirmation */}
                        <div className="text-center">
                          <p style={FONT_FREDOKA} className="text-white/60 text-sm mb-1">
                            Confirmer l'envoi à
                          </p>
                          <p style={{ ...FONT_BANGERS, fontSize: "1.5rem", letterSpacing: "0.06em" }} className="text-yellow-300">
                            {confirmTarget.name}
                          </p>
                          <p style={FONT_FREDOKA} className="text-purple-300 text-xs mt-2">
                            Dette actuelle : <span className="text-white font-bold">{formatPrice(confirmTarget.total)}</span>
                          </p>
                          <p style={FONT_FREDOKA} className="text-red-400 text-xs mt-1">
                            +{formatPrice(pendingT3.nextAmt)} sera ajouté à sa dette
                          </p>
                        </div>

                        {/* Boutons */}
                        <div className="flex gap-3 w-full mt-1">
                          <motion.button
                            whileTap={{ scale: 0.95 } as any}
                            onClick={() => setT3ConfirmTarget(null)}
                            className="flex-1 py-3 rounded-2xl border-[3px] border-black"
                            style={{
                              background: "rgba(255,255,255,0.08)",
                              boxShadow: "4px 4px 0px #000",
                              ...FONT_FREDOKA,
                              color: "#c4b5fd",
                              fontSize: "1rem",
                            }}
                          >
                            Retour
                          </motion.button>
                          <motion.button
                            whileTap={{ scale: 0.95 } as any}
                            onClick={() => { handleConfirmT3Target(t3ConfirmTarget); setT3ConfirmTarget(null); }}
                            className="flex-1 py-3 rounded-2xl border-[3px] border-black"
                            style={{
                              background: "linear-gradient(135deg, #7c3aed, #5b21b6)",
                              boxShadow: "4px 4px 0px #000",
                              ...FONT_BANGERS,
                              color: "#fff",
                              fontSize: "1.1rem",
                              letterSpacing: "0.06em",
                            }}
                          >
                            Confirmer
                          </motion.button>
                        </div>
                      </div>
                    </>
                  );
                })()}
              </motion.div>
            </motion.div>
          );
        })()}
      </AnimatePresence>
    </div>
  );
}
