Torn Quick Deposit

Quick Deposit cash to Ghost Trade / Company Vault / Faction Vault / Property Vault / Stocks, with GUI Settings

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

作者のサイトでサポートを受ける。または、このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください
// ==UserScript==
// @name         Torn Quick Deposit
// @namespace    http://tampermonkey.net/
// @version      1.5.1
// @description  Quick Deposit cash to Ghost Trade / Company Vault / Faction Vault / Property Vault / Stocks, with GUI Settings
// @author       e7cf09 [3441977]
// @icon         https://editor.torn.com/cd385b6f-7625-47bf-88d4-911ee9661b52-3441977.png
// @supportURL   https://www.torn.com/forums.php#/p=threads&f=67&t=16530699
// @match        https://www.torn.com/*
// @run-at       document-start
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // --- CONFIGURATION MANAGEMENT ---
    const STORAGE_KEY = 'torn_quick_deposit';
    
    // SET THIS TO TRUE IF YOU HID THE SETTINGS BUTTON AND CAN'T ACCESS IT!
    const I_MESSED_UP = false; 

    // Note: Changing these values here won't affect your active settings because they are saved in your browser.
    // Please use the Settings button (gear icon) in the script to change options.
    const DEFAULT_CONFIG = {
        MOBILE_MODE: false,
        HIDE_SETTINGS_BTN: false,
        PANIC_THRESHOLD: 20000000,
        STRICT_GHOST_MODE: true,
        GHOST_KEYWORD: "ghost",
        PRIORITY_HIGH: ["GHOST", "FACTION"],
        PRIORITY_HIGH_DISABLED: ["STOCKS", "COMPANY", "PROPERTY"], // Disabled options specifically for High Priority
        PRIORITY_LOW: ["FACTION", "GHOST"],
        PRIORITY_LOW_DISABLED: ["STOCKS", "COMPANY", "PROPERTY"], // Disabled options specifically for Low Priority
        STOCK_ACRONYM: "",
        KEYS: {
            FACTION: [],
            GHOST: [],
            COMPANY: [],
            STOCKS: [],
            PROPERTY: [],
            RESET: [],
            PANIC: ["KeyP"],
            EXECUTE: [],
            SETTINGS: ["KeyS"]
        },
        DEAD_SIGNALS: ["no trade was found", "trade has been accepted", "declined", "cancelled", "locked"]
    };

    let CONFIG = Object.assign({}, DEFAULT_CONFIG);

    function loadConfig() {
        try {
            const saved = localStorage.getItem(STORAGE_KEY);
            if (saved) {
                const parsed = JSON.parse(saved);
                // Merge saved config with default to ensure new keys exist
                CONFIG = { ...DEFAULT_CONFIG, ...parsed, KEYS: { ...DEFAULT_CONFIG.KEYS, ...(parsed.KEYS || {}) } };
            }
        } catch (e) {
            console.error("Torn Quick Deposit: Failed to load config", e);
        }
    }

    function saveConfig() {
        try {
            localStorage.setItem(STORAGE_KEY, JSON.stringify(CONFIG));
            showToast("Settings Saved! Reloading...");
            setTimeout(() => window.location.reload(), 1000);
        } catch (e) {
            console.error("Torn Quick Deposit: Failed to save config", e);
            showToast("Error Saving Settings");
        }
    }

    // Load immediately
    loadConfig();

    // --- APP STATE ---
    const STATE = {
        balance: 0,
        panic: localStorage.getItem('torn_tactical_panic_enabled') !== 'false',
        ghostID: localStorage.getItem('torn_tactical_ghost_id'),
        locks: { panic: false, sending: false, jumping: false, dead: false },
        els: { overlay: null, btn: null, settingsBtn: null }
    };

    // --- UTILS ---
    const qs = (s, p=document) => p.querySelector(s);
    const qsa = (s, p=document) => p.querySelectorAll(s);
    const fmt = (n) => "$" + parseInt(n).toLocaleString('en-US');
    const setStyle = (el, css) => Object.assign(el.style, css);
    const STOCK_LIST = ["", "ASS", "BAG", "CNC", "EWM", "ELT", "EVL", "FHG", "GRN", "CBD", "HRG", "IIL", "IOU", "IST", "LAG", "LOS", "LSC", "MCS", "MSG", "MUN", "PRN", "PTS", "SYM", "SYS", "TCP", "TMI", "TGP", "TCT", "TSB", "TCC", "THS", "TCI", "TCM", "WSU", "WLT", "YAZ"];

    // HELPER FOR ROBUST CLICKING
    const robustClick = (element) => {
        if (!element || element.disabled === true) return;
        const rect = element.getBoundingClientRect();
        const x = rect.left + (rect.width / 2);
        const y = rect.top + (rect.height / 2);
        ['pointerdown', 'mousedown', 'pointerup', 'mouseup', 'click'].forEach(eventType => {
            element.dispatchEvent(new MouseEvent(eventType, {
                bubbles: true, cancelable: true, view: window,
                detail: 1, screenX: x, screenY: y, clientX: x, clientY: y, buttons: 1
            }));
        });
    };

    // --- SETTINGS UI ---
    function openSettingsModal() {
        // Close if exists
        if (document.getElementById('torn-deposit-settings-modal')) return;

        // Deep copy config for editing to avoid mutating live config until save
        const editConfig = JSON.parse(JSON.stringify(CONFIG));

        const modal = document.createElement('div');
        modal.id = 'torn-deposit-settings-modal';
        setStyle(modal, {
            position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)',
            background: '#222', color: '#ddd', padding: '20px', borderRadius: '8px',
            zIndex: '9999999', boxShadow: '0 0 20px rgba(0,0,0,0.8)',
            width: '400px', maxHeight: '90vh', overflowY: 'auto',
            fontFamily: 'Arial, sans-serif', fontSize: '13px', border: '1px solid #444'
        });

        const title = document.createElement('h3');
        title.innerText = 'Deposit Settings';
        title.style.marginTop = '0';
        title.style.borderBottom = '1px solid #555';
        title.style.paddingBottom = '10px';
        title.style.textAlign = 'center';
        modal.appendChild(title);

        // --- Helper: Simple Inputs ---
        const createInput = (label, type, key, description = "", options = null) => {
            const div = document.createElement('div');
            div.style.marginBottom = '15px';
            div.style.borderBottom = '1px solid #333';
            div.style.paddingBottom = '10px';
            
            const lbl = document.createElement('label');
            lbl.innerText = label;
            lbl.style.display = 'block';
            lbl.style.fontWeight = 'bold';
            lbl.style.color = '#fff';
            
            if (description) {
                const desc = document.createElement('div');
                desc.innerText = description;
                desc.style.fontSize = '11px';
                desc.style.color = '#888';
                desc.style.marginBottom = '5px';
                desc.style.fontStyle = 'italic';
                div.appendChild(desc);
            }
            
            let input;
            if (type === 'checkbox') {
                input = document.createElement('input');
                input.type = 'checkbox';
                input.checked = editConfig[key];
                input.style.float = 'right';
                input.style.cursor = 'pointer';
                input.onchange = (e) => { editConfig[key] = e.target.checked; };
                lbl.appendChild(input); 
            } else if (type === 'select') {
                input = document.createElement('select');
                input.style.width = '100%';
                input.style.background = '#333';
                input.style.color = '#fff';
                input.style.border = '1px solid #555';
                input.style.padding = '5px';
                
                (options || []).forEach(opt => {
                    const option = document.createElement('option');
                    option.value = opt;
                    option.innerText = opt;
                    if (opt === editConfig[key]) option.selected = true;
                    input.appendChild(option);
                });
                
                input.onchange = (e) => { editConfig[key] = e.target.value; };
            } else {
                input = document.createElement('input');
                input.type = (type === 'number') ? 'text' : type; // Use text for numbers to remove spinners
                if (type === 'number') {
                    input.inputMode = 'numeric';
                    input.pattern = '[0-9]*';
                }
                input.value = editConfig[key];
                input.style.width = '96%';
                input.style.background = '#333';
                input.style.color = '#fff';
                input.style.border = '1px solid #555';
                input.style.padding = '5px';
                input.onchange = (e) => { 
                    if (type === 'number') {
                        const val = parseInt(e.target.value.replace(/[^0-9]/g, ''));
                        editConfig[key] = isNaN(val) ? 0 : val;
                        e.target.value = editConfig[key]; // Format back
                    } else {
                        editConfig[key] = e.target.value; 
                    }
                };
            }

            div.insertBefore(lbl, div.firstChild);
            if (type !== 'checkbox') div.appendChild(input);
            return div;
        };

        // --- Helper: Sortable List (DnD) ---
        const createSortableList = (label, keyEnabled, description, keyDisabled) => {
            const container = document.createElement('div');
            container.style.marginBottom = '15px';
            container.style.borderBottom = '1px solid #333';
            container.style.paddingBottom = '10px';

            const lbl = document.createElement('label');
            lbl.innerText = label;
            lbl.style.display = 'block';
            lbl.style.fontWeight = 'bold';
            lbl.style.color = '#fff';
            container.appendChild(lbl);

            if (description) {
                const desc = document.createElement('div');
                desc.innerText = description;
                desc.style.fontSize = '11px';
                desc.style.color = '#888';
                desc.style.marginBottom = '5px';
                desc.style.fontStyle = 'italic';
                container.appendChild(desc);
            }

            // Create two lists: Enabled (top) and Disabled (bottom)
            const createSubList = (listKey, title) => {
                const subContainer = document.createElement('div');
                subContainer.style.marginBottom = '10px';
                
                const subTitle = document.createElement('div');
                subTitle.innerText = title;
                subTitle.style.fontSize = '12px';
                subTitle.style.color = '#ccc';
                subTitle.style.marginBottom = '3px';
                subContainer.appendChild(subTitle);

                const listDiv = document.createElement('div');
                listDiv.id = 'list-' + listKey; // Unique ID for DnD
                listDiv.style.background = title.includes('Disabled') ? '#2a2a2a' : '#333';
                listDiv.style.padding = '5px';
                listDiv.style.borderRadius = '4px';
                listDiv.style.display = 'flex';
                listDiv.style.flexDirection = 'column';
                listDiv.style.gap = '4px';
                listDiv.style.minHeight = '30px'; // Ensure empty list is droppable
                
                subContainer.appendChild(listDiv);
                
                // DnD Logic
                listDiv.addEventListener('dragover', (e) => {
                    e.preventDefault();
                    const afterElement = getDragAfterElement(listDiv, e.clientY);
                    const draggingEl = document.querySelector('.dragging');
                    if (draggingEl) {
                        // Only allow dragging between related lists (Enabled <-> Disabled for THIS priority type)
                        const sourceListId = draggingEl.closest('[id^="list-"]').id;
                        const validSourceIds = ['list-' + keyEnabled, 'list-' + keyDisabled];
                        
                        if (validSourceIds.includes(sourceListId)) {
                            if (afterElement == null) {
                                listDiv.appendChild(draggingEl);
                            } else {
                                listDiv.insertBefore(draggingEl, afterElement);
                            }
                            
                            // Update config for both lists
                            [keyEnabled, keyDisabled].forEach(k => {
                                const el = document.getElementById('list-' + k);
                                if (el) {
                                    const newOrder = [];
                                    el.querySelectorAll('div.sortable-item').forEach(item => {
                                        newOrder.push(item.dataset.value);
                                    });
                                    editConfig[k] = newOrder;
                                }
                            });
                        }
                    }
                });

                return { container: subContainer, listDiv: listDiv };
            };

            const enabledList = createSubList(keyEnabled, "Enabled (Ordered)");
            const disabledList = createSubList(keyDisabled, "Disabled");

            container.appendChild(enabledList.container);
            container.appendChild(disabledList.container);

            let draggingItem = null;

            const getDragAfterElement = (container, y) => {
                const draggableElements = [...container.querySelectorAll('div[draggable="true"]:not(.dragging)')];
                return draggableElements.reduce((closest, child) => {
                    const box = child.getBoundingClientRect();
                    const offset = y - box.top - box.height / 2;
                    if (offset < 0 && offset > closest.offset) {
                        return { offset: offset, element: child };
                    } else {
                        return closest;
                    }
                }, { offset: Number.NEGATIVE_INFINITY }).element;
            };

            const renderList = (listDiv, key) => {
                listDiv.innerHTML = '';
                if (!editConfig[key]) editConfig[key] = [];
                
                editConfig[key].forEach((item) => {
                    const itemDiv = document.createElement('div');
                    itemDiv.innerText = item;
                    itemDiv.draggable = true;
                    itemDiv.dataset.value = item;
                    itemDiv.className = 'sortable-item';
                    
                    const isEnabled = key === keyEnabled;
                    setStyle(itemDiv, {
                        background: isEnabled ? '#444' : '#3a3a3a', 
                        color: isEnabled ? '#fff' : '#aaa', 
                        padding: '8px',
                        borderRadius: '3px', cursor: 'grab', 
                        border: '1px solid ' + (isEnabled ? '#555' : '#444'), 
                        userSelect: 'none',
                        display: 'flex', justifyContent: 'space-between', alignItems: 'center'
                    });
                    
                    const handle = document.createElement('span');
                    handle.innerHTML = '☰';
                    handle.style.color = '#888';
                    handle.style.cursor = 'grab';
                    itemDiv.appendChild(handle);

                    itemDiv.addEventListener('dragstart', (e) => {
                        draggingItem = itemDiv;
                        itemDiv.classList.add('dragging');
                        itemDiv.style.opacity = '0.5';
                        e.dataTransfer.effectAllowed = 'move';
                    });

                    itemDiv.addEventListener('dragend', () => {
                        itemDiv.classList.remove('dragging');
                        itemDiv.style.opacity = '1';
                        draggingItem = null;
                        
                        // Update config (already handled in dragover, but good for safety)
                        [keyEnabled, keyDisabled].forEach(k => {
                            const el = document.getElementById('list-' + k);
                            if (el) {
                                const newOrder = [];
                                el.querySelectorAll('div.sortable-item').forEach(item => {
                                    newOrder.push(item.dataset.value);
                                });
                                editConfig[k] = newOrder;
                            }
                        });
                        
                        // Re-render to update styles if moved between lists
                        renderAll();
                    });

                    listDiv.appendChild(itemDiv);
                });
            };

            const renderAll = () => {
                renderList(enabledList.listDiv, keyEnabled);
                renderList(disabledList.listDiv, keyDisabled);
            };
            
            renderAll();
            return container;
        };

        // --- Helper: Interactive Keybinder ---
        const createKeybinder = () => {
            const container = document.createElement('div');
            container.style.marginBottom = '15px';
            
            const lbl = document.createElement('label');
            lbl.innerText = "Keybindings";
            lbl.style.display = 'block';
            lbl.style.fontWeight = 'bold';
            lbl.style.color = '#fff';
            lbl.style.marginBottom = '5px';
            container.appendChild(lbl);

            const desc = document.createElement('div');
            desc.innerText = "Click a button to bind a key. Press 'Backspace' to clear. 'Escape' to cancel.";
            desc.style.fontSize = '11px';
            desc.style.color = '#888';
            desc.style.marginBottom = '10px';
            desc.style.fontStyle = 'italic';
            container.appendChild(desc);

            const grid = document.createElement('div');
            grid.style.display = 'grid';
            grid.style.gridTemplateColumns = '1fr 1fr';
            grid.style.gap = '8px';
            container.appendChild(grid);

            Object.keys(editConfig.KEYS).forEach(action => {
                const row = document.createElement('div');
                row.style.display = 'flex';
                row.style.alignItems = 'center';
                row.style.justifyContent = 'space-between';
                row.style.background = '#333';
                row.style.padding = '5px 10px';
                row.style.borderRadius = '4px';
                row.style.border = '1px solid #444';

                const name = document.createElement('span');
                name.innerText = action;
                name.style.fontWeight = 'bold';
                name.style.fontSize = '12px';

                const btn = document.createElement('button');
                const updateBtnText = () => {
                    const keys = editConfig.KEYS[action];
                    btn.innerText = (keys && keys.length) ? keys[0] : '[None]';
                    btn.style.background = (keys && keys.length) ? '#555' : '#222';
                    btn.style.color = (keys && keys.length) ? '#fff' : '#888';
                };
                updateBtnText();
                
                setStyle(btn, {
                    border: '1px solid #666', padding: '4px 8px', 
                    cursor: 'pointer', borderRadius: '3px', fontSize: '11px', minWidth: '80px',
                    textAlign: 'center'
                });

                btn.onclick = () => {
                    const originalText = btn.innerText;
                    btn.innerText = 'Press Key...';
                    btn.style.background = '#d32f2f'; // Red to indicate recording
                    btn.style.color = 'white';
                    
                    const handler = (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        
                        if (e.code === 'Escape') {
                            // Cancel, do nothing to config
                        } else if (e.code === 'Backspace' || e.code === 'Delete') {
                            editConfig.KEYS[action] = [];
                        } else {
                            editConfig.KEYS[action] = [e.code];
                        }
                        
                        document.removeEventListener('keydown', handler, true);
                        updateBtnText();
                    };
                    
                    document.addEventListener('keydown', handler, { once: true, capture: true });
                };

                row.appendChild(name);
                row.appendChild(btn);
                grid.appendChild(row);
            });

            return container;
        };

        // --- Build UI ---
        modal.appendChild(createInput('Panic Threshold ($)', 'number', 'PANIC_THRESHOLD', 
            "Panic Button triggers if cash exceeds this amount."));
            
        modal.appendChild(createInput('Mobile Panic Button', 'checkbox', 'MOBILE_MODE', 
            "Fixes the Panic Button to the bottom-center of the screen for easier mobile access."));

        modal.appendChild(createInput('Hide Settings Button', 'checkbox', 'HIDE_SETTINGS_BTN', 
            "Hides the ⚙️ button from the sidebar. You can still open settings with the configured shortcut (Default: 's')."));
            
        modal.appendChild(createInput('Strict Ghost Mode', 'checkbox', 'STRICT_GHOST_MODE', 
            "If enabled, only trades with the specified keyword (default: 'Ghost') in chat are used. If disabled, ANY trade you visit is saved."));

        modal.appendChild(createInput('Ghost Keyword', 'text', 'GHOST_KEYWORD', 
            "The keyword to search for in trade (case-insensitive) when Strict Ghost Mode is enabled."));
            
        modal.appendChild(createInput('Stock', 'select', 'STOCK_ACRONYM', 
            "The stock to buy when using Stocks deposit.", STOCK_LIST));
            
        modal.appendChild(createSortableList('High Priority (Panic)', 'PRIORITY_HIGH', 
            "Drag to reorder. Priority when Cash >= Threshold.", 'PRIORITY_HIGH_DISABLED'));
            
        modal.appendChild(createSortableList('Low Priority (Button)', 'PRIORITY_LOW', 
            "Drag to reorder. Priority when Cash < Threshold (Manual).", 'PRIORITY_LOW_DISABLED'));
        
        modal.appendChild(createKeybinder());

        // Footer Buttons
        const btnDiv = document.createElement('div');
        btnDiv.style.marginTop = '20px';
        btnDiv.style.textAlign = 'right';
        btnDiv.style.borderTop = '1px solid #444';
        btnDiv.style.paddingTop = '10px';

        const saveBtn = document.createElement('button');
        saveBtn.innerText = 'Save & Reload';
        setStyle(saveBtn, { background: '#4CAF50', color: 'white', border: 'none', padding: '8px 16px', cursor: 'pointer', borderRadius: '4px', fontWeight: 'bold' });
        
        const cancelBtn = document.createElement('button');
        cancelBtn.innerText = 'Cancel';
        setStyle(cancelBtn, { background: '#666', color: 'white', border: 'none', padding: '8px 16px', cursor: 'pointer', marginRight: '10px', borderRadius: '4px' });

        cancelBtn.onclick = () => modal.remove();
        saveBtn.onclick = () => {
            CONFIG = editConfig;
            saveConfig();
            modal.remove();
        };

        btnDiv.appendChild(cancelBtn);
        btnDiv.appendChild(saveBtn);
        modal.appendChild(btnDiv);

        document.body.appendChild(modal);
    }

    // --- NETWORK INTERCEPT ---
    const intercept = (proto, method, handler) => {
        const orig = proto[method];
        proto[method] = function(...args) {
            handler(this, args);
            return orig.apply(this, args);
        };
    };

    intercept(XMLHttpRequest.prototype, 'open', (xhr, args) => xhr._url = args[1]);
    intercept(XMLHttpRequest.prototype, 'send', (xhr) => {
        xhr.addEventListener('load', () => {
            if (xhr._url?.includes('trade.php')) checkDeadTrade(xhr.responseText, xhr._url);
        });
    });

    const origFetch = window.fetch;
    window.fetch = async (...args) => {
        const res = await origFetch(...args);
        const url = args[0]?.toString() || '';
        
        if (url.match(/sidebar|user/) && res.headers.get('content-type')?.includes('json')) {
            try {
                res.clone().json().then(d => updateBalance(d?.user?.money || d?.sidebarData?.user?.money)).catch(()=>{});
            } catch (e) {}
        }
        return res;
    };

    // --- LOGIC ---
    function checkDeadTrade(text, url) {
        if (!text || text.length < 20) return;
        if (CONFIG.DEAD_SIGNALS.some(s => text.toLowerCase().includes(s))) {
            let id = null;
            if (url && url.includes('ID=')) {
                const match = url.match(/ID=(\d+)/);
                if (match) id = match[1];
            } else {
                const params = new URLSearchParams(window.location.hash.substring(1) || window.location.search);
                id = params.get('ID');
            }

            if (STATE.ghostID && id === STATE.ghostID) {
                localStorage.removeItem('torn_tactical_ghost_id');
                STATE.ghostID = null;
                injectBtn();
            }
        }
    }

    function getStatus() {
        const icons = qsa('ul[class*="status-icons"] > li');
        if (!icons.length) {
            return { faction: true, ghost: true, company: false, stocks: true, property: true, reason: "LOADING" };
        }

        let s = { faction: true, ghost: true, company: false, stocks: true, property: true, reason: "" };
        let isHosp = false, isTravel = false;

        icons.forEach(li => {
            if (li.className.match(/icon1[56]/)) isHosp = true;
            if (li.className.includes('icon71')) isTravel = true;
            if (li.className.includes('icon73')) s.company = true;
        });

        if (isHosp) { s.faction = s.company = s.stocks = s.property = false; s.reason = "HOSP/JAIL"; }
        else if (isTravel) { s.faction = s.ghost = s.company = s.stocks = s.property = false; s.reason = "TRAVEL"; }

        return s;
    }

    function updateBalance(val) {
        if (!val) return;
        const num = parseInt(typeof val === 'object' ? val.value : val);
        if (isNaN(num)) return;

        STATE.balance = num;
        const status = getStatus();
        
        // Check availability - Hide button if no options available (e.g. traveling)
        const availableOptions = Object.values(status).filter(v => v === true).length;
        if (STATE.els.btn) {
            if (availableOptions === 0 && (status.reason === "HOSP/JAIL" || status.reason === "TRAVEL")) {
                 STATE.els.btn.style.display = 'none';
            } else {
                 STATE.els.btn.style.display = 'inline-block';
            }
        }

        // Check for Stocks Back button
        const onStocks = window.location.href.includes('sid=stocks');
        let hasBackBtn = false;
        if (onStocks) {
             const buyBlock = qs('.buyBlock___bIlBS');
             if (buyBlock) {
                 const btns = buyBlock.querySelectorAll('button');
                 hasBackBtn = Array.from(btns).some(b => b.innerText.trim().toLowerCase() === 'back');
                 const confirmBtn = buyBlock.querySelector('button.buy___fcM6a');
                 const isConfirming = confirmBtn && confirmBtn.innerText.toLowerCase().includes('confirm');
                 if (isConfirming) hasBackBtn = false;
             }
        }

        if (STATE.balance <= 0) {
            STATE.locks.sending = false;
            dismissPanic();
        } else if (STATE.balance >= CONFIG.PANIC_THRESHOLD && STATE.panic) {
            if (!STATE.locks.panic) triggerPanic();
            else updateOverlay();
        } else if (STATE.locks.panic) {
             dismissPanic();
        }
        if (STATE.locks.panic) updateOverlay();
    }

    function triggerPanic() {
        if (!STATE.panic || STATE.balance < CONFIG.PANIC_THRESHOLD) return;
        const s = getStatus();
        if (s.reason === 'LOADING') {
             setTimeout(triggerPanic, 500);
             return; 
        }
        
        let available = false;
        for (const type of CONFIG.PRIORITY_HIGH) {
            if (type === 'GHOST' && STATE.ghostID && s.ghost) { available = true; break; }
            if (type === 'COMPANY' && s.company) { available = true; break; }
            if (type === 'FACTION' && s.faction) { available = true; break; }
            if (type === 'STOCKS' && s.stocks) { available = true; break; }
            if (type === 'PROPERTY' && s.property) { available = true; break; }
        }
        
        if (!available) return;
        STATE.locks.panic = true;
        updateOverlay();
    }

    function dismissPanic() {
        STATE.locks.panic = false;
        STATE.locks.sending = false;
        if (STATE.els.overlay) STATE.els.overlay.style.display = 'none';
    }

    async function executeDeposit(mode = 'auto') {
        const box = Array.from(qsa('.cash-confirm')).find(b => b.offsetParent && b.style.display !== 'none');
        if (box) {
            if (box.querySelector('.yes')) {
                if (STATE.els.overlay) STATE.els.overlay.innerHTML = "DEPOSITING...";
                box.querySelector('.yes').click();
                STATE.locks.sending = false;
                return;
            }
        }

        if (!box && STATE.locks.sending) STATE.locks.sending = false;
        if (STATE.locks.sending) return;
        const status = getStatus();

        const currentPriority = (STATE.balance >= CONFIG.PANIC_THRESHOLD) ? CONFIG.PRIORITY_HIGH : CONFIG.PRIORITY_LOW;

        let target = mode;
        if (mode === 'auto') {
            for (const type of currentPriority) {
                if (type === 'GHOST' && STATE.ghostID && status.ghost) { target = 'ghost'; break; }
                if (type === 'COMPANY' && status.company) { target = 'company'; break; }
                if (type === 'FACTION' && status.faction) { target = 'faction'; break; }
                if (type === 'STOCKS' && status.stocks) { target = 'stocks'; break; }
                if (type === 'PROPERTY' && status.property) { target = 'property'; break; }
            }
            if (!target) return;
        }

        if (target === 'ghost') {
            if (!STATE.ghostID || !status.ghost) {
                 if (mode === 'ghost') return;
                 target = status.company ? 'company' : (status.faction ? 'faction' : (status.stocks ? 'stocks' : (status.property ? 'property' : null)));
            }
        }
        if (target === 'company' && !status.company) {
            if (mode !== 'auto') return;
            target = status.faction ? 'faction' : (status.stocks ? 'stocks' : (status.property ? 'property' : null));
        }
        if (target === 'faction' && !status.faction) {
             if (mode !== 'auto') return;
             target = status.stocks ? 'stocks' : (status.property ? 'property' : null);
        }
        if (target === 'property' && !status.property) {
             if (mode !== 'auto') return;
             target = null;
        }
        if (!target) return;

        const setVal = (input, val) => {
            const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
            if (setter) setter.call(input, val);
            else input.value = val;
            input.dispatchEvent(new Event('input', { bubbles: true }));
            input.dispatchEvent(new Event('change', { bubbles: true }));
            input.dispatchEvent(new Event('blur', { bubbles: true }));
        };

        const jump = (url, msg) => {
            if (STATE.locks.jumping) return;
            STATE.locks.jumping = true;
            if (STATE.els.overlay) STATE.els.overlay.innerHTML = msg;
            setTimeout(() => STATE.locks.jumping = false, 1500);
            window.location.href = url;
        };

        if (target === 'ghost') {
            const url = window.location.href;
            const onPageWithID = url.includes('trade.php') && url.includes(STATE.ghostID);
            const input = qs('.input-money[type="text"]');

            if (!onPageWithID || !input) {
                return jump(`https://www.torn.com/trade.php#step=addmoney&ID=${STATE.ghostID}`, "JUMPING<br>TO GHOST");
            }

            STATE.locks.sending = true;
            if (STATE.els.overlay) STATE.els.overlay.innerHTML = "DEPOSITING<br>TO GHOST";
            setVal(input, input.getAttribute('data-money') || STATE.balance);

            const btn = input.form?.querySelector('input[type="submit"], button[type="submit"]') || qs('input[type="submit"][value="Change"], button[type="submit"][value="Change"]');
            if (btn) {
                btn.disabled = false;
                btn.classList.remove('disabled');
                btn.click();
                STATE.locks.jumping = false;
            } else STATE.locks.sending = false;

        } else if (target === 'company') {
            const url = window.location.href;
            const onPage = url.includes('companies.php') && url.includes('option=funds');
            const input = qs('input[aria-labelledby="deposit-label"][type="text"]');

            if (!input) {
                if (!onPage) return jump(`https://www.torn.com/companies.php?step=your&type=1#/option=funds`, "JUMPING<br>TO COMPANY");
                return;
            }

            STATE.locks.sending = true;
            if (STATE.els.overlay) STATE.els.overlay.innerHTML = "DEPOSITING<br>TO COMPANY";
            setVal(input, input.getAttribute('data-money') || STATE.balance);
            const container = input.closest('.funds-cont');
            const btn = container ? container.querySelector('.deposit.btn-wrap button') : null;
            if (btn) {
                btn.disabled = false;
                btn.click();
            } else STATE.locks.sending = false;

        } else if (target === 'stocks') {
            const url = window.location.href;
            const onPage = url.includes('page.php') && url.includes('sid=stocks');
            const acronym = CONFIG.STOCK_ACRONYM || "EVL";
            const stockRow = Array.from(qsa('li.stockName___tLa3y')).find(li => li.querySelector(`span[data-acronym="${acronym}"]`));

            if (!stockRow) {
                if (!onPage) return jump(`https://www.torn.com/page.php?sid=stocks`, "JUMPING<br>TO STOCKS");
                return;
            }

            const parentUl = stockRow.closest('ul.stock___ElSDB');
            if (!parentUl) return;
            const ownedTab = parentUl.querySelector('li.stockOwned___eXJed');
            if (!ownedTab) return;

            const expanded = ownedTab.getAttribute('aria-expanded') === 'true' || ownedTab.classList.contains('active___IUYLC');
            if (!expanded) {
                if (STATE.locks.sending) return;
                STATE.locks.sending = true;
                ownedTab.click();
                setTimeout(() => STATE.locks.sending = false, 500);
                return;
            }

            let visibleBuyBlock = null;
            const panelId = ownedTab.getAttribute('aria-controls');
            if (panelId) {
                const panel = document.getElementById(panelId);
                if (panel && panel.offsetParent !== null) visibleBuyBlock = panel.querySelector('.buyBlock___bIlBS');
            }
            if (!visibleBuyBlock && parentUl) {
                let next = parentUl.nextElementSibling;
                for (let i = 0; i < 3 && next; i++) {
                    if (next.classList.contains('stockDropdown___Y2X_v')) {
                         if (next.offsetParent !== null) visibleBuyBlock = next.querySelector('.buyBlock___bIlBS');
                        if (visibleBuyBlock) break;
                    }
                    next = next.nextElementSibling;
                }
            }
            if (!visibleBuyBlock) {
                let next = ownedTab.nextElementSibling;
                for (let i = 0; i < 3 && next; i++) {
                        if (next.classList.contains('stockDropdown___Y2X_v') || next.querySelector('.buyBlock___bIlBS')) {
                            if (next.offsetParent !== null) visibleBuyBlock = next.querySelector('.buyBlock___bIlBS');
                        if (visibleBuyBlock) break;
                    }
                    next = next.nextElementSibling;
                }
            }

            if (!visibleBuyBlock) {
                if (STATE.els.overlay) STATE.els.overlay.innerHTML = "OPENING...";
                return;
            }

            const backBtn = Array.from(visibleBuyBlock.querySelectorAll('button')).find(b => b.innerText.trim().toLowerCase() === 'back');
            const confirmBtn = visibleBuyBlock.querySelector('button.buy___fcM6a');
            const isConfirming = confirmBtn && confirmBtn.innerText.toLowerCase().includes('confirm');

            if (backBtn && !isConfirming) {
                 if (STATE.balance <= 0) {
                     dismissPanic();
                     return;
                 }
                 STATE.locks.sending = true;
                 if (STATE.els.overlay) STATE.els.overlay.innerHTML = "CONFIRMED";
                 robustClick(backBtn);
                 setTimeout(() => STATE.locks.sending = false, 200);
                 return;
            }

            const currentBtn = visibleBuyBlock.querySelector('button.buy___fcM6a');
            if (currentBtn) {
                const text = (currentBtn.innerText || currentBtn.textContent).trim();
                if (text.toLowerCase().includes("price updating")) {
                    if (STATE.els.overlay) STATE.els.overlay.innerHTML = "UPDATING...";
                    return; 
                }
                if (text.toLowerCase().includes("confirm")) {
                    STATE.locks.sending = true;
                    if (STATE.els.overlay) STATE.els.overlay.innerHTML = "CONFIRMING...";
                    robustClick(currentBtn);
                    return;
                }
            }

            const maxBtn = visibleBuyBlock.querySelector('.wai-btn') || visibleBuyBlock.querySelector('.input-money-symbol');
            const buyInput = visibleBuyBlock.querySelector('input.input-money[type="text"]') || visibleBuyBlock.querySelector('input.input-money:not([type="hidden"])');
            if (!currentBtn) return; 

            STATE.locks.sending = true;
            if (STATE.els.overlay) STATE.els.overlay.innerHTML = `BUYING<br>${acronym}`;

            if (maxBtn) {
                maxBtn.click();
            } else if (buyInput) {
                const maxShares = buyInput.getAttribute('data-money');
                if (maxShares) setVal(buyInput, maxShares);
            }
            robustClick(currentBtn);
            setTimeout(() => STATE.locks.sending = false, 200);
            return;

        } else if (target === 'property') {
            const url = window.location.href;
            const onPage = url.includes('properties.php') && url.includes('tab=vault');
            if (!onPage) {
                 if (url.includes('properties.php')) return jump(url.split('#')[0] + '#/p=options&tab=vault', "JUMPING<br>TO PROPERTY");
                 return jump(`https://www.torn.com/properties.php#/p=options&tab=vault`, "JUMPING<br>TO PROPERTY");
            }

            const inputs = Array.from(qsa('input.input-money'));
            let input = null;
            for (const inp of inputs) {
                const form = inp.closest('form');
                if (form && form.innerText.toLowerCase().includes('deposit')) {
                    input = inp;
                    break;
                }
                const container = inp.closest('div');
                if (container && container.parentElement.innerText.toLowerCase().includes('deposit')) {
                    input = inp;
                    break;
                }
            }
            if (!input && inputs.length > 0) input = inputs[0];
            if (!input) return;

            STATE.locks.sending = true;
            if (STATE.els.overlay) STATE.els.overlay.innerHTML = "DEPOSITING<br>TO PROPERTY";
            setVal(input, STATE.balance);
            const btn = input.form?.querySelector('button, input[type="submit"]') || input.closest('div').parentElement.querySelector('button');
            if (btn) {
                btn.disabled = false;
                btn.click();
            } else STATE.locks.sending = false;

        } else { // Faction
            const form = qs('.give-money-form') || qs('.input-money')?.closest('form');
            const currentUrl = window.location.href;
            const isFactionArmoury = currentUrl.includes('factions.php') && currentUrl.includes('step=your') && currentUrl.includes('tab=armoury');
            const isDonateSub = currentUrl.includes('sub=donate');

            if (!form) {
                if (!isFactionArmoury || !isDonateSub) {
                    return jump(`https://www.torn.com/factions.php?step=your#/tab=armoury&sub=donate`, "JUMPING<br>TO FACTION");
                }
                return;
            }

            const input = form.querySelector('.input-money');
            if (!input) return;

            STATE.locks.sending = true;
            if (STATE.els.overlay) STATE.els.overlay.innerHTML = "DEPOSITING<br>TO FACTION";

            let amt = input.getAttribute('data-money');
            if (!amt) {
                const txt = form.querySelector('.i-have')?.innerText.replace(/[$,]/g, '');
                if (txt && !isNaN(txt)) amt = txt;
            }
            setVal(input, amt || STATE.balance);
            const btn = form.querySelector('button.torn-btn');
            if (btn) {
                btn.disabled = false;
                btn.click();
            } else STATE.locks.sending = false;
        }
    }

    // UI COMPONENTS
    function showToast(html) {
        const t = document.createElement('div');
        t.innerHTML = `<div style="font-size:11px;color:#aaa;margin-bottom:4px;text-transform:uppercase;">Quick Deposit</div>${html}`;
        setStyle(t, {
            position: 'fixed', top: '15%', left: '50%', transform: 'translate(-50%, -50%)',
            zIndex: 2147483647, background: 'rgba(0,0,0,0.85)', color: 'white',
            padding: '12px 24px', borderRadius: '8px', pointerEvents: 'none',
            opacity: 0, transition: 'opacity 0.3s', textAlign: 'center', border: '1px solid #ffffff33'
        });
        document.body.appendChild(t);
        requestAnimationFrame(() => t.style.opacity = '1');
        setTimeout(() => { t.style.opacity = '0'; setTimeout(() => t.remove(), 300); }, 2000);
    }

    function updateOverlay() {
        if (!STATE.locks.panic || STATE.balance <= 0) return dismissPanic();

        if (!STATE.els.overlay) {
            const d = document.createElement('div');
            d.id = 'torn-panic-overlay';
            let css = `position: fixed; z-index: 2147483647; background: rgba(255, 0, 0, 0.9); color: white;
                font-family: 'Arial Black', sans-serif; font-size: 14px; text-align: center;
                padding: 10px 20px; border-radius: 30px; border: 3px solid white;
                box-shadow: 0 0 20px red; cursor: pointer; white-space: nowrap; user-select: none;`;

            if (CONFIG.MOBILE_MODE) {
                css += `bottom: 80px; left: 50%; transform: translateX(-50%);`;
            } else {
                css += `top: -999px; left: -999px; transform: translate(-50%, -50%);`;
            }

            d.style.cssText = css;
            d.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); executeDeposit('auto'); });

            if (!CONFIG.MOBILE_MODE) {
                document.addEventListener('mousemove', e => {
                    if (STATE.locks.panic) {
                        d.style.left = e.clientX + 'px';
                        d.style.top = e.clientY + 'px';
                    }
                });
            }
            document.body.appendChild(d);
            STATE.els.overlay = d;
        }

        STATE.els.overlay.style.display = 'block';
        if (STATE.locks.sending || STATE.locks.jumping) return;

        let txt = "JUMP TO<br>FACTION";
        if (qs('.cash-confirm')) {
            txt = "CONFIRM<br>DEPOSIT";
        } else {
            const s = getStatus();
            let target = null;
            const currentPriority = (STATE.balance >= CONFIG.PANIC_THRESHOLD) ? CONFIG.PRIORITY_HIGH : CONFIG.PRIORITY_LOW;

            for (const type of currentPriority) {
                if (type === 'GHOST' && STATE.ghostID && s.ghost) { target = 'GHOST'; break; }
                if (type === 'COMPANY' && s.company) { target = 'COMPANY'; break; }
                if (type === 'FACTION' && s.faction) { target = 'FACTION'; break; }
                if (type === 'STOCKS' && s.stocks) { target = 'STOCKS'; break; }
                if (type === 'PROPERTY' && s.property) { target = 'PROPERTY'; break; }
            }

            if (target === 'GHOST') {
                const hashParams = new URLSearchParams(window.location.hash.substring(1));
                const searchParams = new URLSearchParams(window.location.search);
                const currentStep = hashParams.get('step') || searchParams.get('step');
                const currentID = hashParams.get('ID') || searchParams.get('ID');
                const onGhostPage = window.location.href.includes('trade.php') && currentStep === 'addmoney' && currentID === STATE.ghostID;
                txt = onGhostPage ? `DEPOSIT<br>${fmt(STATE.balance)}<br><span style='font-size:10px'>GHOST</span>` : "JUMP TO<br>GHOST";

            } else if (target === 'COMPANY') {
                const onCompanyPage = window.location.href.includes('companies.php') && window.location.href.includes('option=funds');
                const container = qs('.funds-cont');
                const ready = onCompanyPage && (container || document.readyState === 'loading');
                txt = ready ? `DEPOSIT<br>${fmt(STATE.balance)}<br><span style='font-size:10px'>COMPANY</span>` : "JUMP TO<br>COMPANY";

            } else if (target === 'STOCKS') {
                const onStocksPage = window.location.href.includes('page.php') && window.location.href.includes('sid=stocks');
                const acronym = CONFIG.STOCK_ACRONYM || "EVL";
                const stockRow = onStocksPage ? Array.from(qsa('li.stockName___tLa3y')).find(li => li.querySelector(`span[data-acronym="${acronym}"]`)) : null;
                const ready = onStocksPage; 

                if (ready) {
                     if (stockRow) {
                         const buyBlock = qs('.buyBlock___bIlBS');
                         let isBack = false;
                         let isConfirm = false;
                         if (buyBlock) {
                             const btns = buyBlock.querySelectorAll('button');
                             isBack = Array.from(btns).some(b => b.innerText.trim().toLowerCase() === 'back');
                             const confirmBtn = buyBlock.querySelector('button.buy___fcM6a');
                             isConfirm = confirmBtn && confirmBtn.innerText.toLowerCase().includes('confirm');
                         }
                         if (isConfirm) {
                             txt = "CONFIRM<br>STOCKS";
                         } else {
                             txt = (isBack && !isConfirm) ? "CONFIRMED" : `BUY ${acronym}<br>${fmt(STATE.balance)}`;
                         }
                     } else {
                         txt = `LOADING<br>STOCKS`;
                     }
                } else {
                    txt = "JUMP TO<br>STOCKS";
                }

            } else if (target === 'PROPERTY') {
                const onPropertyPage = window.location.href.includes('properties.php') && window.location.href.includes('tab=vault');
                const hasInput = !!qs('input.input-money');
                txt = (onPropertyPage && hasInput) ? `DEPOSIT<br>${fmt(STATE.balance)}<br><span style='font-size:10px'>PROPERTY</span>` : "JUMP TO<br>PROPERTY";

            } else {
                const current = window.location.href;
                const onFactionPage = current.includes('factions.php') && current.includes('step=your') && current.includes('tab=armoury') && current.includes('sub=donate');
                const form = qs('.give-money-form');
                const ready = form || onFactionPage;
                txt = ready ? `DEPOSIT<br>${fmt(STATE.balance)}` : "JUMP TO<br>FACTION";
            }
        }
        if (STATE.els.overlay.innerHTML !== txt) STATE.els.overlay.innerHTML = txt;
    }

    function injectBtn() {
        const moneyEl = document.getElementById('user-money');
        if (!moneyEl) return;

        // Cleanup
        const existing = document.querySelectorAll('#torn-tactical-deposit');
        existing.forEach(el => { if (el !== STATE.els.btn) el.remove(); });
        const existingSet = document.querySelectorAll('#torn-tactical-settings');
        existingSet.forEach(el => { if (el !== STATE.els.settingsBtn) el.remove(); });

        if (!STATE.els.btn) {
            const b = document.createElement('a');
            b.id = 'torn-tactical-deposit';
            b.href = '#';
            b.style.marginLeft = '5px';
            b.style.cursor = 'pointer';
            b.className = 'use___wM1PI';
            b.addEventListener('click', (e) => { e.preventDefault(); executeDeposit('auto'); });
            STATE.els.btn = b;
        }

        if (!STATE.els.settingsBtn) {
            const s = document.createElement('a');
            s.id = 'torn-tactical-settings';
            s.href = '#';
            s.innerHTML = '⚙️';
            s.style.marginLeft = '10px';
            s.style.cursor = 'pointer';
            s.style.fontSize = '12px';
            s.style.textDecoration = 'none';
            s.title = 'Quick Deposit Settings';
            s.addEventListener('click', (e) => { 
                e.preventDefault(); 
                const m = document.getElementById('torn-deposit-settings-modal');
                if (m) m.remove();
                else openSettingsModal();
            });
            STATE.els.settingsBtn = s;
        }

        if (moneyEl.parentNode) {
            // 1. Handle Settings Button
            const showSettings = !CONFIG.HIDE_SETTINGS_BTN || I_MESSED_UP;
            if (showSettings) {
                // Ensure settingsBtn is strictly after moneyEl
                if (moneyEl.nextSibling !== STATE.els.settingsBtn) {
                    moneyEl.parentNode.insertBefore(STATE.els.settingsBtn, moneyEl.nextSibling);
                }
            } else {
                if (STATE.els.settingsBtn.parentNode) STATE.els.settingsBtn.remove();
            }
            
            // 2. Handle Deposit Button
            // It should be after the "Anchor" (which is settingsBtn if visible, else moneyEl)
            const anchor = (showSettings && STATE.els.settingsBtn.parentNode) ? STATE.els.settingsBtn : moneyEl;
            
            // We want STATE.els.btn to be immediately after anchor.
            if (anchor.nextSibling !== STATE.els.btn) {
                anchor.parentNode.insertBefore(STATE.els.btn, anchor.nextSibling);
            }
        }

        const s = getStatus();
        let txt = '[deposit]', title = 'Vault Deposit';
        const currentPriority = (STATE.balance >= CONFIG.PANIC_THRESHOLD) ? CONFIG.PRIORITY_HIGH : CONFIG.PRIORITY_LOW;

        for (const type of currentPriority) {
            if (type === 'GHOST' && STATE.ghostID) { txt = '[ghost]'; title = `Ghost ID: ${STATE.ghostID}`; break; }
            if (type === 'COMPANY' && s.company) { txt = '[company]'; title = "Company Vault"; break; }
            if (type === 'FACTION' && s.faction) { txt = '[deposit]'; title = "Faction Vault"; break; }
            if (type === 'STOCKS' && s.stocks) { txt = '[stocks]'; title = `Buy ${CONFIG.STOCK_ACRONYM || "EVL"} Stocks`; break; }
            if (type === 'PROPERTY' && s.property) { txt = '[property]'; title = "Property Vault"; break; }
        }

        if (STATE.els.btn.innerText !== txt) STATE.els.btn.innerText = txt;
        if (STATE.els.btn.title !== title) STATE.els.btn.title = title;
    }

    // EVENT LISTENERS
    window.addEventListener('keydown', e => {
        if (!e.isTrusted || e.target.matches('input, textarea') || e.target.isContentEditable) return;
        const k = e.code;
        const isKey = (type) => CONFIG.KEYS[type] && CONFIG.KEYS[type].includes(k);
        if (Object.values(CONFIG.KEYS).flat().includes(k)) e.preventDefault();

        if (isKey('FACTION')) executeDeposit('faction');
        if (isKey('GHOST') && STATE.ghostID) executeDeposit('ghost');
        if (isKey('COMPANY')) executeDeposit('company');
        if (isKey('STOCKS')) executeDeposit('stocks');
        if (isKey('PROPERTY')) executeDeposit('property');
        if (isKey('EXECUTE')) executeDeposit('auto');
        if (isKey('SETTINGS')) {
            const m = document.getElementById('torn-deposit-settings-modal');
            if (m) m.remove();
            else openSettingsModal();
        }
        if (isKey('RESET')) {
            localStorage.removeItem('torn_tactical_ghost_id');
            STATE.ghostID = null;
            injectBtn();
            showToast("GHOST ID CLEARED");
        }
        if (isKey('PANIC')) {
            STATE.panic = !STATE.panic;
            localStorage.setItem('torn_tactical_panic_enabled', STATE.panic);
            showToast(`PANIC MODE <span style="color:${STATE.panic?'#4dff4d':'#ff4d4d'}">${STATE.panic?'ON':'OFF'}</span>`);
            if (STATE.panic) updateBalance(STATE.balance);
            else dismissPanic();
        }
    });

    window.addEventListener('hashchange', () => {
        if (STATE.locks.jumping && STATE.ghostID && window.location.href.includes(STATE.ghostID)) STATE.locks.jumping = false;
        if (STATE.locks.panic) updateOverlay();
    });

    const scanTrades = () => {
        if (!window.location.href.includes('trade.php')) return;
        const params = new URLSearchParams(window.location.hash.substring(1) || window.location.search);
        const currentID = params.get('ID');

        if (qs('.info-msg, .error-msg')?.innerText.match(new RegExp(CONFIG.DEAD_SIGNALS.join('|'), 'i'))) {
            if (STATE.ghostID && currentID === STATE.ghostID) {
                STATE.ghostID = null; localStorage.removeItem('torn_tactical_ghost_id'); injectBtn();
            }
            return;
        }

        if (currentID) {
            const logs = qsa('ul.log .msg');
            const keyword = String(CONFIG.GHOST_KEYWORD || "ghost").toLowerCase();
            let isGhost = false;
            
            if (!CONFIG.STRICT_GHOST_MODE) {
                isGhost = true;
            } else {
                isGhost = Array.from(logs).some(msg => {
                    const clone = msg.cloneNode(true);
                    clone.querySelector('a')?.remove();
                    return clone.innerText.toLowerCase().includes(keyword);
                });
            }

            if (isGhost && !STATE.ghostID) {
                STATE.ghostID = currentID;
                localStorage.setItem('torn_tactical_ghost_id', currentID);
                injectBtn();
                if (STATE.panic && STATE.balance >= CONFIG.PANIC_THRESHOLD) triggerPanic();
            }
        }

        if (!currentID && !STATE.ghostID) {
            const keyword = String(CONFIG.GHOST_KEYWORD || "ghost").toLowerCase();
            qsa('ul.trade-list-container > li').forEach(li => {
                const clone = li.cloneNode(true);
                clone.querySelector('.user.name')?.remove();
                if (!CONFIG.STRICT_GHOST_MODE || clone.innerText.toLowerCase().includes(keyword)) {
                    const mid = li.querySelector('a.btn-wrap')?.href.match(/ID=(\d+)/);
                    if (mid) {
                        STATE.ghostID = mid[1];
                        localStorage.setItem('torn_tactical_ghost_id', mid[1]);
                        injectBtn();
                        if (STATE.panic && STATE.balance >= CONFIG.PANIC_THRESHOLD) triggerPanic();
                    }
                }
            });
        }
    };

    let mutationTimeout = null;
    const observerCallback = (mutations) => {
        let ignore = true;
        for (const m of mutations) {
            const isElement = m.target.nodeType === 1;
            const targetId = isElement ? m.target.id : '';
            
            if (isElement && (targetId === 'user-money' || m.target.closest?.('#user-money'))) {
                const moneyEl = document.getElementById('user-money');
                if (moneyEl) {
                    const val = moneyEl.getAttribute('data-money') || moneyEl.innerText.replace(/[^\d]/g, '');
                    if (val) updateBalance(val);
                }
                ignore = false;
            }
            if (isElement && (m.target.closest?.('ul[class*="status-icons"]'))) {
                if (STATE.panic && STATE.balance >= CONFIG.PANIC_THRESHOLD) {
                    triggerPanic();
                }
                ignore = false;
            }

            if (!targetId?.includes('torn-') &&
                (!isElement || !m.target.closest?.('#torn-tactical-deposit')) &&
                (!isElement || !m.target.closest?.('#torn-panic-overlay')) &&
                (!isElement || !m.target.closest?.('#torn-deposit-settings-modal')) && // Ignore settings modal
                (!isElement || !m.target.closest?.('#torn-tactical-settings'))) {
                ignore = false;
                break;
            }
        }
        if (ignore) return;

        if (mutationTimeout) clearTimeout(mutationTimeout);
        mutationTimeout = setTimeout(() => {
            injectBtn();
            scanTrades();
            const moneyEl = document.getElementById('user-money');
            if (moneyEl) {
                 const val = moneyEl.getAttribute('data-money') || moneyEl.innerText.replace(/[^\d]/g, '');
                 if (val) updateBalance(val);
            }
            if (STATE.panic && STATE.balance >= CONFIG.PANIC_THRESHOLD) triggerPanic();
        }, 50);
    };

    let init = false;
    const start = () => {
        if (init) return;
        init = true;
        const moneyEl = document.getElementById('user-money');
        if (moneyEl) {
            const val = moneyEl.getAttribute('data-money') || moneyEl.innerText.replace(/[^\d]/g, '');
            if (val) updateBalance(val);
        }
        new MutationObserver(observerCallback).observe(document, { childList: true, subtree: true });
        if (moneyEl) injectBtn();
    };

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

})();