FlopMaster

Poker odds assistant

// ==UserScript==
// @name         FlopMaster
// @namespace    https://greasyfork.org/en/users/1469540-davrone
// @version      1.0
// @description  Poker odds assistant
// @author       Davrone
// @match        https://www.torn.com/page.php?sid=holdem
// @run-at       document-body
// @license MIT
// @grant        none
// ==/UserScript==

function debugBindErrors(methods) {
  for (let method of methods) {
    console.log(`Testing method: ${method}`);
    try {
      if (this[method] === undefined) {
        console.error(`Method ${method} is undefined!`);
      }
    } catch (e) {
      console.error(`Error checking method ${method}:`, e);
    }
  }
}

let GM_addStyle = function(s) {
    let style = document.createElement("style");
    style.type = "text/css";
    style.textContent = s;
    document.head.appendChild(style);
}

class FloatingSuits {
    constructor(container, options = {}) {
        this.container = container;
        this.suits = [];
        this.options = {
            suitCount: options.suitCount || 30,
            minSize: options.minSize || 16,
            maxSize: options.maxSize || 35,
            minSpeed: options.minSpeed || 20,
            maxSpeed: options.maxSpeed || 60,
            minSwayAmount: options.minSwayAmount || 10,
            maxSwayAmount: options.maxSwayAmount || 40,
            minSwayTime: options.minSwayTime || 2,
            maxSwayTime: options.maxSwayTime || 6
        };

        this.suitSymbols = ['♠', '♥', '♦', '♣'];
        this.suitClasses = ['spades', 'hearts', 'diamonds', 'clubs'];
        this.running = false;
        this.suitElements = [];

        this.init();
    }

    init() {

        this.container.innerHTML = '';
        this.suitElements = [];

        const rect = this.container.getBoundingClientRect();

        for (let i = 0; i < this.options.suitCount; i++) {
            this.createSuit(rect, true);
        }
    }

    createSuit(rect, initial = false) {
        const suitIndex = Math.floor(Math.random() * this.suitSymbols.length);
        const size = Math.floor(Math.random() * (this.options.maxSize - this.options.minSize)) + this.options.minSize;

        const suitElement = document.createElement('div');
        suitElement.className = `floating-suit ${this.suitClasses[suitIndex]}`;
        suitElement.textContent = this.suitSymbols[suitIndex];
        suitElement.style.fontSize = `${size}px`;

        if (Math.random() < 0.2) {
            suitElement.classList.add('gold');
        }

        const x = Math.random() * (rect.width - size);
        const y = initial ? Math.random() * rect.height : -size;

        suitElement.style.left = `${x}px`;
        suitElement.style.top = `${y}px`;

        this.container.appendChild(suitElement);

        const speed = this.options.minSpeed + Math.random() * (this.options.maxSpeed - this.options.minSpeed);
        const sway = this.options.minSwayAmount + Math.random() * (this.options.maxSwayAmount - this.options.minSwayAmount);
        const swayTime = this.options.minSwayTime + Math.random() * (this.options.maxSwayTime - this.options.minSwayTime);
        const rotation = Math.random() * 360;
        const rotationSpeed = (Math.random() - 0.5) * 2;

        suitElement.style.transform = `rotate(${rotation}deg)`;

        this.suitElements.push({
            element: suitElement,
            x: x,
            y: y,
            speed: speed,
            sway: sway,
            swayTime: swayTime,
            swayOffset: Math.random() * Math.PI * 2, // Random starting point
            rotation: rotation,
            rotationSpeed: rotationSpeed,
            size: size
        });

        return this.suitElements[this.suitElements.length - 1];
    }

    start() {
        if (!this.running) {
            this.running = true;
            this.lastTime = performance.now();
            requestAnimationFrame(this.update.bind(this));
        }
    }

    stop() {
        this.running = false;
    }

    update(timestamp) {
        if (!this.running) return;

        const deltaTime = (timestamp - this.lastTime) / 1000; // Convert to seconds
        this.lastTime = timestamp;

        const rect = this.container.getBoundingClientRect();

        for (let i = this.suitElements.length - 1; i >= 0; i--) {
            const suit = this.suitElements[i];

            suit.y += suit.speed * deltaTime;

            const swayX = Math.sin((timestamp / 1000 / suit.swayTime) + suit.swayOffset) * suit.sway;
            suit.x = Math.max(0, Math.min(rect.width - suit.size, suit.x + (swayX * deltaTime)));

            suit.rotation += suit.rotationSpeed * deltaTime * 20;

            suit.element.style.transform = `rotate(${suit.rotation}deg)`;
            suit.element.style.left = `${suit.x}px`;
            suit.element.style.top = `${suit.y}px`;

            if (suit.y > rect.height) {
                suit.element.remove();
                this.suitElements.splice(i, 1);

                this.createSuit(rect);
            }
        }

        requestAnimationFrame(this.update.bind(this));
    }

    setDensity(count) {
        const rect = this.container.getBoundingClientRect();
        const currentCount = this.suitElements.length;

        if (count > currentCount) {

            for (let i = 0; i < count - currentCount; i++) {
                this.createSuit(rect);
            }
        } else if (count < currentCount) {

            const toRemove = currentCount - count;
            for (let i = 0; i < toRemove; i++) {
                if (this.suitElements.length > 0) {
                    const index = Math.floor(Math.random() * this.suitElements.length);
                    this.suitElements[index].element.remove();
                    this.suitElements.splice(index, 1);
                }
            }
        }

        this.options.suitCount = count;
    }
}

class PokerCalculatorModule {
    constructor() {
    this.debugMode = false;
    this.lastProcessTime = 0;
    this.processingThrottle = 1500;
    this.lastUpdateTime = 0;
    this.renderDelayTime = 500;

    this.upgradesToShow = 10;
    this.lastLength = 0;
    this.isHandActive = false;
    this.opponentStats = new Map();

    this.preflopStats = {
        'AA': { wins: 85.2, ties: 0.5, total: 85.2 },
        'KK': { wins: 82.4, ties: 0.5, total: 82.4 },
        'QQ': { wins: 80.0, ties: 0.5, total: 80.0 },
        'JJ': { wins: 77.5, ties: 0.5, total: 77.5 },
        'TT': { wins: 75.1, ties: 0.5, total: 75.1 },
        '99': { wins: 72.1, ties: 0.5, total: 72.1 },
        '88': { wins: 69.1, ties: 0.5, total: 69.1 },
        '77': { wins: 66.2, ties: 0.5, total: 66.2 },
        '66': { wins: 63.3, ties: 0.5, total: 63.3 },
        '55': { wins: 60.3, ties: 0.5, total: 60.3 },
        '44': { wins: 57.0, ties: 0.5, total: 57.0 },
        '33': { wins: 53.7, ties: 0.5, total: 53.7 },
        '22': { wins: 50.3, ties: 0.5, total: 50.3 },

        'AKs': { wins: 66.1, ties: 0.9, total: 67.0 },
        'AQs': { wins: 65.3, ties: 0.8, total: 66.1 },
        'AJs': { wins: 64.6, ties: 0.8, total: 65.4 },
        'ATs': { wins: 63.9, ties: 0.8, total: 64.7 },
        'A9s': { wins: 62.3, ties: 0.7, total: 63.0 },
        'A8s': { wins: 61.4, ties: 0.7, total: 62.1 },
        'A7s': { wins: 60.4, ties: 0.7, total: 61.1 },
        'A6s': { wins: 59.3, ties: 0.7, total: 60.0 },
        'A5s': { wins: 59.2, ties: 0.7, total: 59.9 },
        'A4s': { wins: 58.5, ties: 0.7, total: 59.2 },
        'A3s': { wins: 57.8, ties: 0.7, total: 58.5 },
        'A2s': { wins: 57.1, ties: 0.7, total: 57.8 },

        'AK': { wins: 64.5, ties: 0.9, total: 65.4 },
        'AQ': { wins: 63.6, ties: 0.9, total: 64.5 },
        'AJ': { wins: 62.7, ties: 0.9, total: 63.6 },
        'AT': { wins: 62.0, ties: 0.9, total: 62.9 },
        'A9': { wins: 60.2, ties: 0.9, total: 61.1 },
        'A8': { wins: 59.2, ties: 0.9, total: 60.1 },
        'A7': { wins: 58.2, ties: 0.9, total: 59.1 },
        'A6': { wins: 57.1, ties: 0.9, total: 58.0 },
        'A5': { wins: 56.8, ties: 0.9, total: 57.7 },
        'A4': { wins: 56.2, ties: 0.9, total: 57.1 },
        'A3': { wins: 55.5, ties: 0.9, total: 56.4 },
        'A2': { wins: 54.7, ties: 0.9, total: 55.6 },

        'KQs': { wins: 62.5, ties: 0.9, total: 63.4 },
        'KJs': { wins: 61.7, ties: 0.9, total: 62.6 },
        'KTs': { wins: 60.9, ties: 0.9, total: 61.8 },
        'K9s': { wins: 59.1, ties: 0.9, total: 60.0 },
        'K8s': { wins: 57.6, ties: 0.9, total: 58.5 },
        'K7s': { wins: 56.9, ties: 0.9, total: 57.8 },
        'K6s': { wins: 55.9, ties: 0.9, total: 56.8 },
        'K5s': { wins: 55.1, ties: 0.9, total: 56.0 },
        'K4s': { wins: 54.3, ties: 0.9, total: 55.2 },
        'K3s': { wins: 53.6, ties: 0.9, total: 54.5 },
        'K2s': { wins: 52.9, ties: 0.9, total: 53.8 },

        'KQ': { wins: 60.9, ties: 0.9, total: 61.8 },
        'KJ': { wins: 60.0, ties: 0.9, total: 60.9 },
        'KT': { wins: 59.1, ties: 0.9, total: 60.0 },
        'K9': { wins: 57.3, ties: 0.9, total: 58.2 },
        'K8': { wins: 55.9, ties: 0.9, total: 56.8 },
        'K7': { wins: 55.1, ties: 0.9, total: 56.0 },
        'K6': { wins: 54.1, ties: 0.9, total: 55.0 },
        'K5': { wins: 53.3, ties: 0.9, total: 54.2 },
        'K4': { wins: 52.5, ties: 0.9, total: 53.4 },
        'K3': { wins: 51.7, ties: 0.9, total: 52.6 },
        'K2': { wins: 51.0, ties: 0.9, total: 51.9 },

        'QJs': { wins: 59.4, ties: 0.9, total: 60.3 },
        'QTs': { wins: 58.6, ties: 0.9, total: 59.5 },
        'Q9s': { wins: 56.7, ties: 0.9, total: 57.6 },
        'Q8s': { wins: 55.3, ties: 0.9, total: 56.2 },
        'Q7s': { wins: 54.2, ties: 0.9, total: 55.1 },
        'Q6s': { wins: 53.4, ties: 0.9, total: 54.3 },
        'Q5s': { wins: 52.6, ties: 0.9, total: 53.5 },
        'Q4s': { wins: 51.7, ties: 0.9, total: 52.6 },
        'Q3s': { wins: 51.0, ties: 0.9, total: 51.9 },
        'Q2s': { wins: 50.3, ties: 0.9, total: 51.2 },

        'QJ': { wins: 57.6, ties: 0.9, total: 58.5 },
        'QT': { wins: 56.8, ties: 0.9, total: 57.7 },
        'Q9': { wins: 55.0, ties: 0.9, total: 55.9 },
        'Q8': { wins: 53.5, ties: 0.9, total: 54.4 },
        'Q7': { wins: 52.3, ties: 0.9, total: 53.2 },
        'Q6': { wins: 51.5, ties: 0.9, total: 52.4 },
        'Q5': { wins: 50.7, ties: 0.9, total: 51.6 },
        'Q4': { wins: 49.8, ties: 0.9, total: 50.7 },
        'Q3': { wins: 49.1, ties: 0.9, total: 50.0 },
        'Q2': { wins: 48.4, ties: 0.9, total: 49.3 },

        'JTs': { wins: 57.1, ties: 0.9, total: 58.0 },
        'J9s': { wins: 55.1, ties: 0.9, total: 56.0 },
        'J8s': { wins: 53.7, ties: 0.9, total: 54.6 },
        'J7s': { wins: 52.1, ties: 0.9, total: 53.0 },
        'J6s': { wins: 51.0, ties: 0.9, total: 51.9 },
        'J5s': { wins: 50.1, ties: 0.9, total: 51.0 },
        'J4s': { wins: 49.2, ties: 0.9, total: 50.1 },
        'J3s': { wins: 48.5, ties: 0.9, total: 49.4 },
        'J2s': { wins: 47.8, ties: 0.9, total: 48.7 },

        'JT': { wins: 55.3, ties: 0.9, total: 56.2 },
        'J9': { wins: 53.2, ties: 0.9, total: 54.1 },
        'J8': { wins: 51.7, ties: 0.9, total: 52.6 },
        'J7': { wins: 50.5, ties: 0.9, total: 51.4 },
        'J6': { wins: 49.2, ties: 0.9, total: 50.1 },
        'J5': { wins: 48.3, ties: 0.9, total: 49.2 },
        'J4': { wins: 47.4, ties: 0.9, total: 48.3 },
        'J3': { wins: 46.7, ties: 0.9, total: 47.6 },
        'J2': { wins: 46.0, ties: 0.9, total: 46.9 },

        'T9s': { wins: 53.4, ties: 0.9, total: 54.3 },
        'T8s': { wins: 51.9, ties: 0.9, total: 52.8 },
        'T7s': { wins: 50.5, ties: 0.9, total: 51.4 },
        'T6s': { wins: 49.0, ties: 0.9, total: 49.9 },
        'T5s': { wins: 48.0, ties: 0.9, total: 48.9 },
        'T4s': { wins: 47.1, ties: 0.9, total: 48.0 },
        'T3s': { wins: 46.4, ties: 0.9, total: 47.3 },
        'T2s': { wins: 45.7, ties: 0.9, total: 46.6 },

        'T9': { wins: 51.4, ties: 0.9, total: 52.3 },
        'T8': { wins: 49.9, ties: 0.9, total: 50.8 },
        'T7': { wins: 48.6, ties: 0.9, total: 49.5 },
        'T6': { wins: 47.3, ties: 0.9, total: 48.2 },
        'T5': { wins: 46.1, ties: 0.9, total: 47.0 },
        'T4': { wins: 45.2, ties: 0.9, total: 46.1 },
        'T3': { wins: 44.5, ties: 0.9, total: 45.4 },
        'T2': { wins: 43.8, ties: 0.9, total: 44.7 },

        '98s': { wins: 51.4, ties: 0.9, total: 52.3 },
        '97s': { wins: 49.9, ties: 0.9, total: 50.8 },
        '96s': { wins: 48.4, ties: 0.9, total: 49.3 },
        '95s': { wins: 46.9, ties: 0.9, total: 47.8 },
        '94s': { wins: 46.0, ties: 0.9, total: 46.9 },
        '93s': { wins: 45.3, ties: 0.9, total: 46.2 },
        '92s': { wins: 44.6, ties: 0.9, total: 45.5 },

        '98': { wins: 48.1, ties: 0.9, total: 49.0 },
        '97': { wins: 46.9, ties: 0.9, total: 47.8 },
        '96': { wins: 45.5, ties: 0.9, total: 46.4 },
        '95': { wins: 44.2, ties: 0.9, total: 45.1 },
        '94': { wins: 43.3, ties: 0.9, total: 44.2 },
        '93': { wins: 42.6, ties: 0.9, total: 43.5 },
        '92': { wins: 41.9, ties: 0.9, total: 42.8 },

        '87s': { wins: 49.0, ties: 0.9, total: 49.9 },
        '86s': { wins: 47.5, ties: 0.9, total: 48.4 },
        '85s': { wins: 46.1, ties: 0.9, total: 47.0 },
        '84s': { wins: 45.0, ties: 0.9, total: 45.9 },
        '83s': { wins: 44.3, ties: 0.9, total: 45.2 },
        '82s': { wins: 43.6, ties: 0.9, total: 44.5 },

        '87': { wins: 46.1, ties: 0.9, total: 47.0 },
        '86': { wins: 44.4, ties: 0.9, total: 45.3 },
        '85': { wins: 43.2, ties: 0.9, total: 44.1 },
        '84': { wins: 42.1, ties: 0.9, total: 43.0 },
        '83': { wins: 41.4, ties: 0.9, total: 42.3 },
        '82': { wins: 40.7, ties: 0.9, total: 41.6 },

        '76s': { wins: 46.4, ties: 0.9, total: 47.3 },
        '75s': { wins: 44.9, ties: 0.9, total: 45.8 },
        '74s': { wins: 43.7, ties: 0.9, total: 44.6 },
        '73s': { wins: 43.0, ties: 0.9, total: 43.9 },
        '72s': { wins: 42.3, ties: 0.9, total: 43.2 },

        '76': { wins: 43.6, ties: 0.9, total: 44.5 },
        '75': { wins: 41.8, ties: 0.9, total: 42.7 },
        '74': { wins: 40.7, ties: 0.9, total: 41.6 },
        '73': { wins: 40.0, ties: 0.9, total: 40.9 },
        '72': { wins: 39.3, ties: 0.9, total: 40.2 },

        '65s': { wins: 44.1, ties: 0.9, total: 45.0 },
        '64s': { wins: 42.8, ties: 0.9, total: 43.7 },
        '63s': { wins: 42.2, ties: 0.9, total: 43.1 },
        '62s': { wins: 41.5, ties: 0.9, total: 42.4 },

        '65': { wins: 41.0, ties: 0.9, total: 41.9 },
        '64': { wins: 39.9, ties: 0.9, total: 40.8 },
        '63': { wins: 39.2, ties: 0.9, total: 40.1 },
        '62': { wins: 38.5, ties: 0.9, total: 39.4 },

        '54s': { wins: 42.3, ties: 0.9, total: 43.2 },
        '53s': { wins: 41.7, ties: 0.9, total: 42.6 },
        '52s': { wins: 41.0, ties: 0.9, total: 41.9 },

        '54': { wins: 39.4, ties: 0.9, total: 40.3 },
        '53': { wins: 38.7, ties: 0.9, total: 39.6 },
        '52': { wins: 38.0, ties: 0.9, total: 38.9 },

        '43s': { wins: 40.9, ties: 0.9, total: 41.8 },
        '42s': { wins: 40.2, ties: 0.9, total: 41.1 },

        '43': { wins: 37.7, ties: 0.9, total: 38.6 },
        '42': { wins: 37.0, ties: 0.9, total: 37.9 },

        '32s': { wins: 39.4, ties: 0.9, total: 40.3 },
        '32': { wins: 36.3, ties: 0.9, total: 37.2 }
    };

    this.lastBetAmount = 0;
    this.lastRecommendation = "";
    this.lastPlayerDecision = null;
    this.lastCommunityCount = 0;
    this.messageBoxObserverStarted = false;

    this.lastUpdateCall = 0;

    this.history = {
        correctRecommendations: 0,
        totalHands: 0,
        adjustThresholds() {
            if (this.totalHands > 0) {
                const successRate = this.correctRecommendations / this.totalHands;
                if (successRate < 0.5) {
                    this.raiseThreshold -= 5;
                    this.foldThreshold += 5;
                } else if (successRate > 0.7) {
                    this.raiseThreshold += 5;
                    this.foldThreshold -= 5;
                }
            }
        }
    };

    this.addStyle();

    try {
        const savedOpponents = localStorage.getItem('pokerHelperOpponentStats');
        if (savedOpponents) {
            this.opponentStats = new Map(JSON.parse(savedOpponents));
        }
    } catch (e) {
        console.error("Failed to load saved data:", e);
    }

    this.update = this.update.bind(this);
    this.detectHandEnd = this.detectHandEnd.bind(this);
}

