RR Tracker v9.1.0 (Dynamic Bets & UI improvements & Charging shoots)

RR tracker with cool features, now with integrated Martingale bet auto-start, a powerful dynamic bet calculator, and customizable UI.

当前为 2025-08-10 提交的版本,查看 最新版本

// ==UserScript==
// @name         RR Tracker v9.1.0 (Dynamic Bets & UI improvements & Charging shoots)
// @namespace    https://greasyfork.org/users/1493252
// @version      9.1.0
// @description RR tracker with cool features, now with integrated Martingale bet auto-start, a powerful dynamic bet calculator, and customizable UI.
//###Your Torn RR Tracker: Quick Guide
//###Auto-Tracking
//###Just open Russian Roulette, and your tracker starts automatically. It records every win and loss, showing your profit, win rate, and streaks.
//###Panel Controls
//###* Drag: Click and drag the ☰ icon to move the panel anywhere you like.
//###* Shift + Drag: Hold Shift and drag with your mouse from anywhere on the panel to move it.
//###* Collapse/Expand: Click the ► (or ▪) icon to shrink or expand the panel.
//###* Hide/Show: If Auto-Hide is on in settings, the tracker hides when you leave RR and reappears when you return.
//###Settings (⚙️ icon)
//###* Panel Opacity: Adjust how see-through the panel is.
//###* Profit/Loss Alerts: Set targets to be notified when you hit a certain profit or loss.
//###* Mini-Bar Count: Choose how many recent games show in the collapsed view.
//###* Mini-Button Size: Adjust the size of the bet buttons in the collapsed view.
//###* Bet Buttons (NEW!): Use the slider to set how many bet buttons you want (4-16).
//###* Reset Data: Clear all your tracked stats and profit.
//###* Edit Bets: Customize your bet amounts in a dedicated panel.
//###* Charging Shoots: Toggle the auto-shoot helper panel on or off.
//###Bets (💰 icon)
//###* Smart Bets: The panel now shows your recent match history and allows you to auto-start bets.
//###Edit Bets (✏️ NEW LOGIC!)
//###* Enable "Dynamic Bets" to use the new calculator.
//###* Set your strategy (Capital, Streak, Multiplier). Inputs accept abbreviations (e.g., 100k, 2.5m, 1b).
//###* Use the lock icons (🔒/🔓) to choose your calculation method.
//###* Lock 'Gambling Capital' to calculate the 'Starting Bet'.
//###* Lock 'Starting Bet' to calculate the required 'Gambling Capital'.
//###* "Max L Streak" is capped at 15.
//###* The script populates your bet buttons automatically based on your settings.
//###* Disable "Dynamic Bets" to return to setting your bets manually.
//###Charging Shoots (⚡)
//###* When enabled in settings, a new panel appears during matches.
//###* Click "+ Add Charge" to load up to 3 shoots.
//###* The script will automatically click the "Shoot" button for you.
// @match        https://www.torn.com/page.php?sid=russianRoulette*
// @grant        none
// @run-at       document-idle
// @license      MIT
// ==/UserScript==

