Torn Poker Helper

Clean and simple poker helper for Torn City

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Torn Poker Helper
// @namespace    http://tampermonkey.net/
// @version      1.4.2
// @description  Clean and simple poker helper for Torn City
// @author       JESUUS [2353554]
// @match        https://www.torn.com/page.php?sid=holdem*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const ranks = '23456789TJQKA'.split('');
    const expertMode = false;
    const showProbabilities = true;
    const cache = new Map();
    let lastGameState = null;

    const translations = {
        en: {
            yourCards: 'Your cards',
            board: 'Board',
            combination: 'Combination',
            advice: 'Advice',
            draws: 'Draws',
            activePlayers: 'Active players',
            waiting: 'Waiting...',
            empty: 'Empty',
            analyzing: 'Analyzing...',
            outOf: 'outs •',
            chanceOf: '% chance',
            highCard: 'High Card',
            onePair: 'One Pair',
            twoPair: 'Two Pair',
            threeOfAKind: 'Three of a Kind',
            straight: 'Straight',
            flush: 'Flush',
            fullHouse: 'Full House',
            fourOfAKind: 'Four of a Kind',
            straightFlush: 'Straight Flush',
            royalFlush: 'Royal Flush',
            weakHandDrawTemplate:
                '🤔 Weak hand but possible draw ({probability}% chance). {position}',
            inPosition: 'In position, you can call or raise small',
            outOfPosition: 'Out of position, be careful',
            weakHandFollow:
                '🤔 Weak hand but possible draw. Call or check if cheap',
            allIn: '💰 You can go all-in (very strong hand)',
            raiseStrong: '🔥 You can raise big (good hand in position)',
            raiseNormal: '🔥 You can raise (good hand)',
            callOrRaise: '🙂 You can call or small raise (few opponents)',
            callOnly: '🙂 You can call',
            checkInPosition: '🤏 You can check in position',
            foldOrCheck: '🕊️ Wait and see (or fold)',
            fold: '🚫 I advise you to fold',
            winProbability: 'Win chance',
            folded: 'Folded',
            assistant: 'Poker Assistant',
            helper: 'Torn City Helper',
            language: 'Language',
            minimize: 'Minimize',
            maximize: 'Maximize',
            toggleView: 'Toggle view',
        },
        fr: {
            yourCards: 'Tes cartes',
            board: 'Plateau',
            combination: 'Combinaison',
            advice: 'Conseil',
            draws: 'Tirages',
            activePlayers: 'Joueurs actifs',
            waiting: 'En attente...',
            empty: 'Vide',
            analyzing: 'Analyse en cours...',
            outOf: 'outs •',
            chanceOf: '% de chances',
            highCard: 'Aucune combinaison',
            onePair: 'Une paire',
            twoPair: 'Deux paires',
            threeOfAKind: 'Un brelan',
            straight: 'Une suite',
            flush: 'Une couleur',
            fullHouse: 'Un full',
            fourOfAKind: 'Un carré',
            straightFlush: 'Suite couleur',
            royalFlush: 'Quinte flush royale',
            weakHandDrawTemplate:
                '🤔 Main faible mais tirage possible ({probability}% chance). {position}',
            inPosition: 'En position, tu peux suivre ou relancer petit',
            outOfPosition: 'Hors position, prudence',
            weakHandFollow:
                '🤔 Main faible mais tirage possible. Suis ou check si pas cher',
            allIn: '💰 Tu peux tout mettre (très forte main)',
            raiseStrong: '🔥 Tu peux relancer fort (bonne main en position)',
            raiseNormal: '🔥 Tu peux relancer (bonne main)',
            callOrRaise:
                "🙂 Tu peux suivre ou relancer léger (peu d'adversaires)",
            callOnly: '🙂 Tu peux suivre (call)',
            checkInPosition: '🤏 Tu peux checker en position',
            foldOrCheck: '🕊️ Attends de voir (ou couche-toi)',
            fold: '🚫 Je te conseille de te coucher',
            winProbability: 'Chance de victoire',
            folded: 'Couché',
            assistant: 'Assistant Poker',
            helper: 'Aide Torn City',
            language: 'Langue',
            minimize: 'Réduire',
            maximize: 'Agrandir',
            toggleView: 'Changer la vue',
        },
        de: {
            yourCards: 'Deine Karten',
            board: 'Board',
            combination: 'Kombination',
            advice: 'Ratschlag',
            draws: 'Draws',
            activePlayers: 'Aktive Spieler',
            waiting: 'Warten...',
            empty: 'Leer',
            analyzing: 'Analysieren...',
            outOf: 'Outs •',
            chanceOf: '% Chance',
            highCard: 'Höchste Karte',
            onePair: 'Ein Paar',
            twoPair: 'Zwei Paare',
            threeOfAKind: 'Drilling',
            straight: 'Straße',
            flush: 'Flush',
            fullHouse: 'Full House',
            fourOfAKind: 'Vierling',
            straightFlush: 'Straight Flush',
            royalFlush: 'Royal Flush',
            weakHandDrawTemplate:
                '🤔 Schwache Hand aber möglicher Draw ({probability}% Chance). {position}',
            inPosition: 'In Position, du kannst callen oder klein raisen',
            outOfPosition: 'Außerhalb der Position, sei vorsichtig',
            weakHandFollow:
                '🤔 Schwache Hand aber möglicher Draw. Calle oder checke wenn billig',
            allIn: '💰 Du kannst All-in gehen (sehr starke Hand)',
            raiseStrong: '🔥 Du kannst stark erhöhen (gute Hand in Position)',
            raiseNormal: '🔥 Du kannst erhöhen (gute Hand)',
            callOrRaise:
                '🙂 Du kannst callen oder leicht erhöhen (wenige Gegner)',
            callOnly: '🙂 Du kannst callen',
            checkInPosition: '🤏 Du kannst in Position checken',
            foldOrCheck: '🕊️ Warte ab (oder folde)',
            fold: '🚫 Ich rate dir zu folden',
            winProbability: 'Gewinnchance',
            folded: 'Gefoldet',
            assistant: 'Poker Assistent',
            helper: 'Torn City Helfer',
            language: 'Sprache',
            minimize: 'Minimieren',
            maximize: 'Maximieren',
            toggleView: 'Ansicht umschalten',
        },
        es: {
            yourCards: 'Tus cartas',
            board: 'Mesa',
            combination: 'Combinación',
            advice: 'Consejo',
            draws: 'Posibilidades',
            activePlayers: 'Jugadores activos',
            waiting: 'Esperando...',
            empty: 'Vacío',
            analyzing: 'Analizando...',
            outOf: 'outs •',
            chanceOf: '% de probabilidad',
            highCard: 'Carta alta',
            onePair: 'Una pareja',
            twoPair: 'Dos parejas',
            threeOfAKind: 'Trío',
            straight: 'Escalera',
            flush: 'Color',
            fullHouse: 'Full',
            fourOfAKind: 'Póker',
            straightFlush: 'Escalera de color',
            royalFlush: 'Escalera real',
            weakHandDrawTemplate:
                '🤔 Mano débil pero posible proyecto ({probability}% probabilidad). {position}',
            inPosition: 'En posición, puedes ver o subir poco',
            outOfPosition: 'Fuera de posición, ten cuidado',
            weakHandFollow:
                '🤔 Mano débil pero posible proyecto. Ve o pasa si es barato',
            allIn: '💰 Puedes ir all-in (mano muy fuerte)',
            raiseStrong: '🔥 Puedes subir fuerte (buena mano en posición)',
            raiseNormal: '🔥 Puedes subir (buena mano)',
            callOrRaise: '🙂 Puedes ver o subir poco (pocos oponentes)',
            callOnly: '🙂 Puedes ver',
            checkInPosition: '🤏 Puedes pasar en posición',
            foldOrCheck: '🕊️ Espera (o retírate)',
            fold: '🚫 Te aconsejo retirarte',
            winProbability: 'Probabilidad de ganar',
            folded: 'Retirado',
            assistant: 'Asistente de Póker',
            helper: 'Ayudante de Torn City',
            language: 'Idioma',
            minimize: 'Minimizar',
            maximize: 'Maximizar',
            toggleView: 'Cambiar vista',
        },
    };

    let currentLang = localStorage.getItem('tornPokerLanguage') || 'en';
    let isMinimized = localStorage.getItem('tornPokerMinimized') === 'true';
    let isMobileMode = false;
    let mobilePosition =
        localStorage.getItem('tornPokerMobilePosition') || 'bottom-right';
    function detectMobileMode() {
        isMobileMode = window.innerWidth <= 768;
        return isMobileMode;
    }

    window.addEventListener('resize', function () {
        const wasMobile = isMobileMode;
        const isMobileNow = detectMobileMode();

        if (wasMobile !== isMobileNow) {
            const main = lireCartesJoueur();
            const board = lireCartesPlateau();
            afficherInfos(main, board);
        }
    });
    function t(key, replacements = {}) {
        const text =
            translations[currentLang][key] || translations['en'][key] || key;
        return Object.entries(replacements).reduce((result, [key, value]) => {
            return result.replace(new RegExp('{' + key + '}', 'g'), value);
        }, text);
    }

    function changerLangue(lang) {
        if (translations[lang]) {
            currentLang = lang;
            localStorage.setItem('tornPokerLanguage', lang);
            const main = lireCartesJoueur();
            const board = lireCartesPlateau();
            afficherInfos(main, board);
        }
    }

    function changerPositionMobile() {
        const positions = [
            'top-left',
            'top-right',
            'bottom-right',
            'bottom-left',
        ];
        const currentIndex = positions.indexOf(mobilePosition);
        const nextIndex = (currentIndex + 1) % positions.length;
        mobilePosition = positions[nextIndex];
        localStorage.setItem('tornPokerMobilePosition', mobilePosition);

        const main = lireCartesJoueur();
        const board = lireCartesPlateau();
        afficherInfos(main, board);
    }
    function getPositionMobileStyles() {
        switch (mobilePosition) {
            case 'top-left':
                return 'top: 10px; left: 10px;';
            case 'top-right':
                return 'top: 10px; right: 10px;';
            case 'bottom-left':
                return 'bottom: 30px; left: 10px;';
            case 'bottom-right':
            default:
                return 'bottom: 30px; right: 10px;';
        }
    }

    const htmlTemplates = {
        mobileCard: (label, value, color = '#e2e8f0', dataAttr = '') => `
			<div style="
				background: rgba(255, 255, 255, 0.05);
				border-radius: 6px;
				padding: 5px 8px;
				margin-bottom: 4px;
				display: flex;
				justify-content: space-between;
				align-items: center;
			">
				<span style="font-size: 11px; color: ${color}; opacity: 0.9;">${label}</span>
				<span ${dataAttr} style="font-family: 'Courier New', monospace; font-weight: 600; color: ${color}; font-size: 12px;">
					${value}
				</span>
			</div>
		`,

        desktopCard: (
            label,
            value,
            color = '#e2e8f0',
            bgColor = 'rgba(255, 255, 255, 0.05)',
            dataAttr = ''
        ) => `
			<div style="
				background: ${bgColor};
				border-radius: 8px;
				padding: 10px 12px;
				margin-bottom: 16px;
			">
				<div style="display: flex; align-items: center; gap: 8px; margin-bottom: 8px;">
					<div style="width: 6px; height: 6px; background: ${color}; border-radius: 50%; box-shadow: 0 0 8px ${color}60;"></div>
					<span style="font-weight: 600; font-size: 13px; color: #e2e8f0;">${label}</span>
				</div>
				<div ${dataAttr} style="
					background: ${bgColor};
					border: 1px solid ${color}20;
					border-radius: 8px;
					padding: 10px 12px;
					font-family: 'Courier New', monospace;
					font-weight: 600;
					color: ${color};
					font-size: 15px;
				">${value}</div>
			</div>
		`,

        langOption: (code, flag, name, isActive) => `
			<div class="langOption" data-lang="${code}" style="
				display: flex;
				align-items: center;
				gap: 6px;
				padding: 6px 8px;
				color: ${isActive ? '#60a5fa' : '#e2e8f0'};
				font-weight: ${isActive ? '600' : '500'};
				font-size: 11px;
				cursor: pointer;
				transition: background 0.2s ease;
				${isActive ? 'background: rgba(59, 130, 246, 0.1);' : ''}
			">
				<span style="font-size: 12px;">${flag}</span>
				<span>${name}</span>
			</div>
		`,

        generateMobileInterface: (
            couleurAccent,
            main,
            board,
            nomFinal,
            conseilFinal,
            outs,
            nbJoueurs,
            isMinimized,
            winProbability
        ) => {
            if (isMinimized) {
                return `
					<div id="toggleMinimize" style="
						width: 40px;
						height: 40px;
						display: flex;
						align-items: center;
						justify-content: center;
						cursor: pointer;
						background: linear-gradient(135deg, ${couleurAccent}50, ${couleurAccent}30);
						border-radius: 10px;
						position: relative;
					">
						<div style="
							width: 28px;
							height: 28px;
							background: linear-gradient(135deg, ${couleurAccent}, ${couleurAccent}80);
							border-radius: 8px;
							display: flex;
							align-items: center;
							justify-content: center;
							font-size: 14px;
						">🃏</div>
						<div style="
							position: absolute;
							bottom: -1px;
							right: -1px;
							width: 10px;
							height: 10px;
							background: rgba(255, 255, 255, 0.9);
							border-radius: 50%;
							display: flex;
							align-items: center;
							justify-content: center;
							font-size: 7px;
							color: #333;
						">📍</div>
					</div>
				`;
            }

            return `
				<div style="display: flex; flex-direction: column;">
					<div style="
						display: flex;
						align-items: center;
						justify-content: space-between;
						padding: 6px 8px;
						border-bottom: 1px solid rgba(255, 255, 255, 0.1);
					">
						<div style="display: flex; align-items: center; gap: 6px;">
							<div style="
								width: 20px;
								height: 20px;
								background: linear-gradient(135deg, ${couleurAccent}, ${couleurAccent}80);
								border-radius: 5px;
								display: flex;
								align-items: center;
								justify-content: center;
								font-size: 11px;
							">🃏</div>
							<div style="font-weight: 600; font-size: 11px; color: white; opacity: 0.95;">${t(
                                'assistant'
                            )}</div>
						</div>
						<div style="display: flex; gap: 4px;">
							<div id="positionButton" style="
								width: 20px;
								height: 20px;
								display: flex;
								align-items: center;
								justify-content: center;
								background: rgba(255, 255, 255, 0.1);
								border-radius: 5px;
								cursor: pointer;
								font-size: 9px;
							">📍</div>
							<div id="langSelector" style="position: relative;">
								<div id="langButton" style="
									width: 20px;
									height: 20px;
									display: flex;
									align-items: center;
									justify-content: center;
									background: rgba(255, 255, 255, 0.1);
									border-radius: 5px;
									cursor: pointer;
									font-size: 9px;
								">${langConfig[currentLang].flag}</div>
								<div id="langOptions" style="
									display: none;
									position: absolute;
									top: 100%;
									right: 0;
									margin-top: 2px;
									background: rgba(15, 23, 42, 0.98);
									border: 1px solid rgba(255, 255, 255, 0.1);
									border-radius: 5px;
									overflow: hidden;
									box-shadow: 0 4px 12px -2px rgba(0, 0, 0, 0.8);
									width: 90px;
									z-index: 100000;
								">
									${Object.entries(langConfig)
                                        .map(
                                            ([code, { flag, name }]) => `
										<div class="langOption" data-lang="${code}" style="
											display: flex;
											align-items: center;
											gap: 5px;
											padding: 5px 8px;
											color: ${code === currentLang ? '#60a5fa' : '#e2e8f0'};
											font-weight: ${code === currentLang ? '600' : '500'};
											font-size: 9px;
											cursor: pointer;
											transition: background 0.2s ease;
											${code === currentLang ? 'background: rgba(59, 130, 246, 0.1);' : ''}
										">
											<span style="font-size: 9px;">${flag}</span>
											<span>${name}</span>
										</div>
									`
                                        )
                                        .join('')}
								</div>
							</div>
							<div id="toggleMinimize" style="
								width: 20px;
								height: 20px;
								display: flex;
								align-items: center;
								justify-content: center;
								background: rgba(255, 255, 255, 0.1);
								border-radius: 5px;
								cursor: pointer;
								font-size: 11px;
							">–</div>
						</div>
					</div>

					<div style="padding: 6px 8px;">
						${htmlTemplates.mobileCard(
                            t('yourCards'),
                            main.length ? main.join(' ') : t('waiting'),
                            'white',
                            'data-player-cards'
                        )}
						${htmlTemplates.mobileCard(
                            t('board'),
                            board.length ? board.join(' ') : t('empty'),
                            '#10b981',
                            'data-board-cards'
                        )}
						${htmlTemplates.mobileCard(
                            t('combination'),
                            nomFinal || t('analyzing'),
                            '#8b5cf6',
                            'data-combination'
                        )}
						${
                            winProbability > 0
                                ? htmlTemplates.mobileCard(
                                      t('winProbability'),
                                      `${Math.round(winProbability * 100)}%`,
                                      '#3b82f6',
                                      'data-win-probability'
                                  )
                                : ''
                        }
						<div data-advice style="
							background: linear-gradient(135deg, ${couleurAccent}30, ${couleurAccent}15);
							border: 1px solid ${couleurAccent}50;
							border-radius: 6px;
							padding: 5px 8px;
							color: white;
							font-weight: 600;
							font-size: 11px;
							line-height: 1.3;
							text-align: center;
							margin-bottom: 4px;
						">${conseilFinal}</div>
						${
                            outs && outs.nombre > 0
                                ? htmlTemplates.mobileCard(
                                      t('draws'),
                                      `${outs.nombre} ${t(
                                          'outOf'
                                      )} ${Math.round(
                                          outs.probability * 100
                                      )}${t('chanceOf')}`,
                                      '#f59e0b',
                                      'data-outs'
                                  )
                                : ''
                        }
					</div>
				</div>
			`;
        },

        generateLangSelector: (couleurAccent) => `
			<div id="langSelector" style="position: relative;">
				<div id="langButton" style="
					width: 24px;
					height: 24px;
					display: flex;
					align-items: center;
					justify-content: center;
					background: rgba(255, 255, 255, 0.1);
					border-radius: 6px;
					cursor: pointer;
					font-size: 12px;
				">${langConfig[currentLang].flag}</div>
				<div id="langOptions" style="
					display: none;
					position: absolute;
					top: 100%;
					right: 0;
					margin-top: 4px;
					background: rgba(15, 23, 42, 0.98);
					border: 1px solid rgba(255, 255, 255, 0.1);
					border-radius: 6px;
					overflow: hidden;
					box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.7);
					width: 100px;
					z-index: 100000;
				">
					${Object.entries(langConfig)
                        .map(([code, { flag, name }]) =>
                            htmlTemplates.langOption(
                                code,
                                flag,
                                name,
                                code === currentLang
                            )
                        )
                        .join('')}
				</div>
			</div>
		`,

        generateDesktopInterface: (
            couleurAccent,
            main,
            board,
            nomFinal,
            conseilFinal,
            outs,
            nbJoueurs,
            winProbability
        ) => `
			<div data-drag-handle style="
				background: linear-gradient(135deg, ${couleurAccent}20, ${couleurAccent}10);
				padding: 16px 20px;
				border-radius: 14px 14px 0 0;
				border-bottom: 1px solid ${couleurAccent}40;
				position: relative;
			">
				<div style="
					display: flex;
					align-items: center;
					gap: 12px;
					margin-bottom: 12px;
				">
					<div style="
						width: 40px;
						height: 40px;
						background: linear-gradient(135deg, ${couleurAccent}, ${couleurAccent}80);
						border-radius: 12px;
						display: flex;
						align-items: center;
						justify-content: center;
						font-size: 20px;
						box-shadow: 0 4px 12px ${couleurAccent}40;
					">🃏</div>
					<div>
						<div style="font-weight: 700; font-size: 16px; color: white;">${t(
                            'assistant'
                        )}</div>
						<div style="font-size: 12px; color: ${couleurAccent}; opacity: 0.8;">${t(
            'helper'
        )}</div>
					</div>
					${htmlTemplates.generateDesktopLangSelector(couleurAccent)}
				</div>
			</div>

			<div style="padding: 20px;">
				${htmlTemplates.desktopCard(
                    t('yourCards'),
                    main.length ? main.join(' • ') : '🎴 ' + t('waiting'),
                    'white',
                    'rgba(255, 255, 255, 0.05)',
                    'data-player-cards'
                )}
				${htmlTemplates.desktopCard(
                    t('board'),
                    board.length ? board.join(' • ') : '🟢 ' + t('empty'),
                    '#10b981',
                    'rgba(16, 185, 129, 0.1)',
                    'data-board-cards'
                )}
				${htmlTemplates.desktopCard(
                    t('combination'),
                    nomFinal || '🔍 ' + t('analyzing'),
                    '#8b5cf6',
                    'linear-gradient(135deg, rgba(139, 92, 246, 0.15), rgba(139, 92, 246, 0.05))',
                    'data-combination'
                )}
				${
                    winProbability > 0
                        ? htmlTemplates.desktopCard(
                              t('winProbability'),
                              `🎯 ${Math.round(winProbability * 100)}%`,
                              '#3b82f6',
                              'linear-gradient(135deg, rgba(59, 130, 246, 0.15), rgba(59, 130, 246, 0.05))',
                              'data-win-probability'
                          )
                        : ''
                }

				<div style="margin-bottom: ${outs ? '16px' : '0'};">
					<div style="
						display: flex;
						align-items: center;
						gap: 8px;
						margin-bottom: 8px;
					">
						<div style="
							width: 6px;
							height: 6px;
							background: ${couleurAccent};
							border-radius: 50%;
							box-shadow: 0 0 8px ${couleurAccent}60;
						"></div>
						<span style="font-weight: 600; font-size: 13px; color: #e2e8f0;">${t(
                            'advice'
                        )}</span>
					</div>
					<div data-advice style="
						background: linear-gradient(135deg, ${couleurAccent}20, ${couleurAccent}10);
						border: 1px solid ${couleurAccent}40;
						border-radius: 8px;
						padding: 12px;
						color: white;
						font-weight: 600;
						font-size: 14px;
						line-height: 1.4;
					">${conseilFinal}</div>
				</div>

				${
                    outs && outs.nombre > 0
                        ? `
				<div style="margin-bottom: 16px;">
					<div style="
						display: flex;
						align-items: center;
						gap: 8px;
						margin-bottom: 8px;
					">
						<div style="
							width: 6px;
							height: 6px;
							background: #f59e0b;
							border-radius: 50%;
							box-shadow: 0 0 8px #f59e0b60;
						"></div>
						<span style="font-weight: 600; font-size: 13px; color: #e2e8f0;">${t(
                            'draws'
                        )}</span>
					</div>
					<div data-outs style="
						background: linear-gradient(135deg, rgba(245, 158, 11, 0.15), rgba(245, 158, 11, 0.05));
						border: 1px solid rgba(245, 158, 11, 0.3);
						border-radius: 8px;
						padding: 12px;
						color: #fbbf24;
						font-weight: 600;
						font-size: 14px;
					">
						${outs.nombre} ${t('outOf')} ${Math.round(outs.probability * 100)}${t(
                              'chanceOf'
                          )}
						<div style="color: #94a3b8; font-size: 12px; line-height: 1.3; margin-top: 4px;">
							${outs.details.slice(0, 3).join(' • ')}${outs.details.length > 3 ? '...' : ''}
						</div>
					</div>
				</div>
				`
                        : ''
                }

				${
                    nbJoueurs > 0
                        ? `
				<div style="
					margin-top: 16px;
					padding-top: 16px;
					border-top: 1px solid rgba(255, 255, 255, 0.1);
				">
					<div style="
						display: flex;
						justify-content: space-between;
						align-items: center;
					">
						<div style="
							display: flex;
							align-items: center;
							gap: 8px;
						">
							<span style="font-size: 16px;">👥</span>
							<span style="color: #94a3b8; font-size: 13px;">${t('activePlayers')}</span>
						</div>
						<div data-active-players style="
							background: rgba(255, 255, 255, 0.1);
							border-radius: 12px;
							padding: 4px 12px;
							font-weight: 700;
							color: white;
							font-size: 13px;
						">${nbJoueurs}</div>
					</div>
				</div>
				`
                        : ''
                }
			</div>
		`,

        generateDesktopLangSelector: (couleurAccent) => `
			<div id="langSelector" style="
				position: absolute;
				top: 16px;
				right: 16px;
				z-index: 2;
			">
				<div id="langButton" style="
					display: flex;
					align-items: center;
					justify-content: center;
					width: 32px;
					height: 32px;
					background: rgba(255, 255, 255, 0.1);
					border-radius: 8px;
					cursor: pointer;
					user-select: none;
					transition: all 0.2s ease;
				">
					<span style="font-size: 16px;">${langConfig[currentLang].flag}</span>
				</div>
				<div id="langOptions" style="
					display: none;
					position: absolute;
					top: 100%;
					right: 0;
					margin-top: 8px;
					background: rgba(15, 23, 42, 0.95);
					backdrop-filter: blur(12px);
					border: 1px solid rgba(255, 255, 255, 0.1);
					border-radius: 8px;
					overflow: hidden;
					box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.7);
					width: 120px;
					z-index: 3;
				">
					${Object.entries(langConfig)
                        .map(
                            ([code, { flag, name }]) => `
						<div class="langOption" data-lang="${code}" style="
							display: flex;
							align-items: center;
							gap: 8px;
							padding: 10px 12px;
							color: ${code === currentLang ? '#60a5fa' : '#e2e8f0'};
							font-weight: ${code === currentLang ? '700' : '500'};
							font-size: 13px;
							cursor: pointer;
							transition: background 0.2s ease;
							${code === currentLang ? 'background: rgba(59, 130, 246, 0.1);' : ''}
						">
							<span style="font-size: 16px;">${flag}</span>
							<span>${name}</span>
						</div>
					`
                        )
                        .join('')}
				</div>
			</div>
		`,
    };

    function updateContentOnly(main, board, box) {
        const isMobile = window.innerWidth <= 768;
        const joueurAFold = detecterSiJoueurAFold();

        const playerCardsElement = box.querySelector('[data-player-cards]');
        if (playerCardsElement) {
            if (isMobile) {
                playerCardsElement.textContent = main.length
                    ? main.join(' ')
                    : t('waiting');
            } else {
                playerCardsElement.textContent = main.length
                    ? main.join(' • ')
                    : '🎴 ' + t('waiting');
            }
        }

        const boardCardsElement = box.querySelector('[data-board-cards]');
        if (boardCardsElement) {
            if (isMobile) {
                boardCardsElement.textContent = board.length
                    ? board.join(' ')
                    : t('empty');
            } else {
                boardCardsElement.textContent = board.length
                    ? board.join(' • ')
                    : '🟢 ' + t('empty');
            }
        }

        const nbJoueurs = compterJoueursActifs();
        const activePlayersElement = box.querySelector('[data-active-players]');
        if (activePlayersElement) {
            activePlayersElement.textContent = nbJoueurs;
        }

        if (joueurAFold) {
            const winProbabilityElement = box.querySelector(
                '[data-win-probability]'
            );
            if (winProbabilityElement) {
                winProbabilityElement.textContent = t('folded');
            }

            const adviceElement = box.querySelector('[data-advice]');
            if (adviceElement) {
                adviceElement.textContent = t('folded');
            }

            const combinationElement = box.querySelector('[data-combination]');
            if (combinationElement) {
                combinationElement.textContent = '';
            }
        } else if (main.length >= 2) {
            const toutesCartes = [...main, ...board];
            const evaluation = evaluerMain(toutesCartes, true);
            const position = detecterPosition();

            let outs = null;
            if (evaluation.tirage && main.length >= 2 && board.length >= 3) {
                outs = calculerOuts(main, board);
            }

            const winProbability = calculerProbabiliteVictoire(
                main,
                board,
                nbJoueurs,
                500
            );
            const nomFinal = expertMode
                ? evaluation.nom
                : simplifierMain(evaluation.nom);
            const conseilFinal = simplifierConseil(
                evaluation.conseil,
                position,
                nbJoueurs,
                evaluation.tirage,
                outs
            );

            const combinationElement = box.querySelector('[data-combination]');
            if (combinationElement) {
                if (isMobile) {
                    combinationElement.textContent = nomFinal || t('analyzing');
                } else {
                    combinationElement.textContent =
                        nomFinal || '🔍 ' + t('analyzing');
                }
            }

            const winProbabilityElement = box.querySelector(
                '[data-win-probability]'
            );
            if (winProbabilityElement) {
                if (isMobile) {
                    winProbabilityElement.textContent = `${Math.round(
                        winProbability * 100
                    )}%`;
                } else {
                    winProbabilityElement.textContent = `🎯 ${Math.round(
                        winProbability * 100
                    )}%`;
                }
            }

            const adviceElement = box.querySelector('[data-advice]');
            if (adviceElement) {
                adviceElement.textContent = conseilFinal;
            }

            const outsElement = box.querySelector('[data-outs]');
            if (outsElement && outs && outs.nombre > 0) {
                outsElement.textContent = `${outs.nombre} ${t(
                    'outOf'
                )} ${Math.round(outs.probability * 100)}${t('chanceOf')}`;
            }
        }
    }

    function extraireValeurEtCouleur(className) {
        const regex = /(clubs|spades|hearts|diamonds)-([0-9TJQKA]+)/;
        const match = className.match(regex);
        if (!match) {
            return null;
        }
        const couleurMap = {
            clubs: '♣',
            spades: '♠',
            hearts: '♥',
            diamonds: '♦',
        };
        const couleur = couleurMap[match[1]];
        const valeur = match[2].toUpperCase();
        return `${valeur}${couleur}`;
    }

    function lireCartesJoueur() {
        const cartes = document.querySelectorAll(
            '.playerMeGateway___AEI5_ .hand___aOp4l .card___t7csZ .front___osz1p > div'
        );
        return Array.from(cartes)
            .map((c) => extraireValeurEtCouleur(c.className))
            .filter(Boolean);
    }

    function lireCartesPlateau() {
        const cartes = document.querySelectorAll(
            '.communityCards___cGHD3 .front___osz1p > div'
        );
        return Array.from(cartes)
            .map((c) => extraireValeurEtCouleur(c.className))
            .filter(Boolean);
    }

    function compterJoueursActifs() {
        let joueursTable = document.querySelectorAll('[class*="opponent___"]');
        if (joueursTable.length === 0) {
            joueursTable = document.querySelectorAll('[id*="player-"]');
        }
        if (joueursTable.length === 0) {
            joueursTable = Array.from(
                document.querySelectorAll('[class*="name___"]')
            )
                .map((nom) =>
                    nom.closest(
                        'div[class*="player"], div[class*="opponent"], div'
                    )
                )
                .filter(Boolean);
        }

        let joueursActifs = 0;

        if (joueursTable.length > 0) {
            joueursTable.forEach((joueur, index) => {
                const nom = joueur.querySelector
                    ? joueur.querySelector('[class*="name___"]')
                    : null;
                const texteComplet = joueur.textContent
                    ? joueur.textContent.toLowerCase()
                    : '';

                const estInactif =
                    texteComplet.includes('sitting out') ||
                    texteComplet.includes('waiting bb') ||
                    texteComplet.includes('waiting') ||
                    texteComplet.includes('folded') ||
                    texteComplet.includes('fold');

                if (!estInactif) {
                    joueursActifs++;
                }
            });
        } else {
            const nomsJoueurs = document.querySelectorAll('[class*="name___"]');

            nomsJoueurs.forEach((nom, index) => {
                let conteneur = nom.parentElement;
                while (
                    conteneur &&
                    !conteneur.textContent.includes('Sitting out') &&
                    !conteneur.textContent.includes('Waiting') &&
                    conteneur.parentElement
                ) {
                    conteneur = conteneur.parentElement;
                }

                const texteComplet = conteneur
                    ? conteneur.textContent.toLowerCase()
                    : '';
                const estInactif =
                    texteComplet.includes('sitting out') ||
                    texteComplet.includes('waiting bb') ||
                    texteComplet.includes('waiting') ||
                    texteComplet.includes('folded') ||
                    texteComplet.includes('fold');

                if (!estInactif) {
                    joueursActifs++;
                }
            });
        }

        let votreStatut = '';

        const scriptStatus =
            document.querySelector('[data-testid="poker-assistant"]')
                ?.textContent ||
            document.querySelector('.advice')?.textContent ||
            document.querySelector('[class*="advice"]')?.textContent ||
            '';

        const votreJoueur = document.querySelector('.playerMeGateway___AEI5_');
        const playerStatus = votreJoueur
            ? votreJoueur.textContent.toLowerCase()
            : '';

        let yourSpecificStatus = '';
        if (votreJoueur) {
            const yourStatusSpan = votreJoueur.querySelector('span');
            yourSpecificStatus = yourStatusSpan
                ? yourStatusSpan.textContent.toLowerCase()
                : '';
        }

        votreStatut = (
            scriptStatus +
            ' ' +
            playerStatus +
            ' ' +
            yourSpecificStatus
        ).toLowerCase();

        const vosCartes = document.querySelectorAll(
            '.playerMeGateway___AEI5_ .hand___aOp4l .card___t7csZ'
        );
        const avezDesCartes = vosCartes.length >= 2;

        const votreZone = document.querySelector('.playerMeGateway___AEI5_');
        const votreZoneText = votreZone
            ? votreZone.textContent.toLowerCase()
            : '';

        let votreZoneComplete = votreZoneText;
        if (votreZone) {
            const spans = votreZone.querySelectorAll('span, div');
            spans.forEach((span) => {
                votreZoneComplete += ' ' + span.textContent.toLowerCase();
            });
        }

        const vousAvezFolde =
            votreZoneComplete.includes('folded') ||
            votreStatut.includes('folded') ||
            votreStatut.includes('fold');

        const vousEtesActif =
            avezDesCartes &&
            !vousAvezFolde &&
            !votreStatut.includes('waiting') &&
            !votreStatut.includes('sitting out');

        if (vousEtesActif) {
            joueursActifs++;
        }

        if (joueursActifs === 0) {
            const positionsAvecCartes = document.querySelectorAll(
                '[class*="hand___"], [class*="card___"]'
            ).length;
            const positionsAvecJetons = document.querySelectorAll(
                '[class*="bet"], [class*="chip"]'
            ).length;

            joueursActifs = Math.max(
                Math.floor(positionsAvecCartes / 2),
                Math.floor(positionsAvecJetons / 2),
                3
            );
        }

        const resultat = Math.max(joueursActifs, 2);

        if (window.lastPlayerCount !== resultat) {
            window.lastPlayerCount = resultat;
        }

        return resultat;
    }

    function detecterSiJoueurAFold() {
        const vosCartes = document.querySelectorAll(
            '.playerMeGateway___AEI5_ .hand___aOp4l .card___t7csZ'
        );
        const avezDesCartes = vosCartes.length >= 2;

        const votreZone = document.querySelector('.playerMeGateway___AEI5_');
        const votreZoneText = votreZone
            ? votreZone.textContent.toLowerCase()
            : '';

        let votreZoneComplete = votreZoneText;
        if (votreZone) {
            const spans = votreZone.querySelectorAll('span, div');
            spans.forEach((span) => {
                votreZoneComplete += ' ' + span.textContent.toLowerCase();
            });
        }

        const votreJoueur = document.querySelector('.playerMeGateway___AEI5_');
        const playerStatus = votreJoueur
            ? votreJoueur.textContent.toLowerCase()
            : '';

        const vousAvezFolde =
            votreZoneComplete.includes('folded') ||
            playerStatus.includes('folded') ||
            playerStatus.includes('fold');

        return vousAvezFolde;
    }

    function detecterPosition() {
        const bouton = document.querySelector('.yourTurn___b2sZp');
        return bouton && bouton.textContent.includes('Your turn');
    }

    function detecterPositionTable() {
        const tousJoueurs = document.querySelectorAll('.player___Z25g2');
        const monIndex = Array.from(tousJoueurs).findIndex((p) =>
            p.classList.contains('playerMeGateway___AEI5_')
        );

        if (monIndex === -1) {
            return 0;
        }

        const totalJoueurs = tousJoueurs.length;
        if (monIndex === totalJoueurs - 1) {
            return 2; // Button/Dealer
        }
        if (monIndex === 0 || monIndex === 1) {
            return 0; // SB/BB
        }
        return 1; // Position médiane
    }

    function simplifierMain(nom) {
        return t(nom.replace(/\s+/g, '').toLowerCase()) || nom;
    }

    function trouverMeilleureMain(toutesCartes) {
        if (toutesCartes.length < 5) {
            return toutesCartes;
        }

        const combinations = [];

        function getCombinations(arr, size) {
            if (size === 1) {
                return arr.map((el) => [el]);
            }
            const result = [];
            arr.forEach((el, i) => {
                const rest = arr.slice(i + 1);
                const combos = getCombinations(rest, size - 1);
                combos.forEach((combo) => {
                    result.push([el, ...combo]);
                });
            });
            return result;
        }

        const combos = getCombinations(toutesCartes, 5);
        let meilleureCombo = combos[0];
        let meilleureEval = evaluerMain5Cartes(combos[0]);

        combos.forEach((combo) => {
            const evaluate = evaluerMain5Cartes(combo);
            if (comparerMains(evaluate, meilleureEval) > 0) {
                meilleureCombo = combo;
                meilleureEval = evaluate;
            }
        });

        return { cartes: meilleureCombo, evaluation: meilleureEval };
    }

    function comparerMains(main1, main2) {
        if (main1.force !== main2.force) {
            return main1.force - main2.force;
        }

        if (main1.valeurPrincipale !== main2.valeurPrincipale) {
            return main1.valeurPrincipale - main2.valeurPrincipale;
        }

        for (
            let i = 0;
            i < Math.max(main1.kickers.length, main2.kickers.length);
            i++
        ) {
            const k1 = main1.kickers[i] || -1;
            const k2 = main2.kickers[i] || -1;
            if (k1 !== k2) {
                return k1 - k2;
            }
        }

        return 0;
    }

    function evaluerMain5Cartes(cartes5) {
        const suits = { '♠': [], '♥': [], '♦': [], '♣': [] };
        const values = {};
        const allVals = [];

        cartes5.forEach((card) => {
            const match = card.match(/^([0-9TJQKA]+)(.)$/);
            if (!match) {
                return;
            }

            const val = match[1];
            const suit = match[2];
            suits[suit].push(val);
            values[val] = (values[val] || 0) + 1;
            allVals.push(val);
        });

        const countList = Object.values(values).sort((a, b) => b - a);
        const allRanks = allVals
            .map((v) => ranks.indexOf(v))
            .sort((a, b) => b - a);

        const flushSuit = Object.entries(suits).find(
            ([_, list]) => list.length === 5
        );
        const isFlush = !!flushSuit;

        const uniqueRanks = [...new Set(allRanks)].sort((a, b) => a - b);
        let straightFound = false;
        let straightHighCard = 0;

        // Vérifier toutes les suites possibles de 5 cartes consécutives
        for (let i = 0; i <= uniqueRanks.length - 5; i++) {
            const seq = uniqueRanks.slice(i, i + 5);
            // Vérifier si c'est une suite (différence de 4 entre la première et dernière carte)
            if (seq[4] - seq[0] === 4) {
                straightFound = true;
                straightHighCard = seq[4];
                break;
            }
        }

        if (!straightFound) {
            // Vérifier la wheel (A-2-3-4-5)
            const wheelRanks = [
                ranks.indexOf('A'),
                ranks.indexOf('2'),
                ranks.indexOf('3'),
                ranks.indexOf('4'),
                ranks.indexOf('5'),
            ];
            const hasWheel = wheelRanks.every((rank) =>
                uniqueRanks.includes(rank)
            );
            if (hasWheel) {
                straightFound = true;
                straightHighCard = ranks.indexOf('5');
            }
        }

        const royalFlush =
            isFlush && straightFound && straightHighCard === ranks.indexOf('A');

        const valeurPair = Object.entries(values)
            .filter(([_, count]) => count === 2)
            .map(([val, _]) => ranks.indexOf(val))
            .sort((a, b) => b - a);

        const valeurBrelan = Object.entries(values)
            .filter(([_, count]) => count === 3)
            .map(([val, _]) => ranks.indexOf(val))[0];

        const valeurCarre = Object.entries(values)
            .filter(([_, count]) => count === 4)
            .map(([val, _]) => ranks.indexOf(val))[0];

        let kickers = [];
        let force = 0;
        let valeurPrincipale = 0;
        let nom = '';

        if (royalFlush) {
            force = 9;
            valeurPrincipale = ranks.indexOf('A');
            nom = 'Royal Flush';
            kickers = [];
        } else if (isFlush && straightFound) {
            force = 8;
            valeurPrincipale = straightHighCard;
            nom = 'Straight Flush';
            kickers = [];
        } else if (countList[0] === 4) {
            force = 7;
            valeurPrincipale = valeurCarre;
            nom = 'Four of a Kind';
            kickers = allRanks.filter((r) => r !== valeurCarre).slice(0, 1);
        } else if (countList[0] === 3 && countList[1] === 2) {
            force = 6;
            valeurPrincipale = valeurBrelan;
            nom = 'Full House';
            kickers = valeurPair.slice(0, 1);
        } else if (isFlush) {
            force = 5;
            nom = 'Flush';
            const flushCards = suits[flushSuit[0]]
                .map((v) => ranks.indexOf(v))
                .sort((a, b) => b - a);
            valeurPrincipale = flushCards[0];
            kickers = flushCards.slice(1, 5);
        } else if (straightFound) {
            force = 4;
            valeurPrincipale = straightHighCard;
            nom = 'Straight';
            kickers = [];
        } else if (countList[0] === 3) {
            force = 3;
            valeurPrincipale = valeurBrelan;
            nom = 'Three of a Kind';
            kickers = allRanks.filter((r) => r !== valeurBrelan).slice(0, 2);
        } else if (countList[0] === 2 && countList[1] === 2) {
            force = 2;
            valeurPrincipale = valeurPair[0];
            nom = 'Two Pair';
            kickers = [
                valeurPair[1],
                ...allRanks.filter((r) => !valeurPair.includes(r)).slice(0, 1),
            ];
        } else if (countList[0] === 2) {
            force = 1;
            valeurPrincipale = valeurPair[0];
            nom = 'One Pair';
            kickers = allRanks.filter((r) => r !== valeurPair[0]).slice(0, 3);
        } else {
            force = 0;
            valeurPrincipale = allRanks[0];
            nom = 'High Card';
            kickers = allRanks.slice(1, 5);
        }

        return {
            nom,
            force,
            valeurPrincipale,
            kickers,
            cartes: cartes5,
        };
    }

    function calculerOuts(main, board) {
        const toutesCartes = [...main, ...board];
        const cartesUtilisees = new Set(toutesCartes);
        const outs = new Set();
        const outDetails = [];

        // Analyser les tirages possibles
        const flushOuts = calculerFlushOuts(main, board, cartesUtilisees);
        const straightOuts = calculerStraightOuts(main, board, cartesUtilisees);

        // Ajouter les outs de flush
        flushOuts.forEach((carte) => {
            outs.add(carte);
            outDetails.push(`${carte} → Flush`);
        });

        // Ajouter les outs de suite
        straightOuts.forEach((carte) => {
            if (!outs.has(carte)) {
                outDetails.push(`${carte} → Straight`);
            }
            outs.add(carte);
        });

        return {
            nombre: outs.size,
            details: outDetails,
            probability: calculerProbabilite(outs.size, board.length),
        };
    }

    function calculerFlushOuts(main, board, cartesUtilisees) {
        const outs = [];
        const toutesCartes = [...main, ...board];

        // Compter les cartes par couleur
        const suits = { '♠': [], '♥': [], '♦': [], '♣': [] };
        toutesCartes.forEach((carte) => {
            const match = carte.match(/^([0-9TJQKA]+)(.)$/);
            if (match) {
                suits[match[2]].push(match[1]);
            }
        });

        // Chercher un tirage couleur (4 cartes de même couleur)
        Object.entries(suits).forEach(([suit, cartes]) => {
            if (cartes.length === 4) {
                // Ajouter toutes les cartes restantes de cette couleur
                const allRanks = '23456789TJQKA'.split('');
                allRanks.forEach((rank) => {
                    const carte = `${rank}${suit}`;
                    if (!cartesUtilisees.has(carte)) {
                        outs.push(carte);
                    }
                });
            }
        });

        return outs;
    }

    function calculerStraightOuts(main, board, cartesUtilisees) {
        const outs = [];
        const toutesCartes = [...main, ...board];

        // Obtenir les rangs uniques
        const rangs = new Set();
        toutesCartes.forEach((carte) => {
            const match = carte.match(/^([0-9TJQKA]+)(.)$/);
            if (match) {
                rangs.add(ranks.indexOf(match[1]));
            }
        });

        const rangsArray = Array.from(rangs).sort((a, b) => a - b);
        const allSuits = ['♠', '♥', '♦', '♣'];

        // Chercher tous les tirages de suite possibles
        // Pour chaque séquence possible de 5 cartes consécutives
        for (let start = 0; start <= ranks.length - 5; start++) {
            const sequence = [
                start,
                start + 1,
                start + 2,
                start + 3,
                start + 4,
            ];

            // Compter combien de cartes de cette séquence on a
            const cartesPresentes = sequence.filter((rang) =>
                rangsArray.includes(rang)
            );

            // Si on a exactement 4 cartes de la séquence
            if (cartesPresentes.length === 4) {
                // Trouver la carte manquante
                const carteManquante = sequence.find(
                    (rang) => !rangsArray.includes(rang)
                );

                // Ajouter toutes les variantes de couleur de cette carte
                allSuits.forEach((suit) => {
                    const carte = `${ranks[carteManquante]}${suit}`;
                    if (!cartesUtilisees.has(carte)) {
                        outs.push(carte);
                    }
                });
            }
        }

        // Cas spécial pour la wheel (A-2-3-4-5)
        const wheelSequence = [
            ranks.indexOf('A'),
            ranks.indexOf('2'),
            ranks.indexOf('3'),
            ranks.indexOf('4'),
            ranks.indexOf('5'),
        ];
        const wheelPresentes = wheelSequence.filter((rang) =>
            rangsArray.includes(rang)
        );

        if (wheelPresentes.length === 4) {
            const wheelManquante = wheelSequence.find(
                (rang) => !rangsArray.includes(rang)
            );
            allSuits.forEach((suit) => {
                const carte = `${ranks[wheelManquante]}${suit}`;
                if (!cartesUtilisees.has(carte)) {
                    outs.push(carte);
                }
            });
        }

        // Cas spécial pour la suite royale (T-J-Q-K-A)
        const royalSequence = [
            ranks.indexOf('T'),
            ranks.indexOf('J'),
            ranks.indexOf('Q'),
            ranks.indexOf('K'),
            ranks.indexOf('A'),
        ];
        const royalPresentes = royalSequence.filter((rang) =>
            rangsArray.includes(rang)
        );

        if (royalPresentes.length === 4) {
            const royalManquante = royalSequence.find(
                (rang) => !rangsArray.includes(rang)
            );
            allSuits.forEach((suit) => {
                const carte = `${ranks[royalManquante]}${suit}`;
                if (!cartesUtilisees.has(carte)) {
                    outs.push(carte);
                }
            });
        }

        return outs;
    }

    function calculerProbabilite(outs, boardSize) {
        // Formules corrigées pour les probabilités de tirage
        if (boardSize === 3) {
            // Flop vers turn et river (2 cartes restantes)
            // Formule: 1 - ((47-outs)/47) * ((46-outs)/46)
            const cartesRestantes = 52 - 5; // 47 cartes (52 - 2 du joueur - 3 du flop)
            return 1 - Math.pow((cartesRestantes - outs) / cartesRestantes, 2);
        } else if (boardSize === 4) {
            // Turn vers river (1 carte restante)
            const cartesRestantes = 52 - 6; // 46 cartes (52 - 2 du joueur - 4 du board)
            return outs / cartesRestantes;
        } else if (boardSize === 0) {
            // Preflop vers river (5 cartes à venir)
            // Approximation simplifiée pour preflop
            const cartesRestantes = 52 - 2; // 50 cartes
            return 1 - Math.pow((cartesRestantes - outs) / cartesRestantes, 5);
        }
        return 0;
    }

    function calculerProbabiliteVictoire(
        main,
        board,
        nbJoueurs = 2,
        simulations = 1000
    ) {
        if (main.length < 2) {
            return 0;
        }

        const cartesUtilisees = new Set([...main, ...board]);
        const cartesRestantes = [];

        // Créer le deck des cartes restantes
        const allRanks = '23456789TJQKA'.split('');
        const allSuits = ['♠', '♥', '♦', '♣'];

        allRanks.forEach((rank) => {
            allSuits.forEach((suit) => {
                const carte = `${rank}${suit}`;
                if (!cartesUtilisees.has(carte)) {
                    cartesRestantes.push(carte);
                }
            });
        });

        let victoires = 0;

        for (let sim = 0; sim < simulations; sim++) {
            // Mélanger les cartes restantes
            const deck = [...cartesRestantes];
            for (let i = deck.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [deck[i], deck[j]] = [deck[j], deck[i]];
            }

            // Calculer les cartes nécessaires pour board et adversaires
            const cartesNecessairesBoard = Math.max(0, 5 - board.length);
            const cartesNecessairesAdversaires = (nbJoueurs - 1) * 2;
            const cartesTotalesNecessaires =
                cartesNecessairesBoard + cartesNecessairesAdversaires;

            // Vérifier qu'il y a assez de cartes
            if (deck.length < cartesTotalesNecessaires) {
                continue; // Passer cette simulation
            }

            // Compléter le board si nécessaire
            const boardComplet = [...board];
            for (let i = 0; i < cartesNecessairesBoard; i++) {
                boardComplet.push(deck.pop());
            }

            // Évaluer notre main
            const notreMeilleureMain = trouverMeilleureMain([
                ...main,
                ...boardComplet,
            ]);

            // Simuler les mains des adversaires
            let gagne = true;
            let deckIndex = 0;

            for (let adversaire = 1; adversaire < nbJoueurs; adversaire++) {
                const mainAdversaire = [deck[deckIndex], deck[deckIndex + 1]];
                deckIndex += 2;

                const mainAdversaireComplete = trouverMeilleureMain([
                    ...mainAdversaire,
                    ...boardComplet,
                ]);

                if (
                    comparerMains(
                        mainAdversaireComplete.evaluation,
                        notreMeilleureMain.evaluation
                    ) > 0
                ) {
                    gagne = false;
                    break;
                }
            }

            if (gagne) {
                victoires++;
            }
        }

        return victoires / simulations;
    }

    function analyserTirages(toutesCartes) {
        const suits = { '♠': [], '♥': [], '♦': [], '♣': [] };
        const values = {};
        const allVals = [];

        toutesCartes.forEach((card) => {
            const match = card.match(/^([0-9TJQKA]+)(.)$/);
            if (!match) {
                return;
            }

            const val = match[1];
            const suit = match[2];
            suits[suit].push(val);
            values[val] = (values[val] || 0) + 1;
            allVals.push(val);
        });

        const countList = Object.values(values).sort((a, b) => b - a);
        const allRanks = allVals
            .map((v) => ranks.indexOf(v))
            .sort((a, b) => a - b);
        const uniqueRanks = [...new Set(allRanks)].sort((a, b) => a - b);

        const flushDraw = Object.values(suits).some(
            (list) => list.length === 4
        );
        const doubleTwayFlushDraw =
            Object.values(suits).filter((list) => list.length === 3).length >=
            2;

        let openEndedStraight = false;
        let gutShot = false;

        for (let i = 0; i <= uniqueRanks.length - 4; i++) {
            const seq = uniqueRanks.slice(i, i + 4);
            if (seq[3] - seq[0] === 3) {
                openEndedStraight = true;
                break;
            }
        }

        if (!openEndedStraight) {
            for (let i = 0; i <= uniqueRanks.length - 4; i++) {
                const seq = uniqueRanks.slice(i, i + 4);
                if (seq[3] - seq[0] === 4) {
                    gutShot = true;
                    break;
                }
            }
        }

        const nombrePair =
            countList[0] >= 2
                ? Object.entries(values).filter(([_, count]) => count >= 2)
                      .length
                : 0;
        const doublePair = nombrePair >= 2;

        return {
            flushDraw,
            doubleTwayFlushDraw,
            openEndedStraight,
            gutShot,
            nombrePair,
            doublePair,
            possibleStraight: openEndedStraight || gutShot,
            possibleFlush: flushDraw || doubleTwayFlushDraw,
        };
    }

    function simplifierConseil(conseil, position, joueurs, tirage, outs) {
        if (expertMode) {
            return conseil;
        }

        const positionTable = detecterPositionTable();
        const estEnPosition = positionTable === 2;
        const peuJoueurs = joueurs <= 3;
        const bonneProba = outs && outs.probability > 0.3;

        // Gestion des tirages
        if (conseil.includes('tirage')) {
            if (bonneProba) {
                return t('weakHandDrawTemplate', {
                    probability: Math.round(outs.probability * 100),
                    position: estEnPosition
                        ? t('inPosition')
                        : t('outOfPosition'),
                });
            }
            return t('weakHandFollow');
        }

        // Gestion des conseils forts
        if (conseil === 'All-in') {
            return t('allIn');
        }
        if (conseil === 'RAISE fort') {
            return estEnPosition ? t('raiseStrong') : t('raiseNormal');
        }
        if (conseil === 'RAISE') {
            return estEnPosition ? t('raiseStrong') : t('raiseNormal');
        }
        if (conseil === 'Call') {
            return peuJoueurs && estEnPosition
                ? t('callOrRaise')
                : t('callOnly');
        }
        if (conseil === 'Check / Call') {
            return position ? t('checkInPosition') : t('foldOrCheck');
        }
        if (conseil === 'Fold') {
            return t('fold');
        }

        // Si aucune condition n'est remplie, retourner le conseil traduit ou original
        return conseil;
    }

    function evaluerMainPreflop(main) {
        if (main.length !== 2) {
            return null;
        }

        // Extraire les valeurs et couleurs
        const cartes = main.map((carte) => {
            const match = carte.match(/^([0-9TJQKA]+)(.)$/);
            return {
                valeur: match[1],
                couleur: match[2],
                rang: ranks.indexOf(match[1]),
            };
        });

        const valeur1 = cartes[0].rang;
        const valeur2 = cartes[1].rang;
        const memeCouleur = cartes[0].couleur === cartes[1].couleur;

        // Paire
        if (valeur1 === valeur2) {
            const valeurPaire = Math.max(valeur1, valeur2);

            // Stratégie TAG moderne: plus agressive avec les top pairs
            if (valeurPaire >= ranks.indexOf('A')) {
                // AA
                return {
                    nom: 'One Pair',
                    conseil: 'All-in',
                    force: 8,
                    valeurPrincipale: valeurPaire,
                    tirage: false,
                    kickers: [],
                };
            } else if (valeurPaire >= ranks.indexOf('K')) {
                // KK
                return {
                    nom: 'One Pair',
                    conseil: 'RAISE fort',
                    force: 7,
                    valeurPrincipale: valeurPaire,
                    tirage: false,
                    kickers: [],
                };
            } else if (valeurPaire >= ranks.indexOf('Q')) {
                // QQ
                return {
                    nom: 'One Pair',
                    conseil: 'RAISE fort',
                    force: 6,
                    valeurPrincipale: valeurPaire,
                    tirage: false,
                    kickers: [],
                };
            } else if (valeurPaire >= ranks.indexOf('J')) {
                // JJ
                return {
                    nom: 'One Pair',
                    conseil: 'RAISE fort',
                    force: 6,
                    valeurPrincipale: valeurPaire,
                    tirage: false,
                    kickers: [],
                };
            } else if (valeurPaire >= ranks.indexOf('T')) {
                // TT
                return {
                    nom: 'One Pair',
                    conseil: 'RAISE',
                    force: 5,
                    valeurPrincipale: valeurPaire,
                    tirage: false,
                    kickers: [],
                };
            } else if (valeurPaire >= ranks.indexOf('9')) {
                // 99
                return {
                    nom: 'One Pair',
                    conseil: 'RAISE',
                    force: 4,
                    valeurPrincipale: valeurPaire,
                    tirage: false,
                    kickers: [],
                };
            } else if (valeurPaire >= ranks.indexOf('7')) {
                // 88-77
                return {
                    nom: 'One Pair',
                    conseil: 'Call', // Position dependent
                    force: 3,
                    valeurPrincipale: valeurPaire,
                    tirage: false,
                    kickers: [],
                };
            } else {
                // 66-22 - plus strict
                return {
                    nom: 'One Pair',
                    conseil: 'Call', // En position seulement
                    force: 2,
                    valeurPrincipale: valeurPaire,
                    tirage: false,
                    kickers: [],
                };
            }
        }

        // Cartes non appariées - Stratégie TAG moderne
        const hauteValeur = Math.max(valeur1, valeur2);
        const basseValeur = Math.min(valeur1, valeur2);

        // AK - Main premium absolue
        if (
            hauteValeur >= ranks.indexOf('A') &&
            basseValeur >= ranks.indexOf('K')
        ) {
            return {
                nom: 'High Card',
                conseil: 'RAISE fort',
                force: 7,
                valeurPrincipale: hauteValeur,
                tirage: false,
                kickers: [basseValeur],
            };
        }

        // AQ - Très forte mais pas premium
        if (
            hauteValeur >= ranks.indexOf('A') &&
            basseValeur >= ranks.indexOf('Q')
        ) {
            return {
                nom: 'High Card',
                conseil: 'RAISE',
                force: 5,
                valeurPrincipale: hauteValeur,
                tirage: false,
                kickers: [basseValeur],
            };
        }

        // AJ - Bonne main, position dépendante
        if (
            hauteValeur >= ranks.indexOf('A') &&
            basseValeur >= ranks.indexOf('J')
        ) {
            return {
                nom: 'High Card',
                conseil: memeCouleur ? 'RAISE' : 'Call',
                force: memeCouleur ? 4 : 3,
                valeurPrincipale: hauteValeur,
                tirage: false,
                kickers: [basseValeur],
            };
        }

        // AT - Main marginale, suited only
        if (
            hauteValeur >= ranks.indexOf('A') &&
            basseValeur >= ranks.indexOf('T')
        ) {
            return {
                nom: 'High Card',
                conseil: memeCouleur ? 'Call' : 'Fold',
                force: memeCouleur ? 2 : 0,
                valeurPrincipale: hauteValeur,
                tirage: false,
                kickers: [basseValeur],
            };
        }

        // KQ - Main solide
        if (
            hauteValeur >= ranks.indexOf('K') &&
            basseValeur >= ranks.indexOf('Q')
        ) {
            return {
                nom: 'High Card',
                conseil: memeCouleur ? 'Call' : 'Fold',
                force: memeCouleur ? 3 : 1,
                valeurPrincipale: hauteValeur,
                tirage: false,
                kickers: [basseValeur],
            };
        }

        // Connecteurs assortis 65s+ (pour le potentiel post-flop)
        if (
            memeCouleur &&
            Math.abs(hauteValeur - basseValeur) <= 4 &&
            hauteValeur >= ranks.indexOf('9') &&
            basseValeur >= ranks.indexOf('5')
        ) {
            return {
                nom: 'High Card',
                conseil: 'Call',
                force: 2,
                valeurPrincipale: hauteValeur,
                tirage: true,
                kickers: [basseValeur],
            };
        }

        // Autres mains - fold strict
        return {
            nom: 'High Card',
            conseil: 'Fold',
            force: 0,
            valeurPrincipale: hauteValeur,
            tirage: false,
            kickers: [basseValeur],
        };
    }

    function evaluerMain(toutesCartes, inclureDetails = false) {
        const cacheKey = toutesCartes.join(',');
        if (cache.has(cacheKey)) {
            return cache.get(cacheKey);
        }

        let result;
        if (toutesCartes.length < 5) {
            // Si on est preflop (exactement 2 cartes), utiliser l'évaluation preflop
            if (toutesCartes.length === 2) {
                result = evaluerMainPreflop(toutesCartes);
            } else {
                // Sinon utiliser l'analyse de tirage existante
                const tirage = analyserTirages(toutesCartes);
                const isTirage =
                    tirage.possibleFlush || tirage.possibleStraight;

                if (isTirage) {
                    let detailTirage = '';
                    if (tirage.openEndedStraight) {
                        detailTirage += 'Quinte ouverte (8 outs)';
                    }
                    if (tirage.gutShot && !tirage.openEndedStraight) {
                        detailTirage += 'Gutshot (4 outs)';
                    }
                    if (tirage.flushDraw) {
                        detailTirage +=
                            (detailTirage ? ', ' : '') +
                            'Tirage couleur (9 outs)';
                    }

                    result = {
                        nom: 'High Card',
                        conseil:
                            'Main faible avec tirage' +
                            (detailTirage ? ': ' + detailTirage : ''),
                        force: 0.5,
                        valeurPrincipale: 0,
                        tirage: true,
                        detailTirage,
                        kickers: [],
                    };
                } else {
                    result = {
                        nom: 'High Card',
                        conseil: 'Fold',
                        force: 0,
                        valeurPrincipale: 0,
                        tirage: false,
                        kickers: [],
                    };
                }
            }
        } else {
            const meilleureMain = trouverMeilleureMain(toutesCartes);
            const evaluation = meilleureMain.evaluation;

            const conseilMap = {
                9: 'All-in', // Royal Flush
                8: 'All-in', // Straight Flush
                7: 'All-in', // Four of a Kind
                6: 'RAISE fort', // Full House
                5: 'RAISE fort', // Flush
                4: 'RAISE fort', // Straight
                3: 'RAISE', // Three of a Kind
                2: 'Call', // Two Pair
                1: 'Check / Call', // One Pair
                0: 'Fold', // High Card
            };

            let conseil = 'Fold';
            const forces = Object.keys(conseilMap)
                .map((k) => parseInt(k))
                .sort((a, b) => b - a);
            for (const minForce of forces) {
                if (evaluation.force >= minForce) {
                    conseil = conseilMap[minForce];
                    break;
                }
            }

            result = {
                nom: evaluation.nom,
                conseil,
                force: evaluation.force,
                valeurPrincipale: evaluation.valeurPrincipale,
                tirage: false,
                kickers: evaluation.kickers,
            };
        }

        cache.set(cacheKey, result);
        if (cache.size > 100) {
            const firstKey = cache.keys().next().value;
            cache.delete(firstKey);
        }

        return result;
    }

    const getThemeColors = (force) => {
        const themes = {
            9: {
                accent: '#dc2626',
                fond: 'rgba(127, 29, 29, 0.95)',
                bordure: '#dc2626',
            },
            8: {
                accent: '#dc2626',
                fond: 'rgba(127, 29, 29, 0.95)',
                bordure: '#dc2626',
            },
            7: {
                accent: '#dc2626',
                fond: 'rgba(127, 29, 29, 0.95)',
                bordure: '#dc2626',
            },
            6: {
                accent: '#ea580c',
                fond: 'rgba(124, 45, 18, 0.95)',
                bordure: '#ea580c',
            },
            5: {
                accent: '#f59e0b',
                fond: 'rgba(120, 53, 15, 0.95)',
                bordure: '#f59e0b',
            },
            4: {
                accent: '#f59e0b',
                fond: 'rgba(120, 53, 15, 0.95)',
                bordure: '#f59e0b',
            },
            3: {
                accent: '#ca8a04',
                fond: 'rgba(113, 63, 18, 0.95)',
                bordure: '#ca8a04',
            },
            2: {
                accent: '#10b981',
                fond: 'rgba(6, 95, 70, 0.95)',
                bordure: '#10b981',
            },
            1: {
                accent: '#059669',
                fond: 'rgba(6, 78, 59, 0.95)',
                bordure: '#059669',
            },
            0: {
                accent: '#6b7280',
                fond: 'rgba(15, 23, 42, 0.95)',
                bordure: '#374151',
            },
        };

        for (const [minForce, theme] of Object.entries(themes)) {
            if (force >= parseInt(minForce)) {
                return theme;
            }
        }
        return themes[0];
    };

    const langConfig = {
        en: { flag: '🇬🇧', name: 'English' },
        fr: { flag: '🇫🇷', name: 'Français' },
        de: { flag: '🇩🇪', name: 'Deutsch' },
        es: { flag: '🇪🇸', name: 'Español' },
    };

    function afficherInfos(main, board) {
        const nbJoueurs = compterJoueursActifs();
        const joueurAFold = detecterSiJoueurAFold();
        const gameStateKey = `${main.join(',')}-${board.join(
            ','
        )}-${currentLang}-${isMobileMode}-${isMinimized}-${mobilePosition}-${nbJoueurs}-${joueurAFold}`;

        if (lastGameState === gameStateKey) {
            return;
        }

        let box = document.getElementById('mainPokerBox');
        if (!box) {
            box = document.createElement('div');
            box.id = 'mainPokerBox';
            document.body.appendChild(box);
        }

        const langOptions = document.getElementById('langOptions');
        const dropdownIsOpen =
            langOptions && langOptions.style.display === 'block';

        if (dropdownIsOpen && box.innerHTML) {
            updateContentOnly(main, board, box);
            return;
        }

        lastGameState = gameStateKey;

        let evaluation, winProbability, nomFinal, conseilFinal, outs;

        if (joueurAFold) {
            evaluation = {
                nom: '',
                conseil: t('folded'),
                tirage: false,
                force: 0,
            };
            winProbability = 0;
            nomFinal = '';
            conseilFinal = t('folded');
            outs = null;
        } else {
            evaluation =
                main.length < 2
                    ? {
                          nom: '',
                          conseil: t('waiting'),
                          tirage: false,
                          force: 0,
                      }
                    : evaluerMain([...main, ...board], true);

            winProbability =
                main.length >= 2
                    ? calculerProbabiliteVictoire(main, board, nbJoueurs, 500)
                    : 0;

            nomFinal = expertMode
                ? evaluation.nom
                : simplifierMain(evaluation.nom);

            // Calculer les outs AVANT simplifierConseil pour les tirages
            const outs =
                !joueurAFold &&
                evaluation.tirage &&
                main.length >= 2 &&
                board.length >= 3
                    ? calculerOuts(main, board)
                    : null;

            conseilFinal = simplifierConseil(
                evaluation.conseil,
                detecterPosition(),
                nbJoueurs,
                evaluation.tirage,
                outs
            );
        }

        const {
            accent: couleurAccent,
            fond: couleurFond,
            bordure: couleurBordure,
        } = getThemeColors(evaluation.force);

        detectMobileMode();
        box.style.cssText = `
			position: fixed;
			${
                isMobileMode
                    ? getPositionMobileStyles()
                    : `top: ${currentPosition.y}px; left: ${currentPosition.x}px;`
            }
			width: ${isMobileMode ? (isMinimized ? '40px' : '220px') : '350px'};
			background: ${couleurFond};
			backdrop-filter: blur(12px);
			border: ${isMobileMode ? '1px' : '2px'} solid ${couleurBordure};
			border-radius: ${isMobileMode ? '8px' : '16px'};
			padding: 0;
			font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, sans-serif;
			font-size: ${isMobileMode ? '12px' : '14px'};
			color: white;
			z-index: 99999;
			box-shadow: 0 8px 20px -4px rgba(0, 0, 0, 0.6);
			transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
		`;

        if (isMobileMode) {
            box.innerHTML = htmlTemplates.generateMobileInterface(
                couleurAccent,
                main,
                board,
                nomFinal,
                conseilFinal,
                outs,
                nbJoueurs,
                isMinimized,
                winProbability
            );
        } else {
            box.innerHTML = htmlTemplates.generateDesktopInterface(
                couleurAccent,
                main,
                board,
                nomFinal,
                conseilFinal,
                outs,
                nbJoueurs,
                winProbability
            );
        }

        if (!box.dataset.animated) {
            box.style.transform = 'translateX(100%) scale(0.8)';
            box.style.opacity = '0';

            setTimeout(() => {
                box.style.transform = 'translateX(0) scale(1)';
                box.style.opacity = '1';
            }, 100);

            box.dataset.animated = 'true';
        }

        const activePlayersElement = box.querySelector('[data-active-players]');
        if (activePlayersElement) {
            activePlayersElement.textContent = nbJoueurs;
        }

        rendreModaleDraggable(box);
        eventHandlers.setupUIEvents(box);
    }

    let isDragging = false;
    const dragOffset = { x: 0, y: 0 };
    const currentPosition = { x: 20, y: 20 };

    let tapCount = 0;
    let tapTimer = null;

    const eventHandlers = {
        setupUIEvents: (box) => {
            setTimeout(() => {
                const elements = {
                    langButton: document.getElementById('langButton'),
                    langOptions: document.getElementById('langOptions'),
                    toggleMinimize: document.getElementById('toggleMinimize'),
                    positionButton: document.getElementById('positionButton'),
                };

                if (elements.toggleMinimize) {
                    elements.toggleMinimize.addEventListener('click', (e) => {
                        e.stopPropagation();
                        eventHandlers.handleToggleMinimize();
                    });
                }

                if (elements.positionButton && isMobileMode) {
                    elements.positionButton.addEventListener('click', (e) => {
                        e.stopPropagation();
                        changerPositionMobile();
                    });
                }

                if (elements.langButton && elements.langOptions) {
                    eventHandlers.setupLanguageSelector(
                        elements.langButton,
                        elements.langOptions
                    );
                }
            }, 100);
        },

        handleToggleMinimize: () => {
            if (isMobileMode && isMinimized) {
                tapCount++;
                if (tapCount === 1) {
                    tapTimer = setTimeout(() => {
                        isMinimized = false;
                        localStorage.setItem('tornPokerMinimized', isMinimized);
                        eventHandlers.refreshInterface();
                        tapCount = 0;
                    }, 300);
                } else if (tapCount === 2) {
                    clearTimeout(tapTimer);
                    changerPositionMobile();
                    tapCount = 0;
                }
            } else {
                isMinimized = !isMinimized;
                localStorage.setItem('tornPokerMinimized', isMinimized);
                eventHandlers.refreshInterface();
            }
        },

        setupLanguageSelector: (langButton, langOptions) => {
            const newLangButton = langButton.cloneNode(true);
            langButton.parentNode.replaceChild(newLangButton, langButton);

            newLangButton.addEventListener('click', (e) => {
                e.stopPropagation();
                const isDisplayed = langOptions.style.display === 'block';
                langOptions.style.display = isDisplayed ? 'none' : 'block';
            });

            const closeDropdown = (e) => {
                if (!e.target.closest('#langSelector')) {
                    langOptions.style.display = 'none';
                }
            };

            document.removeEventListener('click', closeDropdown);
            document.addEventListener('click', closeDropdown);

            langOptions.addEventListener('click', (e) => e.stopPropagation());

            setTimeout(() => {
                document.querySelectorAll('.langOption').forEach((option) => {
                    const newOption = option.cloneNode(true);
                    option.parentNode.replaceChild(newOption, option);

                    newOption.addEventListener('click', (e) => {
                        e.stopPropagation();
                        const lang = newOption.getAttribute('data-lang');
                        changerLangue(lang);
                        langOptions.style.display = 'none';
                    });

                    newOption.addEventListener('mouseover', () => {
                        if (
                            newOption.getAttribute('data-lang') !== currentLang
                        ) {
                            newOption.style.background =
                                'rgba(255, 255, 255, 0.05)';
                        }
                    });

                    newOption.addEventListener('mouseout', () => {
                        if (
                            newOption.getAttribute('data-lang') !== currentLang
                        ) {
                            newOption.style.background = 'transparent';
                        }
                    });
                });
            }, 50);
        },

        refreshInterface: () => {
            const main = lireCartesJoueur();
            const board = lireCartesPlateau();
            afficherInfos(main, board);
        },
    };

    function rendreModaleDraggable(box) {
        if (isMobileMode) {
            return;
        }

        const header = box.querySelector('[data-drag-handle]');
        if (!header) {
            return;
        }

        header.style.cursor = 'move';
        header.style.userSelect = 'none';

        header.addEventListener('mousedown', function (e) {
            if (
                e.target.closest('#langButton') ||
                e.target.closest('#langOptions')
            ) {
                return;
            }

            isDragging = true;
            const rect = box.getBoundingClientRect();
            dragOffset.x = e.clientX - rect.left;
            dragOffset.y = e.clientY - rect.top;

            box.style.transition = 'none';

            e.preventDefault();
        });

        document.addEventListener('mousemove', function (e) {
            if (!isDragging || isMobileMode) {
                return;
            }

            const newX = e.clientX - dragOffset.x;
            const newY = e.clientY - dragOffset.y;

            const maxX = window.innerWidth - box.offsetWidth;
            const maxY = window.innerHeight - box.offsetHeight;

            currentPosition.x = Math.max(0, Math.min(newX, maxX));
            currentPosition.y = Math.max(0, Math.min(newY, maxY));

            box.style.left = currentPosition.x + 'px';
            box.style.top = currentPosition.y + 'px';
            box.style.right = 'auto';
            box.style.bottom = 'auto';
        });

        document.addEventListener('mouseup', function () {
            if (isDragging) {
                isDragging = false;
                box.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)';
            }
        });
    }

    function ajouterStylesGlobaux() {
        if (document.getElementById('pokerHelperStyles')) {
            return;
        }

        const styles = document.createElement('style');
        styles.id = 'pokerHelperStyles';
        styles.textContent = `
			#mainPokerBox {
				transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important;
			}

			#mainPokerBox:hover {
				transform: translateY(-2px) !important;
			}

			#langButton:hover {
				background: rgba(255, 255, 255, 0.2) !important;
				transform: scale(1.05) !important;
			}

			.langOption:hover {
				background: rgba(255, 255, 255, 0.05) !important;
			}

			[data-drag-handle] {
				cursor: move !important;
			}

			[data-drag-handle]:active {
				cursor: grabbing !important;
			}

			@keyframes pulse {
				0%, 100% { opacity: 1; }
				50% { opacity: 0.7; }
			}

			@keyframes slideIn {
				from {
					transform: translateX(100%) scale(0.8);
					opacity: 0;
				}
				to {
					transform: translateX(0) scale(1);
					opacity: 1;
				}
			}

			@media (max-width: 768px) {
				#mainPokerBox {
                    font-size: 11px !important;
				}

				[data-drag-handle] {
					cursor: default !important;
				}
			}
		`;
        document.head.appendChild(styles);
    }

    const gameLoop = {
        isRunning: false,
        intervalId: null,
        lastPlayerCount: null,

        start: () => {
            if (gameLoop.isRunning) {
                return;
            }

            ajouterStylesGlobaux();
            detectMobileMode();
            gameLoop.isRunning = true;

            gameLoop.intervalId = setInterval(() => {
                const currentPlayerCount = compterJoueursActifs();
                if (gameLoop.lastPlayerCount !== currentPlayerCount) {
                    gameLoop.lastPlayerCount = currentPlayerCount;
                    cache.clear();
                    eventHandlers.refreshInterface();
                }

                const mainCards = document.querySelectorAll(
                    '.playerMeGateway___AEI5_ .hand___aOp4l .card___t7csZ .front___osz1p > div'
                );
                if (mainCards.length >= 2) {
                    eventHandlers.refreshInterface();
                }
            }, 1000);
        },

        stop: () => {
            if (gameLoop.intervalId) {
                clearInterval(gameLoop.intervalId);
                gameLoop.intervalId = null;
                gameLoop.isRunning = false;
            }
        },
    };

    function attendreEtExecuter() {
        gameLoop.start();
    }
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', attendreEtExecuter);
    } else {
        attendreEtExecuter();
    }

    window.addEventListener('load', attendreEtExecuter);
})();