    update() {
        const now = Date.now();
        if (this.lastUpdateTime && now - this.lastUpdateTime < 1000) {
            setTimeout(this.update.bind(this), 1000);
            return;
        }
        this.lastUpdateTime = now;

        let allCards = this.getFullDeck();
        let knownCards = Array.from(document.querySelectorAll("[class*='flipper___'] > div[class*='front___'] > div")).map(e => {
            var card = (e.classList[1] || "null-0").split("_")[0]
                .replace("-A", "-14")
                .replace("-K", "-13")
                .replace("-Q", "-12")
                .replace("-J", "-11");
            if (card == "cardSize") card = "null-0";
            return card;
        });

        let communityCards = knownCards.slice(0, 5);
        let communityCardsCount = communityCards.filter(e => !e.includes("null")).length;
        let isPreFlop = communityCardsCount === 0;

        allCards = this.filterDeck(allCards, communityCards.filter(e => !e.includes("null")));

        if (knownCards.filter(e => !e.includes("null")).length === 0 && communityCardsCount === 0) {
            if (this.isHandActive) {
                this.detectHandEnd();
                this.isHandActive = false;
                document.getElementById("pokerCalc-action").textContent = "Waiting for cards...";
                document.querySelector("#pokerCalc-myHand tbody").innerHTML = "";
                document.querySelector("#pokerCalc-upgrades tbody").innerHTML = "";
                document.querySelector("#pokerCalc-oppPossHands tbody").innerHTML = "";
                document.querySelector("#pokerCalc-preflop tbody").innerHTML = "";

                document.getElementById("pokerCalc-preflop").style.display = "none";
                document.getElementById("pokerCalc-myHand").style.display = "table";
                document.getElementById("pokerCalc-upgrades").style.display = "table";
                document.getElementById("pokerCalc-oppPossHands").style.display = "table";
            }
            setTimeout(this.update.bind(this), 1000);
            return;
        } else {
            this.isHandActive = true;
        }

        if (JSON.stringify(knownCards).length != this.lastLength || communityCardsCount !== this.lastCommunityCount) {
            this.lastCommunityCount = communityCardsCount;

            document.querySelector("#pokerCalc-myHand tbody").innerHTML = "";
            document.querySelector("#pokerCalc-upgrades tbody").innerHTML = "";
            document.querySelector("#pokerCalc-oppPossHands tbody").innerHTML = "";
            document.querySelector("#pokerCalc-preflop tbody").innerHTML = "";

            if (isPreFlop) {
                document.getElementById("pokerCalc-preflop").style.display = "table";
                document.getElementById("pokerCalc-myHand").style.display = "none";
                document.getElementById("pokerCalc-upgrades").style.display = "none";
                document.getElementById("pokerCalc-oppPossHands").style.display = "none";

                this.processPreFlopStats();
            } else {
                document.getElementById("pokerCalc-preflop").style.display = "none";
                document.getElementById("pokerCalc-myHand").style.display = "table";
                document.getElementById("pokerCalc-upgrades").style.display = "table";
                document.getElementById("pokerCalc-oppPossHands").style.display = "table";
                this.processPostFlopStats(knownCards, communityCards, allCards);
            }

            this.lastLength = JSON.stringify(knownCards).length;
        }

        setTimeout(this.update.bind(this), 1000);
    }

    detectHandEnd() {
        this.lastBetAmount = 0;
        this.lastRecommendation = "";
    }

    calculatePreFlopPotential(holeCards, handNotation) {
        const card1Value = parseInt(holeCards[0].split("-")[1]);
        const card2Value = parseInt(holeCards[1].split("-")[1]);
        const hasPair = card1Value === card2Value;
        const isSuited = handNotation.endsWith('s');

        let pairChance = hasPair ? 100 : 32;
        let twoPairChance = 0;
        let tripsChance = hasPair ? 12 : 0;
        let fullHouseChance = 0;
        let straightChance = 0;
        let flushChance = 0;
        let quadsChance = hasPair ? 3 : 0;
        let straightFlushChance = 0;
        let royalFlushChance = 0;

        if (!hasPair) {
            const card1Rank = card1Value;
            const card2Rank = card2Value;
            const gap = Math.abs(card1Rank - card2Rank);

            twoPairChance = 4;

            if (gap <= 4) {
                straightChance = 12 - (gap * 2);
            }

            if (isSuited) {
                flushChance = 6;

                if (gap <= 4) {
                    straightFlushChance = 0.5;

                    if (card1Rank >= 10 && card2Rank >= 10) {
                        royalFlushChance = 0.2;
                    }
                }
            }
        }

        return {
            pairChance,
            twoPairChance,
            tripsChance,
            fullHouseChance,
            straightChance,
            flushChance,
            quadsChance,
            straightFlushChance,
            royalFlushChance
        };
    }

