FlopMaster

Poker odds assistant

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==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);
})();