(function waitUntilReady() {
    'use strict';

    // --- Constants ---
    const PANEL_ID = 'rr-tracker-panel';
    const STORAGE = 'torn_rr_tracker_results';
    const PROFIT_STORAGE = 'torn_rr_total_profit';
    const POS_KEY = 'rr_panelPos';
    const COLLAPSE_KEY = 'rr_panelCollapsed';
    const AUTOHIDE_KEY = 'rr_autoHide';
    const MAX_DISPLAY_KEY = 'rr_maxDisplayMatches';
    const OPACITY_KEY = 'rr_panelOpacity';
    const PROFIT_TARGET_KEY = 'rr_profitTarget';
    const LOSS_LIMIT_KEY = 'rr_lossLimit';
    const ALERT_SHOWN_PROFIT_KEY = 'rr_alertShownProfit';
    const ALERT_SHOWN_LOSS_KEY = 'rr_alertShownLoss';
    const MINI_BAR_COUNT_KEY = 'rr_miniBarCount';
    const MINI_BUTTON_SIZE_KEY = 'rr_miniButtonSize';
    const MANUAL_BETS_STORAGE_KEY = 'RRManualBets_v3'; // Renamed to support dynamic length
    const DEFAULT_MANUAL_BETS = [10000, 20000, 40000, 80000, 160000, 320000, 640000, 1280000, 2560000, 5120000, 10240000];
    const CHARGED_SHOOTS_PANEL_ID = 'rr-charged-shoots-panel';
    const CHARGED_SHOOTS_ENABLED_KEY = 'rr_chargedshootsEnabled';
    const CHARGED_SHOOTS_POS_KEY = 'rr_chargedshootsPanelPos';
    const CHARGED_SHOOTS_COUNT_KEY = 'rr_chargedShootsCount';

    // --- NEW: Dynamic Bets & UI Constants ---
    const DYNAMIC_BETS_ENABLED_KEY = 'rr_dynamicBetsEnabled';
    const DYNAMIC_BETS_SETTINGS_KEY = 'rr_dynamicBetsSettings_v2';
    const UI_BUTTON_COUNT_KEY = 'rr_uiButtonCount';
    const MAX_L_STREAK_CAP = 15;
    const DEFAULT_DYNAMIC_SETTINGS = {
        testBet: 1000,
        capital: 100000000,
        maxLStreak: 10,
        martingaleValue: 2,
        reinforce: false,
        lockedField: 'capital', // 'capital' or 'startingBet'
        startingBet: 0 // This will be calculated
    };

    // --- State Variables ---
    let manualBets, currentBets, showBetsPanel, showEditBetsPanel, isDragging, dragMouseX, dragMouseY, isTwoFingerDragging, initialTouchMidX, initialTouchMidY, initialPanelX, initialPanelY;
    let isChargedshootsEnabled, chargedshoots, chargedshootsPanel, chargedshootsDisplay, isChargedPanelDragging, dragChargedPanelMouseX, dragChargedPanelMouseY, isChargedPanelTwoFingerDragging, initialChargedPanelTouchMidX, initialChargedPanelTouchMidY, initialChargedPanelX, initialChargedPanelY;
    let lastPot, roundActive, hasTracked, results, totalProfit, collapsed, autoHide, showSettings, maxDisplayMatches, currentOpacity, profitTarget, lossLimit, alertShownProfit, alertShownLoss, miniBarCount, miniButtonSize;
    let isShootDelayed = false;
    let uiButtonCount; // NEW: Dynamic button count
    let manualEditInputs = []; // For manual bet input elements

    // --- NEW: Dynamic Bets State ---
    let dynamicBetsEnabled, dynamicBetsSettings;
    let capitalInput, startingBetInput, testBetInput, capitalLock, startingBetLock; // For UI element access

    const nativeSet = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set;

    // --- Initial Checks ---
    if (document.getElementById(PANEL_ID)) return;
    if (!document.body.innerText.includes('Password') && !document.body.innerText.includes('POT MONEY') && !document.body.innerText.includes('Shoot') && !document.body.innerText.includes('Players') && !document.querySelector('.create-game-section') && !document.querySelector('.russian-roulette-container')) {
        return setTimeout(waitUntilReady, 200);
    }

    // --- Load Data and Initialize Variables ---
    function initializeState() {
        manualBets = []; currentBets = []; showBetsPanel = false; showEditBetsPanel = false; isDragging = false; dragMouseX = 0; dragMouseY = 0; isTwoFingerDragging = false; initialTouchMidX = 0; initialTouchMidY = 0; initialPanelX = 0; initialPanelY = 0;
        chargedshoots = parseInt(localStorage.getItem(CHARGED_SHOOTS_COUNT_KEY) || '0', 10);
        isChargedPanelDragging = false; dragChargedPanelMouseX = 0; dragChargedPanelMouseY = 0; isChargedPanelTwoFingerDragging = false;
        lastPot = 0; roundActive = true; hasTracked = false;
        results = JSON.parse(localStorage.getItem(STORAGE) || '[]');
        totalProfit = parseFloat(localStorage.getItem(PROFIT_STORAGE) || '0');
        collapsed = JSON.parse(localStorage.getItem(COLLAPSE_KEY) || 'false');
        autoHide = JSON.parse(localStorage.getItem(AUTOHIDE_KEY) || 'false');
        showSettings = false;
        maxDisplayMatches = parseInt(localStorage.getItem(MAX_DISPLAY_KEY) || '100', 10);
        if (isNaN(maxDisplayMatches) || maxDisplayMatches < 1) { maxDisplayMatches = 100; localStorage.setItem(MAX_DISPLAY_KEY, maxDisplayMatches.toString()); }
        currentOpacity = parseFloat(localStorage.getItem(OPACITY_KEY) || '0.6');
        if (isNaN(currentOpacity) || currentOpacity < 0.1 || currentOpacity > 1.0) { currentOpacity = 0.6; localStorage.setItem(OPACITY_KEY, currentOpacity.toString()); }
        profitTarget = parseFloat(localStorage.getItem(PROFIT_TARGET_KEY) || '0');
        lossLimit = parseFloat(localStorage.getItem(LOSS_LIMIT_KEY) || '0');
        alertShownProfit = JSON.parse(localStorage.getItem(ALERT_SHOWN_PROFIT_KEY) || 'false');
        alertShownLoss = JSON.parse(localStorage.getItem(ALERT_SHOWN_LOSS_KEY) || 'false');
        miniBarCount = parseInt(localStorage.getItem(MINI_BAR_COUNT_KEY) || '10', 10);
        if (isNaN(miniBarCount) || miniBarCount < 1 || miniBarCount > 50) { miniBarCount = 10; localStorage.setItem(MINI_BAR_COUNT_KEY, miniBarCount.toString()); }
        miniButtonSize = parseInt(localStorage.getItem(MINI_BUTTON_SIZE_KEY) || '9', 10);
        if (isNaN(miniButtonSize) || miniButtonSize < 7 || miniButtonSize > 14) { miniButtonSize = 9; localStorage.setItem(MINI_BUTTON_SIZE_KEY, miniButtonSize.toString()); }
        isChargedshootsEnabled = JSON.parse(localStorage.getItem(CHARGED_SHOOTS_ENABLED_KEY) || 'false');
        uiButtonCount = parseInt(localStorage.getItem(UI_BUTTON_COUNT_KEY) || '11', 10);
        if (isNaN(uiButtonCount) || uiButtonCount < 4 || uiButtonCount > 16) { uiButtonCount = 11; localStorage.setItem(UI_BUTTON_COUNT_KEY, uiButtonCount.toString()); }

        // --- NEW/MODIFIED: Load Bet Configurations ---
        dynamicBetsEnabled = JSON.parse(localStorage.getItem(DYNAMIC_BETS_ENABLED_KEY) || 'false');
        try {
            const storedDynamicSettings = JSON.parse(localStorage.getItem(DYNAMIC_BETS_SETTINGS_KEY));
            dynamicBetsSettings = { ...DEFAULT_DYNAMIC_SETTINGS, ...storedDynamicSettings };
        } catch {
            dynamicBetsSettings = { ...DEFAULT_DYNAMIC_SETTINGS };
        }
        manualBets = loadManualBets();
        adjustManualBetsArray(); // Ensure manual bets array matches UI button count
    }
    initializeState();

    // --- UI Creation ---
    const panel = document.createElement('div');
    panel.id = PANEL_ID;
    Object.assign(panel.style, {
        position: 'fixed', top: '12px', left: '12px', background: `rgba(0,0,0,${currentOpacity})`, color: '#fff',
        fontFamily: 'monospace', fontSize: '14px', padding: '36px 12px 12px', borderRadius: '10px',
        boxShadow: '0 0 12px rgba(255,0,0,0.3)', zIndex: '9999999', userSelect: 'none', display: 'flex',
        flexDirection: 'column', gap: '8px', minWidth: '140px'
    });
    document.body.appendChild(panel);
    try { const pos = JSON.parse(localStorage.getItem(POS_KEY) || '{}'); if (pos.top && pos.left) { panel.style.top = pos.top; panel.style.left = pos.left; } } catch {}

    chargedshootsPanel = document.createElement('div');
    chargedshootsPanel.id = CHARGED_SHOOTS_PANEL_ID;
    Object.assign(chargedshootsPanel.style, { position: 'fixed', top: '150px', left: '12px', background: `rgba(0,0,0,${currentOpacity})`, color: '#fff', fontFamily: 'monospace', fontSize: '14px', padding: '10px 12px', borderRadius: '10px', boxShadow: '0 0 12px rgba(255,0,0,0.3)', zIndex: '9999998', userSelect: 'none', display: 'none', flexDirection: 'column', alignItems: 'center', gap: '8px', touchAction: 'none' });
    document.body.appendChild(chargedshootsPanel);
    try { const pos = JSON.parse(localStorage.getItem(CHARGED_SHOOTS_POS_KEY) || '{}'); if (pos.top && pos.left) { chargedshootsPanel.style.top = pos.top; chargedshootsPanel.style.left = pos.left; } } catch {}

    const chargedshootsTitle = document.createElement('div'); chargedshootsTitle.textContent = 'Charging Shoots'; chargedshootsTitle.style.fontWeight = 'bold'; chargedshootsPanel.appendChild(chargedshootsTitle);
    chargedshootsDisplay = document.createElement('div'); chargedshootsDisplay.textContent = `Charges: ${chargedshoots} / 3`; chargedshootsDisplay.style.fontSize = '16px'; chargedshootsDisplay.title = "Shows how many auto-shoots are currently loaded. Resets after each match."; chargedshootsPanel.appendChild(chargedshootsDisplay);
    const addChargeBtn = document.createElement('button'); addChargeBtn.textContent = '+ Add Charge'; addChargeBtn.title = "Click to add a 'charge'. The script will automatically click the 'Shoot' button once per charge during a match.";
    Object.assign(addChargeBtn.style, { background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 8px', cursor: 'pointer', width: '100%' });
    addChargeBtn.onmouseenter = () => addChargeBtn.style.background = 'rgba(255,255,255,0.2)'; addChargeBtn.onmouseleave = () => addChargeBtn.style.background = 'rgba(255,255,255,0.1)';
    addChargeBtn.onclick = () => { if (chargedshoots < 3) { chargedshoots++; updateChargedshootsDisplay(); localStorage.setItem(CHARGED_SHOOTS_COUNT_KEY, chargedshoots.toString()); } }; chargedshootsPanel.appendChild(addChargeBtn);

    const alertMessageDiv = document.createElement('div');
    alertMessageDiv.id = 'rr-alert-message';
    Object.assign(alertMessageDiv.style, { display: 'none', padding: '8px', marginBottom: '8px', borderRadius: '6px', textAlign: 'center', fontWeight: 'bold', fontSize: '16px', color: 'white', cursor: 'pointer', border: '1px solid transparent', transition: 'background-color 0.3s, border-color 0.3s' });
    panel.appendChild(alertMessageDiv);

    const miniBar = document.createElement('div');
    Object.assign(miniBar.style, { display: 'none', flexDirection: 'column', gap: '2px', padding: '4px 0' });
    panel.appendChild(miniBar);

    const profitMini = document.createElement('div');
    Object.assign(profitMini.style, { display: 'none', fontSize: '14px', fontFamily: 'monospace', margin: '2px 0' });
    panel.appendChild(profitMini);

    const statusDiv = document.createElement('div'); statusDiv.title = "Collapse/Expand the tracker panel.";
    Object.assign(statusDiv.style, { position: 'absolute', top: '8px', left: '8px', width: '20px', height: '20px', fontSize: '18px', cursor: 'pointer', color: 'rgba(255,255,255,0.7)' });
    panel.appendChild(statusDiv);

    const dragHandle = document.createElement('div'); dragHandle.textContent = '☰'; dragHandle.title = "Click and drag to move the panel.";
    Object.assign(dragHandle.style, { position: 'absolute', top: '8px', right: '8px', width: '20px', height: '20px', fontSize: '18px', cursor: 'move', color: 'rgba(255,255,255,0.7)', touchAction: 'none' });
    panel.appendChild(dragHandle);

    const statsGroup = document.createElement('div');
    Object.assign(statsGroup.style, { display: 'flex', flexDirection: 'column', gap: '4px' });
    panel.appendChild(statsGroup);

    const profitDiv = document.createElement('div'); profitDiv.title = "Total profit or loss tracked since the last reset.";
    const winrateDiv = document.createElement('div');
    const streakDiv = document.createElement('div');
    statsGroup.append(profitDiv, winrateDiv, streakDiv);

    const resultsContainer = document.createElement('div');
    Object.assign(resultsContainer.style, { maxHeight: '140px', overflowY: 'auto', marginTop: '4px' });
    statsGroup.appendChild(resultsContainer);

       const settingsPanel = document.createElement('div');
    Object.assign(settingsPanel.style, { display: 'none', flexDirection: 'column', gap: '8px', padding: '12px 0' });
    panel.appendChild(settingsPanel);

    const settingsTitle = document.createElement('div'); settingsTitle.textContent = 'Settings';
    Object.assign(settingsTitle.style, { fontSize: '16px', fontWeight: 'bold', marginBottom: '4px' });
    settingsPanel.appendChild(settingsTitle);

    const backButtonSettings = document.createElement('button'); backButtonSettings.textContent = '← Back';
    Object.assign(backButtonSettings.style, { alignSelf: 'flex-start', background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 8px', cursor: 'pointer', marginBottom: '8px' });
    backButtonSettings.onmouseenter = () => backButtonSettings.style.background = 'rgba(255,255,255,0.2)'; backButtonSettings.onmouseleave = () => backButtonSettings.style.background = 'rgba(255,255,255,0.1)';
    backButtonSettings.onclick = () => { showSettings = false; showBetsPanel = false; showEditBetsPanel = false; refreshAll(); };
    settingsPanel.appendChild(backButtonSettings);

    // --- NEW: Scrollable container for settings ---
    const settingsScrollContainer = document.createElement('div');
    Object.assign(settingsScrollContainer.style, {
        display: 'flex',
        flexDirection: 'column',
        gap: '8px', // Keeps the spacing between settings items
        maxHeight: '300px', // Set a maximum height. You can change this value (e.g., '250px').
        overflowY: 'auto',   // Add a vertical scrollbar only when needed
        paddingRight: '5px'  // Add some space for the scrollbar to prevent overlap
    });
    settingsPanel.appendChild(settingsScrollContainer);
    // --- All settings items will now be added to this container ---

    const maxMatchesSettingDiv = document.createElement('div'); Object.assign(maxMatchesSettingDiv.style, { display: 'flex', alignItems: 'center', gap: '8px' });
    const maxMatchesLabel = document.createElement('label'); maxMatchesLabel.textContent = 'Max Matches Displayed:'; maxMatchesLabel.htmlFor = 'max-matches-input'; Object.assign(maxMatchesLabel.style, { flexShrink: '0' });
    const maxMatchesInput = document.createElement('input'); maxMatchesInput.type = 'number'; maxMatchesInput.id = 'max-matches-input'; maxMatchesInput.min = '1'; maxMatchesInput.max = '500'; maxMatchesInput.value = maxDisplayMatches; maxMatchesInput.title = "Set the maximum number of recent matches to show in the main panel."; Object.assign(maxMatchesInput.style, { width: '60px', padding: '4px', border: '1px solid #555', borderRadius: '4px', background: 'rgba(255,255,255,0.1)', color: '#fff' });
    maxMatchesInput.onchange = () => { let newValue = parseInt(maxMatchesInput.value, 10); if (isNaN(newValue) || newValue < 1) { newValue = 1; } if (newValue > 500) newValue = 500; maxDisplayMatches = newValue; maxMatchesInput.value = maxDisplayMatches; localStorage.setItem(MAX_DISPLAY_KEY, maxDisplayMatches.toString()); while (results.length > maxDisplayMatches) { results.pop(); } saveResults(); refreshAll(); };
    maxMatchesSettingDiv.append(maxMatchesLabel, maxMatchesInput);
    settingsScrollContainer.appendChild(maxMatchesSettingDiv); // <-- Appended to scroll container

    const transparencySettingDiv = document.createElement('div'); Object.assign(transparencySettingDiv.style, { display: 'flex', alignItems: 'center', gap: '8px' });
    const transparencyLabel = document.createElement('label'); transparencyLabel.textContent = 'Panel Opacity:'; transparencyLabel.htmlFor = 'transparency-slider'; Object.assign(transparencyLabel.style, { flexShrink: '0' });
    const transparencySlider = document.createElement('input'); transparencySlider.type = 'range'; transparencySlider.id = 'transparency-slider'; transparencySlider.min = '0.1'; transparencySlider.max = '1.0'; transparencySlider.step = '0.05'; transparencySlider.value = currentOpacity; transparencySlider.title = "Adjust the transparency of the tracker panel."; Object.assign(transparencySlider.style, { width: '100px', padding: '4px', border: 'none', background: 'transparent', cursor: 'pointer' });
    transparencySlider.oninput = () => { currentOpacity = parseFloat(transparencySlider.value); panel.style.background = `rgba(0,0,0,${currentOpacity})`; localStorage.setItem(OPACITY_KEY, currentOpacity.toString()); refreshAll(); };
    transparencySettingDiv.append(transparencyLabel, transparencySlider);
    settingsScrollContainer.appendChild(transparencySettingDiv); // <-- Appended to scroll container

    const profitTargetSettingDiv = document.createElement('div'); Object.assign(profitTargetSettingDiv.style, { display: 'flex', alignItems: 'center', gap: '8px' });
    const profitTargetLabel = document.createElement('label'); profitTargetLabel.textContent = 'Profit Target ($):'; profitTargetLabel.htmlFor = 'profit-target-input'; Object.assign(profitTargetLabel.style, { flexShrink: '0' });
    const profitTargetInput = document.createElement('input'); profitTargetInput.type = 'text'; profitTargetInput.id = 'profit-target-input'; profitTargetInput.value = profitTarget; profitTargetInput.title = "Set a profit target. You'll get a persistent alert when this target is reached."; Object.assign(profitTargetInput.style, { width: '80px', padding: '4px', border: '1px solid #555', borderRadius: '4px', background: 'rgba(255,255,255,0.1)', color: '#fff' });
    profitTargetInput.onchange = () => { let newValue = parseBetInput(profitTargetInput.value); if (newValue === null || newValue < 0) newValue = 0; profitTarget = newValue; profitTargetInput.value = formatNumberToKMB(profitTarget); localStorage.setItem(PROFIT_TARGET_KEY, profitTarget.toString()); alertShownProfit = false; localStorage.setItem(ALERT_SHOWN_PROFIT_KEY, 'false'); refreshAll(); };
    profitTargetSettingDiv.append(profitTargetLabel, profitTargetInput);
    settingsScrollContainer.appendChild(profitTargetSettingDiv); // <-- Appended to scroll container

    const lossLimitSettingDiv = document.createElement('div'); Object.assign(lossLimitSettingDiv.style, { display: 'flex', alignItems: 'center', gap: '8px' });
    const lossLimitLabel = document.createElement('label'); lossLimitLabel.textContent = 'Loss Limit ($):'; lossLimitLabel.htmlFor = 'loss-limit-input'; Object.assign(lossLimitLabel.style, { flexShrink: '0' });
    const lossLimitInput = document.createElement('input'); lossLimitInput.type = 'text'; lossLimitInput.id = 'loss-limit-input'; lossLimitInput.value = lossLimit; lossLimitInput.title = "Set a loss limit. You'll get a persistent alert if your losses reach this amount."; Object.assign(lossLimitInput.style, { width: '80px', padding: '4px', border: '1px solid #555', borderRadius: '4px', background: 'rgba(255,255,255,0.1)', color: '#fff' });
    lossLimitInput.onchange = () => { let newValue = parseBetInput(lossLimitInput.value); if (newValue === null || newValue < 0) newValue = 0; lossLimit = newValue; lossLimitInput.value = formatNumberToKMB(lossLimit); localStorage.setItem(LOSS_LIMIT_KEY, lossLimit.toString()); alertShownLoss = false; localStorage.setItem(ALERT_SHOWN_LOSS_KEY, 'false'); refreshAll(); };
    lossLimitSettingDiv.append(lossLimitLabel, lossLimitInput);
    settingsScrollContainer.appendChild(lossLimitSettingDiv); // <-- Appended to scroll container

    const clearAlertsBtn = document.createElement('button'); clearAlertsBtn.textContent = '✔️ Clear Alerts'; clearAlertsBtn.title = "Dismiss any active Profit Target or Loss Limit alerts."; Object.assign(clearAlertsBtn.style, { alignSelf: 'flex-start', background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 8px', cursor: 'pointer' });
    clearAlertsBtn.onmouseenter = () => clearAlertsBtn.style.background = 'rgba(255,255,255,0.2)'; clearAlertsBtn.onmouseleave = () => clearAlertsBtn.style.background = 'rgba(255,255,255,0.1)';
    clearAlertsBtn.onclick = () => { alertShownProfit = false; alertShownLoss = false; localStorage.setItem(ALERT_SHOWN_PROFIT_KEY, 'false'); localStorage.setItem(ALERT_SHOWN_LOSS_KEY, 'false'); alertMessageDiv.style.display = 'none'; refreshAll(); };
    settingsScrollContainer.appendChild(clearAlertsBtn); // <-- Appended to scroll container

    const miniBarCountSettingDiv = document.createElement('div'); Object.assign(miniBarCountSettingDiv.style, { display: 'flex', alignItems: 'center', gap: '8px' });
    const miniBarCountLabel = document.createElement('label'); miniBarCountLabel.textContent = 'Mini-Bar Count:'; miniBarCountLabel.htmlFor = 'mini-bar-count-input'; Object.assign(miniBarCountLabel.style, { flexShrink: '0' });
    const miniBarCountInput = document.createElement('input'); miniBarCountInput.type = 'number'; miniBarCountInput.id = 'mini-bar-count-input'; miniBarCountInput.min = '1'; miniBarCountInput.max = '50'; miniBarCountInput.value = miniBarCount; miniBarCountInput.title = "Set how many recent match indicators (W/L circles) are shown in the collapsed view."; Object.assign(miniBarCountInput.style, { width: '60px', padding: '4px', border: '1px solid #555', borderRadius: '4px', background: 'rgba(255,255,255,0.1)', color: '#fff' });
    miniBarCountInput.onchange = () => { let newValue = parseInt(miniBarCountInput.value, 10); if (isNaN(newValue) || newValue < 1) newValue = 1; if (newValue > 50) newValue = 50; miniBarCount = newValue; miniBarCountInput.value = miniBarCount; localStorage.setItem(MINI_BAR_COUNT_KEY, miniBarCount.toString()); refreshAll(); };
    miniBarCountSettingDiv.append(miniBarCountLabel, miniBarCountInput);
    settingsScrollContainer.appendChild(miniBarCountSettingDiv); // <-- Appended to scroll container

    const miniButtonSizeSettingDiv = document.createElement('div'); Object.assign(miniButtonSizeSettingDiv.style, { display: 'flex', alignItems: 'center', gap: '8px' });
    const miniButtonSizeLabel = document.createElement('label'); miniButtonSizeLabel.textContent = 'Mini-Button Size:'; miniButtonSizeLabel.htmlFor = 'mini-button-size-slider'; Object.assign(miniButtonSizeLabel.style, { flexShrink: '0' });
    const miniButtonSizeSlider = document.createElement('input'); miniButtonSizeSlider.type = 'range'; miniButtonSizeSlider.id = 'mini-button-size-slider'; miniButtonSizeSlider.min = '7'; miniButtonSizeSlider.max = '14'; miniButtonSizeSlider.step = '1'; miniButtonSizeSlider.value = miniButtonSize; miniButtonSizeSlider.title = "Adjust the font size of the bet buttons in the collapsed view."; Object.assign(miniButtonSizeSlider.style, { width: '100px', padding: '4px', border: 'none', background: 'transparent', cursor: 'pointer' });
    miniButtonSizeSlider.oninput = () => { miniButtonSize = parseInt(miniButtonSizeSlider.value, 10); localStorage.setItem(MINI_BUTTON_SIZE_KEY, miniButtonSize.toString()); refreshAll(); };
    miniButtonSizeSettingDiv.append(miniButtonSizeLabel, miniButtonSizeSlider);
    settingsScrollContainer.appendChild(miniButtonSizeSettingDiv); // <-- Appended to scroll container

    const buttonCountSettingDiv = document.createElement('div'); Object.assign(buttonCountSettingDiv.style, { display: 'flex', alignItems: 'center', gap: '8px' });
    const buttonCountLabel = document.createElement('label'); buttonCountLabel.textContent = `Bet Buttons (${uiButtonCount}):`; buttonCountLabel.htmlFor = 'button-count-slider'; Object.assign(buttonCountLabel.style, { flexShrink: '0' });
    const buttonCountSlider = document.createElement('input'); buttonCountSlider.type = 'range'; buttonCountSlider.id = 'button-count-slider'; buttonCountSlider.min = '4'; buttonCountSlider.max = '16'; buttonCountSlider.step = '1'; buttonCountSlider.value = uiButtonCount;
    buttonCountSlider.title = "Set how many bet buttons are available in the UI (4 to 16).";
    Object.assign(buttonCountSlider.style, { width: '100px', padding: '4px', border: 'none', background: 'transparent', cursor: 'pointer' });
    buttonCountSlider.oninput = () => { buttonCountLabel.textContent = `Bet Buttons (${buttonCountSlider.value}):`; };
    buttonCountSlider.onchange = () => {
        uiButtonCount = parseInt(buttonCountSlider.value, 10);
        localStorage.setItem(UI_BUTTON_COUNT_KEY, uiButtonCount.toString());
        adjustManualBetsArray();
        buildManualBetInputs();
        calculateBetsAndRefresh();
    };
    buttonCountSettingDiv.append(buttonCountLabel, buttonCountSlider);
    settingsScrollContainer.appendChild(buttonCountSettingDiv); // <-- Appended to scroll container

    const editBetsButton = document.createElement('button'); editBetsButton.textContent = '✏️ Edit Bets'; editBetsButton.title = "Open the panel to configure your manual or dynamic betting strategy.";
    Object.assign(editBetsButton.style, { alignSelf: 'flex-start', background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 8px', cursor: 'pointer' });
    editBetsButton.onmouseenter = () => editBetsButton.style.background = 'rgba(255,255,255,0.2)'; editBetsButton.onmouseleave = () => editBetsButton.style.background = 'rgba(255,255,255,0.1)';
    editBetsButton.onclick = () => { showSettings = false; showBetsPanel = false; showEditBetsPanel = true; refreshAll(); };
    settingsScrollContainer.appendChild(editBetsButton); // <-- Appended to scroll container

    const chargedshootsToggleBtn = document.createElement('button');
    const updateChargedshootsButtonText = () => { chargedshootsToggleBtn.textContent = `⚡ Charging Shoots: ${isChargedshootsEnabled ? 'On' : 'Off'}`; };
    updateChargedshootsButtonText();
    chargedshootsToggleBtn.title = "Toggle the 'Charging Shoots' helper panel. When ON, you can pre-load shoots to be fired automatically in a match.";
    Object.assign(chargedshootsToggleBtn.style, { alignSelf: 'flex-start', background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 8px', cursor: 'pointer' });
    chargedshootsToggleBtn.onmouseenter = () => chargedshootsToggleBtn.style.background = 'rgba(255,255,255,0.2)'; chargedshootsToggleBtn.onmouseleave = () => chargedshootsToggleBtn.style.background = 'rgba(255,255,255,0.1)';
    chargedshootsToggleBtn.onclick = () => { isChargedshootsEnabled = !isChargedshootsEnabled; localStorage.setItem(CHARGED_SHOOTS_ENABLED_KEY, JSON.stringify(isChargedshootsEnabled)); updateChargedshootsButtonText(); updateChargedshootsPanelVisibility(); };
    settingsScrollContainer.appendChild(chargedshootsToggleBtn); // <-- Appended to scroll container

    const resetBtn = document.createElement('button'); resetBtn.textContent = '🔄 Reset Data'; resetBtn.title = "WARNING: This will clear all tracked stats, profit, and reset all bet configurations to default.";
    Object.assign(resetBtn.style, { alignSelf: 'flex-start', background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 8px', cursor: 'pointer' });
    resetBtn.onmouseenter = () => resetBtn.style.background = 'rgba(255,255,255,0.2)'; resetBtn.onmouseleave = () => resetBtn.style.background = 'rgba(255,255,255,0.1)';
    resetBtn.onclick = () => {
        if (confirm('Clear all results and reset profit? This will also reset all bet configurations.')) {
            localStorage.removeItem(STORAGE); localStorage.removeItem(PROFIT_STORAGE); localStorage.removeItem(ALERT_SHOWN_PROFIT_KEY); localStorage.removeItem(ALERT_SHOWN_LOSS_KEY); localStorage.removeItem(CHARGED_SHOOTS_COUNT_KEY);
            localStorage.removeItem(MANUAL_BETS_STORAGE_KEY); localStorage.removeItem(DYNAMIC_BETS_ENABLED_KEY); localStorage.removeItem(DYNAMIC_BETS_SETTINGS_KEY); localStorage.removeItem(UI_BUTTON_COUNT_KEY);
            initializeState(); refreshAll();
        }
    };
    settingsScrollContainer.appendChild(resetBtn); // <-- Appended to scroll container

    const autoHideBtn = document.createElement('button'); autoHideBtn.title = "When ON, the tracker will automatically hide when you are not on a Russian Roulette page.";
    const updateAutoHideBtnText = () => { autoHideBtn.textContent = autoHide ? 'Auto-Hide: On' : 'Auto-Hide: Off'; }
    updateAutoHideBtnText();
    Object.assign(autoHideBtn.style, { alignSelf: 'flex-start', background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 8px', cursor: 'pointer' });
    autoHideBtn.onmouseenter = () => autoHideBtn.style.background = 'rgba(255,255,255,0.2)'; autoHideBtn.onmouseleave = () => autoHideBtn.style.background = 'rgba(255,255,255,0.1)';
    autoHideBtn.onclick = () => { autoHide = !autoHide; localStorage.setItem(AUTOHIDE_KEY, JSON.stringify(autoHide)); updateAutoHideBtnText(); refreshAll(); };
    settingsScrollContainer.appendChild(autoHideBtn); // <-- Appended to scroll container

    const settingsButton = document.createElement('button'); settingsButton.textContent = '⚙️ Settings'; settingsButton.title = "Open the settings panel.";
    Object.assign(settingsButton.style, { alignSelf: 'flex-start', background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 8px', cursor: 'pointer', marginTop: '4px' });
    settingsButton.onmouseenter = () => settingsButton.style.background = 'rgba(255,255,255,0.2)';
    settingsButton.onmouseleave = () => settingsButton.style.background = 'rgba(255,255,255,0.1)';
    settingsButton.onclick = () => { showSettings = !showSettings; showBetsPanel = false; showEditBetsPanel = false; refreshAll(); };
    panel.appendChild(settingsButton);

    const betsPanel = document.createElement('div');
    Object.assign(betsPanel.style, { display: 'none', flexDirection: 'column', gap: '8px', padding: '12px 0' });
    panel.appendChild(betsPanel);
    const betsPanelLastMatchesTitle = document.createElement('div'); betsPanelLastMatchesTitle.textContent = `Last ${miniBarCount} Matches`; Object.assign(betsPanelLastMatchesTitle.style, { fontSize: '13px', color: 'rgba(255,255,255,0.8)', textAlign: 'center', marginBottom: '-4px' });
    const betsPanelCirclesContainer = document.createElement('div'); Object.assign(betsPanelCirclesContainer.style, { display: 'flex', flexWrap: 'wrap', gap: '3px', justifyContent: 'center', marginBottom: '6px' });
    betsPanel.appendChild(betsPanelLastMatchesTitle); betsPanel.appendChild(betsPanelCirclesContainer);
    const betsTitle = document.createElement('div'); betsTitle.textContent = 'Smart Bets'; Object.assign(betsTitle.style, { fontSize: '16px', fontWeight: 'bold', marginBottom: '4px', textAlign: 'center' });
    betsPanel.appendChild(betsTitle);
    const backButtonBets = document.createElement('button'); backButtonBets.textContent = '← Back'; Object.assign(backButtonBets.style, { alignSelf: 'flex-start', background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 8px', cursor: 'pointer', marginBottom: '8px' });
    backButtonBets.onmouseenter = () => backButtonBets.style.background = 'rgba(255,255,255,0.2)'; backButtonBets.onmouseleave = () => backButtonBets.style.background = 'rgba(255,255,255,0.1)';
    backButtonBets.onclick = () => { showBetsPanel = false; showSettings = false; showEditBetsPanel = false; refreshAll(); };
    betsPanel.appendChild(backButtonBets);
    const betButtonsContainer = document.createElement('div'); Object.assign(betButtonsContainer.style, { display: 'flex', flexDirection: 'column', gap: '6px', marginTop: '6px' });
    betsPanel.appendChild(betButtonsContainer);

    // --- NEW: Edit Bets Panel (Completely Overhauled) ---
    const editBetsPanel = document.createElement('div');
    Object.assign(editBetsPanel.style, { display: 'none', flexDirection: 'column', gap: '8px', padding: '12px 0' });
    panel.appendChild(editBetsPanel);
    const editBetsTitle = document.createElement('div'); editBetsTitle.textContent = 'Edit Bets';
    Object.assign(editBetsTitle.style, { fontSize: '16px', fontWeight: 'bold', marginBottom: '4px' });
    editBetsPanel.appendChild(editBetsTitle);
    const backButtonEditBets = document.createElement('button'); backButtonEditBets.textContent = '← Back to Settings';
    Object.assign(backButtonEditBets.style, { alignSelf: 'flex-start', background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 8px', cursor: 'pointer', marginBottom: '8px' });
    backButtonEditBets.onmouseenter = () => backButtonEditBets.style.background = 'rgba(255,255,255,0.2)'; backButtonEditBets.onmouseleave = () => backButtonEditBets.style.background = 'rgba(255,255,255,0.1)';
    backButtonEditBets.onclick = () => { showEditBetsPanel = false; showSettings = true; refreshAll(); };
    editBetsPanel.appendChild(backButtonEditBets);

    // Dynamic Bets Toggle
    const dynamicBetsToggleContainer = document.createElement('div');
    Object.assign(dynamicBetsToggleContainer.style, { display: 'flex', alignItems: 'center', gap: '8px', padding: '8px', background: 'rgba(255,255,255,0.05)', borderRadius: '6px' });
    const dynamicBetsToggle = document.createElement('input'); dynamicBetsToggle.type = 'checkbox'; dynamicBetsToggle.id = 'dynamic-bets-toggle'; dynamicBetsToggle.checked = dynamicBetsEnabled;
    const dynamicBetsLabel = document.createElement('label'); dynamicBetsLabel.textContent = 'Enable Dynamic Bets'; dynamicBetsLabel.htmlFor = 'dynamic-bets-toggle'; dynamicBetsLabel.style.cursor = 'pointer';
    dynamicBetsToggleContainer.title = "Toggle between setting manual bet amounts and using the dynamic bet calculator.";
    dynamicBetsToggleContainer.append(dynamicBetsToggle, dynamicBetsLabel);
    editBetsPanel.appendChild(dynamicBetsToggleContainer);

    // Container for Dynamic Bet Settings
    const dynamicBetsContainer = document.createElement('div');
    Object.assign(dynamicBetsContainer.style, { display: dynamicBetsEnabled ? 'grid' : 'none', gridTemplateColumns: 'auto 1fr auto', gap: '8px 10px', marginTop: '10px' });
    editBetsPanel.appendChild(dynamicBetsContainer);

    // Container for Manual Bet Settings
    const manualBetsContainer = document.createElement('div');
    Object.assign(manualBetsContainer.style, { display: dynamicBetsEnabled ? 'none' : 'block', marginTop: '10px' });
    editBetsPanel.appendChild(manualBetsContainer);
    const manualBetsTitle = document.createElement('div'); manualBetsTitle.textContent = 'Manual Bet Configuration';
    Object.assign(manualBetsTitle.style, { fontSize: '13px', color: 'rgba(255,255,255,0.7)', marginBottom: '8px' });
    manualBetsContainer.appendChild(manualBetsTitle);
    const manualEditGrid = document.createElement('div');
    Object.assign(manualEditGrid.style, { display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '6px 10px', overflowY: 'auto', maxHeight: '200px' });
    manualBetsContainer.appendChild(manualEditGrid);

    // Build Dynamic Bet Inputs
    const createDynamicInput = (label, id, value, title, type = 'text') => {
        const lbl = document.createElement('label'); lbl.textContent = label; lbl.htmlFor = id;
        const input = document.createElement('input'); input.type = type; input.id = id; input.value = value; input.title = title;
        Object.assign(input.style, { width: '100%', padding: '4px', border: '1px solid #555', borderRadius: '4px', background: 'rgba(255,255,255,0.1)', color: '#fff' });
        const lock = document.createElement('button'); lock.style.cursor = 'pointer'; lock.style.background = 'none'; lock.style.border = 'none'; lock.style.color = '#fff'; lock.style.fontSize = '16px'; lock.style.padding = '0 5px';
        return [lbl, input, lock];
    };

    const [testBetLabel, localTestBetInput] = createDynamicInput('Test Bet:', 'dyn-test-bet', dynamicBetsSettings.testBet, "A small, fixed bet for the first UI button. Accepts k/m/b suffixes.", 'text');
    testBetInput = localTestBetInput;
    testBetInput.onchange = () => {
        const parsed = parseBetInput(testBetInput.value);
        if (parsed !== null) {
            dynamicBetsSettings.testBet = Math.max(0, parsed);
            saveDynamicBetsSettings();
            calculateBetsAndRefresh();
        } else {
            testBetInput.value = formatNumberToKMB(dynamicBetsSettings.testBet);
        }
    };
    dynamicBetsContainer.append(testBetLabel, testBetInput, document.createElement('div'));

    const [capitalLabel, localCapitalInput, localCapitalLock] = createDynamicInput('Gambling Capital:', 'dyn-capital', dynamicBetsSettings.capital, "Define your total risk. Lock this (🔒) to have the script calculate the 'Starting Bet' for you. Accepts k/m/b suffixes.", 'text');
    capitalInput = localCapitalInput; capitalLock = localCapitalLock;
    capitalInput.onchange = () => {
        if (dynamicBetsSettings.lockedField === 'capital') {
            const parsed = parseBetInput(capitalInput.value);
            if (parsed !== null) {
                dynamicBetsSettings.capital = Math.max(0, parsed);
                saveDynamicBetsSettings();
                calculateBetsAndRefresh();
            } else {
                capitalInput.value = formatNumberToKMB(dynamicBetsSettings.capital);
            }
        }
    };
    capitalLock.onclick = () => { dynamicBetsSettings.lockedField = 'capital'; saveDynamicBetsSettings(); calculateBetsAndRefresh(); };
    dynamicBetsContainer.append(capitalLabel, capitalInput, capitalLock);

    const [startingBetLabel, localStartingBetInput, localStartingBetLock] = createDynamicInput('Starting Bet (x):', 'dyn-starting-bet', dynamicBetsSettings.startingBet, "Define your ideal first bet. Lock this (🔒) to have the script calculate the total 'Gambling Capital' required. Accepts k/m/b suffixes.", 'text');
    startingBetInput = localStartingBetInput; startingBetLock = localStartingBetLock;
    startingBetInput.onchange = () => {
        if (dynamicBetsSettings.lockedField === 'startingBet') {
            const parsed = parseBetInput(startingBetInput.value);
            if (parsed !== null) {
                dynamicBetsSettings.startingBet = Math.max(0, parsed);
                saveDynamicBetsSettings();
                calculateBetsAndRefresh();
            } else {
                startingBetInput.value = formatNumberToKMB(dynamicBetsSettings.startingBet);
            }
        }
    };
    startingBetLock.onclick = () => { dynamicBetsSettings.lockedField = 'startingBet'; saveDynamicBetsSettings(); calculateBetsAndRefresh(); };
    dynamicBetsContainer.append(startingBetLabel, startingBetInput, startingBetLock);

    const [maxLLabel, maxLInput] = createDynamicInput('Max L Streak:', 'dyn-max-l', dynamicBetsSettings.maxLStreak, `The maximum number of consecutive losses your strategy should be able to withstand. Max: ${MAX_L_STREAK_CAP}.`, 'number');
    maxLInput.max = MAX_L_STREAK_CAP;
    maxLInput.onchange = () => {
        let val = Math.max(1, parseInt(maxLInput.value, 10) || 1);
        val = Math.min(val, MAX_L_STREAK_CAP);
        dynamicBetsSettings.maxLStreak = val;
        maxLInput.value = val;
        saveDynamicBetsSettings();
        calculateBetsAndRefresh();
    };
    dynamicBetsContainer.append(maxLLabel, maxLInput, document.createElement('div'));

    const [martingaleLabel, martingaleInput] = createDynamicInput('Martingale Value:', 'dyn-martingale', dynamicBetsSettings.martingaleValue, "The multiplier for your bets (e.g., 2 for doubling, 3 for tripling).", 'number');
    martingaleInput.step = '0.1';
    martingaleInput.onchange = () => {
        let val = Math.max(1.1, parseFloat(martingaleInput.value) || 1.1);
        dynamicBetsSettings.martingaleValue = val;
        martingaleInput.value = val;
        saveDynamicBetsSettings();
        calculateBetsAndRefresh();
    };
    dynamicBetsContainer.append(martingaleLabel, martingaleInput, document.createElement('div'));

    const reinforceContainer = document.createElement('div');
    Object.assign(reinforceContainer.style, { gridColumn: '1 / -1', display: 'flex', alignItems: 'center', gap: '8px' });
    const reinforceCheck = document.createElement('input'); reinforceCheck.type = 'checkbox'; reinforceCheck.id = 'dyn-reinforce'; reinforceCheck.checked = dynamicBetsSettings.reinforce;
    const reinforceLabel = document.createElement('label'); reinforceLabel.textContent = 'Reinforce Bet'; reinforceLabel.htmlFor = 'dyn-reinforce'; reinforceLabel.style.cursor = 'pointer';
    reinforceContainer.title = "If checked, adds the Starting Bet back into the calculation on odd-numbered bets (3rd, 5th, etc.) for a more aggressive progression.";
    reinforceCheck.onchange = () => { dynamicBetsSettings.reinforce = reinforceCheck.checked; saveDynamicBetsSettings(); calculateBetsAndRefresh(); };
    reinforceContainer.append(reinforceCheck, reinforceLabel);
    dynamicBetsContainer.appendChild(reinforceContainer);

    dynamicBetsToggle.onchange = () => {
        dynamicBetsEnabled = dynamicBetsToggle.checked;
        localStorage.setItem(DYNAMIC_BETS_ENABLED_KEY, JSON.stringify(dynamicBetsEnabled));
        dynamicBetsContainer.style.display = dynamicBetsEnabled ? 'grid' : 'none';
        manualBetsContainer.style.display = dynamicBetsEnabled ? 'none' : 'block';
        calculateBetsAndRefresh();
    };


    const betsButton = document.createElement('button'); betsButton.textContent = '💰 Bets'; betsButton.title = "Open the Smart Bets panel to start a match.";
    Object.assign(betsButton.style, { alignSelf: 'flex-start', background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 8px', cursor: 'pointer', marginTop: '4px' });
    betsButton.onmouseenter = () => betsButton.style.background = 'rgba(255,255,255,0.2)';
    betsButton.onmouseleave = () => betsButton.style.background = 'rgba(255,255,255,0.1)';
    betsButton.onclick = () => { showBetsPanel = !showBetsPanel; showSettings = false; showEditBetsPanel = false; refreshAll(); };
    panel.appendChild(betsButton);

    // --- Core Functions ---
    const saveResults = () => localStorage.setItem(STORAGE, JSON.stringify(results));
    const saveTotalProfit = () => localStorage.setItem(PROFIT_STORAGE, totalProfit.toString());
    const saveCollapsed = () => localStorage.setItem(COLLAPSE_KEY, JSON.stringify(collapsed));
    const saveChargedshoots = () => localStorage.setItem(CHARGED_SHOOTS_COUNT_KEY, chargedshoots.toString());
    const saveManualBets = () => localStorage.setItem(MANUAL_BETS_STORAGE_KEY, JSON.stringify(manualBets));
    const saveDynamicBetsSettings = () => localStorage.setItem(DYNAMIC_BETS_SETTINGS_KEY, JSON.stringify(dynamicBetsSettings));

    function calculateBetsAndRefresh() {
        calculateBets();
        refreshAll();
    }

    function updateChargedshootsDisplay() { if (chargedshootsDisplay) chargedshootsDisplay.textContent = `Charges: ${chargedshoots} / 3`; }

    function updateChargedshootsPanelVisibility() {
        const inMatch = document.body.innerText.includes('POT MONEY') && !document.body.innerText.includes('Create Game');
        if (isChargedshootsEnabled && inMatch) {
            chargedshootsPanel.style.display = 'flex';
            chargedshootsPanel.style.background = `rgba(0,0,0,${currentOpacity})`;
        } else {
            chargedshootsPanel.style.display = 'none';
        }
    }

    function performAutoShoot() {
        if (!isChargedshootsEnabled || chargedshoots <= 0 || isShootDelayed) return;
        const shootButton = [...document.querySelectorAll('button.torn-btn, button.btn')].find(b => b.textContent.trim().toLowerCase() === 'shoot');
        if (shootButton && !shootButton.disabled && shootButton.offsetParent !== null) {
            isShootDelayed = true;
            setTimeout(() => {
                const currentShootButton = [...document.querySelectorAll('button.torn-btn, button.btn')].find(b => b.textContent.trim().toLowerCase() === 'shoot');
                if (currentShootButton && !currentShootButton.disabled && currentShootButton.offsetParent !== null) {
                    currentShootButton.click();
                    chargedshoots--;
                    saveChargedshoots();
                    updateChargedshootsDisplay();
                }
                isShootDelayed = false;
            }, 500);
        }
    }

    function parseBetInput(str) {
        if (typeof str !== 'string') str = String(str);
        str = str.toLowerCase().replace(/,/g, '').trim();
        let m = 1;
        if (str.endsWith('k')) { m = 1e3; str = str.slice(0, -1); }
        else if (str.endsWith('m')) { m = 1e6; str = str.slice(0, -1); }
        else if (str.endsWith('b')) { m = 1e9; str = str.slice(0, -1); }
        let v = parseFloat(str);
        return (isNaN(v) || v < 0) ? null : Math.floor(v * m);
    }

    function formatNumberToKMB(num) {
        if (num === null || isNaN(num)) return '';
        if (num >= 1e9) return (num / 1e9).toFixed(2).replace(/\.00$/, '').replace(/\.([1-9])0$/, '.$1') + 'b';
        if (num >= 1e6) return (num / 1e6).toFixed(2).replace(/\.00$/, '').replace(/\.([1-9])0$/, '.$1') + 'm';
        if (num >= 1e3) return (num / 1e3).toFixed(2).replace(/\.00$/, '').replace(/\.([1-9])0$/, '.$1') + 'k';
        return num.toLocaleString();
    }

    function loadManualBets() {
        try {
            const storedJson = localStorage.getItem(MANUAL_BETS_STORAGE_KEY);
            if (storedJson) {
                const parsed = JSON.parse(storedJson);
                if (Array.isArray(parsed)) return parsed;
            }
        } catch (e) { console.error("Error parsing stored manual bets:", e); }
        return [...DEFAULT_MANUAL_BETS];
    }

    function adjustManualBetsArray() {
        const currentLength = manualBets.length;
        if (currentLength === uiButtonCount) return;

        if (currentLength < uiButtonCount) {
            const lastValue = currentLength > 0 ? manualBets[currentLength - 1] : 10000;
            for (let i = currentLength; i < uiButtonCount; i++) {
                manualBets.push(lastValue * Math.pow(2, i - currentLength + 1));
            }
        } else {
            manualBets = manualBets.slice(0, uiButtonCount);
        }
        saveManualBets();
    }

    function buildManualBetInputs() {
        manualEditGrid.innerHTML = '';
        manualEditInputs = [];
        for (let i = 0; i < uiButtonCount; i++) {
            const label = document.createElement('label');
            label.textContent = `Bet ${i + 1}:`;
            Object.assign(label.style, { fontSize: '13px', paddingTop: '4px' });
            manualEditGrid.appendChild(label);

            const input = document.createElement('input');
            input.type = 'text';
            input.placeholder = 'e.g., 10k';
            input.title = `Set the manual bet amount for UI button ${i + 1}.`;
            Object.assign(input.style, { width: '80px', padding: '4px', border: '1px solid #555', borderRadius: '4px', background: 'rgba(255,255,255,0.1)', color: '#fff' });

            input.dataset.index = i;
            input.onchange = (e) => {
                const index = parseInt(e.target.dataset.index, 10);
                const parsed = parseBetInput(e.target.value);
                if (parsed !== null) {
                    manualBets[index] = parsed;
                    saveManualBets();
                    e.target.value = formatNumberToKMB(parsed);
                    calculateBetsAndRefresh();
                } else if (e.target.value !== '') {
                    alert('Invalid input. Please use numbers or suffixes like K/M/B (e.g., 25k, 2.5m).');
                    e.target.value = formatNumberToKMB(manualBets[index]);
                }
            };
            manualEditGrid.appendChild(input);
            manualEditInputs.push(input);
        }
    }
    buildManualBetInputs(); // Initial build

    function startMatch(originalButtonBetValue) {
        const inputBox = document.querySelector('input[aria-label="Money value"]');
        if (inputBox) {
            nativeSet.call(inputBox, originalButtonBetValue.toLocaleString('en-US'));
            inputBox.dispatchEvent(new Event('input', { bubbles: true }));
            inputBox.dispatchEvent(new Event('change', { bubbles: true }));
            const betAfterInputSet = parseBetInput(inputBox.value);
            if (betAfterInputSet === null || betAfterInputSet <= 0) { alert("Invalid bet amount currently in the input box. Please ensure it's a valid number."); return; }
            if (betAfterInputSet < originalButtonBetValue) { alert(`The bet amount in the box ($${betAfterInputSet.toLocaleString()}) is less than the button's intended value ($${originalButtonBetValue.toLocaleString()}).\nMatch not started.`); return; }
            let startButton = [...document.querySelectorAll('button')].find(b => b.textContent.trim().toLowerCase() === 'start');
            if (startButton) startButton.click();
        } else {
            setTimeout(() => { let yesButton = [...document.querySelectorAll('button')].find(b => b.textContent.trim().toLowerCase() === 'yes'); if (yesButton) yesButton.click(); }, 400);
        }
    }

        function getSumOfRatios(L, M, reinforce, numCoeffs) {
        if (numCoeffs <= 0 || M <= 1) return { sum: 0, coeffs: [] };

        const maxCoeffs = Math.max(L, numCoeffs); // Generate enough coeffs for both calculations
        const allCoeffs = [];

        if (!reinforce) {
            for (let i = 0; i < maxCoeffs; i++) {
                allCoeffs.push(Math.pow(M, i));
            }
        } else {
            let lastCoeff = 0;
            for (let i = 1; i <= maxCoeffs; i++) {
                let currentCoeff;
                if (i === 1) {
                    currentCoeff = 1;
                } else if (i % 2 === 0) {
                    currentCoeff = M * lastCoeff;
                } else {
                    currentCoeff = (M * lastCoeff) + 1;
                }
                allCoeffs.push(currentCoeff);
                lastCoeff = currentCoeff;
            }
        }

        // Calculate sum based on L (maxLStreak)
        const sum = allCoeffs.slice(0, L).reduce((acc, val) => acc + val, 0);

        // Return the required number of coeffs for display
        const coeffsForDisplay = allCoeffs.slice(0, numCoeffs);

        return { sum, coeffs: coeffsForDisplay };
    }

    function calculateBets() {
        if (dynamicBetsEnabled) {
            const { capital, maxLStreak, martingaleValue, reinforce, lockedField } = dynamicBetsSettings;
            let startingBet = dynamicBetsSettings.startingBet;

            const numCoeffsToGenerate = uiButtonCount - 1;
            const { sum, coeffs } = getSumOfRatios(maxLStreak, martingaleValue, reinforce, numCoeffsToGenerate);

            if (lockedField === 'capital') {
                startingBet = (sum > 0) ? Math.floor(capital / sum) : 0;
                dynamicBetsSettings.startingBet = startingBet;
            } else {
                dynamicBetsSettings.capital = Math.floor(startingBet * sum);
            }

            currentBets = [];
            currentBets.push(dynamicBetsSettings.testBet);

            // We now have exactly the right number of coefficients for all UI buttons
            for (let i = 0; i < coeffs.length; i++) {
                const betValue = Math.floor(startingBet * coeffs[i]);
                currentBets.push(betValue);
            }

        } else {
            currentBets = [...manualBets];
        }
    }


    function buildBetButtons() {
        betButtonsContainer.innerHTML = '';
        if (!currentBets || currentBets.length !== uiButtonCount) return;

        const firstBetRow = document.createElement('div');
        Object.assign(firstBetRow.style, { display: 'flex', justifyContent: 'center', width: '100%' });
        let b0 = document.createElement('button');
        b0.textContent = formatNumberToKMB(currentBets[0]);
        b0.title = `$${currentBets[0].toLocaleString()}`;
        Object.assign(b0.style, { background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 10px', cursor: 'pointer', fontSize: '11px', minWidth: '80px' });
        b0.onmouseenter = () => b0.style.background = 'rgba(255,255,255,0.2)'; b0.onmouseleave = () => b0.style.background = 'rgba(255,255,255,0.1)';
        b0.onclick = () => startMatch(currentBets[0]);
        firstBetRow.appendChild(b0);
        betButtonsContainer.appendChild(firstBetRow);

        for (let i = 1; i < uiButtonCount; i += 2) {
            const row = document.createElement('div');
            Object.assign(row.style, { display: 'flex', justifyContent: 'space-around', gap: '6px', width: '100%' });
            let b1 = document.createElement('button');
            b1.textContent = formatNumberToKMB(currentBets[i]);
            b1.title = `$${currentBets[i].toLocaleString()}`;
            Object.assign(b1.style, { background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 10px', cursor: 'pointer', fontSize: '11px', flex: '1', minWidth: '70px' });
            b1.onmouseenter = () => b1.style.background = 'rgba(255,255,255,0.2)'; b1.onmouseleave = () => b1.style.background = 'rgba(255,255,255,0.1)';
            b1.onclick = () => startMatch(currentBets[i]);
            row.appendChild(b1);
            if (i + 1 < uiButtonCount) {
                let b2 = document.createElement('button');
                b2.textContent = formatNumberToKMB(currentBets[i + 1]);
                b2.title = `$${currentBets[i + 1].toLocaleString()}`;
                Object.assign(b2.style, { background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '4px 10px', cursor: 'pointer', fontSize: '11px', flex: '1', minWidth: '70px' });
                b2.onmouseenter = () => b2.style.background = 'rgba(255,255,255,0.2)'; b2.onmouseleave = () => b2.style.background = 'rgba(255,255,255,0.1)';
                b2.onclick = () => startMatch(currentBets[i + 1]);
                row.appendChild(b2);
            }
            betButtonsContainer.appendChild(row);
        }

        miniBar.innerHTML = '';
        const miniCirclesContainer = document.createElement('div');
        Object.assign(miniCirclesContainer.style, { display: 'flex', flexWrap: 'wrap', gap: '2px', justifyContent: 'center' });
        results.slice(0, miniBarCount).forEach((r, idx) => miniCirclesContainer.append(makeCircle(r.result, r.bet, idx)));
        miniBar.appendChild(miniCirclesContainer);

        betsPanelCirclesContainer.innerHTML = '';
        results.slice(0, miniBarCount).forEach((r, idx) => betsPanelCirclesContainer.append(makeCircle(r.result, r.bet, idx)));
        betsPanelLastMatchesTitle.textContent = `Last ${miniBarCount} Matches`;

        if (collapsed && !showBetsPanel && !showSettings && !showEditBetsPanel) {
            const miniBetContainer = document.createElement('div');
            Object.assign(miniBetContainer.style, { display: 'flex', flexDirection: 'column', gap: '2px', alignItems: 'center' });

            // --- NEW: Set a fixed number of buttons per row ---
            const buttonsPerRow = 4;

            let currentRow = document.createElement('div');
            Object.assign(currentRow.style, { display: 'flex', flexWrap: 'nowrap', gap: '2px', justifyContent: 'center' });
            miniBetContainer.appendChild(currentRow);

            currentBets.forEach((bet, i) => {
                if (i > 0 && i % buttonsPerRow === 0) {
                    currentRow = document.createElement('div');
                    Object.assign(currentRow.style, { display: 'flex', flexWrap: 'nowrap', gap: '2px', justifyContent: 'center', marginTop: '2px' });
                    miniBetContainer.appendChild(currentRow);
                }
                let miniB = document.createElement('button');
                miniB.textContent = formatNumberToKMB(bet);
                miniB.title = `$${bet.toLocaleString()}`;
                Object.assign(miniB.style, { background: 'rgba(255,255,255,0.1)', color: '#fff', border: 'none', borderRadius: '6px', padding: '3px 6px', cursor: 'pointer', fontSize: `${miniButtonSize}px`, width: 'auto' });
                miniB.onmouseenter = () => miniB.style.background = 'rgba(255,255,255,0.2)'; miniB.onmouseleave = () => miniB.style.background = 'rgba(255,255,255,0.1)';
                miniB.onclick = () => startMatch(bet);
                currentRow.appendChild(miniB);
            });
            miniBar.appendChild(miniBetContainer);
        }
    }

  

    const makeCircle = (result, bet, index) => {
        const container = document.createElement('span');
        Object.assign(container.style, { display: 'inline-block', width: '14px', height: '14px', borderRadius: '50%', backgroundColor: result === 'win' ? '#4CAF50' : '#E53935', marginRight: '2px', cursor: 'pointer', position: 'relative' });
        container.title = `${result.toUpperCase()}: $${bet.toLocaleString()}`;
        container.addEventListener('click', (e) => {
            e.stopPropagation(); if (isDragging || isTwoFingerDragging) return;
            Array.from(container.children).forEach(child => { if (child.classList.contains('rr-temp-popup')) container.removeChild(child); });
            const tempPopup = document.createElement('div'); tempPopup.classList.add('rr-temp-popup'); tempPopup.textContent = `${result.toUpperCase()}: $${bet.toLocaleString()}`;
            Object.assign(tempPopup.style, { position: 'absolute', background: 'rgba(0,0,0,0.9)', border: '1px solid #555', color: 'white', padding: '4px 8px', borderRadius: '4px', fontSize: '12px', whiteSpace: 'nowrap', zIndex: '10000000', top: '-28px', left: '50%', transform: 'translateX(-50%)', pointerEvents: 'none', opacity: '0', transition: 'opacity 0.2s ease-in-out' });
            container.appendChild(tempPopup);
            setTimeout(() => tempPopup.style.opacity = '1', 10);
            setTimeout(() => { tempPopup.style.opacity = '0'; setTimeout(() => { if (container.contains(tempPopup)) container.removeChild(tempPopup); }, 200); }, 1500);
        });
        return container;
    };

    function updateStatus() { statusDiv.textContent = collapsed ? '▪' : (roundActive ? '►' : '▸'); }

    function updatePanelVisibility() {
        const onRRPage = document.body.innerText.includes('POT MONEY') || document.body.innerText.includes('Waiting:') || document.body.innerText.includes('You take your winnings') || document.body.innerText.includes('BANG! You fall down');
        if (!autoHide) { panel.style.display = 'flex'; return; }
        panel.style.display = onRRPage ? 'flex' : 'none';
    }

    function refreshAll() {
        alertMessageDiv.style.display = 'none';
        let showAlert = false, alertText = '', alertBackgroundColor = '', alertBorderColor = '';
        if (lossLimit > 0 && totalProfit <= -lossLimit && !alertShownLoss) { showAlert = true; alertText = `🚨 LOSS LIMIT REACHED! -$${lossLimit.toLocaleString()}`; alertBackgroundColor = 'rgba(229, 57, 53, 0.8)'; alertBorderColor = '#E53935'; alertShownLoss = true; localStorage.setItem(ALERT_SHOWN_LOSS_KEY, 'true'); }
        else if (profitTarget > 0 && totalProfit >= profitTarget && !alertShownProfit) { showAlert = true; alertText = `🎯 PROFIT TARGET REACHED! +$${profitTarget.toLocaleString()}`; alertBackgroundColor = 'rgba(76, 175, 80, 0.8)'; alertBorderColor = '#4CAF50'; alertShownProfit = true; localStorage.setItem(ALERT_SHOWN_PROFIT_KEY, 'true'); }
        if (showAlert) { alertMessageDiv.textContent = alertText; Object.assign(alertMessageDiv.style, { background: alertBackgroundColor, borderColor: alertBorderColor, display: 'block' }); }

        const sign = totalProfit >= 0 ? '+' : '–';
        profitMini.textContent = `${sign}$${Math.abs(totalProfit).toLocaleString()}`;
        profitMini.style.color = totalProfit >= 0 ? '#4CAF50' : '#E53935';
        profitDiv.textContent = `💰 Profit: ${sign}$${Math.abs(totalProfit).toLocaleString()}`;
        profitDiv.style.color = totalProfit >= 0 ? '#4CAF50' : '#E53935';
        const wins = results.filter(r => r.result === 'win').length;
        const tot = results.length;
        winrateDiv.textContent = `🎯 Win Rate: ${tot ? ((wins / tot) * 100).toFixed(1) : '0.0'}% (${wins}/${tot})`;
        let w = 0, l = 0;
        for (const r of results) { if (r.result === 'win') { if (l) break; w++; } else { if (w) break; l++; } }
        streakDiv.textContent = w ? `🔥 Streak: ${w}` : l ? `💀 Streak: ${l}` : '⏸️ No streak';
        resultsContainer.innerHTML = '';
        results.slice(0, maxDisplayMatches).forEach((r, i) => { const row = document.createElement('div'); row.append(makeCircle(r.result, r.bet, i), document.createTextNode(`${i + 1}. ${r.result.toUpperCase()} — $${r.bet.toLocaleString()}`)); resultsContainer.appendChild(row); });

        // Update Bet Edit UI values
        if (showEditBetsPanel) {
            manualEditInputs.forEach((input, i) => { if (manualBets[i] !== undefined) input.value = formatNumberToKMB(manualBets[i]); });
            testBetInput.value = formatNumberToKMB(dynamicBetsSettings.testBet);
            capitalInput.value = formatNumberToKMB(dynamicBetsSettings.capital);
            startingBetInput.value = formatNumberToKMB(dynamicBetsSettings.startingBet);
            capitalLock.textContent = dynamicBetsSettings.lockedField === 'capital' ? '🔒' : '🔓';
            startingBetLock.textContent = dynamicBetsSettings.lockedField === 'startingBet' ? '🔒' : '🔓';
            capitalInput.readOnly = dynamicBetsSettings.lockedField !== 'capital';
            startingBetInput.readOnly = dynamicBetsSettings.lockedField !== 'startingBet';
            capitalInput.style.background = dynamicBetsSettings.lockedField === 'capital' ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.2)';
            startingBetInput.style.background = dynamicBetsSettings.lockedField === 'startingBet' ? 'rgba(255,255,255,0.1)' : 'rgba(0,0,0,0.2)';
        }
        if(showSettings) {
            profitTargetInput.value = formatNumberToKMB(profitTarget);
            lossLimitInput.value = formatNumberToKMB(lossLimit);
        }

        statsGroup.style.display = 'none'; settingsPanel.style.display = 'none'; betsPanel.style.display = 'none'; editBetsPanel.style.display = 'none'; miniBar.style.display = 'none'; profitMini.style.display = 'none';
        settingsButton.style.display = 'none'; betsButton.style.display = 'none';

        if (showSettings) settingsPanel.style.display = 'flex';
        else if (showBetsPanel) betsPanel.style.display = 'flex';
        else if (showEditBetsPanel) editBetsPanel.style.display = 'flex';
        else if (collapsed) { miniBar.style.display = 'flex'; profitMini.style.display = 'block'; }
        else { statsGroup.style.display = 'flex'; settingsButton.style.display = 'inline-block'; betsButton.style.display = 'inline-block'; }

        buildBetButtons();
        updateStatus();
        updatePanelVisibility();
        updateChargedshootsPanelVisibility();
    }

    function addResult(type) {
        if (!roundActive) return;
        if (type === 'win') totalProfit += lastPot; else totalProfit -= lastPot;
        saveTotalProfit();
        results.unshift({ result: type, bet: lastPot });
        if (results.length > maxDisplayMatches) results.pop();
        saveResults();
        roundActive = false;
        hasTracked = true;
        chargedshoots = 0;
        saveChargedshoots();
        updateChargedshootsDisplay();
        if (profitTarget > 0 && alertShownProfit && totalProfit < profitTarget) { alertShownProfit = false; localStorage.setItem(ALERT_SHOWN_PROFIT_KEY, 'false'); }
        if (lossLimit > 0 && alertShownLoss && totalProfit > -lossLimit) { alertShownLoss = false; localStorage.setItem(ALERT_SHOWN_LOSS_KEY, 'false'); }
        refreshAll();
    }

    function scanPot() {
        document.querySelectorAll('body *').forEach(el => { const txt = el.innerText?.trim(); if (txt?.includes('POT MONEY:$')) { const m = txt.match(/POT MONEY:\$\s*([\d,]+)/); if (m) lastPot = Math.floor(parseInt(m[1].replace(/,/g, ''), 10) / 2); } });
    }

    function scanResult() {
        if (!roundActive) return;
        document.querySelectorAll('body *').forEach(el => { const txt = el.innerText?.trim(); if (txt?.includes('You take your winnings')) addResult('win'); if (txt?.includes('BANG! You fall down')) addResult('lose'); });
    }

    function scanStart() {
        if (hasTracked && (document.body.innerText.includes('Waiting:') || document.body.innerText.includes('Create Game') || document.querySelector('button.start-game'))) {
            roundActive = true; hasTracked = false; updateStatus();
        }
    }

    const savePos = () => localStorage.setItem(POS_KEY, JSON.stringify({ top: panel.style.top, left: panel.style.left }));
    function onDragMove(e) { if (!isDragging) return; e.preventDefault(); const moveEvent = e.touches ? e.touches[0] : e; if (typeof moveEvent.clientX === 'undefined') return; const dx = moveEvent.clientX - dragMouseX; const dy = moveEvent.clientY - dragMouseY; dragMouseX = moveEvent.clientX; dragMouseY = moveEvent.clientY; panel.style.left = (panel.offsetLeft + dx) + 'px'; panel.style.top = (panel.offsetTop + dy) + 'px'; }
    function onDragEnd() { if (!isDragging) return; isDragging = false; document.removeEventListener('mousemove', onDragMove); document.removeEventListener('mouseup', onDragEnd); document.removeEventListener('touchmove', onDragMove); document.removeEventListener('touchend', onDragEnd); savePos(); panel.style.cursor = ''; document.body.style.cursor = ''; }
    function startDrag(e) { if (isTwoFingerDragging) return; e.preventDefault(); const startEvent = e.touches ? e.touches[0] : e; if (typeof startEvent.clientX === 'undefined') return; isDragging = true; dragMouseX = startEvent.clientX; dragMouseY = startEvent.clientY; panel.style.cursor = 'grabbing'; document.body.style.cursor = 'grabbing'; document.addEventListener('mousemove', onDragMove); document.addEventListener('mouseup', onDragEnd); document.addEventListener('touchmove', onDragMove, { passive: false }); document.addEventListener('touchend', onDragEnd); }
    dragHandle.addEventListener('mousedown', startDrag);
    dragHandle.addEventListener('touchstart', e => { if (e.touches.length === 1) startDrag(e); });
    panel.addEventListener('mousedown', e => { if (e.shiftKey && e.target !== dragHandle) startDrag(e); });
    panel.addEventListener('touchstart', e => { if (e.touches.length === 2) { e.preventDefault(); isTwoFingerDragging = true; isDragging = false; initialTouchMidX = (e.touches[0].clientX + e.touches[1].clientX) / 2; initialTouchMidY = (e.touches[0].clientY + e.touches[1].clientY) / 2; initialPanelX = panel.offsetLeft; initialPanelY = panel.offsetTop; panel.style.cursor = 'grabbing'; document.body.style.cursor = 'grabbing'; document.addEventListener('touchmove', onTwoFingerMove, { passive: false }); document.addEventListener('touchend', onTwoFingerEnd); } });
    function onTwoFingerMove(e) { if (!isTwoFingerDragging || e.touches.length !== 2) { onTwoFingerEnd(e); return; } e.preventDefault(); const currentTouchMidX = (e.touches[0].clientX + e.touches[1].clientX) / 2; const currentTouchMidY = (e.touches[0].clientY + e.touches[1].clientY) / 2; const dx = currentTouchMidX - initialTouchMidX; const dy = currentTouchMidY - initialTouchMidY; panel.style.left = (initialPanelX + dx) + 'px'; panel.style.top = (initialPanelY + dy) + 'px'; }
    function onTwoFingerEnd(e) { if (!isTwoFingerDragging) return; if (e.touches.length < 2) { document.removeEventListener('touchmove', onTwoFingerMove); document.removeEventListener('touchend', onTwoFingerEnd); savePos(); isTwoFingerDragging = false; panel.style.cursor = ''; document.body.style.cursor = ''; } }

    const saveChargedshootsPos = () => localStorage.setItem(CHARGED_SHOOTS_POS_KEY, JSON.stringify({ top: chargedshootsPanel.style.top, left: chargedshootsPanel.style.left }));
    function onChargedPanelDragMove(e) { if (!isChargedPanelDragging) return; e.preventDefault(); const moveEvent = e.touches ? e.touches[0] : e; if (typeof moveEvent.clientX === 'undefined') return; const dx = moveEvent.clientX - dragChargedPanelMouseX; const dy = moveEvent.clientY - dragChargedPanelMouseY; dragChargedPanelMouseX = moveEvent.clientX; dragChargedPanelMouseY = moveEvent.clientY; chargedshootsPanel.style.left = (chargedshootsPanel.offsetLeft + dx) + 'px'; chargedshootsPanel.style.top = (chargedshootsPanel.offsetTop + dy) + 'px'; }
    function onChargedPanelDragEnd() { if (!isChargedPanelDragging) return; isChargedPanelDragging = false; document.removeEventListener('mousemove', onChargedPanelDragMove); document.removeEventListener('mouseup', onChargedPanelDragEnd); document.removeEventListener('touchmove', onChargedPanelDragMove); document.removeEventListener('touchend', onChargedPanelDragEnd); saveChargedshootsPos(); chargedshootsPanel.style.cursor = ''; document.body.style.cursor = ''; }
    function startChargedPanelDrag(e) { if (isChargedPanelTwoFingerDragging) return; e.preventDefault(); const startEvent = e.touches ? e.touches[0] : e; if (typeof startEvent.clientX === 'undefined') return; isChargedPanelDragging = true; dragChargedPanelMouseX = startEvent.clientX; dragChargedPanelMouseY = startEvent.clientY; chargedshootsPanel.style.cursor = 'grabbing'; document.body.style.cursor = 'grabbing'; document.addEventListener('mousemove', onChargedPanelDragMove); document.addEventListener('mouseup', onChargedPanelDragEnd); document.addEventListener('touchmove', onChargedPanelDragMove, { passive: false }); document.addEventListener('touchend', onChargedPanelDragEnd); }
    chargedshootsPanel.addEventListener('mousedown', e => { if (e.shiftKey) startChargedPanelDrag(e); });
    chargedshootsPanel.addEventListener('touchstart', e => { if (e.touches.length === 2) { e.preventDefault(); isChargedPanelTwoFingerDragging = true; isChargedPanelDragging = false; initialChargedPanelTouchMidX = (e.touches[0].clientX + e.touches[1].clientX) / 2; initialChargedPanelTouchMidY = (e.touches[0].clientY + e.touches[1].clientY) / 2; initialChargedPanelX = chargedshootsPanel.offsetLeft; initialChargedPanelY = chargedshootsPanel.offsetTop; chargedshootsPanel.style.cursor = 'grabbing'; document.body.style.cursor = 'grabbing'; document.addEventListener('touchmove', onChargedPanelTwoFingerMove, { passive: false }); document.addEventListener('touchend', onChargedPanelTwoFingerEnd); } });
    function onChargedPanelTwoFingerMove(e) { if (!isChargedPanelTwoFingerDragging || e.touches.length !== 2) { onChargedPanelTwoFingerEnd(e); return; } e.preventDefault(); const currentTouchMidX = (e.touches[0].clientX + e.touches[1].clientX) / 2; const currentTouchMidY = (e.touches[0].clientY + e.touches[1].clientY) / 2; const dx = currentTouchMidX - initialChargedPanelTouchMidX; const dy = currentTouchMidY - initialChargedPanelTouchMidY; chargedshootsPanel.style.left = (initialChargedPanelX + dx) + 'px'; chargedshootsPanel.style.top = (initialChargedPanelY + dy) + 'px'; }
    function onChargedPanelTwoFingerEnd(e) { if (!isChargedPanelTwoFingerDragging) return; if (e.touches.length < 2) { document.removeEventListener('touchmove', onChargedPanelTwoFingerMove); document.removeEventListener('touchend', onChargedPanelTwoFingerEnd); saveChargedshootsPos(); isChargedPanelTwoFingerDragging = false; chargedshootsPanel.style.cursor = ''; document.body.style.cursor = ''; } }

    statusDiv.addEventListener('click', () => { if (isDragging || isTwoFingerDragging) return; collapsed = !collapsed; if (collapsed) { showSettings = false; showBetsPanel = false; showEditBetsPanel = false; } saveCollapsed(); refreshAll(); });
    alertMessageDiv.addEventListener('click', () => { alertMessageDiv.style.display = 'none'; });

    // --- Main Loop ---
    calculateBetsAndRefresh(); // Initial calculation and render
    setInterval(() => {
        updatePanelVisibility();
        scanStart();
        scanPot();
        scanResult();
        updateChargedshootsPanelVisibility();
        performAutoShoot();
    }, 500);

})();