    calculateDrawPotential(holeCards, communityCards) {
        const allCards = [...holeCards, ...communityCards].filter(c => !c.includes("null"));

        let pairChance = 0;
        let twoPairChance = 0;
        let tripsChance = 0;
        let fullHouseChance = 0;
        let straightChance = 0;
        let flushChance = 0;
        let quadsChance = 0;
        let straightFlushChance = 0;
        let royalFlushChance = 0;

        if (allCards.length < 2) return {
            pairChance, twoPairChance, tripsChance, fullHouseChance,
            straightChance, flushChance, quadsChance, straightFlushChance, royalFlushChance
        };

        const ranks = allCards.map(card => parseInt(card.split("-")[1]));
        const suits = allCards.map(card => card.split("-")[0]);

        const rankCounts = {};
        ranks.forEach(rank => {
            rankCounts[rank] = (rankCounts[rank] || 0) + 1;
        });

        const suitCounts = {};
        suits.forEach(suit => {
            suitCounts[suit] = (suitCounts[suit] || 0) + 1;
        });

        const handObject = this.makeHandObject(allCards);
        const hasPair = this.hasPair(allCards, handObject);
        const hasTwoPair = this.hasTwoPairs(allCards, handObject);
        const hasTrips = this.hasThreeOfAKind(allCards, handObject);
        const hasQuads = this.hasFourOfAKind(allCards, handObject);
        const hasFullHouse = this.hasFullHouse(allCards, handObject);
        const hasStraight = this.hasStraight(allCards, handObject);
        const hasFlush = this.hasFlush(allCards, handObject);
        const hasStraightFlush = this.hasStraightFlush(allCards, handObject);
        const hasRoyalFlush = this.hasRoyalFlush(allCards, handObject);

        if (hasPair) pairChance = 100;
        if (hasTwoPair) twoPairChance = 100;
        if (hasTrips) tripsChance = 100;
        if (hasQuads) quadsChance = 100;
        if (hasFullHouse) fullHouseChance = 100;
        if (hasStraight) straightChance = 100;
        if (hasFlush) flushChance = 100;
        if (hasStraightFlush) straightFlushChance = 100;
        if (hasRoyalFlush) royalFlushChance = 100;

        const communityCount = communityCards.filter(c => !c.includes("null")).length;
        const cardsToBeDealt = 5 - communityCount;

        if (cardsToBeDealt > 0 && !hasRoyalFlush) {
            if (!hasPair && !hasTwoPair && !hasTrips) {
                const pairOptions = Object.values(rankCounts).filter(count => count === 1).length;
                pairChance = Math.min(100, (pairOptions * 3 * cardsToBeDealt / 47) * 100);
            }

            if (hasPair && !hasTwoPair && !hasFullHouse) {
                const unpaired = ranks.filter(rank => rankCounts[rank] === 1);
                twoPairChance = Math.min(100, (unpaired.length * 3 * cardsToBeDealt / 47) * 100);
            }

            if ((hasPair || hasTwoPair) && !hasTrips) {
                const pairRanks = Object.entries(rankCounts)
                    .filter(([rank, count]) => count === 2)
                    .map(([rank]) => parseInt(rank));

                if (pairRanks.length > 0) {
                    tripsChance = Math.min(100, (pairRanks.length * 2 * cardsToBeDealt / 47) * 100);
                }
            }

            if (hasTrips && !hasQuads) {
                const tripRanks = Object.entries(rankCounts)
                    .filter(([rank, count]) => count === 3)
                    .map(([rank]) => parseInt(rank));

                if (tripRanks.length > 0) {
                    quadsChance = Math.min(100, (tripRanks.length * cardsToBeDealt / 47) * 100);
                }
            }

            if (hasTrips && !hasFullHouse) {
                const singleCards = Object.entries(rankCounts)
                    .filter(([rank, count]) => count === 1)
                    .length;

                fullHouseChance = Math.min(100, (singleCards * 3 * cardsToBeDealt / 47) * 100);
            } else if (hasTwoPair && !hasFullHouse) {
                fullHouseChance = Math.min(100, (4 * cardsToBeDealt / 47) * 100);
            }

            if (!hasStraight) {
                const uniqueRanks = [...new Set(ranks)].sort((a, b) => a - b);

                if (uniqueRanks.includes(14)) {
                    uniqueRanks.push(1);
                }

                let outCount = 0;

                for (let i = 0; i <= uniqueRanks.length - 4; i++) {
                    if (uniqueRanks[i+3] - uniqueRanks[i] <= 4) {
                        const gap = uniqueRanks[i+3] - uniqueRanks[i] - 3;
                        if (gap === 0) {
                            outCount = Math.max(outCount, 8);
                        } else if (gap === 1) {
                            outCount = Math.max(outCount, 4);
                        }
                    }
                }

                straightChance = Math.min(100, (outCount * cardsToBeDealt / 47) * 100);
            }

            if (!hasFlush) {
                const maxSuitCount = Math.max(...Object.values(suitCounts).map(count => count || 0));

                if (maxSuitCount >= 4) {
                    flushChance = Math.min(100, (9 * cardsToBeDealt / 47) * 100);
                } else if (maxSuitCount === 3 && communityCount <= 3) {
                    flushChance = Math.min(100, (cardsToBeDealt / 47) * 100);
                }
            }

            if (!hasStraightFlush && flushChance > 0 && straightChance > 0) {
                const flushSuit = Object.entries(suitCounts)
                    .filter(([suit, count]) => count >= 3)
                    .map(([suit]) => suit);

                if (flushSuit.length > 0) {
                    const suitedCards = allCards.filter(card => card.startsWith(flushSuit[0]));
                    const suitedRanks = suitedCards.map(card => parseInt(card.split("-")[1]));

                    const uniqueRanks = [...new Set(suitedRanks)].sort((a, b) => a - b);

                    for (let i = 0; i <= uniqueRanks.length - 3; i++) {
                        if (uniqueRanks[i+2] - uniqueRanks[i] <= 4) {
                            straightFlushChance = Math.min(100, (cardsToBeDealt / 47) * 25);

                            if (uniqueRanks.includes(10) && uniqueRanks.includes(11) &&
                                uniqueRanks.includes(12) && uniqueRanks.includes(13) &&
                                uniqueRanks.includes(14)) {
                                royalFlushChance = 100;
                            } else if (uniqueRanks.some(r => r >= 10) &&
                                      uniqueRanks.every(r => r <= 14)) {
                                royalFlushChance = Math.min(100, (cardsToBeDealt / 47) * 5);
                            }

                            break;
                        }
                    }
                }
            }
        }

        return {
            pairChance: Math.min(100, Math.max(0, Math.round(pairChance))),
            twoPairChance: Math.min(100, Math.max(0, Math.round(twoPairChance))),
            tripsChance: Math.min(100, Math.max(0, Math.round(tripsChance))),
            fullHouseChance: Math.min(100, Math.max(0, Math.round(fullHouseChance))),
            straightChance: Math.min(100, Math.max(0, Math.round(straightChance))),
            flushChance: Math.min(100, Math.max(0, Math.round(flushChance))),
            quadsChance: Math.min(100, Math.max(0, Math.round(quadsChance))),
            straightFlushChance: Math.min(100, Math.max(0, Math.round(straightFlushChance))),
            royalFlushChance: Math.min(100, Math.max(0, Math.round(royalFlushChance)))
        };
    }

    processPreFlopStats() {
        let playerNodes = document.querySelectorAll("[class*='playerMeGateway___']");
        if (!playerNodes || playerNodes.length === 0) return;

        let holeCards = Array.from(playerNodes[0].querySelectorAll("div[class*='front___'] > div")).map(e => {
            var card = (e.classList[1] || "null-0").split("_")[0]
                .replace("-A", "-14")
                .replace("-K", "-13")
                .replace("-Q", "-12")
                .replace("-J", "-11");
            if (card == "cardSize") card = "null-0";
            return card;
        }).filter(c => !c.includes("null"));

        if (holeCards.length !== 2) return;

        const card1 = this.convertToNotation(holeCards[0]);
        const card2 = this.convertToNotation(holeCards[1]);

        if (!card1 || !card2) return;

        const card1Value = parseInt(holeCards[0].split("-")[1]);
        const card2Value = parseInt(holeCards[1].split("-")[1]);
        const hasPair = card1Value === card2Value;

        const suited = holeCards[0].split("-")[0] === holeCards[1].split("-")[0];

        let handNotation;
        if (card1 === card2) {
            handNotation = card1 + card1;
        } else {
            const sortedCards = [card1, card2].sort((a, b) => {
                const values = { 'A': 14, 'K': 13, 'Q': 12, 'J': 11, 'T': 10 };
                const valA = values[a] || parseInt(a);
                const valB = values[b] || parseInt(b);
                return valB - valA;
            });

            handNotation = sortedCards[0] + sortedCards[1];
            if (suited) handNotation += 's';
        }

        const winEquity = this.calculatePreflopEquity(handNotation);

        const drawPotentials = this.calculatePreFlopPotential(holeCards, handNotation);

        this.updateProbabilityMeter(winEquity, drawPotentials);

        const handStats = this.preflopStats[handNotation];

        if (handStats) {
            const recommendation = this.getPreFlopRecommendation(handStats.total);
            const actionButton = document.getElementById("pokerCalc-action");
            actionButton.textContent = recommendation;

            actionButton.classList.remove("action-raise", "action-call", "action-fold");

            if (recommendation.includes("Raise")) {
                actionButton.classList.add("action-raise");
            } else if (recommendation.includes("Call")) {
                actionButton.classList.add("action-call");
            } else if (recommendation.includes("Fold")) {
                actionButton.classList.add("action-fold");
            }

            this.lastRecommendation = recommendation;

            let statsHTML = `<tr>
                <td>${handNotation}</td>
                <td>${handStats.wins.toFixed(2)}%</td>
                <td>${handStats.ties.toFixed(2)}%</td>
                <td>${handStats.total.toFixed(2)}%</td>
                <td>${this.getPreflopHandTier(handStats.total)}</td>
            </tr>`;

            document.querySelector("#pokerCalc-preflop tbody").innerHTML = statsHTML;
        } else {
            this.estimateHandStats(handNotation);
        }
    }

    processPostFlopStats(knownCards, communityCards, allCards) {
        let playerNodes = document.querySelectorAll("[class*='playerMeGateway___']");
        playerNodes.forEach(player => {
            let myCards = Array.from(player.querySelectorAll("div[class*='front___'] > div")).map(e => {
                var card = (e.classList[1] || "null-0").split("_")[0]
                    .replace("-A", "-14")
                    .replace("-K", "-13")
                    .replace("-Q", "-12")
                    .replace("-J", "-11");
                if (card == "cardSize") card = "null-0";
                return card;
            });

            let myHand = this.getHandScore(communityCards.concat(myCards));

            if (myHand.score > 0) {
                const drawPotentials = this.calculateDrawPotential(myCards, communityCards);

                let myRank = this.calculateHandRank(myHand, communityCards, allCards);

                const potSize = parseInt(document.querySelector(".pot-display")?.textContent || 0);
                const betToCall = parseInt(document.querySelector(".bet-to-call")?.textContent || 0);
                const potOdds = betToCall / (potSize + betToCall);
                const recommendation = this.getRecommendation(myRank.topNumber, potOdds);

                const actionButton = document.getElementById("pokerCalc-action");
                actionButton.textContent = recommendation;

                actionButton.classList.remove("action-raise", "action-call", "action-fold");

                if (recommendation.includes("Raise") || recommendation.includes("Bet")) {
                    actionButton.classList.add("action-raise");
                } else if (recommendation.includes("Call") || recommendation.includes("Check")) {
                    actionButton.classList.add("action-call");
                } else if (recommendation.includes("Fold")) {
                    actionButton.classList.add("action-fold");
                }

                this.lastRecommendation = recommendation;

                document.querySelector("#pokerCalc-myHand tbody").innerHTML += `<tr><td>Me</td><td>${myHand.description}</td><td>${myRank.rank}</td><td>${myRank.top}</td></tr>`;

                let myUpgrades = {};
                let bestOppHands = {};
                let additionalCards = [];
                let additionalOppCards = [];

                if (communityCards.filter(e => !e.includes("null")).length == 3) {
                    for (let a of allCards) {
                        for (let b of allCards) {
                            if (a > b) additionalCards.push([a, b]);
                        }
                    }
                } else if (communityCards.filter(e => !e.includes("null")).length == 4) {
                    for (let a of allCards) additionalCards.push([a]);
                } else if (communityCards.filter(e => !e.includes("null")).length == 5) {
                    for (let a of allCards) {
                        for (let b of allCards) {
                            if (a > b) additionalOppCards.push([a, b]);
                        }
                    }
                }

                for (let cards of additionalCards) {
                    let thisHand = this.getHandScore(communityCards.concat(cards).concat(myCards));
                    if (thisHand.score > myHand.score) {
                        let type = thisHand.description.split(":")[0];
                        if (thisHand.description.includes("Four of a kind") || thisHand.description.includes("Three of a kind") || thisHand.description.includes("Pair")) {
                            type += ": " + thisHand.description.split("</span>")[1].split("<span")[0].trim() + "s";
                        } else if (thisHand.description.includes("Full house")) {
                            type += ": " + thisHand.description.split("</span>")[1].split("<span")[0].trim() + "s full of " + thisHand.description.split("</span>").reverse()[0].split("</td>")[0] + "s";
                        } else if (thisHand.description.includes("Straight")) {
                            type += ": " + thisHand.description.split("</span>")[1].split("<span")[0].trim() + "-high";
                        } else if (thisHand.description.includes("Two pairs")) {
                            type += ": " + thisHand.description.split("</span>")[1].split("<span")[0].trim() + "s and " + thisHand.description.split("</span>")[3].split("<span")[0].trim() + "s";
                        }

                        if (!myUpgrades.hasOwnProperty(type)) {
                            myUpgrades[type] = { hand: thisHand, type: type, cards: cards, score: thisHand.score, duplicates: 0, chance: 0 };
                        }
                        myUpgrades[type].description = thisHand.description;
                        myUpgrades[type].duplicates++;
                    }
                }

                let topUpgrades = Object.values(myUpgrades).map(e => {
                    const chance = (e.duplicates / additionalCards.length) * 100;

                    const newCommunity = communityCards.concat(e.cards);
                    const remainingDeck = this.filterDeck(allCards, [...e.cards, ...myCards]);
                    const handRank = this.calculateHandRank(e.hand, newCommunity, remainingDeck);

                    return {
                        ...e,
                        chance: chance,
                        rank: handRank.rank || "N/A",
                        top: handRank.top || "N/A"
                    };
                });

                let aggregatedChances = {
                    pairChance: 0,
                    twoPairChance: 0,
                    tripsChance: 0,
                    fullHouseChance: 0,
                    straightChance: 0,
                    flushChance: 0,
                    quadsChance: 0,
                    straightFlushChance: 0,
                    royalFlushChance: 0
                };

                topUpgrades.forEach(upgrade => {
                    const type = upgrade.type.split(':')[0].trim();

                    if (type.includes('Pair') && !type.includes('Two')) {
                        aggregatedChances.pairChance += upgrade.chance;
                    } else if (type.includes('Two pairs')) {
                        aggregatedChances.twoPairChance += upgrade.chance;
                    } else if (type.includes('Three of a kind')) {
                        aggregatedChances.tripsChance += upgrade.chance;
                    } else if (type.includes('Full house')) {
                        aggregatedChances.fullHouseChance += upgrade.chance;
                    } else if (type.includes('Four of a kind')) {
                        aggregatedChances.quadsChance += upgrade.chance;
                    } else if (type.includes('Straight') && !type.includes('flush')) {
                        aggregatedChances.straightChance += upgrade.chance;
                    } else if (type.includes('Flush') && !type.includes('Straight') && !type.includes('Royal')) {
                        aggregatedChances.flushChance += upgrade.chance;
                    } else if (type.includes('Straight flush') && !type.includes('Royal')) {
                        aggregatedChances.straightFlushChance += upgrade.chance;
                    } else if (type.includes('Royal flush')) {
                        aggregatedChances.royalFlushChance += upgrade.chance;
                    }
                });

                if (myHand.description.includes('Pair') && !myHand.description.includes('Two')) {
                    aggregatedChances.pairChance = 100;
                } else if (myHand.description.includes('Two pairs')) {
                    aggregatedChances.pairChance = 100;
                    aggregatedChances.twoPairChance = 100;
                } else if (myHand.description.includes('Three of a kind')) {
                    aggregatedChances.pairChance = 100;
                    aggregatedChances.tripsChance = 100;
                } else if (myHand.description.includes('Straight') && !myHand.description.includes('flush')) {
                    aggregatedChances.straightChance = 100;
                } else if (myHand.description.includes('Flush') && !myHand.description.includes('Straight') && !myHand.description.includes('Royal')) {
                    aggregatedChances.flushChance = 100;
                } else if (myHand.description.includes('Full house')) {
                    aggregatedChances.pairChance = 100;
                    aggregatedChances.twoPairChance = 100;
                    aggregatedChances.tripsChance = 100;
                    aggregatedChances.fullHouseChance = 100;
                } else if (myHand.description.includes('Four of a kind')) {
                    aggregatedChances.pairChance = 100;
                    aggregatedChances.tripsChance = 100;
                    aggregatedChances.quadsChance = 100;
                } else if (myHand.description.includes('Straight flush') && !myHand.description.includes('Royal')) {
                    aggregatedChances.straightChance = 100;
                    aggregatedChances.flushChance = 100;
                    aggregatedChances.straightFlushChance = 100;
                } else if (myHand.description.includes('Royal flush')) {
                    aggregatedChances.straightChance = 100;
                    aggregatedChances.flushChance = 100;
                    aggregatedChances.straightFlushChance = 100;
                    aggregatedChances.royalFlushChance = 100;
                }

                Object.keys(aggregatedChances).forEach(key => {
                    aggregatedChances[key] = Math.min(100, aggregatedChances[key]);
                });

                this.updateProbabilityMeter(myRank.winProbability, aggregatedChances);

                let bestUpgradeChance = -1;
                let bestUpgradeIndex = -1;

                for (let i = 0; i < topUpgrades.length; i++) {
                    if (topUpgrades[i].chance > bestUpgradeChance) {
                        bestUpgradeChance = topUpgrades[i].chance;
                        bestUpgradeIndex = i;
                    }
                }

                let upgradeString = "";
                for (let i = 0; i < topUpgrades.length; i++) {
                    const upgrade = topUpgrades[i];
                    const isBestHand = i === bestUpgradeIndex;
                    upgradeString += `<tr class="${isBestHand ? 'best-hand' : ''}">`;
                    upgradeString += `<td>${upgrade.chance.toFixed(2)}%</td><td>${upgrade.type}</td><td>${upgrade.rank}</td><td>${upgrade.top}</td>`;
                    upgradeString += "</tr>";
                }
                document.querySelector("#pokerCalc-upgrades tbody").innerHTML = upgradeString;

                for (let cards of additionalOppCards) {
                    let oppPossHand = this.getHandScore(communityCards.concat(cards));
                    let type = oppPossHand.description.split(":")[0];
                    if (oppPossHand.description.includes("Four of a kind") || oppPossHand.description.includes("Three of a kind") || oppPossHand.description.includes("Pair")) {
                        type += ": " + oppPossHand.description.split("</span>")[1].split("<span")[0].trim() + "s";
                    } else if (oppPossHand.description.includes("Full house")) {
                        type += ": " + oppPossHand.description.split("</span>")[1].split("<span")[0].trim() + "s full of " + oppPossHand.description.split("</span>").reverse()[0].split("</td>")[0] + "s";
                    } else if (oppPossHand.description.includes("Straight")) {
                        type += ": " + oppPossHand.description.split("</span>")[1].split("<span")[0].trim() + "-high";
                    } else if (oppPossHand.description.includes("Two pairs")) {
                        type += ": " + oppPossHand.description.split("</span>")[1].split("<span")[0].trim() + "s and " + oppPossHand.description.split("</span>")[3].split("<span")[0].trim() + "s";
                    }

                   if (!bestOppHands.hasOwnProperty(type)) {
                        bestOppHands[type] = { hand: oppPossHand, type: type, cards: cards, score: oppPossHand.score, duplicates: 0, chance: 0 };
                    }
                    bestOppHands[type].description = oppPossHand.description;
                    bestOppHands[type].duplicates++;
                }

                let topOppHands = Object.values(bestOppHands);
                topOppHands.forEach(e => {
                    e.chance = (e.duplicates / additionalOppCards.length) * 100;
                });
                topOppHands = topOppHands
                    .sort((a, b) => b.score - a.score)
                    .slice(0, this.upgradesToShow);

                topOppHands.forEach(e => {
                    const newCommunity = communityCards.concat(e.cards);
                    const remainingDeck = this.filterDeck(allCards, e.cards);
                    const thisRank = this.calculateHandRank(e.hand, newCommunity, remainingDeck);
                    e.rank = thisRank.rank;
                    e.top = thisRank.top;
                });

                let bestOppHandScore = -1;
                let bestOppHandIndex = -1;

                for (let i = 0; i < topOppHands.length; i++) {
                    if (topOppHands[i].score > bestOppHandScore) {
                        bestOppHandScore = topOppHands[i].score;
                        bestOppHandIndex = i;
                    }
                }

                let oppHandString = "";
                for (let i = 0; i < topOppHands.length; i++) {
                    const upgrade = topOppHands[i];
                    const isBestHand = i === bestOppHandIndex;
                    oppHandString += `<tr class="${isBestHand ? 'best-opp-hand' : ''}">`;
                    oppHandString += `<td>${upgrade.chance.toFixed(2)}%</td><td>${upgrade.type}</td><td>${upgrade.rank}</td><td>${upgrade.top}</td>`;
                    oppHandString += "</tr>";
                }
                document.querySelector("#pokerCalc-oppPossHands tbody").innerHTML = oppHandString;
            }
        });
    }

    getRecommendation(topNumber, potOdds) {
        const topPercent = topNumber * 100;
        const thresholds = {
            'pre-flop': { raise: 25, fold: 60 },
            'flop': { raise: 20, fold: 50 },
            'turn': { raise: 15, fold: 40 },
            'river': { raise: 10, fold: 30 }
        };
        const betRound = this.getBettingRound();
        const { raise, fold } = thresholds[betRound] || { raise: 20, fold: 50 };

        if (topPercent <= raise) {
            return "Raise/Bet - Strong Hand";
        } else if (topPercent <= fold) {
            if (potOdds > 0 && potOdds < topNumber) {
                return "Call - Pot Odds Favorable";
            }
            return "Call/Check - Moderate";
        } else {
            return "Fold - Weak Hand";
        }
    }

    getBettingRound() {
        const communityCards = Array.from(document.querySelectorAll("[class*='flipper___'] > div[class*='front___'] > div")).slice(0, 5);
        const numCards = communityCards.filter(e => !e.classList.contains("null-0")).length;
        switch (numCards) {
            case 0: return 'pre-flop';
            case 3: return 'flop';
            case 4: return 'turn';
            case 5: return 'river';
            default: return 'unknown';
        }
    }

    addStatisticsTable() {
        const observer = new MutationObserver((mutations, obs) => {
            const reactRoot = document.querySelector("#react-root");
            if (reactRoot) {
                if (!document.getElementById("pokerCalc-div")) {
                    const div = document.createElement("div");
                    div.id = "pokerCalc-div";
                    div.style.position = "relative";
                    div.innerHTML = `
                        <div class="suits-container"></div>
                        <div class="flopmaster-header">
                            <div id="pokerCalc-recommendations">
                                <div class="action-chip">
                                    <div class="chip-inner">
                                        <span id="pokerCalc-action">Waiting for cards...</span>
                                    </div>
                                    <div class="chip-edge"></div>
                                </div>
                            </div>

                            <div id="flopmaster-logo">
                                <div class="logo-container">
                                    <div class="logo-card">
                                        <span class="logo-text">FlopMaster</span>
                                        <div class="logo-suits">
                                            <span class="suit hearts">♥</span>
                                            <span class="suit spades">♠</span>
                                            <span class="suit diamonds">♦</span>
                                            <span class="suit clubs">♣</span>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <div class="win-probability-meter">
                            <div class="meter-label">Win Probability</div>
                            <div class="meter-container">
                                <div class="meter-groove"></div>
                                <div class="meter-bar" style="width: 0%"></div>
                                <div class="meter-value">0%</div>
                            </div>
                        </div>

                       <div class="mini-meters-container">
    <div class="mini-meter pair-meter">
        <div class="mini-meter-label">Pair</div>
        <div class="mini-meter-container">
            <div class="mini-meter-groove"></div>
            <div class="mini-meter-bar" data-type="pair" style="width: 0%"></div>
            <div class="mini-meter-value">0%</div>
        </div>
    </div>

    <div class="mini-meter two-pair-meter">
        <div class="mini-meter-label">Two Pair</div>
        <div class="mini-meter-container">
            <div class="mini-meter-groove"></div>
            <div class="mini-meter-bar" data-type="twoPair" style="width: 0%"></div>
            <div class="mini-meter-value">0%</div>
        </div>
    </div>

    <div class="mini-meter trips-meter">
        <div class="mini-meter-label">Three of a Kind</div>
        <div class="mini-meter-container">
            <div class="mini-meter-groove"></div>
            <div class="mini-meter-bar" data-type="trips" style="width: 0%"></div>
            <div class="mini-meter-value">0%</div>
        </div>
    </div>

    <div class="mini-meter straight-meter">
        <div class="mini-meter-label">Straight</div>
        <div class="mini-meter-container">
            <div class="mini-meter-groove"></div>
            <div class="mini-meter-bar" data-type="straight" style="width: 0%"></div>
            <div class="mini-meter-value">0%</div>
        </div>
    </div>

    <div class="mini-meter flush-meter">
        <div class="mini-meter-label">Flush</div>
        <div class="mini-meter-container">
            <div class="mini-meter-groove"></div>
            <div class="mini-meter-bar" data-type="flush" style="width: 0%"></div>
            <div class="mini-meter-value">0%</div>
        </div>
    </div>

    <div class="mini-meter full-house-meter">
        <div class="mini-meter-label">Full House</div>
        <div class="mini-meter-container">
            <div class="mini-meter-groove"></div>
            <div class="mini-meter-bar" data-type="fullHouse" style="width: 0%"></div>
            <div class="mini-meter-value">0%</div>
        </div>
    </div>

    <div class="mini-meter quads-meter">
        <div class="mini-meter-label">Four of a Kind</div>
        <div class="mini-meter-container">
            <div class="mini-meter-groove"></div>
            <div class="mini-meter-bar" data-type="quads" style="width: 0%"></div>
            <div class="mini-meter-value">0%</div>
        </div>
    </div>

    <div class="mini-meter straight-flush-meter">
        <div class="mini-meter-label">Straight Flush</div>
        <div class="mini-meter-container">
            <div class="mini-meter-groove"></div>
            <div class="mini-meter-bar" data-type="straightFlush" style="width: 0%"></div>
            <div class="mini-meter-value">0%</div>
        </div>
    </div>

    <div class="mini-meter royal-flush-meter">
        <div class="mini-meter-label">Royal Flush</div>
        <div class="mini-meter-container">
            <div class="mini-meter-groove"></div>
            <div class="mini-meter-bar" data-type="royalFlush" style="width: 0%"></div>
            <div class="mini-meter-value">0%</div>
        </div>
    </div>
</div>

                        <table id="pokerCalc-preflop" style="display: none;">
                            <caption>Pre-Flop Hand Statistics</caption>
                            <thead>
                                <tr>
                                    <th>Hand</th>
                                    <th>Win %</th>
                                    <th>Tie %</th>
                                    <th>Total %</th>
                                    <th>Tier</th>
                                </tr>
                            </thead>
                            <tbody></tbody>
                        </table>
                        <table id="pokerCalc-myHand">
                            <caption>Your Hand</caption>
                            <thead>
                                <tr>
                                    <th>Name</th>
                                    <th>Hand</th>
                                    <th>Rank</th>
                                    <th>Top</th>
                                </tr>
                            </thead>
                            <tbody></tbody>
                        </table>
                        <table id="pokerCalc-upgrades">
                            <caption>Your Potential Hands</caption>
                            <thead>
                                <tr>
                                    <th>Chance</th>
                                    <th>Hand</th>
                                    <th>Rank</th>
                                    <th>Top</th>
                                </tr>
                            </thead>
                            <tbody></tbody>
                        </table>
                        <table id="pokerCalc-oppPossHands">
                            <caption>Opponent Potential Hands</caption>
                            <thead>
                                <tr>
                                    <th>Chance</th>
                                    <th>Hand</th>
                                    <th>Rank</th>
                                    <th>Top</th>
                                </tr>
                            </thead>
                            <tbody></tbody>
                        </table>
                    `;
                    reactRoot.after(div);

                    this.initProbabilityMeter();

                    setTimeout(() => {
                        const suitsContainer = document.querySelector('.suits-container');
                        if (suitsContainer) {
                            const floatingSuits = new FloatingSuits(suitsContainer, {
                                suitCount: 25,
                                minSize: 18,
                                maxSize: 42,
                                minSpeed: 10,
                                maxSpeed: 80
                            });

                            window.pokerFloatingSuits = floatingSuits;
                            floatingSuits.start();

                            setTimeout(() => {

                                const fps = window.performance?.now ? 60 : 30; // Simplified - assume 60 FPS for modern browsers
                                if (fps < 40) {
                                    floatingSuits.setDensity(20); // Reduce number of suits on lower-end devices
                                }
                            }, 3000);
                        }
                    }, 500);
                }
                obs.disconnect();
                this.update();
            }
        });
        observer.observe(document, { childList: true, subtree: true });
    }

    initProbabilityMeter() {
        const updateMeter = (percentage = 0, handStats = null) => {
            const meterBar = document.querySelector('.meter-bar');
            const meterValue = document.querySelector('.meter-value');

            if (meterBar && meterValue) {
                meterBar.style.transition = 'width 0.8s ease-in-out';
                meterBar.style.width = `${percentage}%`;

                meterValue.textContent = `${percentage.toFixed(1)}%`;

                if (percentage >= 70) {
                    meterBar.style.backgroundColor = '#4CAF50';
                } else if (percentage >= 40) {
                    meterBar.style.backgroundColor = '#FFC107';
                } else {
                    meterBar.style.backgroundColor = '#F44336';
                }

                if (handStats) {
                    this.updateMiniMeters(handStats);
                }
            }
        };

        this.updateProbabilityMeter = updateMeter;

        updateMeter(0);
    }

    updateMiniMeters(stats = {}) {
        const pairChance = stats.pairChance || 0;
        const twoPairChance = stats.twoPairChance || 0;
        const tripsChance = stats.tripsChance || 0;
        const fullHouseChance = stats.fullHouseChance || 0;
        const straightChance = stats.straightChance || 0;
        const flushChance = stats.flushChance || 0;
        const quadsChance = stats.quadsChance || 0;
        const straightFlushChance = stats.straightFlushChance || 0;
        const royalFlushChance = stats.royalFlushChance || 0;

        const pairBar = document.querySelector('.mini-meter-bar[data-type="pair"]');
        const pairValue = pairBar?.parentNode.querySelector('.mini-meter-value');
        if (pairBar && pairValue) {
            pairBar.style.width = `${pairChance}%`;
            pairValue.textContent = `${pairChance.toFixed(1)}%`;
        }

        const twoPairBar = document.querySelector('.mini-meter-bar[data-type="twoPair"]');
        const twoPairValue = twoPairBar?.parentNode.querySelector('.mini-meter-value');
        if (twoPairBar && twoPairValue) {
            twoPairBar.style.width = `${twoPairChance}%`;
            twoPairValue.textContent = `${twoPairChance.toFixed(1)}%`;
        }

        const tripsBar = document.querySelector('.mini-meter-bar[data-type="trips"]');
        const tripsValue = tripsBar?.parentNode.querySelector('.mini-meter-value');
        if (tripsBar && tripsValue) {
            tripsBar.style.width = `${tripsChance}%`;
            tripsValue.textContent = `${tripsChance.toFixed(1)}%`;
        }

        const quadsBar = document.querySelector('.mini-meter-bar[data-type="quads"]');
        const quadsValue = quadsBar?.parentNode.querySelector('.mini-meter-value');
        if (quadsBar && quadsValue) {
            quadsBar.style.width = `${quadsChance}%`;
            quadsValue.textContent = `${quadsChance.toFixed(1)}%`;
        }

        const fullHouseBar = document.querySelector('.mini-meter-bar[data-type="fullHouse"]');
        const fullHouseValue = fullHouseBar?.parentNode.querySelector('.mini-meter-value');
        if (fullHouseBar && fullHouseValue) {
            fullHouseBar.style.width = `${fullHouseChance}%`;
            fullHouseValue.textContent = `${fullHouseChance.toFixed(1)}%`;
        }

        const straightBar = document.querySelector('.mini-meter-bar[data-type="straight"]');
        const straightValue = straightBar?.parentNode.querySelector('.mini-meter-value');
        if (straightBar && straightValue) {
            straightBar.style.width = `${straightChance}%`;
            straightValue.textContent = `${straightChance.toFixed(1)}%`;
        }

        const flushBar = document.querySelector('.mini-meter-bar[data-type="flush"]');
        const flushValue = flushBar?.parentNode.querySelector('.mini-meter-value');
        if (flushBar && flushValue) {
            flushBar.style.width = `${flushChance}%`;
            flushValue.textContent = `${flushChance.toFixed(1)}%`;
        }

        const straightFlushBar = document.querySelector('.mini-meter-bar[data-type="straightFlush"]');
        const straightFlushValue = straightFlushBar?.parentNode.querySelector('.mini-meter-value');
        if (straightFlushBar && straightFlushValue) {
            straightFlushBar.style.width = `${straightFlushChance}%`;
            straightFlushValue.textContent = `${straightFlushChance.toFixed(1)}%`;
        }

        const royalFlushBar = document.querySelector('.mini-meter-bar[data-type="royalFlush"]');
        const royalFlushValue = royalFlushBar?.parentNode.querySelector('.mini-meter-value');
        if (royalFlushBar && royalFlushValue) {
            royalFlushBar.style.width = `${royalFlushChance}%`;
            royalFlushValue.textContent = `${royalFlushChance.toFixed(1)}%`;
        }
    }

    calculatePreflopEquity(handNotation) {
        if (this.preflopStats[handNotation]) {
            return this.preflopStats[handNotation].total;
        }

        const isPair = handNotation.length === 2;
        const isSuited = handNotation.endsWith('s');

        let card1, card2;
        if (isPair) {
            card1 = card2 = this.getCardRank(handNotation[0]);
        } else {
            card1 = this.getCardRank(handNotation[0]);
            card2 = this.getCardRank(handNotation[1].replace('s', ''));
        }

        let equity = 0;

        if (isPair) {
            equity = 50 + (card1 * 2.5);
        } else {
            let baseEquity = (card1 + card2) * 1.5;
            const isConnected = Math.abs(card1 - card2) <= 2;

            if (isSuited) baseEquity += 5;
            if (isConnected) baseEquity += 3;

            equity = baseEquity;
        }

        return Math.min(Math.max(equity, 30), 85);
    }

    getCardRank(cardValue) {
        const values = { 'A': 14, 'K': 13, 'Q': 12, 'J': 11, 'T': 10 };
        return values[cardValue] || parseInt(cardValue);
    }

    estimateHandStats(handNotation) {
        const winEquity = this.calculatePreflopEquity(handNotation);

        const isPocketPair = handNotation.length === 2 && handNotation[0] === handNotation[1];
        const isSuited = handNotation.endsWith('s');

        let pairChance = isPocketPair ? 100 : 40;
        let twoPairChance = isPocketPair ? 20 : 5;
        let tripsChance = isPocketPair ? 25 : 0;
        let fullHouseChance = isPocketPair ? 5 : 0;
        let straightChance = 0;
        let flushChance = 0;
        let quadsChance = isPocketPair ? 3 : 0;
        let straightFlushChance = 0;
        let royalFlushChance = 0;

        if (!isPocketPair) {
            const card1 = this.getCardRank(handNotation[0]);
            const card2 = this.getCardRank(handNotation[1].replace('s', ''));
            const isConnected = Math.abs(card1 - card2) <= 3;

            if (isConnected) {
                straightChance = 20 - (Math.abs(card1 - card2) * 5);
            }

            if (isSuited) {
                flushChance = 15;

                if (isConnected) {
                    straightFlushChance = 1;

                    if (card1 >= 10 && card2 >= 10) {
                        royalFlushChance = 0.5;
                    }
                }
            }
        }

        const recommendation = this.getPreFlopRecommendation(winEquity);
        const actionButton = document.getElementById("pokerCalc-action");
        actionButton.textContent = recommendation;

        actionButton.classList.remove("action-raise", "action-call", "action-fold");

        if (recommendation.includes("Raise")) {
            actionButton.classList.add("action-raise");
        } else if (recommendation.includes("Call")) {
            actionButton.classList.add("action-call");
        } else if (recommendation.includes("Fold")) {
            actionButton.classList.add("action-fold");
        }

        this.lastRecommendation = recommendation;

        let statsHTML = `<tr>
            <td>${handNotation}</td>
            <td>${(winEquity * 0.95).toFixed(2)}%</td>
            <td>${(winEquity * 0.05).toFixed(2)}%</td>
            <td>${winEquity.toFixed(2)}%</td>
            <td>${this.getPreflopHandTier(winEquity)}</td>
        </tr>`;

        document.querySelector("#pokerCalc-preflop tbody").innerHTML = statsHTML;

        this.updateProbabilityMeter(winEquity, {
            pairChance,
            twoPairChance,
            tripsChance,
            fullHouseChance,
            straightChance,
            flushChance,
            quadsChance,
            straightFlushChance,
            royalFlushChance
        });
    }

    convertToNotation(card) {
        if (!card || card === "null-0") return null;

        const value = card.split("-")[1];
        switch (value) {
            case "14": return "A";
            case "13": return "K";
            case "12": return "Q";
            case "11": return "J";
            case "10": return "T";
            default: return value;
        }
    }

    getPreflopHandTier(winPercentage) {
        if (winPercentage >= 75) return "Premium";
        if (winPercentage >= 65) return "Strong";
        if (winPercentage >= 55) return "Playable";
        if (winPercentage >= 45) return "Speculative";
        return "Weak";
    }

    getPreFlopRecommendation(winPercentage) {
        const position = this.getPlayerPosition();

        let raiseThreshold, callThreshold;

        switch (position) {
            case 'early':
                raiseThreshold = 70;
                callThreshold = 60;
                break;
            case 'middle':
                raiseThreshold = 65;
                callThreshold = 55;
                break;
            case 'late':
                raiseThreshold = 60;
                callThreshold = 50;
                break;
            case 'button':
            case 'smallBlind':
                raiseThreshold = 55;
                callThreshold = 45;
                break;
            case 'bigBlind':
                raiseThreshold = 60;
                callThreshold = 40;
                break;
            default:
                raiseThreshold = 65;
                callThreshold = 50;
        }

        if (winPercentage < 30) {
            return "Fold - Weak Hand";
        }

        if (winPercentage >= raiseThreshold) {
            return "Raise - Strong Hand";
        } else if (winPercentage >= callThreshold) {
            return "Call - Moderate Hand";
        } else {
            return "Fold - Weak Hand";
        }
    }

    getPlayerPosition() {
        return 'middle';
    }

    getFullDeck() {
        let result = [];
        for (let suit of ["hearts", "diamonds", "spades", "clubs"]) {
            for (let value of [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]) {
                result.push(suit + "-" + value);
            }
        }
        return result;
    }

    filterDeck(deck, cards) {
        for (let card of cards) {
            let index = deck.indexOf(card);
            if (index != -1) {
                delete deck[index];
            }
        }
        return deck.filter(e => e != "empty");
    }

    calculateHandRank(myHand, communityCards, allCards) {
        if (!myHand?.score || !Array.isArray(communityCards) || !Array.isArray(allCards) ||
            communityCards.length === 0 || allCards.length === 0) {
            return {
                rank: "N/A",
                top: "N/A",
                topNumber: 0,
                betterHands: 0,
                equalHands: 0,
                worseHands: 0,
                totalHands: 0
            };
        }

        let betterHands = 0;
        let equalHands = 0;
        let worseHands = 0;
        let totalHands = 0;

        const availableCards = allCards.filter(card =>
            card &&
            typeof card === 'string' &&
            !communityCards.includes(card) &&
            !myHand.result.includes(card)
        );

        if (availableCards.length < 2) {
            return {
                rank: "N/A",
                top: "N/A",
                topNumber: 0.5
            };
        }

        for (let i = 0; i < availableCards.length - 1; i++) {
            for (let j = i + 1; j < availableCards.length; j++) {
                const combo = [availableCards[i], availableCards[j]];
                let thisHand = this.getHandScore(communityCards.concat(combo));

                if (thisHand.score > myHand.score) {
                    betterHands++;
                } else if (thisHand.score === myHand.score) {
                    const tieBreaker = this.compareTiedHands(myHand, thisHand);
                    if (tieBreaker > 0) betterHands++;
                    else if (tieBreaker < 0) worseHands++;
                    else equalHands++;
                } else {
                    worseHands++;
                }
                totalHands++;
            }
        }

        if (totalHands === 0) {
            return {
                rank: "N/A",
                top: "N/A",
                topNumber: 0.5
            };
        }

        const trueRank = betterHands + Math.ceil(equalHands / 2);
        const percentile = ((betterHands + equalHands / 2) / totalHands) * 100;

        const winProbability = 100 - percentile;

        return {
            rank: `${trueRank + 1} / ${totalHands}`,
            top: `${percentile.toFixed(1)}%`,
            topNumber: percentile / 100,
            winProbability: winProbability
        };
    }

    compareTiedHands(hand1, hand2) {
        const kickers1 = hand1.result.map(card => parseInt(card.split('-')[1])).sort((a, b) => b - a);
        const kickers2 = hand2.result.map(card => parseInt(card.split('-')[1])).sort((a, b) => b - a);

        for (let i = 0; i < kickers1.length; i++) {
            if (kickers1[i] !== kickers2[i]) {
                return kickers2[i] - kickers1[i];
            }
        }
        return 0;
    }

    prettifyHand(hand) {
        let resultText = "";
        for (let card of hand) {
            if (card != "null-0") {
                resultText += " " + card
                    .replace("diamonds", "<span class='diamonds'>♦</span>")
                    .replace("spades", "<span class='spades'>♠</span>")
                    .replace("hearts", "<span class='hearts'>♥</span>")
                    .replace("clubs", "<span class='clubs'>♣</span>")
                    .replace("-14", "-A")
                    .replace("-13", "K")
                    .replace("-12", "Q")
                    .replace("-11", "J")
                    .replace("-", "");
            }
        }
        return resultText;
    }

    getHandScore(hand) {
        hand = hand.filter(e => !e.includes("null"));

        if (hand.length < 5) { return { description: "", score: 0 }; }

        let resultString = "";
        let resultText = "";
        let handResult;
        let handObject = this.makeHandObject(hand);

        if (handResult = this.hasFourOfAKind(hand, handObject)) {
            resultString += "7";
            resultText += "Four of a kind:";
        } else if (handResult = this.hasFullHouse(hand, handObject)) {
            resultString += "6";
            resultText += "Full house:";
        } else if (handResult = this.hasFlush(hand, handObject)) {
            let isRoyal = this.hasRoyalFlush(hand, handObject);

            if (isRoyal) {
                handResult = isRoyal;
                resultString += "9";
                resultText += "Royal flush:";
            } else {
                let isStraight = this.hasStraightFlush(hand, handObject);

                if (isStraight) {
                    handResult = isStraight;
                    resultString += "8";
                    resultText += "Straight flush:";
                } else {
                    resultString += "5";
                    resultText += "Flush:";
                }
            }
        } else if (handResult = this.hasStraight(hand, handObject)) {
            resultString += "4";
            resultText += "Straight:";
        } else if (handResult = this.hasThreeOfAKind(hand, handObject)) {
            resultString += "3";
            resultText += "Three of a kind:";
        } else if (handResult = this.hasTwoPairs(hand, handObject)) {
            resultString += "2";
            resultText += "Two pairs:";
        } else if (handResult = this.hasPair(hand, handObject)) {
            resultString += "1";
            resultText += "Pair:";
        } else {
            resultString += "0";
            resultText += "High card:";
            handResult = hand.slice(0, 5);
        }

        for (let card of handResult) {
            resultString += parseInt(card.split("-")[1]).toString(16);
        }

        resultText += this.prettifyHand(handResult);

        return { description: resultText, result: handResult, score: parseInt(resultString, 16) };
    }

    makeHandObject(hand) {
        let resultMap = { cards: hand, suits: {}, values: {} };

        hand.sort((a, b) => parseInt(b.split("-")[1]) - parseInt(a.split("-")[1])).filter(e => e != "null-0").forEach(e => {
            let suit = e.split("-")[0];
            let value = e.split("-")[1];

            if (!resultMap.suits.hasOwnProperty(suit)) {
                resultMap.suits[suit] = [];
            }

            if (!resultMap.values.hasOwnProperty(value)) {
                resultMap.values[value] = [];
            }

            resultMap.suits[suit].push(e);
            resultMap.values[value].push(e);
        });

        return resultMap;
    }

    hasRoyalFlush(hand, handObject) {
        for (let suit in handObject.suits) {
            const suitCards = handObject.suits[suit];
            if (suitCards.length >= 5) {
                const values = new Set(suitCards.map(card => parseInt(card.split("-")[1])));
                if ([10, 11, 12, 13, 14].every(value => values.has(value))) {
                    return suitCards
                        .filter(card => parseInt(card.split("-")[1]) >= 10)
                        .sort((a, b) => parseInt(b.split("-")[1]) - parseInt(a.split("-")[1]))
                        .slice(0, 5);
                }
            }
        }
        return null;
    }

    hasStraightFlush(hand, handObject) {
        for (let suit in handObject.suits) {
            const suitCards = handObject.suits[suit];
            if (suitCards.length >= 5) {
                const straightFlush = this.hasStraight(suitCards, this.makeHandObject(suitCards));
                if (straightFlush) {
                    return straightFlush;
                }
            }
        }
        return null;
    }

    hasFourOfAKind(hand, handObject) {
        let quadruplets = Object.values(handObject.values).filter(e => e.length == 4);

        if (quadruplets.length > 0) {
            delete hand[hand.indexOf(quadruplets[0][0])];
            delete hand[hand.indexOf(quadruplets[0][1])];
            delete hand[hand.indexOf(quadruplets[0][2])];
            delete hand[hand.indexOf(quadruplets[0][3])];

            hand = hand.filter(e => e != "empty");

            return quadruplets[0].concat(hand).slice(0, 5);
        }
        return null;
    }

    hasFullHouse(hand, handObject) {
        let triplets = Object.values(handObject.values)
            .filter(e => e.length === 3)
            .sort((a, b) => parseInt(b[0].split("-")[1]) - parseInt(a[0].split("-")[1]));

        if (triplets.length === 0) {
            return null;
        }

        for (let threeOfKind of triplets) {
            const threeValue = parseInt(threeOfKind[0].split("-")[1]);

            const pairs = Object.values(handObject.values)
                .filter(e => e.length >= 2 && parseInt(e[0].split("-")[1]) !== threeValue)
                .sort((a, b) => parseInt(b[0].split("-")[1]) - parseInt(a[0].split("-")[1]));

            if (pairs.length > 0) {
                return threeOfKind.slice(0, 3).concat(pairs[0].slice(0, 2));
            }
        }
        return null;
    }

    hasFlush(hand, handObject) {
        for (let suit in handObject.suits) {
            if (handObject.suits[suit].length >= 5) {
                return handObject.suits[suit]
                    .sort((a, b) => parseInt(b.split("-")[1]) - parseInt(a.split("-")[1]))
                    .slice(0, 5);
            }
        }
        return null;
    }

    hasStraight(hand, handObject) {
        const valueMap = new Map();
        hand.forEach(card => {
            const value = parseInt(card.split("-")[1]);
            if (!valueMap.has(value) || parseInt(valueMap.get(value).split("-")[1]) < value) {
                valueMap.set(value, card);
            }
        });

        const uniqueValues = Array.from(valueMap.keys()).sort((a, b) => b - a);

        for (let i = 0; i <= uniqueValues.length - 5; i++) {
            const possibleStraight = uniqueValues.slice(i, i + 5);
            if (possibleStraight[0] - possibleStraight[4] === 4) {
                return possibleStraight.map(value => valueMap.get(value));
            }
        }

        if (uniqueValues.includes(14) &&
            uniqueValues.includes(2) &&
            uniqueValues.includes(3) &&
            uniqueValues.includes(4) &&
            uniqueValues.includes(5)) {
            return [
                valueMap.get(5),
                valueMap.get(4),
                valueMap.get(3),
                valueMap.get(2),
                valueMap.get(14)
            ];
        }

        return null;
    }

    hasThreeOfAKind(hand, handObject) {
        let triplets = Object.values(handObject.values).filter(e => e.length == 3);

        if (triplets.length > 0) {
            delete hand[hand.indexOf(triplets[0][0])];
            delete hand[hand.indexOf(triplets[0][1])];
            delete hand[hand.indexOf(triplets[0][2])];

            hand = hand.filter(e => e != "empty");

            return triplets[0].concat(hand).slice(0, 5);
        }
        return null;
    }

    hasTwoPairs(hand, handObject) {
        let pairs = Object.values(handObject.values).filter(e => e.length == 2);

        if (pairs.length > 1) {
            delete hand[hand.indexOf(pairs[0][0])];
            delete hand[hand.indexOf(pairs[0][1])];
            delete hand[hand.indexOf(pairs[1][0])];
            delete hand[hand.indexOf(pairs[1][1])];

            hand = hand.filter(e => e != "empty");

            if (parseInt(pairs[0][0].split("-")[1]) > parseInt(pairs[1][0].split("-")[1])) {
                return pairs[0].concat(pairs[1].concat(hand)).slice(0, 5);
            } else {
                return pairs[1].concat(pairs[0].concat(hand)).slice(0, 5);
            }
        }
        return null;
    }

    hasPair(hand, handObject) {
        let pairs = Object.values(handObject.values).filter(e => e.length == 2);

        if (pairs.length > 0) {
            delete hand[hand.indexOf(pairs[0][0])];
            delete hand[hand.indexOf(pairs[0][1])];

            hand = hand.filter(e => e != "empty");

            return pairs[0].concat(hand).slice(0, 5);
        }
        return null;
    }

    addStyle() {
    try {
        const styleText = `
        @import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@600;700&family=Roboto:wght@400;500;700&display=swap');

        #pokerCalc-div * {
            font-family: 'Roboto', 'Arial', sans-serif;
            box-sizing: border-box;
            color: #fbf7d5;
        }

        .flopmaster-header {
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 20px;
            gap: 20px;
        }

        #flopmaster-logo {
            text-align: right;
            padding: 5px 0;
            position: relative;
            flex: 0 0 auto;
        }

        .logo-container {
            position: relative;
            display: inline-block;
            perspective: 1200px;
            transform-style: preserve-3d;
        }

        .logo-card {
            position: relative;
            background: linear-gradient(145deg, #0e7a38 0%, #054122 90%);
            border-radius: 12px;
            padding: 15px 25px;
            box-shadow:
                0 10px 25px rgba(0,0,0,0.6),
                0 0 20px rgba(255,255,255,0.15) inset;
            border: 2px solid rgba(255,215,0,0.4);
            overflow: hidden;
            transform-style: preserve-3d;
            transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
            min-width: 240px;
            animation: floatCard 5s ease-in-out infinite alternate;
        }

        .logo-card::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAiIGhlaWdodD0iNjAiIHZpZXdCb3g9IjAgMCA2MCA2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxwYXRoIGQ9Ik0zNiAzNGMwLTEuMTA1LS44OTUtMi0yLTJzLTIgLjg5NS0yIDJjMCAxLjEwNC44OTUgMiAyIDJzMi0uODk2IDItMnoiIGZpbGw9InJnYmEoMjU1LDI1NSwyNTUsMC4wNSkiLz48L2c+PC9zdmc+');
            opacity: 0.2;
            z-index: 0;
        }

        .logo-card:hover {
            transform: translateY(-5px) rotateX(5deg) rotateY(5deg);
            box-shadow:
                0 15px 25px rgba(0,0,0,0.6),
                0 0 30px rgba(212, 175, 55, 0.4);
            cursor: pointer;
        }

        @keyframes floatCard {
            0% { transform: translateY(0) rotateZ(0deg); }
            50% { transform: translateY(-5px) rotateZ(0.5deg); }
            100% { transform: translateY(-3px) rotateZ(-0.5deg); }
        }

        @keyframes softGreenPulse {
            0% { filter: hue-rotate(-10deg) brightness(0.95); }
            33% { filter: hue-rotate(0deg) brightness(1.05); }
            66% { filter: hue-rotate(10deg) brightness(1.1); }
            100% { filter: hue-rotate(0deg) brightness(1); }
        }

        .logo-text {
            font-size: 35px;
            font-weight: 800;
            font-family: 'Playfair Display', serif;
            letter-spacing: 1px;
            display: block;
            width: 100%;
            text-align: center;
            position: relative;
            z-index: 2;
            color: #fff6c8;
            margin: 5px 0;
            text-shadow:
                0 0 5px #fff,
                0 0 10px #fff,
                0 0 20px #fff,
                0 0 40px #ffb700,
                0 0 80px #ffb700;
            animation: neonGoldGlow 1.5s ease-in-out infinite alternate;
        }

        .logo-suits {
            position: relative;
            display: flex;
            justify-content: space-around;
            padding: 2px 10px;
            margin-top: 5px;
        }

        .logo-suits .suit {
            font-size: 14px;
            transform-origin: center;
            animation: pulsate 3s infinite;
            filter: drop-shadow(0 3px 4px rgba(0,0,0,0.7));
            transition: all 0.3s ease;
            background-image: none !important;
            -webkit-text-fill-color: initial !important;
            -webkit-background-clip: initial !important;
            background-clip: initial !important;
        }

        .logo-suits .suit:hover {
            transform: scale(1.3) translateY(-3px);
            filter: drop-shadow(0 5px 10px rgba(0,0,0,0.8));
        }

        .logo-suits .suit.hearts,
        .logo-suits .suit.diamonds {
            color: #e62222 !important;
            text-shadow: 0 0 5px rgba(230, 34, 34, 0.7);
        }

        .logo-suits .suit.clubs,
        .logo-suits .suit.spades {
            color: #000000 !important;
            text-shadow: 0 0 5px rgba(255, 255, 255, 0.5);
        }

        .suit.hearts { animation-delay: 0s; }
        .suit.diamonds { animation-delay: 0.75s; }
        .suit.clubs { animation-delay: 1.5s; }
        .suit.spades { animation-delay: 2.25s; }

        @keyframes pulsate {
            0%, 100% { transform: scale(1); opacity: 0.8; }
            50% { transform: scale(2); opacity: 1; }
        }

        /* Floating suits animation */
        .suits-container {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            overflow: hidden;
            pointer-events: none;
            z-index: -1;
        }

        .floating-suit {
            position: absolute;
            display: inline-block;
            opacity: 0.12;
            user-select: none;
            transition: transform 0.3s ease;
            z-index: -1;
            will-change: transform, top, left;
        }

        .floating-suit.hearts,
        .floating-suit.diamonds {
            color: #e62222;
            text-shadow: 0 0 3px rgba(230, 34, 34, 0.3);
        }

        .floating-suit.clubs,
        .floating-suit.spades {
            color: #000;
            text-shadow: 0 0 3px rgba(0, 0, 0, 0.2);
        }

        .floating-suit.gold {
            color: #d4af37;
            text-shadow: 0 0 4px rgba(212, 175, 55, 0.5);
        }

        #pokerCalc-div::after {
            content: "";
            position: absolute;
            bottom: 0;
            left: 50%;
            transform: translateX(-50%);
            width: 80%;
            height: 1px;
            background: linear-gradient(to right, transparent, rgba(212, 175, 55, 0.5), transparent);
        }

        #pokerCalc-div {
            background: linear-gradient(160deg, #0a5f2a 0%, #052517 100%);
            color: #fbf7d5;
            padding: 25px;
            margin: 15px;
            border-radius: 16px;
            box-shadow:
                0 10px 35px rgba(0,0,0,0.5),
                0 0 40px rgba(0,0,0,0.1) inset;
            border: 3px solid;
            border-image: linear-gradient(45deg, #d4af37, #f1c736, #d4af37) 1;
            position: relative;
            overflow: hidden;
            z-index: 1;
        }

        #pokerCalc-div::before {
            content: "";
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background-image:
                url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><rect width="100" height="100" fill="none" stroke="%23d4af37" stroke-width="0.5" stroke-dasharray="5,5"/></svg>'),
                url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1IiBoZWlnaHQ9IjUiPgo8cmVjdCB3aWR0aD0iNSIgaGVpZ2h0PSI1IiBmaWxsPSIjMGE1ZjJhIj48L3JlY3Q+CjxwYXRoIGQ9Ik0wIDVMNSAwWk02IDRMNCA2Wk0tMSAxTDEgLTFaIiBzdHJva2U9IiMwNzRhMjMiIHN0cm9rZS13aWR0aD0iMSI+PC9wYXRoPgo8L3N2Zz4='),
                radial-gradient(circle at 100% 100%, rgba(7,74,35,0.6) 0%, transparent 50%),
                radial-gradient(circle at 0% 0%, rgba(20,140,60,0.3) 0%, transparent 50%);
            opacity: 0.5;
            z-index: -1;
            pointer-events: none;
            animation: moveGrid 20s linear infinite;
        }

        @keyframes moveGrid {
            0% { background-position: 0 0, 0 0, 0 0, 0 0; }
            100% { background-position: 100px 100px, 0 0, 0 0, 0 0; }
        }

        /* 3D Enhanced Win Probability Meter */
        .win-probability-meter {
            margin: 25px auto 15px;
            max-width: 90%;
            position: relative;
        }

        .meter-label {
            font-size: 14px;
            font-weight: 500;
            margin-bottom: 5px;
            color: #fbf7d5;
            text-align: center;
            letter-spacing: 0.5px;
            text-shadow: 0 2px 4px rgba(0,0,0,0.7);
            position: relative;
        }

        .meter-container {
            height: 25px;
            position: relative;
            border-radius: 12px;
            background: linear-gradient(to bottom, #052517, #0a5f2a);
            padding: 4px;
            box-shadow:
                0 4px 10px rgba(0,0,0,0.7),
                0 10px 20px rgba(0,0,0,0.3);
            position: relative;
            overflow: hidden;
            border: 1px solid rgba(212, 175, 55, 0.6);
            transform-style: preserve-3d;
            perspective: 500px;
        }

        .meter-groove {
            position: absolute;
            top: 4px;
            left: 4px;
            right: 4px;
            bottom: 4px;
            background: rgba(0,0,0,0.6);
            border-radius: 9px;
            box-shadow:
                inset 0 2px 6px rgba(0,0,0,0.8),
                inset 0 0 3px rgba(0,0,0,0.6);
            background-image:
                linear-gradient(rgba(10,10,10,0.6) 1px, transparent 1px),
                linear-gradient(90deg, rgba(10,10,10,0.6) 1px, transparent 1px);
            background-size: 5px 5px;
            z-index: 1;
        }

        .meter-bar {
            height: 17px;
            margin-top: 0;
            width: 0%;
            background: linear-gradient(to bottom,
                rgba(255,255,255,0.15) 0%,
                rgba(255,255,255,0) 40%,
                rgba(0,0,0,0.3) 100%),
                linear-gradient(to right, #F44336, #FFC107, #4CAF50);
            border-radius: 8px;
            transition: width 0.8s cubic-bezier(0.22, 1, 0.36, 1);
            position: relative;
            box-shadow:
                0 0 10px rgba(255,255,255,0.3),
                0 1px 1px rgba(255,255,255,0.5) inset,
                0 -1px 1px rgba(0,0,0,0.5) inset;
            z-index: 2;
            transform: translateZ(3px);
        }

        .meter-bar::after {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 8px;
            background: linear-gradient(to bottom, rgba(255,255,255,0.3), transparent);
            border-radius: 8px 8px 0 0;
            z-index: 3;
        }

        .meter-container::before {
            content: '';
            position: absolute;
            top: -5px;
            left: 0;
            right: 0;
            height: 10px;
            background: linear-gradient(to bottom, transparent, rgba(0,0,0,0.3));
            z-index: 0;
            transform: rotateX(45deg);
            transform-origin: bottom;
        }

        .meter-container::after {
            content: '';
            position: absolute;
            bottom: -5px;
            left: 0;
            right: 0;
            height: 10px;
            background: linear-gradient(to top, transparent, rgba(0,0,0,0.3));
            z-index: 0;
            transform: rotateX(-45deg);
            transform-origin: top;
        }

        .meter-value {
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 14px;
            text-shadow: 0 1px 2px rgba(0,0,0,0.9), 0 0 10px rgba(0,0,0,0.5);
            z-index: 4;
            transform: translateZ(5px);
        }

        /* Mini Meters Styling */
        .mini-meters-container {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 10px;
    margin: 5px auto 15px;
    max-width: 94%;
}

.mini-meter {
    flex: 1 1 30%;
    min-width: 120px;
    margin-bottom: 5px;
}

.mini-meter-label {
    font-size: 11px;
    font-weight: 500;
    margin-bottom: 3px;
    color: #fbf7d5;
    text-align: center;
    letter-spacing: 0.5px;
    text-shadow: 0 1px 3px rgba(0,0,0,0.7);
}

.mini-meter-container {
    height: 16px;
    position: relative;
    border-radius: 8px;
    background: linear-gradient(to bottom, #052517, #0a5f2a);
    padding: 3px;
    box-shadow:
        0 2px 6px rgba(0,0,0,0.6),
        0 6px 10px rgba(0,0,0,0.2);
    position: relative;
    overflow: hidden;
    border: 1px solid rgba(212, 175, 55, 0.4);
    transform-style: preserve-3d;
}

.mini-meter-groove {
    position: absolute;
    top: 3px;
    left: 3px;
    right: 3px;
    bottom: 3px;
    background: rgba(0,0,0,0.6);
    border-radius: 6px;
    box-shadow: inset 0 1px 4px rgba(0,0,0,0.8);
    background-image:
        linear-gradient(rgba(10,10,10,0.6) 1px, transparent 1px),
        linear-gradient(90deg, rgba(10,10,10,0.6) 1px, transparent 1px);
    background-size: 4px 4px;
    z-index: 1;
}

.mini-meter-bar {
    height: 10px;
    margin-top: 0;
    width: 0%;
    border-radius: 5px;
    transition: width 0.6s cubic-bezier(0.22, 1, 0.36, 1);
    position: relative;
    box-shadow:
        0 0 6px rgba(255,255,255,0.2),
        0 1px 1px rgba(255,255,255,0.3) inset;
    z-index: 2;
    transform: translateZ(2px);
}

/* More vibrant color scheme */
.mini-meter-bar[data-type="pair"] {
    background: #5C6BC0;
}

.mini-meter-bar[data-type="twoPair"] {
    background: #42A5F5;
}

.mini-meter-bar[data-type="trips"] {
    background: #AB47BC;
}

.mini-meter-bar[data-type="fullHouse"] {
    background: #7E57C2;
}

.mini-meter-bar[data-type="straight"] {
    background: #FFA726;
}

.mini-meter-bar[data-type="flush"] {
    background: #66BB6A;
}

.mini-meter-bar[data-type="quads"] {
    background: #EC407A;
}

.mini-meter-bar[data-type="straightFlush"] {
    background: #26C6DA;
}

.mini-meter-bar[data-type="royalFlush"] {
    background: linear-gradient(45deg, #FFEB3B, #FFC107, #FF9800);
    box-shadow: 0 0 10px 2px rgba(255, 215, 0, 0.7);
    animation: royal-glow 2s infinite alternate;
}

@keyframes royal-glow {
    0% { box-shadow: 0 0 5px 1px rgba(255, 215, 0, 0.5); }
    100% { box-shadow: 0 0 15px 3px rgba(255, 215, 0, 0.9); }
}

.mini-meter-bar {
    transition:
        width 0.8s cubic-bezier(0.22, 1, 0.36, 1),
        background-color 0.5s ease;
}

/* Pulse animation for high percentages */
.mini-meter-bar[style*="90%"] {
    animation: high-percent-pulse 1.5s infinite;
}

@keyframes high-percent-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.8; }
}

.mini-meter-value {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    font-weight: bold;
    font-size: 10px;
    text-shadow: 0 1px 2px rgba(0,0,0,0.9);
    z-index: 4;
    transform: translateZ(3px);
}

        #pokerCalc-recommendations {
            flex: 1;
            display: flex;
            align-items: center;
            justify-content: flex-start;
            margin-right: 20px;
        }

        .action-chip {
            position: relative;
            width: 280px;
            height: 80px;
            cursor: pointer;
            overflow: visible;
        }

        .chip-inner {
            position: absolute;
            width: 100%;
            height: 100%;
            border-radius: 40px;
            background: linear-gradient(145deg, #2d2d2d, #151515);
            box-shadow: 0 5px 15px rgba(0,0,0,0.6);
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 2;
            transition: all 0.3s ease;
            border: 8px dashed rgba(255,255,255,0.15);
        }

        .action-chip:hover .chip-inner {
            box-shadow: 0 8px 25px rgba(0,0,0,0.7);
        }

        .chip-inner::after {
            content: "";
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            height: 40%;
            background: linear-gradient(to bottom, rgba(255,255,255,0.15), transparent);
            pointer-events: none;
            border-radius: 40px 40px 0 0;
        }

        .chip-inner::before {
            content: "";
            position: absolute;
            inset: 8px;
            border-radius: 32px;
            background: radial-gradient(circle at center, #262626, #111111);
            z-index: -1;
        }

        .chip-edge {
            position: absolute;
            width: calc(100% - 16px);
            height: calc(100% - 16px);
            top: 8px;
            left: 8px;
            border-radius: 32px;
            z-index: 1;
            transition: all 0.3s ease;
        }

        #pokerCalc-action {
            color: #fff;
            font-weight: bold;
            font-size: 18px;
            padding: 8px 20px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            letter-spacing: 0.5px;
            transition: all 0.3s ease;
            text-align: center;
            font-family: 'Roboto', 'Arial Black', Arial, sans-serif;
            position: relative;
            line-height: 1.3;
        }

        #pokerCalc-action::before,
        #pokerCalc-action::after {
            content: "";
            position: absolute;
            width: 10px;
            height: 10px;
            border-radius: 50%;
            background-color: currentColor;
            opacity: 0.7;
            transition: all 0.3s ease;
            box-shadow: 0 0 10px currentColor;
        }

        #pokerCalc-action::before {
            left: -25px;
        }

        #pokerCalc-action::after {
            right: -25px;
        }

        #pokerCalc-action.action-raise {
            color: #50e150;
            animation: neonGreenGlow 1.5s ease-in-out infinite alternate;
            text-shadow:
                0 0 5px #fff,
                0 0 10px #fff,
                0 0 20px #fff,
                0 0 40px #50e150,
                0 0 80px #50e150;
        }

        #pokerCalc-action.action-raise ~ .chip-edge {
            box-shadow: 0 0 20px 5px rgba(80, 225, 80, 0.4);
            animation: pulse-chip-green 2s infinite alternate;
        }

        #pokerCalc-action.action-call {
            color: #f0ad4e;
            animation: neonOrangeGlow 1.5s ease-in-out infinite alternate;
            text-shadow:
                0 0 5px #fff,
                0 0 10px #fff,
                0 0 20px #fff,
                0 0 40px #f0ad4e,
                0 0 80px #f0ad4e;
        }

        #pokerCalc-action.action-call ~ .chip-edge {
            box-shadow: 0 0 20px 5px rgba(240, 173, 78, 0.4);
            animation: pulse-chip-orange 2s infinite alternate;
        }

        #pokerCalc-action.action-fold {
            color: #f05050;
            animation: neonRedGlow 1.5s ease-in-out infinite alternate;
            text-shadow:
                0 0 5px #fff,
                0 0 10px #fff,
                0 0 20px #fff,
                0 0 40px #f05050,
                0 0 80px #f05050;
        }

        #pokerCalc-action.action-fold ~ .chip-edge {
            box-shadow: 0 0 20px 5px rgba(240, 80, 80, 0.4);
            animation: pulse-chip-red 2s infinite alternate;
        }

        @keyframes pulse-chip-green {
            0% { box-shadow: 0 0 10px 5px rgba(80, 225, 80, 0.4); }
            100% { box-shadow: 0 0 25px 8px rgba(80, 225, 80, 0.7); }
        }

        @keyframes pulse-chip-orange {
            0% { box-shadow: 0 0 10px 5px rgba(240, 173, 78, 0.4); }
            100% { box-shadow: 0 0 25px 8px rgba(240, 173, 78, 0.7); }
        }

        @keyframes pulse-chip-red {
            0% { box-shadow: 0 0 10px 5px rgba(240, 80, 80, 0.4); }
            100% { box-shadow: 0 0 25px 8px rgba(240, 80, 80, 0.7); }
        }

        /* Enhanced Holographic Table Effect */
        #pokerCalc-div table {
            border-collapse: separate;
            border-spacing: 0;
            margin: 25px 0;
            width: 100%;
            border-radius: 12px;
            transition: all 0.3s ease;
            background: linear-gradient(
                135deg,
                rgba(10, 30, 20, 0.8) 0%,
                rgba(20, 60, 40, 0.8) 50%,
                rgba(10, 30, 20, 0.8) 100%
            );
            backdrop-filter: blur(5px);
            border: 1px solid rgba(212, 175, 55, 0.5);
            box-shadow:
                0 0 20px rgba(212, 175, 55, 0.3),
                0 0 40px rgba(212, 175, 55, 0.2);
            position: relative;
            overflow: hidden;
        }

        /* Primary shimmer layer - more visible but still seamless */
        #pokerCalc-div table::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: linear-gradient(
                70deg,
                rgba(255,255,255,0) 0%,
                rgba(255,255,255,0) 35%,
                rgba(255,255,255,0.15) 45%,
                rgba(255,255,255,0.2) 50%,
                rgba(255,255,255,0.15) 55%,
                rgba(255,255,255,0) 65%,
                rgba(255,255,255,0) 100%
            );
            background-size: 200% 200%;
            background-position: 0% 0;
            animation: hologram-flow 12s linear infinite;
            pointer-events: none;
            z-index: 1;
        }

        /* Secondary subtle gold shimmer layer */
        #pokerCalc-div table::after {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            background: linear-gradient(
                110deg,
                rgba(212, 175, 55, 0) 0%,
                rgba(212, 175, 55, 0) 40%,
                rgba(212, 175, 55, 0.07) 47%,
                rgba(212, 175, 55, 0.1) 50%,
                rgba(212, 175, 55, 0.07) 53%,
                rgba(212, 175, 55, 0) 60%,
                rgba(212, 175, 55, 0) 100%
            );
            background-size: 200% 200%;
            background-position: 100% 0;
            animation: hologram-flow 18s linear infinite;
            pointer-events: none;
            z-index: 1;
            opacity: 0.9;
        }

        @keyframes hologram-flow {
            0% { background-position: 100% 0; }
            100% { background-position: -100% 0; }
        }

        #pokerCalc-div table:hover {
            box-shadow:
                0 12px 20px rgba(0, 0, 0, 0.3),
                0 0 20px rgba(212, 175, 55, 0.4);
            transform: translateY(-3px);
        }

        #pokerCalc-div th {
            background: linear-gradient(145deg, #272727, #1c1c1c);
            color: #fbf7d5;
            padding: 15px 12px;
            font-weight: 600;
            font-size: 14px;
            text-transform: uppercase;
            letter-spacing: 1.5px;
            border-bottom: 2px solid rgba(212, 175, 55, 0.3);
            position: relative;
            overflow: hidden;
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.8);
            z-index: 2;
        }

        #pokerCalc-div th::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 0;
            right: 0;
            height: 1px;
            background: linear-gradient(to right, transparent, rgba(212, 175, 55, 0.5), transparent);
        }

        #pokerCalc-div td {
            background: rgba(26, 26, 26, 0.8);
            padding: 12px;
            border-bottom: 1px solid rgba(255, 255, 255, 0.05);
            position: relative;
            transition: all 0.3s ease;
            color: #fbf7d5;
            font-size: 14px;
            z-index: 2;
        }

        #pokerCalc-div tr:hover td {
            background: rgba(40, 40, 40, 0.8);
            transform: translateX(3px);
            box-shadow: -3px 0 10px rgba(0, 0, 0, 0.2);
        }

        #pokerCalc-div tr:last-child td {
            border-bottom: none;
        }

        #pokerCalc-div tbody tr {
            position: relative;
            transition: all 0.3s ease;
        }

        #pokerCalc-div tbody tr:hover {
            background: rgba(212, 175, 55, 0.1);
            transform: scale(1.01);
            z-index: 2;
        }

        #pokerCalc-div caption {
            color: #fbf7d5;
            font-size: 1.2em;
            font-weight: bold;
            margin: 15px 0 10px;
            text-align: left;
            letter-spacing: 1px;
            position: relative;
            padding-left: 40px;
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
            font-family: 'Playfair Display', serif;
            animation: neonGoldGlow 3s ease-in-out infinite alternate;
        }

        #pokerCalc-div caption::before {
            content: '♠♣♥♦';
            position: absolute;
            left: 3px;
            top: 50%;
            transform: translateY(-50%);
            font-size: 0.9em;
            letter-spacing: 2px;
        }

        #pokerCalc-div caption::before {
            text-shadow: 0 0 5px rgba(0, 0, 0, 0.5);
        }

        /* Style the individual suit icons in captions */
        #pokerCalc-myHand caption::before,
        #pokerCalc-preflop caption::before {
            content: '♠♣♥♦';
        }

        #pokerCalc-upgrades caption::before {
            content: '♠♣♥♦';
        }

        #pokerCalc-oppPossHands caption::before {
            content: '♠♣♥♦';
        }

        /* Make caption icons black and red */
        #pokerCalc-div caption::before {
            background: linear-gradient(to right,
                black 0%, black 25%,
                black 25%, black 50%,
                #e62222 50%, #e62222 75%,
                #e62222 75%, #e62222 100%);
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            background-clip: text;
        }

        #pokerCalc-div td:nth-child(1) {
            font-weight: bold;
            color: #fbf7d5;
            position: relative;
            background: rgba(30, 30, 30, 0.9);
        }

        #pokerCalc-div td:nth-child(3),
        #pokerCalc-div td:nth-child(4) {
            font-weight: bold;
            color: #fbf7d5;
        }

        .rank-up {
            color: #70ff70 !important;
            text-shadow: 0 0 5px rgba(112, 255, 112, 0.5);
        }

        .rank-down {
            color: #ff7070 !important;
            text-shadow: 0 0 5px rgba(255, 112, 112, 0.5);
        }

        .similar-hand td {
            opacity: 0.7;
        }

        .best-hand {
            background: rgba(64, 195, 64, 0.2) !important;
            border-left: 4px solid #40c340 !important;
            animation: glowGreen 2s infinite alternate;
        }

        @keyframes glowGreen {
            0% { box-shadow: inset 0 0 5px rgba(64, 195, 64, 0.5); }
            100% { box-shadow: inset 0 0 15px rgba(64, 195, 64, 0.8); }
        }

        .best-hand td {
            color: #fbf7d5 !important;
            font-weight: bold;
        }

        .best-hand td:first-child {
            position: relative;
        }

        .best-hand td:first-child::before {
            content: '★';
            position: absolute;
            left: -20px;
            top: 50%;
            transform: translateY(-50%);
            color: #40c340;
            animation: starPulse 1.5s infinite alternate;
        }

        @keyframes starPulse {
            0% { transform: translateY(-50%) scale(1); opacity: 0.7; }
            100% { transform: translateY(-50%) scale(1.3); opacity: 1; }
        }

        .potential-best-hand {
            background: rgba(64, 64, 195, 0.2) !important;
            border-left: 4px solid #4040c3 !important;
            animation: glowBlue 2s infinite alternate;
        }

        @keyframes glowBlue {
            0% { box-shadow: inset 0 0 5px rgba(64, 64, 195, 0.5); }
            100% { box-shadow: inset 0 0 15px rgba(64, 64, 195, 0.8); }
        }

        .potential-best-hand td {
            color: #fbf7d5 !important;
            font-weight: bold;
        }

        .best-opp-hand {
            background: rgba(195, 64, 64, 0.2) !important;
            border-left: 4px solid #c34040 !important;
            animation: glowRed 2s infinite alternate;
        }

        @keyframes glowRed {
            0% { box-shadow: inset 0 0 5px rgba(195, 64, 64, 0.5); }
            100% { box-shadow: inset 0 0 15px rgba(195, 64, 64, 0.8); }
        }

        .best-opp-hand td {
            color: #fbf7d5 !important;
            font-weight: bold;
        }

        .ev-positive {
            border-left: 4px solid #40c340 !important;
            box-shadow: inset 3px 0 10px rgba(64, 195, 64, 0.3);
        }

        .ev-negative {
            border-left: 4px solid #c34040 !important;
            box-shadow: inset 3px 0 10px rgba(195, 64, 64, 0.3);
        }

        .bluff-alert {
            animation: pulse-red 1.5s infinite;
            position: relative;
        }

        .bluff-alert::before {
            content: '⚠️';
            position: absolute;
            left: -25px;
            animation: shakeWarning 0.8s infinite;
        }

        @keyframes shakeWarning {
            0%, 100% { transform: translateX(0); }
            25% { transform: translateX(-2px); }
            75% { transform: translateX(2px); }
        }

        @keyframes pulse-red {
            0%, 100% {
                border-color: #c34040;
                box-shadow: 0 0 5px rgba(195, 64, 64, 0.6);
            }
            50% {
                border-color: #ff4040;
                box-shadow: 0 0 15px rgba(255, 64, 64, 0.9);
            }
        }

        @keyframes float {
            0%, 100% {
                transform: translateY(0);
            }
            50% {
                transform: translateY(-8px);
            }
        }

        /* Card Icons in Statistics */
        span[class*="spades"], span[class*="hearts"],
        span[class*="clubs"], span[class*="diamonds"] {
            display: inline-block;
            font-size: 16px;
            margin: 0 1px;
            vertical-align: middle;
            filter: drop-shadow(0 2px 2px rgba(0,0,0,0.5));
        }

        span[class*="hearts"], span[class*="diamonds"] {
            color: #ff5555 !important;
        }

        span[class*="spades"], span[class*="clubs"] {
            color: #ffffff !important;
        }

        /* Neon Glow Effects */
        .neon-text {
            text-shadow:
                0 0 5px #fff,
                0 0 10px #fff,
                0 0 20px #fff,
                0 0 40px #0ff,
                0 0 80px #0ff,
                0 0 90px #0ff,
                0 0 100px #0ff,
                0 0 150px #0ff;
            animation: neonGlow 1.5s ease-in-out infinite alternate;
        }

        @keyframes neonGlow {
            from {
                text-shadow:
                    0 0 5px #fff,
                    0 0 10px #fff,
                    0 0 20px #fff,
                    0 0 40px #0ff,
                    0 0 80px #0ff,
                    0 0 90px #0ff,
                    0 0 100px #0ff,
                    0 0 150px #0ff;
            }
            to {
                text-shadow:
                    0 0 2px #fff,
                    0 0 5px #fff,
                    0 0 10px #fff,
                    0 0 20px #0ff,
                    0 0 40px #0ff,
                    0 0 60px #0ff,
                    0 0 70px #0ff,
                    0 0 100px #0ff;
            }
        }

       @keyframes neonGoldGlow {
    from {
        text-shadow:
            0 0 2px #fff,
            0 0 5px #fff,
            0 0 10px #ffb700,
            0 0 20px rgba(255, 183, 0, 0.5);
    }
    to {
        text-shadow:
            0 0 1px #fff,
            0 0 3px #fff,
            0 0 5px #ffb700,
            0 0 10px rgba(255, 183, 0, 0.3);
    }
}

        @keyframes neonGreenGlow {
    from {
        text-shadow:
            0 0 2px #fff,
            0 0 5px #fff,
            0 0 10px rgba(80, 225, 80, 0.4);
    }
    to {
        text-shadow:
            0 0 1px #fff,
            0 0 3px #fff,
            0 0 5px rgba(80, 225, 80, 0.2);
    }
}

       @keyframes neonOrangeGlow {
    from {
        text-shadow:
            0 0 2px #fff,
            0 0 5px #fff,
            0 0 10px rgba(240, 173, 78, 0.4);
    }
    to {
        text-shadow:
            0 0 1px #fff,
            0 0 3px #fff,
            0 0 5px rgba(240, 173, 78, 0.2);
    }
}

        @keyframes neonRedGlow {
    from {
        text-shadow:
            0 0 2px #fff,
            0 0 5px #fff,
            0 0 10px rgba(240, 80, 80, 0.4);
    }
    to {
        text-shadow:
            0 0 1px #fff,
            0 0 3px #fff,
            0 0 5px rgba(240, 80, 80, 0.2);
    }
}
        `;

        const style = document.createElement("style");
        style.type = "text/css";

        if (style.styleSheet) {
            style.styleSheet.cssText = styleText;
        } else {
            style.appendChild(document.createTextNode(styleText));
        }

        document.head.appendChild(style);
    } catch (e) {
        console.error("Error adding styles:", e);

        const minimalStyle = document.createElement("style");
        minimalStyle.textContent = "#pokerCalc-div { font-family: Arial; color: gold; background: #0a5f2a; padding: 20px; }";
        document.head.appendChild(minimalStyle);
    }
}
}

window.pokerCalculator = new PokerCalculatorModule();
window.pokerCalculator.addStatisticsTable();

window.addEventListener("hashchange", () => {
    if (window.location.href.includes("sid=holdem")) {
        if (!document.getElementById("pokerCalc-div")) {
            window.pokerCalculator = new PokerCalculatorModule();
            window.pokerCalculator.addStatisticsTable();
        }
    }
});

window.addEventListener("error", (e) => {
    if (e.message && e.message.includes("pokerCalculator")) {
        console.log("Poker Helper error detected, attempting to recover...");
        try {
            window.pokerCalculator = new PokerCalculatorModule();
            window.pokerCalculator.addStatisticsTable();
        } catch (err) {
            console.error("Could not recover poker helper:", err);
        }
    }
});

(() => {
    setTimeout(() => {
        const div = document.getElementById("pokerCalc-div");
        if (div) {
            const versionInfo = document.createElement("div");
            versionInfo.style.fontSize = "11px";
            versionInfo.style.color = "#d4af37";
            versionInfo.style.textAlign = "right";
            versionInfo.style.marginTop = "10px";
            versionInfo.style.letterSpacing = "0.5px";
            versionInfo.style.fontFamily = "'Roboto', sans-serif";
            versionInfo.style.textShadow = "0 1px 2px rgba(0,0,0,0.8)";
            versionInfo.innerHTML = "FlopMaster v1.0 <span style='opacity:0.7;'></span> <span style='font-size:9px;opacity:0.8;'></span>";
            div.appendChild(versionInfo);
        }
    }, 3000);
})();